5 ms·
Normally if the process group leader dies the system will send SIGHUP to all the members of the process group. The default behavior is to exit. So on Unix syste
by xenadu02 3y ago
Normally if the process group leader dies the system will send SIGHUP to all the members of the process group. The default behavior is to exit. So on Unix systems the first process calls setpgrp() and becomes the leader of a new process group. All of its children will, by default, be members of the group, and their children, and so on. When the leader dies they'll all get SIGHUP and die as well. They have the option (if needed) to ignore that signal or spawn their own process group.
Session leaders are similar in some ways. When a session leader dies SIGHUP is sent to all members of that session's foreground process group and its controlling tty is released but IIRC it doesn't do anything about background process groups. (Session leaders control this with tcsetpgrp()).
- petters 3y agoIf this works, why does the featured article exist?
- tedunangst 3y agoNot every process wants to be the leader of its own process group.
- Animats 3y agoI'm puzzled, too. The example is about spawning threads in Rust, not processes under UNIX. In Rust, if the main thread dies, all other threads get killed. So child threads outliving the main thread is not a problem. A harder problem is making sure that the program shuts down if some thread panics. There are several ways to do that, but it's not automatic. Incidentally, regular mutexes are "poisoned" if the thread holding them panics. Anyone trying to lock the mutex gets an error. However, parking_lot mutexes do not do this. If the thread holding one of those panics, the mutex unlocks. This may be unsafe.
- neandrake 3y agoI think the example is the code for a child process which must use a separate thread to block on stdin for the whole process. As soon as the parent process dies (no example code?), the connection to the child process’ stdin will be unblock, causing the child monitor thread to detect and panic.
- thecodedmessage 3y agoThe example is for the child process. The threads in Rust is meant as an implementation detail. This is super unclear and should’ve been explained.
- userbinator 3y agoNot everyone knows everything, and people will reinvent using what they do know. The process group mechanism may be one of the less well-known parts of UNIX.
- petters 3y agoThe article mentions > There’s process group mechanism, but it is one-level deep and is mostly reserved for the shell. So the author seems aware that they exist, at least
- thayne 3y agoWell for one thing, the child process could handle sighup, or just mask it and ignore it. And as another comment mentioned, it only goes one level, so it won't signal grandchildren. But, if you control the code of the child, as this article assumes, you could probably deal with that.
- c7DJTLrn 3y ago>Well for one thing, the child process could handle sighup I've come across programs that use SIGHUP for various things like config reloading when they could use USR1/USR2 instead. UNIX signals are kind of crap in my opinion. USR1/USR2 should probably not even exist, there should be some other way to 'message' processes without IPC.
- xenadu02 3y agoThe article is wrong FWIW. By default a child is a member of the same process group as its parent no matter how many levels deep. Shells push each job into a separate group, making the shell interpreter the process group leader. Thats why suspend works, it sends that whole process group to the background. Depending on how an interpreter is setup a shell script might end up under its own progress group if the shell always creates one... usually when invoked as an interpreter it shouldn't be making a new one though.
- thayne 3y agowell process groups aren't hierarchal. So if a child (or other descendant) process sets itself as a process group leader, so that it can kill it's children, it escapes your process group. So it isn't composable.
- xenadu02 3y agoProcess groups aren't hierarchical because it is a two-level namespace: process groups (jobs) are members of a session and all processes in a job must be members of the same session. All child processes inherit their parent's process group and session. If they didn't then such a program would not work correctly in any shell pipeline and a bunch of other behavior would break. I'm assuming all processes are under your control in this scenario. It should be very rare for any process that isn't a shell or daemon to create its own process group or session. Sessions can optionally have a controlling terminal, one (and only one) foreground process group, plus any number of background process groups. The foreground job is how the system decides who receives signals generated by the TTY. If the controlling TTY disconnects or is closed the session leader gets SIGHUP which it usually uses to signal all the process groups it created. If the session leader dies or exits then all processes in the foreground process group get a SIGHUP. If you exit an interactive shell or close your SSH session the system generally cleans everything up as you would expect. The processes involved generally don't implement any special handling code to make this happen: the session leader (your login shell) uses the standard Unix job control APIs to manage the session + process groups and the expected behavior falls out naturally. Unless there is a good reason to implement this differently: don't. Use the standard Unix job control APIs as they were designed to be used.
- mananaysiempre 3y agoStructured concurrency as commonly understood requires children to not outlive parents, recursively. For example, if A spawns B spawns C, then B cancels for C with timeout 30s, then 5s later A cancels B with timeout 5s, then the timeout for C must be effectively reduced by 20s[1]. But the issue here is more basic than timeouts. If we are to use process groups in the example, then B must be a process group leader for C and simultaneously belong to the process group led by A, which is impossible on Unix—that’s what TFA means by “[the] process group mechanism [is] one-level deep”. Close but no cigar. (On the other hand, no reason this can’t be an extension to—I would even say a rationalization of—the process group mechanism. It doesn’t exist right now, though.) [1] https://250bpm.com/blog:71/ https://250bpm.com/blog:71/
- pjmlp 3y agoI also miss any reference to wait()/waitpid() on the article, it looks like the author isn't really confortable with UNIX systems programming.
- matklad 3y agowaitpid is inherently racy. wait is covered by This can not be achieved using a pattern equivalent to { ... }. The parent process itself might be abruptly killed, and the finally blocks / destructors / atexit hooks are not run in this case.
- pjmlp 3y agoThat pattern is wrong. You call waitpid() directly, configured for timeout, and if it returns with error that the process is no longer available, then act upon it.
- matklad 3y agoTwo scenarios where this breaks: * parent process is killed after it forks, but before it calls `waitpid`. Nothing even attempts to kill&wait for the child * parent process is killed after it issues `waitpid` syscall. The child continues to happily execute while the parent is dead.
- pjmlp 3y ago- waitpid returns after timeout, assume the process is dead, collect all zombie processes just in case. - yeah this one is a bummer, write the child pids, collect them via a watchdog process