[go: up one dir, main page]

|
|
Log in / Subscribe / Register

Toward race-free process signaling

Toward race-free process signaling

Posted Dec 12, 2018 5:43 UTC (Wed) by kmeyer (subscriber, #50720)
In reply to: Toward race-free process signaling by nybble41
Parent article: Toward race-free process signaling

> That would also work, but no, I meant "integers". I suppose some would say that the file descriptor *is* the integer, and representationally that's often true, but to me the term refers conceptually to an active entry in the file descriptor table (a particular file/pipe/socket/device, set of flags, position, etc.), and the integer is just the index into the table.

Ok — this might just be a terminology difference between FreeBSD and Linux. In FreeBSD, file descriptors are definitely integers. They index a per-process table of 'struct filedescent's named the 'fdescenttbl.' Each filedescent has a 'struct file' pointer, 'struct filecaps', flags, and a sequence number associated with it.

The 'struct file' tracks things like 'f_type' (DTYPE_VNODE for regular files, DTYPE_SOCKET, DTYPE_PIPE, DTYPE_KQUEUE, etc); 'fileops' (file-level vtable of operations); file-associated credentials; associated 'struct vnode' (inode in Linux terminology), if any; the file offset (for operations like read(2) or write(2) that don't take an explicit offset); etc.

So you can understand my confusion — we would call what you're talking about a 'filedescent' or just 'file'.

> all file descriptors have unique integer identifiers within a process

Ok, definitely 'filedescent' in our terminology, rather than 'file' (which would be shared by a dup(2)ed fd).

> Outside the process, however, you need some other way to identify the state that a file descriptor stands for; the index alone, without context, isn't enough.

Sure. That state can be passed between processes using unix domain sockets and control messages, though. That's not as frictionless as copying and pasting some pid number between arbitrary processes, but it's not like the credential is locked to the original process exclusively.

> How exactly does one pass a file descriptor to or from a shell script using Unix-domain sockets, for example?

It could readily be done with an extension builtin, or a helper program. (Or something crazy like ctypes.sh.) Yeah, it's higher friction than just passing around some integer. On the flip side, it works without increasing pid space to 64 bits.

> It also doesn't address the use case of serializing the identifier to a file, where there may not be any process running to hold the file descriptor open.

I'm not sure it's reasonable to serialize a process handle of any kind to a file and expect it to be meaningful later. Say your file is on NFS, or backed up to a remote system. Or even a local filesystem, but the machine has been rebooted. I'm not overly concerned with not handling that case.

Thanks for the discussion, it's been interesting and given me some food for thought.


to post comments

Toward race-free process signaling

Posted Dec 12, 2018 22:34 UTC (Wed) by nybble41 (subscriber, #55106) [Link] (2 responses)

> In FreeBSD, file descriptors are definitely integers. They index a per-process table of 'struct filedescent's named the 'fdescenttbl.'

So to unpack the abbreviations a bit, you're saying that in FreeBSD, "file descriptors" are integers which identify "file descriptor entry" structures in a per-process "file descriptor entry table". I can see how that would be confusing.

I'm not sure it's a FreeBSD vs. Linux thing, but to me including "entry" in the name of the type for the elements of an array seems a bit awkward. I would just say "file descriptor table" for the array, and the elements of the array ("file descriptor table entries") would simply be referred to as "file descriptors". If the "file descriptor" is a member of the current process's "file descriptor table", as is usually the case, then it can be referred to simply by its index in the table (its "file descriptor number"). One might casually refer to this as "passing a file descriptor" when one is really just passing the index of the file descriptor, much like "passing an object" usually just means passing the address of the object.

(BTW, note the terminology in that document you linked to: "Passing File Descriptors over UNIX Domain Sockets". It is not the *integer* which is being passed over the socket—the receiving process will most likely get a different integer—but rather the object which the integer refers to.)

>> How exactly does one pass a file descriptor to or from a shell script using Unix-domain sockets, for example?
> It could readily be done with an extension builtin, or a helper program.

It could be, but now we're talking about adding dependencies on external programs which (a) haven't been written yet and (b) won't necessarily be present on every system. In the end you could just rewrite any shell script in C, but I wouldn't consider that a realistic solution to the problem of "how to do X in a shell script". The object is to create a script which works with existing systems and commonly available tools.

> On the flip side, it works without increasing pid space to 64 bits.

Along those lines, the only change that's really needed is for open references to /proc/PID directories (or their contents) to block PID reuse. As others have pointed out, there are ways to tag processes via their environment variables—as long as they are willing to cooperate—so any process could (1) open the PID directory, (2) check for the matching environment variable, and (3) send the signal if the environment matches, knowing that the PID won't be reused since the directory is open. The kernel could improve on this somewhat by implementing pdfork() and assigning unforgeable identifiers when processes are created, but it's not really necessary just to prevent races for most use cases.

Toward race-free process signaling

Posted Dec 15, 2018 16:14 UTC (Sat) by nix (subscriber, #2304) [Link] (1 responses)

POSIX already has terms for these things. The things open(2) returns are 'file descriptions': the file description is where things like the open flags and file offset reside: the file descriptor is an integer pointer to a file description, which also has flags of its own (currently only O_CLOEXEC). dup() and fork() copy the descriptor, but leave it referring to the same description. close() closes a descriptor, and if no descriptors are left referencing its description, the description is also closed.

Toward race-free process signaling

Posted Dec 18, 2018 16:35 UTC (Tue) by nybble41 (subscriber, #55106) [Link]

> the file descriptor is an integer pointer to a file description, which also has flags of its own (currently only O_CLOEXEC).

This is interesting but it really just adds another layer of indirection: file descriptor number (integer) -> file descriptor (object with flags) -> file description (object with flags & file offset) -> file. It's still true that a file descriptor is not simply an integer, since integers don't have O_CLOEXEC flags.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds