ECE344 Fall 2026 (Sec 1) Lec 8 - Event Loops and Process Groups
Watch on YouTube →
Overview
Jon Eyolfson shows how Linux programs can wait efficiently for multiple events without busy polling or unsafe signal handlers: block SIGCHLD, expose it through signalfd, and use poll alongside standard input. A working event loop then reaps all terminated children, while the lecture also explains how process groups let shells signal related processes together and how systemd cgroups provide stronger grouping.
Key takeaways
- A blocked SIGCHLD remains pending without running a handler, and because standard signals can coalesce, one notification should trigger a waitpid(-1, ..., WNOHANG) loop that reaps all available children.
- Linux signalfd turns blocked pending signals into readable file descriptors, allowing signal handling to happen in normal program flow rather than an asynchronous handler.
- poll can sleep until any monitored descriptor is ready, making it suitable for a single-threaded event loop that must respond to both standard input and child exits.
- A child inherits its parent's signal mask across fork, and blocked signals remain blocked across execve; restore the desired mask in the child before execvp.
- A negative process-group ID passed to kill targets all processes in that group, while systemd cgroups provide stronger membership control because processes cannot simply leave the group.
Chapters
0:00
Why Child-Exit Polling and Signal Handlers Fall Short
- Repeated waitpid(..., WNOHANG) calls waste CPU; adding sleeps saves CPU at the cost of response time.
- A SIGCHLD handler can react to child termination, but asynchronous handlers introduce concurrency and can interrupt code at unsafe points.
- Lab 2's subprocess daemon must handle both client requests and child exits without blocking on either one.
7:14
Block SIGCHLD and Convert Pending Signals with signalfd
- sigprocmask blocks selected signals so their handlers do not run; blocked signals remain pending until unblocked.
- Standard signals are tracked as pending rather than counted, so several child exits can coalesce into one SIGCHLD notification.
- Linux signalfd exposes blocked, pending signals as a readable file descriptor, letting ordinary code handle them when it chooses.
14:38
Use poll to Sleep Until a File Descriptor Is Ready
- poll waits for readiness across an array of file descriptors and sleeps until an event or timeout, rather than repeatedly checking them.
- A descriptor is ready for reading when a read will not block; POLLIN signals available input, while POLLOUT indicates writing can proceed.
- The pollfd revents field reports returned events, including POLLHUP or POLLERR even when those events were not requested.
22:54
Design an Event Loop for Input and Child Termination
- The example program must accept numbers from standard input to launch sleep children and report child exits promptly.
- Blocking on standard input alone can delay child cleanup; handling both input and exits in a signal handler risks unsafe operations such as printf.
- The design monitors standard input and a SIGCHLD signalfd together, then checks both descriptors because both may become ready.
27:29
Build the poll Loop and Launch sleep Processes
- The program initializes a signal set with SIGCHLD, blocks it with sigprocmask, and creates a close-on-exec signalfd.
- Its poll array watches file descriptor 0 and the signal FD for POLLIN; poll waits indefinitely and retries if interrupted with EINTR.
- When standard input is ready, the program reads a line and forks a child that uses execvp to run sleep with the supplied duration.
31:39
Restore Child Signal State and Reap Every Exited Process
- The child inherits its parent's blocked signal mask, so it unblocks SIGCHLD before execvp to avoid passing an unexpected blocked state to the new program.
- The close-on-exec flag prevents the signal FD from leaking into the executed sleep process.
- After reading signalfd's siginfo structure, the parent loops on waitpid(-1, ..., WNOHANG) to reap every exited child because one SIGCHLD may represent multiple exits.
- waitpid returning 0 means children remain but none has exited; ECHILD means there are no children left to reap.
40:42
Event Loops and the Node.js Single-Threaded Model
- The example is an event loop: one thread waits for input and child events, then handles ready events without asynchronous signal-handler code.
- Jon Eyolfson compares this structure to Node.js, where a single JavaScript thread can handle I/O-heavy workloads without application-level concurrency.
- The approach avoids busy polling and uses poll to sleep until the kernel reports an event.
44:23
Signal Masks and Handlers Across execve
- After execve, caught signal handlers reset to their default behavior because the old program's memory and handler code are replaced.
- Blocked and ignored signal states survive execve, so a child should restore the intended mask before launching another program.
- The previous mask can be saved with sigprocmask and restored later; Linux also exposes blocked-signal information in /proc process status.
47:02
Signal Related Processes with Process Groups
- Every process belongs to a process group; setpgid(0, 0) places the calling process in a new group identified by its PID.
- Passing a negative process-group ID to kill sends the signal to every process in that group, rather than to one PID.
- Shells commonly group commands and their subprocesses together, allowing one signal to affect the related processes; processes can still leave a process group.
51:27
Why systemd Uses Cgroups for Stronger Process Grouping
- Linux cgroups group processes for services and, unlike process groups, prevent a process from leaving its assigned group through ordinary process-group operations.
- Jon Eyolfson explains that killing a systemd user service can bring down the desktop because its processes share a cgroup.
- The lecture's core pattern is to block SIGCHLD, read it through signalfd, wait with poll, and reap all exited children; child processes should unblock signals before exec.
Summary, takeaways, and chapters were generated by AI from the video's transcript and may contain errors. The video belongs to its creator, Jon Eyolfson.