The beginning of a process-builder API

pykello1 pts0 comments

The beginning of a process-builder API [LWN.net]

LWN<br>.net<br>News from the source

Content Weekly Edition<br>Archives<br>Search<br>Kernel<br>Security<br>Events calendar<br>Unread comments

LWN FAQ<br>Write for us

Edition Return to the Front page

User:<br>Password: |

Log in /<br>Subscribe /<br>Register

The beginning of a process-builder API

Ready to give LWN a try?

With a subscription to LWN, you can stay current with what is happening in the Linux and free-software community and take advantage of subscriber-only site features. We are pleased to offer you a free trial subscription , no credit card required, so that you can see for yourself. Please, join us!

By Jonathan Corbet<br>August 4, 2026

The recent discussion on "spawn templates"<br>raised questions about whether it was time to provide an alternative to the<br>classic Unix fork()/exec() pattern for process creation.<br>One idea that was raised there was to shift the template pattern into an<br>interface that could be used to efficiently assemble new processes from<br>bare cloth, without duplicating the parent process. Preferably, that<br>interface would be able to implement posix_spawn().<br>Li Chen, the author of the spawn-template work, has now responded with a patch series<br>(written with significant LLM assistance) showing what a process-builder<br>API for Linux might look like.

In the Unix model, a call to fork() (which ends up being a variant<br>of clone()<br>on Linux systems) creates a copy of the calling process, which involves a<br>fair amount of work. The child then typically modifies its<br>environment in whatever ways are necessary — opening or closing files, for<br>example — before making a call to execve()<br>to run a new program. That latter call ends up throwing away most of the<br>work that was done to copy the parent process, which is not entirely<br>efficient. In cases where the intent is to immediately run a different<br>program, a better model might be to piece together the new process from the<br>beginning, without involving (much of) the parent process's state.

Process creation

In Chen's patch series, the way to do that is to start by creating an empty<br>process with a call to the existing pidfd_open()<br>system call:

new_process_fd = pidfd_open(0, PIDFD_EMPTY);

The new PIDFD_EMPTY flag requests the creation of a process shell<br>that will have its details filled out later. The return value is a real<br>pidfd, but most of the resources associated with a process are not yet<br>present. There is no process ID, no task structure in the kernel, and no<br>charge against the parent's process-count resource limit. Most kernel<br>operations that act on a pidfd will refuse to do anything with this one at<br>this stage.

The next step is to put together the information that drives the<br>construction of the new process; this work is centered around this<br>structure:

struct pidfd_spawn_run_args {<br>__u32 flags;<br>__u32 nr_actions;<br>__aligned_u64 path;<br>__aligned_u64 argv;<br>__aligned_u64 envp;<br>__aligned_u64 actions;<br>__u32 action_size;<br>__u32 reserved0;<br>__u64 reserved[2];<br>};

The path field is a pointer to a string containing the path to the<br>executable that the new process should run; as described below, it can be<br>NULL in some cases. The argv and envp<br>parameters point to the usual argument and environment arrays. The<br>flags field must be zero, as must the reserved fields. Filling in<br>those fields (the rest will be covered shortly) provides enough information<br>to build and run the process with a call to the first of two new system<br>calls:

int pidfd_spawn_run(int pidfd, struct pidfd_spawn_run_args *args, int arg_size);

Here, pidfd is the pidfd for the under-construction process,<br>args is a pointer to the above structure, and arg_size is<br>the size of that structure. If all goes well, this call will create the<br>full process and set it running with the indicated program; the return<br>value will be the ID of the now fully fleshed-out process. The original<br>pidfd remains valid and attached to this process. Should some sort of<br>error happen, instead, the process shell will be left in a sort of dead<br>state, and any further attempts to operate on it will fail.

Configuration

Providing an executable image, arguments, and environment is normally just<br>the beginning of configuring a new process; a typical application will want<br>to set up the process's file descriptors and, perhaps, adjust many other<br>things. That is what the actions field of the<br>pidfd_spawn_run_args structure is for. It points to an array of<br>this structure type:

struct pidfd_spawn_action {<br>__u32 type;<br>__u32 flags;<br>__u32 fd;<br>__u32 newfd;<br>__u64 reserved[2];<br>};

The type field describes an action that should be carried out<br>before the process is instantiated and launched. The actions currently<br>defined in this patch set (which are a small subset of what would eventually<br>be needed) are:

PIDFD_SPAWN_ACTION_DUP2 : duplicates an existing file<br>descriptor using dup2().<br>The existing file descriptor should be passed in the fd<br>field, while the intended new descriptor goes in newfd.<br>PIDFD_SPAWN_ACTION_CLOSE_RANGE : closes...

process __u32 call pidfd structure beginning

Related Articles