Please forward to the ECE397A mailing list Important process related Unix system calls  and hints for HW1 For HW1 use "sleep(seconds)" for sleeping a process. Read below for the  other Unix calls. Use "kill(pid, signal_type)" to kill a process.  Use the fork() call to create a process. Use the wait and waitpid()  to wait inbetween the parent and children (see below). See below for more information related to UNIX calls that could be used and examples.  If you have questions please send email to me or the TAs. The fork() System Call To create a new process in UNIX the fork() system call is used. fork() creates a new context based on the context of the calling process. The fork() call is unusual in that it returns twice: It returns in both the process calling fork() and in the newly created process.  The synopsis for fork() is as follows:         #include         pid_t fork(void);        pid_t vfork(void); If fork() is sucessful, it returns a number of type pid_t which is greater than 0 and represents the PID of the newly created child process. In the child process, fork() returns 0. If fork() fails then its return value will be less than 0. vfork() is a more efficient version of fork(), which does not duplicate the entire parent context. vfork() is suitable for use with exec(), which will be described later.  A trivial example of fork() follows. Here, the parent process prints ``Hello'' to stdout, and the new child process prints ``World.''. Note that the order of printing is not guaranteed. Without some method of synchronising the processes execution, ``Hello'' may or may not be printed before ``World.''.          #include          #include  	         char string1[] = "Hello";         char string2[] = "World.\\n";         int main(void)         {                 pid_t PID;		                 PID = fork();                 if (PID == 0)                   /* In the child process? */                         printf("%s", string2);                 else                            /* In the parent process */                         printf("%s", string1);                 exit(0);                        /* Executed by both processes */   The exec() Family of System Calls Often we wish to spawn a different process as a child of the process that is executing. In order to accomplish this, we must first create a new process using fork() and then replace the image of the child process with a new process image. The image of a new process is created by the operating system from an executable binary file stored on disk.  The exec() family of system calls replace the image of the calling process with the image of a different process stored on disk. The synopsis of the exec() family of system calls follows:         #include         extern char **environ;        int execl( const char *path, const char *arg, ...);        int execlp( const char *file, const char *arg, ...);        int execle( const char *path, const char *arg , ..., char *const envp[]);        int exect( const char *path, char *const argv[]);        int execv( const char *path, char *const argv[]);        int execvp( const char *file, char *const argv[]); Refer to the exec manual page for a detailed discription of these functions. We shall only discuss execlp(). The listing below shows how execlp() is used to execute the UNIX ls program as a child of the parent process.          #include          #include          int main(void)         {                 pid_t PID;                 PID = vfork();                 if (PID == 0)                   /* In the child process? */                         execlp("/bin/ls", "");  /* Execute ls as the child */                 wait((int *) 0);                /* Wait for the child */                 printf("done!\\n");                 exit(0);         } When the child process executes execlp() its PID does not change, and the operating system still recognises the child process as belonging to the parent process. The child process terminates its execution as soon as ls has finished executing. Should execlp() (or any other member of the exec() family) fail to create a new process image then they will return a number less than 0.  The wait() System Call In the above example for execl(), the wait() system call is being used to force the parent process to wait until its child process has terminated before it resumes execution. Hence ``done!'' is always going to be printed to the terminal after the output of ls has been displayed.  The synopsis for wait() is as follows:         #include         #include         pid_t wait(int *status)        pid_t waitpid(pid_t pid, int *status, int options); The wait() system call suspends execution of the current process until a child of that process has terminated. If the child exits before wait() is executed then wait returns immediately. wait() accepts a single call-by-reference argument in which wait() stores the child processes exit value. If the argument to wait() is 0 then no attempt to return the childs exit status is made.  The waitpid() system call suspends execution of the current process until the child with the specified PID terminates. This is useful if the current process has spawned multiple children but is only required to wait on a particular one. Refer to the on-line UNIX wait manual page for further details of waitpid().  The exit() System Call The purpose of the exit() system call is to gracefully terminate the currently executing process. A status number is returned by exit() to the parent of the terminating process. The status value is used to indicate if the terminating process was successful or not. Typically negative status values indicate an error occured, while 0 indicates successful execution.  The synopsis for exit() follows:         #include         void exit(int status); The use of exit() to terminate a process is not required, but is encouraged to ensure that the status value of the terminating process is explicitly set. exit() never returns to the calling process, so it's return type is void. Any open streams and files belonging to the terminating process are automatically flushed and closed during exit().  Sending a Signal Unix supports the idea of sending software signals to a process. These signals are ways for other processes to interact with a running process outside the context of the hardware. The kill command is used to send a signal to a process. In addition, it is possible to write a signal handler in either C or the Shell that responds to a signal being sent. For example, many system administration utilities, such as the name server, respond to SIGHUP signal by re-reading their configuration file. This can then be used to update the process while running without having to terminate and restart the process.  For many signals there is really nothing that can be done other than printing an appropriate error message and terminating the process. The signals that system administrators will use the most are the HUP, KILL, and STOP signals. The HUP signal as mentioned previously is used by some utilities as a way to notify the process to do something. The KILL signal is used to abort a process. The STOP command is used to pause a process.  A common problem system administrators will see is one where a user made a mistake and is continuely forking new processes. While all users have some limit on the number of processes they can fork, as they reach that limit they will wait, if you kill a process the system will resume creating new processes on behalf of the user. The best way to handle this is to send the STOP signal to all processes. In this way, all processes are now suspended, then you can send a KILL signal to the processes. Since the processes were first suspended they can't create new processes as you kill the ones off.  Signals available under Unix       SIGHUP     01       hangup      SIGINT     02       interrupt      SIGQUIT    03[1]    quit      SIGILL     04[1]    illegal instruction (not reset when caught)      SIGTRAP    05[1][5] trace trap (not reset when caught)      SIGABRT    06[1]    abort      SIGEMT     07[1][4] EMT instruction      SIGFPE     08[1]    floating point exception      SIGKILL    09       kill (cannot be caught or ignored)      SIGBUS     10[1]    bus error      SIGSEGV    11[1]    segmentation violation      SIGSYS     12[1]    bad argument to system call      SIGPIPE    13       write on a pipe with no one to read it      SIGALRM    14       alarm clock      SIGTERM    15       software termination signal      SIGUSR1    16       user-defined signal 1      SIGUSR2    17       user-defined signal 2      SIGCLD     18[2]    death of a child      SIGPWR     19[2]    power fail (not reset when caught)      SIGSTOP    20[6]    stop (cannot be caught or ignored)      SIGTSTP    21[6]    stop signal generated from keyboard      SIGPOLL    22[3]    selectable event pending      SIGIO      23[2]    input/output possible      SIGURG     24[2]    urgent condition on IO channel      SIGWINCH   25[2]    window size changes      SIGVTALRM  26       virtual time alarm      SIGPROF    27       profiling alarm      SIGCONT    28[6]    continue after stop (cannot be ignored)      SIGTTIN    29[6]    background read from control terminal      SIGTTOU    30[6]    background write to control terminal      SIGXCPU    31       cpu time limit exceeded [see setrlimit(2)]      SIGXFSZ    32       file size limit exceeded [see setrlimit(2)]  Sending a Signal to Another Process: System Call kill()  To send a signal to another process, we need to use the Unix system kill(). The following is the prototype of kill(): int  kill(pid_t pid, int sig) a.. System call kill() takes two arguments. The first, pid, is the process ID you want to send a signal to, and the second, sig, is the signal you want to send. Therefore, you have to find some way to know the process ID of the other party. b.. If the call to kill() is successful, it returns 0; otherwise, the returned value is negative. c.. Because of this capability, kill() can also be considered as a communication mechanism among processes with signals SIGUSR1 and SIGUSR2. d.. The pid argument can also be zero or negative to indicate that the signal should be sent to a group of processes. But, for simplicity, we will not discuss this case.