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 withpstreecommand

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
...