1

Clone

In the manual page for clone()/clone3() system call I find:

CLONE_THREAD (since Linux 2.4.0).

If CLONE_THREAD is set, the child is placed in the same thread group as the calling process. To make the remainder of the discussion of CLONE_THREAD more readable, the term "thread" is used to refer to the processes within a thread group.

So, as I understand, from the clone's perspective, a thread is something that was created with the CLONE_THREAD flag set (and, thus, ended up in the same thread group as the caller).

Futex

But looking at, for instance, the manual page for futex(), I find:

FUTEX_PRIVATE_FLAG (since Linux 2.6.22)

This option bit can be employed with all futex operations. It tells the kernel that the futex is process-private and not shared with another process (i.e., it is being used for synchronization only between threads of the same process). This allows the kernel to make some additional performance optimizations.

This seems to relate with the definition of clone, but not quite. When a thread (as in clone is created (that is, the CLONE_THREAD flag is specified), the created tasks also have to share their VM. However, it is possible to create two tasks which are not threads (as in clone), which would still sharing VM (just specifying CLONE_VM). But, judging by the FUTEX : new PRIVATE futexes article/patch, the optimization used for _PRIVATE futexes is that the virtual address of a futex word are used rather than the physical ones, so, one could probably use private futexes in tasks created with CLONE_VM... but the man for futex() forbids that.

That is not a critical issue, though: the manual imposes a (seemingly unnecessary) restriction but it doesn't break anything. So, here goes a more thrilling example.

Close

From the manual for the close() system call:

Furthermore, consider the following scenario where two threads are performing operations on the same file descriptor:

(1) One thread is blocked in an I/O system call on the file descriptor. For example, it is trying to write(2) to a pipe that is already full, or trying to read(2) from a stream socket which currently has no available data.

(2) Another thread closes the file descriptor.

The behavior in this situation varies across systems. <...>

Clearly, it is assumed here that the two tasks share a file descriptor table, but being threads (as in clone) is neither necessary nor sufficient to claim they do!

If a task is created with CLONE_THREAD|...|CLONE_FILES, it's all good, but if it's just CLONE_THREAD|... (which is allowed), the two threads (as in clone) do not share file descriptors, and the tasks cloned with ...|CLONE_FILES are not threads but do share file descriptors!

Question

First of all, is this (at least the close() example) a bug in the manual? Is it because it was written before the clone() system call was designed? Or am I missing something?

In general: when using a particular system call that has the term "thread" used in its manual, how do I tell what's implied?

In particular (assuming I want to write code that will work on future kernel versions): would it be ok to use private futexes in tasks that share VM but are not threads (as in clone)? Would it be ok thread-safe to call close in threads (as in clone) that do not share file descriptor tables, as the common sense suggests?

ilkkachu
  • 138,973
Kolay.Ne
  • 166
  • @Kolay.Ne, it's not the exact same quote, even if it's from the same part of the same man page. The text you have bolded there doesn't appear in the linked one, and the other one has an explanation in the end that doesn't appear in your quote. Probably due to differences between versions of the man page. The background to the confusing in terminology is there in the linked Q and A (and linked articles), though you may want to read the other answers too, not just the one that was linked to directly. – ilkkachu Jul 22 '23 at 16:13

1 Answers1

1

2.4 was the Linux version that introduced "threads" as we know them (discussed here). And CLONE_THREAD is the flag to ask clone() for a thread instead of a process.

Prior to 2.4 Linux only had "processes"... and the word "thread" was historically used to refer to any parallel execution. So historically a process was a form of thread.

The wording in the clone page can be read as explaining the new concept of threads (as we know them now) to an audience that understood everything is a process. As such this clone() wording is very out dated. But not "wrong".

That is, this phrase introduces the new term "thread" to an audience that only had processes.

the term "thread" is used to refer to the processes within a thread group.

But this precise definition is explicitly only valid for the discussion of CLONE_THREAD for clone():

To make the remainder of the discussion of CLONE_THREAD more readable

Elsewhere you should assume "thread" is as it's understood in POSIX and common technical language: IE that it also implies threads in the same process share memory (CLONE_VM) and share file descriptors (CLONE_FILES) etc.

Unless the documentation explicitly discusses specific clone flags in other sys calls, you should not use the term "thread" in documentation to reason on what will happen if some but not all such flags are set. Such behaviour may be considered "undefined".


Just to be confusing... The Linux community still retains echos of a time when there was no distinction, and "thread" still gets (erroneously) used to mean process... I know of no other system call documentation example of that.

  • From the discussion in the linked Q&A (and some other sources there), I gather that it's more a distinction between the terminology within the Linux kernel implementation (thread groups that contain processes), vs. the more usual terminology used, well, everywhere else, including the Linux userspace (processes containing threads) rather than a distinction between old and new. Though of course the history of the old non-POSIX implementation in Linux is the background to all that. – ilkkachu Jul 22 '23 at 16:37
  • 1
    The actual current Linux implementation doesn't exactly fit the common processes/threads terminology, since (as the Q says), there's no strict division between the two wrt. sharing VM and fds etc. so you can have distinct "processes" that share some things, or "threads" that don't. (I'd have to check the details.) The clone() man page likely uses different terminology exactly because it describes the Linux implementation, while the others assume the more commonly used terminology. – ilkkachu Jul 22 '23 at 16:38
  • Okay, thank you for the historical context. However, this still does not help me in understanding manuals for system calls that don't have to do with threads creation. For instance, a practical question that I might have: if I use a futex to synchronize tasks that were created with CLONE_VM and without CLONE_THREAD, would it be safe (and, preferably, portable to future Linux versions) to use _PRIVATE futex operations in that case? – Kolay.Ne Jul 22 '23 at 16:55
  • @Kolay.Ne now I re-read everything and your question I think the posix definition should be taken elsewhere. Thus whatever flags pthread_create passes in Linux implementations. I don't have that list. Beyond that read mix/match flags as undefined or undocumented. – Philip Couling Jul 22 '23 at 18:02