fork, pipe
see: https://github.com/osue-tuwien/osue-tuwien.github.com/wiki/fork-exec-and-unnamed-pipes
see: https://www.gnu.org/software/libc/manual/html_node/Pipes-and-FIFOs.html
see: https://www.gnu.org/software/libc/manual/html_node/Creating-a-Pipe.html
Fork
fork()
create a process (copy process image).
child inherits current state of process and its values but can change it.
use
fflush()
to flush all open streams because they get inherited to the child.
pid_t fork(); // <-- PC of child @ next instruction
switch (pid) {
case -1:
// error
case 0:
// child tasks
default:
// parent tasks
}
see: process hierarchy withpstree
command
see:set follow-fork-mode [child|parent]
in gdb
Exec
exec...()
execute / load new program into processes memory / replace process image under the same PID.
all exec functions are the frontend of
execve()
.
execlp()
is the easiest to use.
// e: exec_e ⟶ also set environment variable (see 'man environ')
// p: exec_p ⟶ search for environment variable $PATH for given program// l: execl_ ⟶ variable arguments input
int execl (char *path, char *arg, ...);
int execlp (char *file, char *arg, ...);
int execle (char *path, char *arg, ..., char *envp[]);// v: execv_ ⟶ array input
int execv (char *path, char *argv[]);
int execvp (char *file, char *argv[]);
int execvpe (char *file, char *argv[], char *envp[]);// fexecve,execveat ⟶ accepts file descriptor instead of path
int fexecve (int fd, char *argv[], char *envp[]);
int execveat(int dirfd, char *pathname, char *argv[], char *envp[], int flags);
char *cmd[] = { "ls", "-l", (char *)0 };
execv("/bin/ls", cmd); or execvp("ls", cmd);execl("/bin/ls", "ls", "-l", NULL);execlp("ls", "ls", "-l", NULL);
exit()
terminate self, send PID and exit status to parents.
delete temproary files from
tmpfile()
and call
atexit()
.
_exit()
does almost the same, but closes all file descriptors and doesn’t call
atexit()
see: all exit codeshttps://tldp.org/LDP/abs/html/exitcodes.htmland also<sysexits.h>
wait()
/
waitpid()
blocks until a process terminates (called by parent) or
EINTR
returns PID and exit status.
Synchronous waiting and busy waiting through
waitpid(-1, &status, WNOHANG)
.
Asynchronous waiting by waiting until
SIGCHLD
is sent to parent as soon child stops.
pid = waitpid(cid, &status, 0); // waits on a child process with PID ’cid’
pid = waitpid(-1, &status, 0); // equivalent to wait
pid = waitpid(-1, &status, WNOHANG); // does not block
zombie = child waiting for parent to call
wait()
orphan = child of dead parent (owned by init-process until it terminates)
Unnamed pipes
pipe()
unnamed pipe
(equivalent to|
in bash)
unidirectional interprocess communication for related processes .
int pipe(int pipefd[2]);
pipefd[1] // -> fd for write-end (start of pipe)
pipefd[0] // -> fd for reading-end (end of pipe)
when using two pipes it can cause deadlocks if both processes read from an empty pipe.
writing into pipe:
blocks on full pipe
if reading-end is closed:
SIGPIPE
signal,
errno == EPIPE
reading from pipe:
blocks on empty pipe
if writing-end is closed: returns
EOF
dup2()
used for redirection
int dup2(int oldfd, int newfd); // dup2: "olddf ist jetzt dein neues newdf"
close(oldfd);
int file_fd = open("log.txt", O_WRONLY | O_CREAT);
dup2(file_fd, STDOUT_FILENO); // file_fd <-- stdout_fd
close(file_fd);
execlp("ls", "ls", NULL); // prints something to stdout
int pipefd[2];
pipe(pipefd); // create pipepid_t pid = fork();switch(pid) {
case 0: // child
close(pipefd[1]); // won't use pipe write-end
dup2(pipefd[0], STDIN_FILENO); // pipe read-end -> stdin
close(pipefd[0]); // close pipe read-end
execlp("wc", "wc", "-l", NULL);
// error: reached this line
...