#include <libcork/os.h>
The functions in this section let you fork child processes, run arbitrary commands in them, and collect any output that they produce.
Represents a child process. There are several functions for creating child processes, described below.
Free a subprocess. The subprocess must not currently be executing.
There are several functions that you can use to create child processes.
Create a new subprocess that will execute the body callback object.
Create a new subprocess that will execute another program. program should either be an absolute path to an executable on the local filesystem, or the name of an executable that should be found in the current PATH. params should be a parameter array suitable to pass into the program’s main function. (It must be NULL-terminated, and its first element must be the program.)
For all of these functions, you can collect the data that the subprocess writes to its stdout and stderr streams by passing in stream consumer instances for the stdout and/or stderr parameters. If either (or both) of these parameters is NULL, then the child process will inherit the corresponding output stream from the current process. (Usually, this means that the child’s stdout or stderr will be interleaved with the parent’s.)
The functions for executing subprocesses actually work on a group of subprocesses. This lets you start up several subprocesses at the same time, and wait for them all to finish. If you only want to execute one subprocess, that’s fine; just make a group containing one subprocess.
A group of subprocesses that will all be executed simultaneously.
Create a new group of subprocesses. The group will initially be empty.
Free a subprocess group. This frees all of the subprocesses in the group, too. If you’ve started executing the subprocesses in the group, you must not call this function until they have finished executing. (You can use the cork_subprocess_group_is_finished() function to see if the group is still executing, and the cork_subprocess_group_abort() to terminate the subprocesses before freeing the group.)
Add the given subprocess to group. The group takes control of the subprocess; you should not try to free it yourself.
Once you’ve created your group of subprocesses, you can start them executing:
Execute all of the subprocesses in group. We immediately return once the processes have been started. You can use the cork_subprocess_group_drain() and cork_subprocess_group_wait() functions to wait for the subprocesses to complete.
If there are any errors starting the subprocesses, we’ll terminate any subprocesses that we were able to start, set an error condition, and return -1.
Note
This function is not thread-safe. You cannot execute two groups of subprocesses simultaneously.
Since we immediately return after starting the subprocesses, you must somehow wait for them to finish. There are two strategies for doing so. If you don’t need to communicate with the subprocesses (by writing to their stdin streams or sending them signals), the simplest strategy is to just wait for them to finish:
Wait until all of the subprocesses in group have finished executing. While waiting, we’ll continue to read data from the subprocesses stdout and stderr streams as we can.
If there are any errors reading from the subprocesses, we’ll terminate all of the subprocesses that are still executing, set an error condition, and return -1. If the group has already finished, the function doesn’t do anything.
As an example:
struct cork_subprocess_group *group = /* from somewhere */;
/* Wait for the subprocesses to finish */
if (cork_subprocess_group_wait(group) == -1) {
/* An error occurred; handle it! */
}
/* At this point, we're guaranteed that the subprocesses have all been
* terminated; either everything finished successfully, or the subprocesses
* were terminated for us when an error was detected. */
cork_subprocess_group_free(group);
If you do need to communicate with the subprocesses, then you need more control over when we try to read from their stdout and stderr streams. (The pipes that connect the subprocesses to the parent process are fixed size, and so without careful orchestration, you can easily get a deadlock. Moreover, the right pattern of reading and writing depends on the subprocesses that you’re executing, so it’s not something that we can handle for you automatically.)
Return whether all of the subprocesses in group have finished executing.
Immediately terminate the subprocesses in group. This can be used to clean up if you detect an error condition and need to close the subprocesses early. If the group has already finished, the function doesn’t do anything.
Check the subprocesses in group for any output on their stdout and stderr streams. We’ll read in as much data as we can from all of the subprocesses without blocking, and then return. (Of course, we only do those for those subprocesses that you provided stdout or stderr consumers for.)
This function lets you (TODO: eventually) pass data into the subprocesses’s stdin streams, or send them signals, and handle any orchestration that’s necessarily to ensure that the subprocesses don’t deadlock.
If there are any errors reading from the subprocesses, we’ll terminate all of the subprocesses that are still executing, set an error condition, and return -1. If the group has already finished, the function doesn’t do anything.
To do this, you continue to “drain” the subprocesses whenever you’re ready to read from their stdout and stderr streams. You repeat this in a loop, writing to the stdin streams or sending signals as necessary, until all of the subprocesses have finished:
struct cork_subprocess_group *group = /* from somewhere */;
while (!cork_subprocess_group_is_finished(group)) {
/* Drain the stdout and stderr streams */
if (cork_subprocess_group_drain(group) == -1) {
/* An error occurred; handle it! */
} else {
/* Write to the stdin streams or send signals */
}
}
/* At this point, we're guaranteed that the subprocesses have all been
* terminated; either everything finished successfully, or the subprocesses
* were terminated for us when an error was detected. */
cork_subprocess_group_free(group);