1.unix processes
DESCRIPTION
unix processTRANSCRIPT
© 2009 Wipro Ltd - Confidential2 © 2009 Wipro Ltd - Confidential2
Agenda
3
4 Signals
1 Process Environment
2 Process Control
Process Relationships
5 Daemon Processes
© 2009 Wipro Ltd - Confidential4 © 2009 Wipro Ltd - Confidential4
Process
• Process is an instance of a program in execution.• Process is uniquely identified by its PID or process id.• Multiple processes can execute simultaneously on a system.
– Single processor executes only one process at a given instance.• Managed by the process control subsystem.
© 2009 Wipro Ltd - Confidential5 © 2009 Wipro Ltd - Confidential5
Process Control è Key Services
• Process scheduling– Allocates processes to CPU using a scheduling algorithm.– Every process is given a time slice for execution.– Context switching when it changes execution context from one process
to another.– Processes run till their time slices elapse and are then swapped out of
CPU.– Alternately, they voluntarily relinquish CPU while awaiting a resource.
• Process synchronization– Between parent-child processes.
• Inter-process communication– Asynchronous signaling of events.– Synchronous transmission of messages between processes.
© 2009 Wipro Ltd - Confidential6 © 2009 Wipro Ltd - Confidential6
Process Control è Key Services
• Memory management– Manages allocation of memory for an executing process.– Protection of private address space of a process.– Memory management by writing process memory temporarily to
secondary memory.• Swapping: Entire process written to swap device.• Paging: Pages of memory written to swap device.
© 2009 Wipro Ltd - Confidential7 © 2009 Wipro Ltd - Confidential7
Process è Attributes
• Key process attributes include:– Process ID (PID)
• Unique per process– Parent process ID (PPID)– Process group ID
• System assigns process group ID to every process• Same as process ID of group leader• Signals propagate to all processes in a group
– User and group ID (real and effective)• Real user and group ID is that of the user who invoked the process• Effective user and group ID is to run the process as its program owner
– Process priority
© 2009 Wipro Ltd - Confidential8 © 2009 Wipro Ltd - Confidential8
Process Creation• Every process except process 0 is created by the fork() system call.
– Process 0 (swapper) is created by system at boot time.– Process 1 (init), created by swapper, is the ancestor of all processes.
• Process that invoked fork is called the parent process; newly created process is called the child process (of this parent).
• With a fork, child process is created with the same text and data segment as parent.
• Using an exec in the child process overlays current process with a new program.
• When a command is executed from the shell, it internally does a fork and exec.
• Parent process needs to “wait” on a child to receive its exit status, and cleanup process table entry for child.
• Any process can have only one parent process.– Indicated by PPID (parent process id) attribute.
• A process can have any number of children.– Well, there is an upper limit.
© 2009 Wipro Ltd - Confidential9 © 2009 Wipro Ltd - Confidential9
Orphan & Zombie Processes
• Orphaned process– Parent dies before child exits.– Child process is adopted by init.
• Child’s parent becomes init à its PPID becomes 1.– init does a wait on the orphaned child process and handles its cleanup
from process table on exit.• Defunct or Zombie process
– Child process exits, but still has an entry in process table.– Parent is notified with a SIGCHLD signal.– Child is in defunct or zombie state till the parent does a wait and reads
the exit status of the child.• Child process does not consume CPU resources, only occupies an entry in
process table.
© 2009 Wipro Ltd - Confidential10 © 2009 Wipro Ltd - Confidential10
Process States
• Common Process StatesProcess State
Description
R Process is running or scheduled to run (runnable ) and is on the run queue.S Process is in an interruptible sleep state (waiting for an event to complete).D Process is in an uninterruptible sleep (usually IO).T Process has been stopped (either by a job control signal or because it is
being traced).Z Zombie (or defunct) process, terminated but not reaped by its parent.
© 2009 Wipro Ltd - Confidential11 © 2009 Wipro Ltd - Confidential11
Process Priority
• Process attribute used by scheduler to decide the execution order.• Lower the priority number, higher the priority.• Each process has a nice value which can be used to influence its
scheduling.– Higher nice values è process wants to be nice (to other processes) è
run at lower priority.– Lower nice values è process wants to be less nice è run at higher
priority.– Typically, a process with a smaller nice value runs to completion more
quickly than an equivalent process with a higher nice value.– Can be changed with nice or renice.– A typical process starts out with 20; it can be as nice as 39 or as not-
nice as 0.
© 2009 Wipro Ltd - Confidential12 © 2009 Wipro Ltd - Confidential12
Process Related Tools
• Shell è command interpreter & job control.– When a user logins in, kernel starts a shell (Eg: sh, bash, ksh).– All processes started by user from shell run as its child processes.
• Shell does a fork and exec to execute the command or process started.– Jobs (or processes)
• Can be run as:– Foreground jobs
» Has control of shell; associated with terminal; can accept user input.– Background jobs
» Invoked with & suffix; independent of user input from terminal.• Foreground job may be suspended by pressing <Ctrl-Z>.
– Shell sends SIGTSTP signal to process.• Suspended job may be resumed in foreground (fg command) or in background (bg
command).– Shell sends SIGCONT signal to process.
• Background job also may be made to run in foreground using fg command.• List of all processes started by shell (and not exited) may be obtained by using jobs
command.• Foreground job may be interrupted by pressing <Ctrl-C>.
– Shell sends SIGINT signal to process.
© 2009 Wipro Ltd - Confidential13 © 2009 Wipro Ltd - Confidential13
Process Related Tools• psè Report a snapshot of processes.• topè Provide a dynamic real-time view of a running system.• killè Send a signal to a process.
– kill <pid> sends default signal (SIGTERM).– kill -9 <pid> sends SIGKILL signal for forceful termination.
• killallè Send a signal to all processes running a specified command.• sleepè Delay/suspend command execution for a specified period of time.• nohupè Run a command immune to hangups.
– On shell exit, it sends a hangup signal (SIGHUP) to all its children, causing them to be killed.
– Can be used when you want the command execution to continue even after shell exits.
– For applying this behaviour to existing jobs not started with nohup, some shells provide the disown command.
• timeè Find system resource usage during command execution.• nice, reniceè Change nice value of processes.• pidofè Find PID of a running program.• ulimitè Get/set user resurce limits.• priocntlè Get/set scheduling parameters of processes.
© 2009 Wipro Ltd - Confidential14 © 2009 Wipro Ltd - Confidential14
• A C program starts execution with a function called main.– int main(int argc, char *argv[]);
• When it is executed by the kernel by one of the exec functions, a special start-up routine is called before main.
• The executable program file specifies this routine as the starting address for the program.– This is set up by the link editor when it is invoked by the C compiler.– This start-up routine takes values from the kernel the command-line
arguments and the environment and sets things up for main.
Process Start-up
© 2009 Wipro Ltd - Confidential15 © 2009 Wipro Ltd - Confidential15
Process Termination
• 8 ways:– Normal termination:
1. Return from main2. Calling exit3. Calling _exit or _Exit4. Return of the last thread from its start routine5. Calling pthread_exit from the last thread
– Abnormal termination:6. Calling abort7. Receipt of a signal8. Response of the last thread to a cancellation request
• Start-up routine is written so that if main returns, exit is called.• Exit handlers can be registered & be automatically called by exit.
– int atexit(void (*func)(void))– An exit handler is called once for each time it is registered.
© 2009 Wipro Ltd - Confidential17 © 2009 Wipro Ltd - Confidential17
atexitè Examplestatic void my_exit1(void){ printf("first exit handler\n");}
static void my_exit2(void){ printf("second exit handler\n");}
int main(int ac, char *av[]){ if (atexit(my_exit2) != 0) err_sys("can't register my_exit2"); if (atexit(my_exit1) != 0) err_sys("can't register my_exit1"); if (atexit(my_exit1) != 0) err_sys("can't register my_exit1"); printf("main is done\n");
(ac == 2) ? _exit(0) : exit(0);}
© 2009 Wipro Ltd - Confidential18 © 2009 Wipro Ltd - Confidential18
atexitè Example$ ./a.outmain is donefirst exit handlerfirst exit handlersecond exit handler$ ./a.out nmain is done$
© 2009 Wipro Ltd - Confidential19 © 2009 Wipro Ltd - Confidential19
Arguments & Environment
• Command-line arguments to a program can be accessed as argv[1]to argv[argc – 1].– The name with which the process was invoked is argv[0].
• Each program is also passed an environment list.– Accessible via a global variable.
• extern char **environ;
– name=value strings• PATH=:/bin:/usr/bin• HOME=/home/wipro
– Specific environment variables should be accessed using getenv and putenv functions.
• char *getenv(const char *name)• int putenv(char *str)• int setenv(const char *name, const char *value, int rewrite)• int unsetenv(const char *name)
© 2009 Wipro Ltd - Confidential20 © 2009 Wipro Ltd - Confidential20
Memory Layout Of A Program
• Text segment– Machine instructions that the CPU executes.– Read-only.– Sharable so that a single copy in memory can be used by programs.
• Initialized data segment (Data segment)– Global variables that are specifically initialized.
• int answer = 42;
• Uninitialized data segment (BSS)– Initialized by the kernel to arithmetic 0 or null pointers before the program starts
executing.– Not stored in the program file on the disk.
• long days_of_week[7];
• Stack– Temporary data storage.– Automatic variables, along with information that is saved each time a function is
called (parameters to functions, pointer to previous stack frame etc.).• Heap
– Where dynamic memory allocation usually takes place.
© 2009 Wipro Ltd - Confidential21 © 2009 Wipro Ltd - Confidential21
Typical Memory Arrangement
High address Command-line arguments & environment variables
Low address
Initialized Data(read-only)
Text
Initialized to zero by exec
Read from the program file by exec
Stack
Heap
Uninitialized Data(BSS)
Initialized Data(read-write)
© 2009 Wipro Ltd - Confidential22 © 2009 Wipro Ltd - Confidential22
Dynamic Memory Management
• void *malloc(size_t size)• void *calloc(size_t nobj, size_t size)• void *realloc(void *ptr, size_t newsize)• void free(void *ptr)
• Usually implemented with the sbrk system call.– Expands or contracts the heap of the process.
© 2009 Wipro Ltd - Confidential23 © 2009 Wipro Ltd - Confidential23
Resource Limits
• Every process has a set of resource limits.• int getrlimit(int resource, struct rlimit *rlptr)• int setrlimit(int resource, const struct rlimit *rlptr)
• rlimit has a soft limit & a hard limit.– A process can:
• Change its soft limit to a value <= its hard limit.• Lower its hard limit to a value >= its soft limit.
– Only a superuser process can raise a hard limit.• Eg: RLIMIT_AS (maximum size of process’ virtual memory),
RLIMIT_CORE (maximum size of core file), RLIMIT_CPU (CPU time limit in seconds), RLIMIT_FSIZE (maximum size of files that the process may create) etc.
• Inherited by any of its children.– ulimit capability built into most of the shells.
© 2009 Wipro Ltd - Confidential24 © 2009 Wipro Ltd - Confidential24
Exercises
1. Print all the environment variables from a program using environ.2. Find out the resources & the resource limits on your system. Use
getrlimit to find the limits. Compare the values obtained with those obtained via ulimit command. Can you change all the limits as a normal user?
© 2009 Wipro Ltd - Confidential26 © 2009 Wipro Ltd - Confidential26
• Every process has a unique process ID (PID).– Can be reused.– PID 0
• Usually the scheduler process and is often known as the swapper.• No program on disk corresponds to this process, which is part of the kernel.
– PID 1• Usually the init process.• Invoked by the kernel at the end of the bootstrap procedure.• Never dies though it is a normal user process.• Becomes the parent process of any orphaned child process.
– pid_t getpid(void)– pid_t getppid(void)– uid_t getuid(void)– uid_t geteuid(void)– gid_t getgid(void)– gid_t getegid(void)
Process Identifiers
© 2009 Wipro Ltd - Confidential27 © 2009 Wipro Ltd - Confidential27
Process Creation è fork
• An existing process (parent) can create a new one (child).• pid_t fork(void)
– This function is called once but returns twice.• Return value in the child is 0.• Return value in the parent is the PID of the new child.
– A process can have more than one child.– No function that allows a process to obtain the PIDs of its children.
– Both child and parent continue executing with the instruction that follows the call to fork.
– The child is a copy of the parent.• Child gets a copy of parent’s data space, heap, and stack.• They share the text segment.• Modern implementations don’t perform a complete copy, since a fork is often followed
by an exec.• Copy-on-write (COW)
– Regions are shared by parent and child and have their protection changed by the kernel to read-only.
– If either process tries to modify these regions, the kernel then makes a copy of that piece of memory only.
© 2009 Wipro Ltd - Confidential28 © 2009 Wipro Ltd - Confidential28
fork è Exampleint glob = 6; /* external variable in initialized data */char buf[] = "a write to stdout\n";
int main(void){ int var = 88; /* automatic variable on the stack */ pid_t pid;
write(STDOUT_FILENO, buf, sizeof(buf) - 1); printf("before fork\n"); /* we don't flush stdout */
if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* child */ glob++; /* modify variables */ var++; } else { sleep(2); /* parent */ } printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var); exit(0);}
© 2009 Wipro Ltd - Confidential29 © 2009 Wipro Ltd - Confidential29
fork è Example$ ./a.outa write to stdoutbefore forkpid = 430, glob = 7, var = 89 child's variables were changedpid = 429, glob = 6, var = 88 parent's copy was not changed$ ./a.out > temp.out$ cat temp.outa write to stdoutbefore forkpid = 432, glob = 7, var = 89before forkpid = 431, glob = 6, var = 88
• Who runs first?– In general, we never know whether the child starts executing before the
parent or vice versa. – Depends on the scheduling algorithm used by the kernel. – If both need to synchronize, some form of inter-process communication
is required.• In the example, we put the parent to sleep for 2 seconds.
© 2009 Wipro Ltd - Confidential30 © 2009 Wipro Ltd - Confidential30
fork è Example
• Why is the behaviour different between the 2 invocations?– write function is not buffered.– Because write is called before fork, its data is written once to stdout.– Standard I/O library is buffered.
• stdout is line buffered if it is connected to a terminal device.• Else, it is fully buffered.
– [1] When the program is run interactively, we get only a single copy of the printf line, because the stdout buffer is flushed by the newline.
– [2] when we redirect stdout to a file, printf before the fork is called once, but the line remains in the buffer when fork is called.
• This buffer is then copied into child when parent’s data space is copied.• Both parent and child now have a standard I/O buffer with this line in it.• The second printf, right before the exit, just appends its data to the
existing buffer.• When each process terminates, its copy of the buffer is finally flushed.
© 2009 Wipro Ltd - Confidential31 © 2009 Wipro Ltd - Confidential31
fork è Example/* fork.c -- Using multiple forks */
int main(){ fork(); fork(); fork(); fork(); printf("Hello World\n"); return 0;}
$ ./forkHello WorldHello World. . . repeated 16 timesHello World
© 2009 Wipro Ltd - Confidential32 © 2009 Wipro Ltd - Confidential32
fork è Exampleforkforkforkfork
printf
forkforkfork
printf
forkforkfork
printf
forkfork
printf
forkfork
printf
forkfork
printf
forkfork
printf
forkprintf
forkprintf
forkprintf
forkprintf
forkprintf
forkprintf
forkprintf
forkprintf
printf printf printf printf printf printf printf printf printf printf printf printf printf printf printf printf
© 2009 Wipro Ltd - Confidential33 © 2009 Wipro Ltd - Confidential33
fork è File Sharing
• All file descriptors that are open in parent are duplicated in child.– As if dup had been called for each descriptor.– Parent and child share a file table entry for every open descriptor.
• Eg: Consider a process that has three different files opened for stdin, stdout and stderr. On return from fork, open files are shared.
• It is important that parent and child share the same file offset.– A process forks a child, then waits for child to complete.– Both processes write to stdout as part of their normal processing.– If parent has its stdout redirected (Eg: by a shell), it is essential that
parent’s file offset be updated by child when child writes to stdout.– Child can write to stdout while parent is waiting for it.– On completion of child, parent can continue writing to stdout, knowing
that its output will be appended to whatever child wrote.– If they did not share the same file offset, this type of interaction would
be more difficult to accomplish.
© 2009 Wipro Ltd - Confidential35 © 2009 Wipro Ltd - Confidential35
fork è File Sharing
• If parent and child write to the same descriptor without any form of synchronization, their output will be intermixed.
• 2 normal cases for handling descriptors after fork:– Parent waits for child to complete.
• Parent does not need to do anything with its descriptors.• When child terminates, any of the shared descriptors that child read from or
wrote to will have their file offsets updated accordingly.– Parent and child go their own ways.
• After fork, parent closes descriptors that it doesn’t need. Child does the same thing.
• This way, neither interferes with other’s open descriptors.• Often done in network servers.
© 2009 Wipro Ltd - Confidential36 © 2009 Wipro Ltd - Confidential36
fork è Inherited Attributes
• Open files• Real user ID, real group ID,
effective user ID, effective group ID
• Supplementary group IDs• Process group ID• Session ID• Controlling terminal• set-user-ID and set-group-ID
flags• Current working directory
• Root directory• File mode creation mask• Signal mask and dispositions• The close-on-exec flag for any
open file descriptors• Environment• Attached shared memory
segments• Memory mappings• Resource limits
© 2009 Wipro Ltd - Confidential37 © 2009 Wipro Ltd - Confidential37
fork è Non-inherited Attributes
• Return value from fork• Process IDs• Parent process IDs
– Parent process ID of child is parent– Parent process ID of parent doesn’t change
• Child’s tms_utime, tms_stime, tms_cutime, and tms_cstime values (set to 0)
• File locks set by parent are not inherited by child• Pending alarms are cleared for child• Set of pending signals for child is set to the empty set
© 2009 Wipro Ltd - Confidential38 © 2009 Wipro Ltd - Confidential38
fork è Uses
• When a process wants to duplicate itself so that parent and child can each execute different sections of code at the same time.– Common for network servers.– Parent waits for a service request from a client.– When the request arrives, parent calls fork and lets child handle the
request.– Parent goes back to waiting for the next service request to arrive.
• When a process wants to execute a different program. – Common for shells.– Child does an exec right after it returns from fork.
• Note: fork may fail due to:– Insufficient memory available for creation of child process.– Calling process has exceeded the resource limit of child processes.
© 2009 Wipro Ltd - Confidential39 © 2009 Wipro Ltd - Confidential39
Process Termination
• For any of the 8 ways of termination, we want the terminating process to be able to notify its parent how it terminated.– For exit functions, this is done by passing an exit status as the argument
to the function.– For abnormal termination, kernel generates a termination status to
indicate the reason.– Parent can obtain the termination status from either wait or waitpid
function.• What happens if parent terminates before child?
– init becomes the parent process of child.• When a process terminates, kernel goes through all active processes to see
whether it is the parent of any existing process.• If so, parent PID of the surviving process is changed to be 1.• Guaranteed that every process has a parent.
© 2009 Wipro Ltd - Confidential40 © 2009 Wipro Ltd - Confidential40
Process Termination
• What happens if child terminates before parent?– If child disappears completely, parent won’t be able to fetch child’s
termination status.• By the time parent is ready to check termination status, kernel may have
discarded it.– Zombieà A process that has terminated, but whose parent has not yet
waited for it.– If we write a long-running program that forks many child processes, they
become zombies unless we wait for them and fetch their termination status.
• What happens when a process that has been inherited by initterminates?– Does it become a zombie? No.– init is written so that whenever one of its children terminates, init
calls one of the wait functions to fetch the termination status.– init prevents the system from being clogged by zombies.
© 2009 Wipro Ltd - Confidential41 © 2009 Wipro Ltd - Confidential41
Process Termination Status
• When a process terminates (normally or abnormally), kernel notifies parent by sending SIGCHLD signal to parent.– Parent can choose to ignore it (default action), or– It can provide a signal handler.
• pid_t wait(int *statloc)• pid_t waitpid(pid_t pid, int *statloc, int options)
– Block, if all of its children are still running.– Return immediately with termination status of a child, if it has terminated
and is waiting for its termination status to be fetched.– Return immediately with an error, if it doesn’t have any child processes.
• Termination status is different from exit status.– Exit status is argument to one of the exit functions or return value from
main.– Converted into a termination status by the kernel when _exit is finally
called.
© 2009 Wipro Ltd - Confidential42 © 2009 Wipro Ltd - Confidential42
Process Termination Status
– Macros to examine termination status returned by wait & waitpid.
Macro Description Additional InformationWIFEXITED(status) True if status was returned for a
child that terminated normally.WEXITSTATUS(status)to fetch the low-order 8 bits of the argument that the child passed to exit, _exit,or _Exit.
WIFSIGNALED(status) True if status was returned for a child that terminated abnormally, by receipt of a signal that it didn't catch.
WTERMSIG(status)to fetch the signal number that caused the termination.
WIFSTOPPED(status) True if status was returned for a child that is currently stopped.
WSTOPSIG(status)to fetch the signal number that caused the child to stop.
WIFCONTINUED(status) True if status was returned for a child that has been continued after a job control stop.
© 2009 Wipro Ltd - Confidential43 © 2009 Wipro Ltd - Confidential43
Process Termination
• Differences between wait & waitpid:– wait can block the caller until a child process terminates; waitpid has
an option that prevents it from blocking.– waitpid doesn't wait for the child that terminates first; it has a number
of options that control which process it waits for.• If a child has already terminated and is a zombie, wait returns
immediately with that child’s status.• Otherwise, it blocks the caller until a child terminates.
– If the caller blocks and has multiple children, wait returns when one terminates.
– We can find out which child has terminated because its PID is returned by wait.
© 2009 Wipro Ltd - Confidential44 © 2009 Wipro Ltd - Confidential44
Process Termination
• Eg: Print a description of the exit status.
void pr_exit(int status){ if (WIFEXITED(status)) printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("abnormal termination, signal number = %d\n", WTERMSIG(status)); else if (WIFSTOPPED(status)) printf("child stopped, signal number = %d\n", WSTOPSIG(status));}
© 2009 Wipro Ltd - Confidential45 © 2009 Wipro Ltd - Confidential45
Process Termination
• Eg: Termination status with multiple children.int main(void){ pid_t pid; int status;
if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) /* child */ exit(7);
if (wait(&status) != pid) /* wait for child */ err_sys("wait error"); pr_exit(status); /* and print its status */
if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) /* child */ abort(); /* generates SIGABRT */
© 2009 Wipro Ltd - Confidential46 © 2009 Wipro Ltd - Confidential46
Process Termination
• Eg: Termination status with multiple children (continued). if (wait(&status) != pid) /* wait for child */ err_sys("wait error"); pr_exit(status); /* and print its status */
if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) /* child */ status /= 0; /* divide by 0 generates SIGFPE */
if (wait(&status) != pid) /* wait for child */ err_sys("wait error"); pr_exit(status); /* and print its status */ exit(0);}
$ ./a.outnormal termination, exit status = 7abnormal termination, signal number = 6abnormal termination, signal number = 8
© 2009 Wipro Ltd - Confidential47 © 2009 Wipro Ltd - Confidential47
Waiting For A Specific Process
• waitpid provides ability to wait for a specific process to terminate.
pid argument Behaviourpid == -1 Waits for any child process. (Equivalent to wait.)pid > 0 Waits for the child whose process ID equals pid.pid == 0 Waits for any child whose process group ID equals that of
the calling process.pid < -1 Waits for any child whose process group ID equals the
absolute value of pid.
© 2009 Wipro Ltd - Confidential48 © 2009 Wipro Ltd - Confidential48
Zombie Process è Example/* mkzombie.c -- Create some defunct processes */
int main(void){ pid_t pids[5]; int i;
for (i = 4; i >= 0; --i) { pids[i] = fork(); if (pids[i] == 0) _exit(0); }
sleep(5);
for (i = 4; i >= 0; --i) waitpid(pids[i], NULL, 0);
return 0;}
© 2009 Wipro Ltd - Confidential49 © 2009 Wipro Ltd - Confidential49
Zombie Process è Example
$ ./mkzombie & ps jHT[1] 18306 PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18307 Rs 1002 0:00 -bash13700 18306 18306 13700 pts/5 18307 S 1002 0:00 ./mkzombie13700 18307 18307 13700 pts/5 18307 R+ 1002 0:00 ps jHT18306 18308 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18309 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18310 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18311 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18312 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>$ after 5 seconds$ ps jHT PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18317 Ss 1002 0:00 -bash13700 18317 18317 13700 pts/5 18317 R+ 1002 0:00 ps jHT[1]+ Done ./mkzombie$
Exact options might vary across systems.
© 2009 Wipro Ltd - Confidential50 © 2009 Wipro Ltd - Confidential50
Orphan Process è Example
/* mkorphan.c -- Create some orphan processes */
int main(void){ pid_t pids[5]; int i;
for (i = 4; i >= 0; --i) { pids[i] = fork(); if (pids[i] == 0) { /* to avoid child exiting before parent */ sleep(5); _exit(0); } }
/* exit without waiting for children */ return 0;}
© 2009 Wipro Ltd - Confidential51 © 2009 Wipro Ltd - Confidential51
Zombie Process è Example
$ ./mkorphan & ps jHT[1] 18463 PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18464 Rs 1002 0:00 -bash13700 18463 18463 13700 pts/5 18464 Z 1002 0:00 [mkorphan] <defunct>13700 18464 18464 13700 pts/5 18464 R+ 1002 0:00 ps jHT 1 18465 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18466 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18467 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18468 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18469 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan[1]+ Done ./mkorphan$ after ~5 seconds$ ps jHT PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18476 Ss 1002 0:00 -bash13700 18476 18476 13700 pts/5 18476 R+ 1002 0:00 ps jHT$
Exact options might vary across systems.
A very transient state.
© 2009 Wipro Ltd - Confidential52 © 2009 Wipro Ltd - Confidential52
exec Functions
• When a process calls one of the exec functions, that process is completely replaced by the new program.
• New program starts executing at its main function.• PID does not change across an exec.
– A new process is not created.– exec merely replaces the current process’ text, data, heap and stack
segments with a new program from disk.
© 2009 Wipro Ltd - Confidential53 © 2009 Wipro Ltd - Confidential53
Process Life Cycle è date
PID à 300PPID à 200
_______________sh
PID à 400PPID à 300
_______________date
PID à 400PPID à 300
_______________sh
Zombie
fork()
exec()exit()
exit status
© 2009 Wipro Ltd - Confidential54 © 2009 Wipro Ltd - Confidential54
exec Functions
• 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[])
© 2009 Wipro Ltd - Confidential55 © 2009 Wipro Ltd - Confidential55
exec Functions
• l stands for list:– Require each of the command-line arguments to new program to be
specified as separate arguments. – End of arguments marked with a NULL pointer.
• v stands for vector:– Build an array of pointers to the arguments, and the address of this
array is the argument.• p stands for path:
– Takes a filename argument.– Uses the PATH environment variable to find the executable file.
• e stands for environment:– Takes an envp[] array instead of using the current environment.
© 2009 Wipro Ltd - Confidential56 © 2009 Wipro Ltd - Confidential56
exec Functions è Inherited Properties
• Process ID and parent process ID• Real user ID, real group ID, Supplementary group IDs• Process group ID• Session ID• Controlling terminal• Time left until alarm clock• Current working directory• Root directory• File mode creation mask• File locks• Process signal mask• Pending signals• Resource limits• Values for tms_utime, tms_stime, tms_cutime and tms_cstime
© 2009 Wipro Ltd - Confidential57 © 2009 Wipro Ltd - Confidential57
exec è Exampleint main(){ pid_t pid; int status;
char *arg[] = { "/usr/bin/whoami", 0 }; extern char **environ;
switch (pid = fork()) { case -1: sys_err("fork failed"); case 0: /* On success, execve does not return */ execve(arg[0], arg, environ); printf("exec succeeded\n"); default: wait(&status); } return 0;}
$ ./a.outharry$
© 2009 Wipro Ltd - Confidential58 © 2009 Wipro Ltd - Confidential58
Exercises
1. A program which has opened some files calls _exit() without closing the file descriptors. Will the files remain open? Will the process exit properly? Is the behaviour any different if exit() was used instead?
2. From a process, create a child using fork(). Try to print the values of inheritable & non-inheritable attributes from both parent & child.
3. Write your own implementation of the system() library call.
© 2009 Wipro Ltd - Confidential60 © 2009 Wipro Ltd - Confidential60
Process Groups
• Each process belongs to a process group.• A process group is a collection of one or more processes.
– Usually associated with the same job.– Can receive signals from the same terminal.– Each process group has a unique process group ID.
• pid_t getpgrp(void)– Returns the process group ID of calling process.
• Each process group can have a process group leader.– Identified by its process group ID being equal to its process ID.– Possible for a process group leader to create a process group, create
processes in the group, and then terminate.– Process group still exists, as long as at least one process is in group,
regardless of whether process group leader terminates.
© 2009 Wipro Ltd - Confidential61 © 2009 Wipro Ltd - Confidential61
Process Groups
• int setpgid(pid_t pid, pid_t pgid)– A process can join an existing process group or create a new process
group.– A process can set the process group ID of only itself or any of its
children.• It is possible to:
– Send a signal to either a single process or a process group.– Wait for a single process or one process from a specified process group
using waitpid.
© 2009 Wipro Ltd - Confidential62 © 2009 Wipro Ltd - Confidential62
Sessions
• A session is a collection of one or more process groups.– Eg:
$ proc1 | proc2 &$ proc3 | proc4 | proc5
© 2009 Wipro Ltd - Confidential63 © 2009 Wipro Ltd - Confidential63
Sessions
• Process that creates a session is called a session leader.• A process establishes a new session by:
– pid_t setsid(void)– If calling process is not a process group leader,
• It becomes session leader of this new session. It is the only process in this new session.
• It becomes process group leader of a new process group. The new process group ID is the process ID of the calling process.
• It has no controlling terminal. If it had a controlling terminal before calling setsid, that association is broken.
© 2009 Wipro Ltd - Confidential64 © 2009 Wipro Ltd - Confidential64
Sessions è Example/* setsid.c -- Session example */
int main(){ pid_t pid, sid;
if ((pid = fork()) == -1) sys_err("fork error"); else if (pid != 0) { printf("parent=%d, child=%d\n", getpid(), pid); exit(EXIT_SUCCESS); } if ((sid = setsid()) == -1) sys_err("setsid error");
printf("pid=%d, sid=%d, pgid=%d\n", getpid(), sid, getpgrp()); return 0;}
$ ./setsidparent=29512, child=29513pid=29513, sid=29513, pgid=29513
© 2009 Wipro Ltd - Confidential66 © 2009 Wipro Ltd - Confidential66
• Software interrupts.• Provide a way of handling asynchronous events.
– Eg: A user at a terminal typing the interrupt key to stop a program, letting parent process know that its child has terminated etc.
• Every signal has a name (beginning with “SIG”).– Defined by positive integer constants (signal number) in <signal.h>.– Eg: Some well known signals:
Introduction
Signal Value CommentSIGHUP 1 Hangup detected on controlling terminal or death of controlling processSIGINT 2 Interrupt from keyboardSIGKILL 9 Kill signalSIGSEGV 11 Invalid memory referenceSIGTERM 15 Termination signal
© 2009 Wipro Ltd - Confidential67 © 2009 Wipro Ltd - Confidential67
• Numerous conditions can generate a signal:– Terminal-generated signals occur when users press certain terminal
keys.• Eg: <Control-C> causing SIGINT to be generated.
– Hardware exceptions. • Kernel generates appropriate signal for the process.• Eg: Divide by 0, invalid memory reference.
– kill system call allows a process to send any signal to another process or process group.
• Have to be the owner of the process that we're sending the signal to, or be the superuser.
• Also used by kill command.– Software conditions.
• Eg: SIGPIPE generated when a process writes to a pipe after the reader of the pipe has terminated.
Signal Generation
© 2009 Wipro Ltd - Confidential68 © 2009 Wipro Ltd - Confidential68
Handling Signals
• To a process, signals seemingly appear to be random.– So it can’t simply test a variable to see whether a signal has occurred.– Instead, process has to tell kernel “if and when this signal occurs, do the
following.” (Disposition of the signal, or the action associated it)• Possible actions:
– Ignore the signal.• SIGKILL and SIGSTOP can never be ignored.
– Catch the signal.• By telling the kernel to call a function (signal handler) of ours whenever the signal
occurs.• Handling the condition is left to the function implementation.
– When SIGCHLD is caught, calling waitpid to fetch child's PID and termination status.
– Handling SIGTERM (default signal sent by kill command) to clean up temporary files created by the process.
• SIGKILL and SIGSTOP cannot be caught.– Let the default action apply.
• Every signal has a default action.
© 2009 Wipro Ltd - Confidential69 © 2009 Wipro Ltd - Confidential69
Handling Signals• void (*signal(int signo, void (*func)(int)))(int)
– func is SIG_IGN (ignore), SIG_DFL (default) or address of signal handler.
static void sig_usr(int signo) /* argument is signal number */{ if (signo == SIGUSR1) printf("received SIGUSR1\n"); else if (signo == SIGUSR2) printf("received SIGUSR2\n"); else err_dump("received signal %d\n", signo);}
int main(void){ if (signal(SIGUSR1, sig_usr) == SIG_ERR) err_sys("can't catch SIGUSR1"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) err_sys("can't catch SIGUSR2"); for ( ; ; ) pause(); /* suspends calling process until a signal is received */}
It is possible to use the same signal handler for handling multiple signals.
© 2009 Wipro Ltd - Confidential70 © 2009 Wipro Ltd - Confidential70
Handling Signals
– Behaviour from command line:
– When a process calls fork, child inherits parent’s signal dispositions.• So address of a signal-catching function has meaning in the child.
$ ./a.out & start process in background[1] 7216 job-control shell prints job number & Process ID$ kill -USR1 7216 send it SIGUSR1received SIGUSR1$ kill -USR1 7216 send it SIGUSR1 againreceived SIGUSR1$ kill -USR1 7216 send it SIGUSR1 one last timereceived SIGUSR1$ kill -USR2 7216 send it SIGUSR2received SIGUSR2$ kill 7216 now send it SIGTERM[1]+ Terminated ./a.out
© 2009 Wipro Ltd - Confidential71 © 2009 Wipro Ltd - Confidential71
• Signal generation– A signal is generated for a process (or sent to a process) when the
event that causes the signal occurs.• Event could be a hardware exception (Eg: divide by 0), a software condition
(Eg: an alarm timer expiring), a terminal-generated signal, or a call to killfunction.
– When the signal is generated, kernel sets a flag of some form in the process table.
• Signal delivery– A signal is delivered to a process when the action for a signal is taken.
• Signal pending– During the time between generation of a signal and its delivery, the
signal is said to be pending.
Signal Terminology
© 2009 Wipro Ltd - Confidential72 © 2009 Wipro Ltd - Confidential72
Signal Terminology
• Signal blocking– A process has the option of blocking the delivery of a signal.– If a signal that is blocked is generated for a process, and if the action for
that signal is either the default action or to catch the signal, then the signal remains pending for the process until the process either:
• unblocks the signal, or • changes the action to ignore the signal.
– The system determines what to do with a blocked signal when the signal is delivered, not when it's generated.
• Signal mask– Each process has a signal mask that defines the set of signals currently
blocked from delivery to that process.• Signal set
– Data type (sigset_t) to represent multiple signals.– Eg: Signal mask is stored in a signal set.
© 2009 Wipro Ltd - Confidential73 © 2009 Wipro Ltd - Confidential73
Signal Generation è kill and raise
• int kill(pid_t pid, int signo)– Sends a signal to a process or a group of processes.
• int raise(int signo)– Allows a process to send a signal to itself.– Equivalent to: kill(getpid(), signo);
pid Behaviour> 0 Signal is sent to the process whose process ID is pid.== 0 Signal is sent to all processes whose process group ID equals the
process group ID of the sender and for which the sender has permission to send the signal.
< -1 Signal is sent to all processes whose process group ID equals the absolute value of pid and for which the sender has permission to send the signal.
== -1 Signal is sent to all processes on the system for which the sender has permission to send the signal.
Note: (For the last 3 cases (pid <= 0), system processes (kernel processes and init) are excluded.
© 2009 Wipro Ltd - Confidential74 © 2009 Wipro Ltd - Confidential74
Signal Generation è kill and raise
• A process needs permission to send a signal to another process.– Superuser can send a signal to any process.– For other users, basic rule is:
• Real or effective user ID of sender = Real or effective user ID of receiver.
© 2009 Wipro Ltd - Confidential75 © 2009 Wipro Ltd - Confidential75
Signal Generation è alarm and pause
• unsigned int alarm(unsigned int seconds)– Sets a timer that will expire at a specified time in future.
• When timer expires, SIGALRM signal is generated.– Default action is to terminate the process.
• But most processes that use an alarm clock catch SIGALRM.– Ensure that signal handler is installed before calling alarm.
– Only one alarm clock per process.• If we call alarm, and a previously registered alarm has not expired:
– Time left for previous alarm clock is returned.– Previous registered alarm clock is replaced by new value.
– fork clears pending alarms in child process.• int pause(void)
– Suspends calling process until a signal is caught.• If signal’s action is to terminate the process, pause will not return.• If action is to execute a signal handler, pause will return -1 after handler
returns.
© 2009 Wipro Ltd - Confidential76 © 2009 Wipro Ltd - Confidential76
alarm & pause è Examplestatic void catch_sig(int signo){ if (signo == SIGALRM) printf("Caught SIGALRM\n");}
int main(void){ signal(SIGALRM, catch_sig); printf("Timeout in 5 seconds\n");
alarm(5); /* Timeout in 5 seconds */ pause();
return 0;}
$ ./a.outTimeout in 5 secondsCaught SIGALRM$
© 2009 Wipro Ltd - Confidential77 © 2009 Wipro Ltd - Confidential77
Signal Set Operations• int sigemptyset(sigset_t *set)
– Initialize signal set so that all signals are excluded.• int sigfillset(sigset_t *set)
– Initialize signal set so that all signals are included.• int sigaddset(sigset_t *set, int signo)
– Add a signal to an existing set.• int sigdelset(sigset_t *set, int signo)
– Remove a signal from an existing set.• int sigismember(const sigset_t *set, int signo)
– Tests whether a signal is a member of an existing set.
• Note:– No signal set should be used unless sigemptyset or sigfillset has
been called to initialize the set.– Any signal set function can be applied after initialization has been
performed.
© 2009 Wipro Ltd - Confidential78 © 2009 Wipro Ltd - Confidential78
Signal Set Operations è Exampleint main(){ sigset_t sigset1, sigset2;
sigemptyset(&sigset1); /* Initialize as empty */ sigaddset(&sigset1, SIGINT); /* Add SIGINT to set */ sigaddset(&sigset1, SIGPIPE); /* Add SIGPIPE to set */
sigfillset(&sigset2); /* Initialize with all sigs */ sigdelset(&sigset2, SIGINT); /* Del SIGINT from set */
if (sigismember(&sigset1, SIGINT)) printf("sigset1 has SIGINT\n"); else printf("sigset1 doesn't have SIGINT\n");
if (sigismember(&sigset1, SIGTERM)) printf("sigset1 has SIGTERM\n"); else printf("sigset1 doesn't have SIGTERM\n");
© 2009 Wipro Ltd - Confidential79 © 2009 Wipro Ltd - Confidential79
Signal Set Operations è Example if (sigismember(&sigset2, SIGINT)) printf("sigset2 has SIGINT\n"); else printf("sigset2 doesn't have SIGINT\n");
if (sigismember(&sigset2, SIGTERM)) printf("sigset2 has SIGTERM\n"); else printf("sigset2 doesn't have SIGTERM\n");
return 0;}
$ ./a.outsigset1 has SIGINTsigset1 doesn't have SIGTERMsigset2 doesn't have SIGINTsigset2 has SIGTERM
© 2009 Wipro Ltd - Confidential80 © 2009 Wipro Ltd - Confidential80
Blocking Signals
• Certain signals could be blocked during call to signal handler.• Use case è An application can enter a critical piece of code where
signals could cause problems.– Eg:
• A program is keeping track of child process termination status in a linked list.• If program is updating the list, you do not want signal handler to be called
until the list has been completely updated.• Otherwise, corruption of the list would result.
– Critical sections of code can block certain signals from taking place.– Once critical section is completed, then selected signals can be
enabled.– This functionality is supported by sigprocmask.
© 2009 Wipro Ltd - Confidential81 © 2009 Wipro Ltd - Confidential81
Signal Mask Operations• int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
– A process can examine its signal mask, change its signal mask, or perform both operations in one step.
– If oldset is a non-NULL, process’ current signal mask is returned through it.– If set is a non-NULL, how indicates how current signal mask is modified.
– After calling sigprocmask, if any unblocked signals are pending, at least one of them is delivered to the process before sigprocmask returns.
– Defined only for single-threaded processes.
how DescriptionSIG_BLOCK New signal mask = Current signal mask U set.
(set contains additional signals to be blocked.)SIG_UNBLOCK New signal mask = Current signal mask • Complement of set.
(set contains the additional signals to be unblocked.)
SIG_SETMASK New signal mask = set.
© 2009 Wipro Ltd - Confidential82 © 2009 Wipro Ltd - Confidential82
Signal Mask Operations è Example
/* Example showing how to block signals SIGINT & SIGPIPE from being received */
sigset_t set_block; /* Signals to block */sigset_t set_save; /* Saved signal mask */
sigemptyset(&set_block); /* Clear set */sigaddset(&set_block, SIGINT); /* Add SIGINT */sigaddset(&set_block, SIGPIPE); /* Add SIGPIPE */sigprocmask(SIG_BLOCK, &set_block, &set_save); /* Block signals */
/* !!! Critical code goes here !!! */
sigprocmask(SIG_SETMASK, &set_save, 0); /* Restore mask */
© 2009 Wipro Ltd - Confidential83 © 2009 Wipro Ltd - Confidential83
Pending Signals
• When signals are blocked by sigprocmask,– They are not ‘lost’.– Rather, they become pending signals.– A program can inquire if a signal is pending.
• int sigpending(sigset_t *set)– Gets set of signals that are blocked from delivery and currently pending
for the calling process.– Once pending set is obtained, you can query for a specific signal using
sigismember.
© 2009 Wipro Ltd - Confidential84 © 2009 Wipro Ltd - Confidential84
Signal Mask/Set/Pending è Examplestatic void sig_quit(int signo){ printf("caught SIGQUIT\n"); if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) printf("can't reset SIGQUIT");}
int main(void){ sigset_t newmask, oldmask, pendmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR) printf("can't catch SIGQUIT");
/* Block SIGQUIT and save current signal mask. */ sigemptyset(&newmask); sigaddset(&newmask, SIGQUIT); if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) printf("SIG_BLOCK error");
Beware: changing the order of sigemptysetand sigaddset is a common bug.
© 2009 Wipro Ltd - Confidential85 © 2009 Wipro Ltd - Confidential85
Signal Mask/Set/Pending è Example sleep(5); /* SIGQUIT here will remain pending */ if (sigpending(&pendmask) < 0) printf("sigpending error"); if (sigismember(&pendmask, SIGQUIT)) printf("\nSIGQUIT pending\n");
/* Reset signal mask which unblocks SIGQUIT. */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) printf("SIG_SETMASK error"); printf("SIGQUIT unblocked\n");
sleep(5); /* SIGQUIT here will terminate with core file */ exit(0);}
$ ./a.out^\ generate signal once (before 5 seconds are up)SIGQUIT pending after return from sleepcaught SIGQUIT in signal handlerSIGQUIT unblocked after return from sigprocmask^\Quit(coredump) generate signal again; printed by shell$
© 2009 Wipro Ltd - Confidential86 © 2009 Wipro Ltd - Confidential86
Signal Mask/Set/Pending è Example
– Notes:• <Control-backslash> is the terminal quit character.
– Understand the correct characters on your system by running ‘stty –a’command.
• If a signal is pending and becomes unblocked, it is delivered before sigprocmask returns.
• Though the quit signal is generated multiple times while the process is asleep, it is delivered only once to the process when it’s unblocked.
– Signals are not queued.• The message Quit(coredump) is printed by the shell when it sees that its
child terminated abnormally.
$ ./a.out^\^\^\ generate signal 3 times (before 5 seconds are up)SIGQUIT pending after return from sleepcaught SIGQUIT in signal handler; signal is generated only onceSIGQUIT unblocked after return from sigprocmask^\Quit(coredump) generate signal again; printed by shell$
© 2009 Wipro Ltd - Confidential87 © 2009 Wipro Ltd - Confidential87
Signal Action• int sigaction(int signo, const struct sigaction *act, struct
sigaction *oldact)– Examine or modify (or both) action associated with a particular signal.– Supersedes signal.
– oldact allows us to obtain original handler state.• Used when new handler is temporary, such as within a library function.• Before library function returns, original signal action can be restored
precisely as it was.– sa_mask represents the set of other signals that should be blocked
while current signal is being processed.• In addition, signal being processed will be blocked unless SA_NODEFER or SA_NOMASK flag is used.
struct sigaction { void (*sa_handler)(int); /* address of signal handler, */ /* or SIG_IGN, or SIG_DFL */ sigset_t sa_mask; /* additional signals to block */ int sa_flags; /* signal options */ void (*sa_sigaction)(int, siginfo_t *, void *); /* alternate handler */};
© 2009 Wipro Ltd - Confidential88 © 2009 Wipro Ltd - Confidential88
Signal Action è Examplestatic int count = 0;
void handler(int signo){ ++count; printf("Got SIGINT (%d)\n", signo);}
void get_handler_status(int signo){ struct sigaction sa_old;
if (sigaction(signo, 0, &sa_old) == -1) /* Query signal */ sys_err("sigaction failed");
if (sa_old.sa_handler == SIG_DFL) printf("SIG_DFL - System default\n"); else if (sa_old.sa_handler == SIG_IGN) printf("SIG_IGN - Ignore signal\n"); else printf("sa_handler=%p\n", sa_old.sa_handler);}
© 2009 Wipro Ltd - Confidential89 © 2009 Wipro Ltd - Confidential89
Signal Action è Exampleint main(void){ struct sigaction sa_old, sa_new;
get_handler_status(SIGINT); /* Get default action */
sa_new.sa_handler = handler; sigemptyset(&sa_new.sa_mask); sa_new.sa_flags = 0; sigaction(SIGINT, &sa_new, &sa_old); /* Save old action */ get_handler_status(SIGINT); /* Verify new action */
while (count < 2) { printf("Waiting for SIGINT...\n"); sleep(4); }
sigaction(SIGINT, &sa_old, 0); /* Restore old action */ get_handler_status(SIGINT); /* Verify old action */ return 0;}
© 2009 Wipro Ltd - Confidential90 © 2009 Wipro Ltd - Confidential90
Signal Action è Example$ ./a.outSIG_DFL - System defaultsa_handler=0x4006dcWaiting for SIGINT...Waiting for SIGINT...Waiting for SIGINT...Waiting for SIGINT...^CGot SIGINT (2)Waiting for SIGINT...Waiting for SIGINT...^CGot SIGINT (2)SIG_DFL - System default$
© 2009 Wipro Ltd - Confidential91 © 2009 Wipro Ltd - Confidential91
Unblocking Pending Signals
• After noting that a signal is pending, we need a way to unblock that signal and allow the signal to be raised.
• int sigsuspend(sigset_t *set)– Temporarily applies the signal mask supplied and waits for signal to be
raised.– If the mask permits the signal you know to be pending, signal action will
take place immediately.– Otherwise, the program will pause indefinitely until an unblocked signal
is received.– Once signal action is carried out, original signal mask is re-established.
• When sigsuspend is called, program is suspended indefinitely until a signal is raised.
© 2009 Wipro Ltd - Confidential92 © 2009 Wipro Ltd - Confidential92
sigsuspendè Examplesigset_t pending; /* Pending signal set */sigset_t notpipe; /* All but SIGPIPE */
sigfillset(¬pipe); /* Set to all signals */sigdelset(¬pipe, SIGPIPE); /* Remove SIGPIPE */
sigpending(&pending); /* Query which signals are pending */if (sigismember(&pending, SIGPIPE)) /* Is SIGPIPE pending? */ sigsuspend(¬pipe); /* Yes, allow SIGPIPE to be raised */
© 2009 Wipro Ltd - Confidential93 © 2009 Wipro Ltd - Confidential93
sigsuspendè Examplestatic void catch_sig(int signo){ if (signo == SIGINT) { alarm(0); /* Cancel the timer */ printf("CAUGHT SIGINT\n"); } else if (signo == SIGALRM) printf("CAUGHT SIGALRM\n");}
int main(void){ sigset_t sigs; struct sigaction sa_old, sa_new;
sa_new.sa_handler = catch_sig; sigemptyset(&sa_new.sa_mask); sigaddset(&sa_new.sa_mask, SIGALRM); sigaddset(&sa_new.sa_mask, SIGINT); sa_new.sa_flags = 0;
sigaction(SIGINT, &sa_new, &sa_old); sigaction(SIGALRM, &sa_new, 0);
© 2009 Wipro Ltd - Confidential94 © 2009 Wipro Ltd - Confidential94
sigsuspendè Example sigfillset(&sigs); sigdelset(&sigs, SIGINT); sigdelset(&sigs, SIGALRM);
printf("You have 10 seconds to SIGINT:\n");
alarm(10); /* Timeout in 10 seconds */ sigsuspend(&sigs); /* Wait for SIGINT or SIGALRM */
printf("Done\n"); return 0;}
$ ./a.outYou have 10 seconds to SIGINT:CAUGHT SIGALRMDone$ ./a.outYou have 10 seconds to SIGINT:CAUGHT SIGINTDone$
Let the timer expire by not issuing a keyboard interrupt.
Before the timer expires, issue a keyboard interrupt.
© 2009 Wipro Ltd - Confidential95 © 2009 Wipro Ltd - Confidential95
Job-Control Signals
• Usually 6.
SIGCHLD Child process has stopped or terminated.SIGCONT Continue process, if stopped.SIGSTOP Stop signal (can't be caught or ignored).SIGTSTP Interactive stop signal.SIGTTIN Read from controlling terminal by member of a background process group.SIGTTOU Write to controlling terminal by member of a background process group.
© 2009 Wipro Ltd - Confidential97 © 2009 Wipro Ltd - Confidential97
• Processes that live for a long time.– Often started during system boot-up & terminate only when system is
shutdown.– Perform specific perform day-to-day activities.
• Don’t have a controlling terminal; so they “run in the background”.• Typical output from ps command:
Daemon Characteristics
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 3809 3809 3809 ? -1 Ss 101 0:02 /sbin/syslogd1 3866 3866 3866 ? -1 Ss 0 0:00 /usr/sbin/sshd1 3882 3882 3882 ? -1 Ss 0 0:11 /usr/sbin/nmbd -D1 3884 3884 3884 ? -1 Ss 0 0:00 /usr/sbin/smbd -D1 3900 3899 3899 ? -1 S 0 0:00 /usr/sbin/vsftpd1 3931 3931 3931 ? -1 Ss 1 0:00 /usr/sbin/atd1 3956 3956 3956 ? -1 Ss 0 0:02 /usr/sbin/cron1 3975 3975 3975 ? -1 Ss 0 0:13 /usr/sbin/apache2
© 2009 Wipro Ltd - Confidential98 © 2009 Wipro Ltd - Confidential98
Coding Rules
1. Call umask to set file mode creation mask to 0.– Mask that’s inherited could be set to deny certain permissions.– If daemon process is going to create files, it may want to set specific
permissions.2. Call fork and have parent exit.
– If daemon was started from a shell, having parent terminate makes the shell think that the command is done.
– Inherits process group ID of parent but gets a new PID.• Guarantees that child is not a process group leader.• Prerequisite for Step 3.
3. Call setsid to create a new session.– The process:
• Becomes a session leader of a new session.• Becomes process group leader of a new process group.• Has no controlling terminal.
© 2009 Wipro Ltd - Confidential99 © 2009 Wipro Ltd - Confidential99
Coding Rules
4. Change current working directory (CWD) to root directory.– CWD inherited from parent could be on a mounted file system.– Since daemons normally exist until the system is rebooted, if the
daemon stays on a mounted file system, that file system cannot be unmounted.
5. Unneeded file descriptors should be closed.– Prevent daemon from holding open any descriptors that it may have
inherited from its parent.6. Some daemons open file descriptors 0, 1, and 2 to /dev/null.
– Any library routines that try to read from standard input or write to standard output or standard error will have no effect.
• Some systems provide a daemon routine to achieve these.– We will implement our own version of this.
© 2009 Wipro Ltd - Confidential100 © 2009 Wipro Ltd - Confidential100
Daemon Coding Rules è Examplevoid daemonize(const char *cmd){ int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; struct sigaction sa;
/* Clear file creation mask. */ umask(0);
/* Get maximum number of file descriptors. */ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) err_quit("%s: can't get file limit", cmd);
/* Become a session leader to lose controlling TTY. */ if ((pid = fork()) < 0) err_quit("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0); setsid();
© 2009 Wipro Ltd - Confidential101 © 2009 Wipro Ltd - Confidential101
Daemon Coding Rules è Example /* Ensure future opens won't allocate controlling TTYs. */ sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) err_quit("%s: can't ignore SIGHUP"); if ((pid = fork()) < 0) err_quit("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0);
/* Change the current working directory to the root so * we won't prevent file systems from being unmounted. */ if (chdir("/") < 0) err_quit("%s: can't change directory to /");
/* Close all open file descriptors. */ if (rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; for (i = 0; i < rl.rlim_max; i++) close(i);
© 2009 Wipro Ltd - Confidential102 © 2009 Wipro Ltd - Confidential102
Daemon Coding Rules è Example /* Attach file descriptors 0, 1, and 2 to /dev/null. */ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0);
/* Initialize the log file. */ openlog(cmd, LOG_CONS, LOG_DAEMON); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2); exit(1); }}
© 2009 Wipro Ltd - Confidential103 © 2009 Wipro Ltd - Confidential103
Daemon Conventions
• Single-instance daemons use file locking to ensure that only one copy of a daemon is running.– Daemon creates a file and places a write lock on the entire file. – Another attempt to write lock will fail, indicating that another daemon
instance is already running.– Lock will be removed automatically if daemon exits.
• If daemon uses a lock file, it is usually stored in /var/run.– Usually <name>.pid, where <name> is name of daemon or service.
• If daemon supports configuration options, they are usually stored in /etc.– Usually named <name>.conf.
• Usually started from one of system initialization scripts (/etc/rc* or /etc/init.d/*).
• If a daemon has a configuration file, it is read only on start-up.– To reload any of the configuration changes, daemons will catch SIGHUP
and re-read configuration files when they receive the signal.
© 2009 Wipro Ltd - Confidential104 © 2009 Wipro Ltd - Confidential104
References / Further Reading
• Advanced Programming in the UNIX Environment (2nd Edition) è by W. Richard Stevens, Stephen A. Rago
• Unix Programming Environmentè by Brian W. Kernighan, Rob Pike
• Advanced UNIX Programming (2nd Edition) è by Marc J. Rochkind• Design of the UNIX Operating Systemè by Maurice J. Bach