pid_t fork()
Creates a new process that is a memory copy of the calling process. On error return
1. On success returns 0 to the new child process and the process id of the new child
to the parent process. Parent and child will have different address spaces, but will share
offsets of open files. The child inherits the entire U-area of the parent.
pid_t vfork()
Similar for fork, used when process creation is followed immidiately by exec() or exit().
Parent and child will share address space and U-area. Also, child is ensured to run first
until it executes exec() or exit() may cause deadlock!
int exit(int status);
int _exit(int status);
Terminate the current process. exit() flushes and closes all open files, but
_exit() doesnt.
An example program for fork() versus vfork() and exit() versus _exit():
int global = 0;
pid_t pid;
int main() {
printf(before fork\n);
if ((pid = fork()) < 0)
{ perror(fork); exit(1); }
else if (pid == 0) {
global++;
exit(0);
}
printf(after fork, global = %d\n, global);
}
If we use fork() both lines are printed, and the global will be zero. If we use vfork()
and _exit() both lines will be printed, and global will be 1. If we use vfork() and
exit(), only the first line will be printed because the child will close the parents
standard output.
int atexit(void (*func)(void));
Registers a function to be performed when the process exits. Up to 32 functions can be
registered, functions may be registered more than once, and are executed in reverse order
of registration.
pid_t getpid(void);
pid_t getppid(void);
Get process id or the parent process id of the current process.
Get the real user id, effective user id, real group id or effective group id of the
process.
pid_t wait(int *statloc);
Waits for one of the child processes of the current process to stop or terminate. When
someone does, it returns termination status (not exit status!) in statloc, and the process
id as a return value. Returns 1 on error. If statloc is null, nothing is inserted to
it.
pid_t waitpid(pid_t pid, int *statloc, int options);
Similar to wait(), but can be either blocking (options = 0) or non-blocking
(options = WHOHANG), and can wait for a specific pid (wait for anyone if pid = -1, wait
for a specific process if pid > 0). Same return value as wait(), termination status in
statloc.
int execl(const char *pathname, const char *arg0, ..., (char*)0);
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0, ..., (char*)0,
char *const envp[]);
int execve(const char *pathname,char *const argv[],char *const envp[]);
int execlp(const char *filename, const char *arg0, ..., (char*)0);
int execvp(const char *filename, char *const argv[]);
Replaces the current process with a new program. No new process is created!
l stands for arguments list, v for vector. e stands
for environment variables list. p stands for look in the PATH of the
process if you dont file the file in the current directory.
All these functions return 1 on error, otherwise they never return.
int system(const char *cmdstring);
Forks a new process and executes a shell to process the given command string. This is a
library function that calls fork(), exec() and waitpid() in the backgroud.
Signals
Signals are messages sent to processes. It can be a program event (child died, broken
pipe), a hardware error (devision by zero), or a message from another process. Signals are
sent and handled by either a default handler or a specified handler. There is no order in
which signals are sent to a process, and in most systems signals are not queued while
inside the signal handler for that signal.
Sigfunc *signal(int signo, Sigfunc *func);
Defines func as a signal handler for signal number signo. Sigfunc is defined as:
typedef void Sigfunc(int);
func can also be one of the special constants SIG_ERR, SIG_DFL or SIG_IGN.
There are constants for all signal numbers: SIGCHLD, SIGALRM, SIGABRT, SIGKILL, SIGFPE,
SIGSEGV, SIGPIPE, SIGUSR1, SIGUSR2 and others.
int kill(pid_t pid, int signo);
int raise(int signo);
Send a signal to another process, or to yourself. Returns 1 on error or 0 on
success.
int pause(void);
Pause the process until a signal (any signal) is sent to it.
int alarm(unsigned int seconds);
The process will receive a SIGALRM signals after the specified number of seconds. Note
that the process may handle the signal later, when the scheduler wakes it up. The default
behavior of the signal is to terminate the process. There is only one alarm per process,
so calling the function while a previous alarm is set will cancel the previous one;
calling alarm(0) cancels the alarm. Note a race condition in this code (error handling
removed):
signal(SIGALRM, SIG_IGN); alarm(10); pause();
void abort(void);
Sends SIGABRT to the process. This function never returns the signal handler should
do process clean-up and then call exit().
int sleep(int seconds);
The process will be suspended for the specified number of seconds, or until it receives a
signal. Return value is zero if no signal was received, or the number of unslept seconds
otherwise.
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(sigset_t *set, int signo);
First four functions empty, fill, add a signal or delete a signal from a signal set. The
fifth function returns 1 if and only if signo is a member of the set, 0 otherwise.
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
Blocks or unblocks signals useful for critical sections. If oset is not null,
returns current block mask in it. If how is SIG_BLOCK, blocks the signals in
set from now on. If how is SIG_UNBLOCK, unblocks the signals in
set. If how is SIG_SETMASK, sets the block mask to be set.
int sigpending(sigset_t *set);
Returns in set the set of signals that are blocked from delivery and currently
pending for the current process.
Shell Redirection
Using the shell, you can ask programs to redirect their standard input, standard output
or standard error to specific files instead of using the keyboard and screen:
ls > my_output_file1
date >> my_appended_output_file2
sort < my_input_file3
sort < my_input_file3 > my_output_file4
ls >& my_error_file
ls >>& my_appended_error_file
You can also create pipes, in which the output of one program becomes the
input of the next one in the pipe:
ls | sort
cat < input_file | sort | head 20 > output_file
Pipes and redirection can be as long as use wish. The only thing you cant do
is redirect a file to more than one place, as in:
ls | sort < my_file
ls > my_file | sort
Pipes and redirection characters are interpreted by the shell, and the programs
dont see them. So redirection and pipes will work for any program.
However, to make life easier, it is a convention that filter programs such as sort or head
process the list of files they are given as arguments, or the standard input if they were
executed with no arguments. This convention also works well for wildcards.
Wildcards are also interpreted by the shell: * stands for any zero or
more characters, ? stands for exactly one character, and
[list] stands for exactly one of the characters in the list.
Examples:
ls *.a , ls file??.tmp , ls temp[123].old , ls
temp[A-Z].old
Implementing Redirection
The pipe() system call and the dup2() system call can be used together to implement
redirection as done by the shell. If, for example, we would like to execute a program
called prog but make it think that its standard input is not the screen but a
file we write to, then we call pipe() and fork() as in the previous example, but the child
process code will now be:
close(fd[1]);
if (f[0] != STDIN_FILENO)
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
{ perror(dup2); exit(1); }
close(fd[0]);
if (execl(prog, (char*)0) < 0)
{ perror(execl); exit(1); }
Redirecting the standard output or standard error can be done in the same way:
Duplicate a file descriptor of your choice to STDOUT_FILENO or STDERR_FILENO.