Processes and Signals

Many examples come from either Beginning Linux Programming by Neil Matthew and Richard Stones Or from Dr. Robert Siegfried

Process definition: Address space; threads (program(s)) running inside that space); required system resources for those threads.

Process contents: program code, data, variables in system memory, open files (file descriptors), and an environment space filled with environment variables, and its own program counter to keep track of which statement it is executing in each of its threads. (Linux actually shares one copy of code used by more than one process – like windows DLL.)

picture from https://courses.cs.washington.edu/courses/cse451/04wi/section/ab/notes/fork/

Operating system handles many processes appearing to run at the same time. (many users, many jobs from each user, many system processes – all at once)

See my process: (looking at Linux's process table)

PEPPER>ps –f (use psef to see all system processes)

UID

PID

PPID

C

STIME

TTY

TIME

CMD

PEPPER

17154

17153

0

12:04

pts/1

00:00:00

-bash

PEPPER

17277

17154

0

12:19

pts/1

00:00:00

ps –f

 

·         PID is process identifier

·         PPID is parent process ID. (See how my bash launched my ps)

·         C is CPU utilization percentage.

·         CMD is the command used to start the process

o   See process values with cd /proc/<your process id>

 PEPPER>ps -ax | egrep 'PEPPER|PID|init'

PID

TTY

STAT

TIME

COMMAND

1

?

Ss

0:04

/sbin/init

17153

?

S

0:00

sshd: PEPPER@pts/1

17411

pts/1

S+

0:00

egrep PEPPER|PID

 

init – startup process, parent to all others

PROCESS STAT CODES

       Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to describe the state of a process: from http://askubuntu.com/questions/360252/what-do-the-stat-column-values-in-ps-mean

·         D    uninterruptible sleep (usually IO)

·         R    running or runnable (on run queue)

·         S    interruptible sleep (waiting for an event to complete)

·         T    stopped, either by a job control signal or because it is being traced.

·         W    paging (not valid since the 2.6.xx kernel)

·         X    dead (should never be seen)

·         Z    defunct ("zombie") process, terminated but not reaped by its parent.

·         <    high-priority (not nice to other users)

·         N    low-priority (nice to other users)

·         L    has pages locked into memory (for real-time and custom IO)

·         s    is a session leader

·         l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

·         +    is in the foreground process group.

How does Linux decide who gets what timeslice for how long?

·         Has a niceness measure. See with ps –l

·         Well-behaved programs that do not hog cpu are nice, such as those that wait for some input occasionally.

·         Linux adjusts nice value, rewarding waits for input. You can also forcefully set your nice value to increase your priority. 

·         The lower the number the higher the priority.

How Linux starts your login:

·         fork – new process id

·         exec – replace existing process with a new program

 

https://www.washington.edu/R870/img/fork-exec.gif

·         picture from https://www.washington.edu/R870/img/fork-exec.gif

 

Starting new processes  with system – launch a shell process which launches another process

Use system to Launch one program from inside another and wait for its response. It first creates a child shell and then executes the program from that shell

use system from inside stdlib.h

int system (const char *string);

response : 127 = shell cannot be started for the new process; -1 = any other error; any other code: the exit code of the command called.

Make it not wait by sending the process to the background.  

Example: wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/process1.c

·         #include <stdlib.h>

·         #include <stdio.h>

·         int main()

·         {

·         printf("running ps with system\n");

·         system("ps ax &"); // when & sends to background, done prints first,

·                                       // remove & to make done print last

·         printf("Done.\n");

·         exit(0);

·         }

Replacing a Process Image with exec family

The exec series of commands will hand off execution from one program to another. The launching program space is replaced by the new program, keeping the open file descriptors and some other process settings.

more efficient than the system command

inside unistd.h

·         execl, exclp, execl3 – take a variable number of arguments ending with a null pointer.

·         execv, execvp, execve – take a second argument as an array of strings.

·         ending e- also sends an environment variable

·         ending p – just give the file and it will search your path

·         return value: only returns with error because the process is being replaced. -1 is an error.

o   Sample calls: wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/process2.c

§  #include <unistd.h>

§  int main(int argc, char *argv[])

§  {

§  // set an environment to be used to pass to the commands ending in e

§  char * const ps_env[] = {"PATH=/bin:/usr/bin" "TERM=console", NULL};

§  execl("/bin/ps", "ps","ax",NULL);

§  execlp("ps", "ps","ax",NULL);

§  execle("/bin/ps", "ps","ax",NULL, ps_env);

§  // assume program is called with parms "ps", "ax" , 0

§  execv("/bin/ps", argv);

§  execvp("ps", argv);

§  execve("/bin/ps", argv, ps_env);

§  }

 

Duplicate a Process from within that Process using fork – can wait for response

The fork command will create a new process almost identical to the parent process, executing the same code, but with its own data space, environment, and file descriptors.

function prototype: pid_t fork(void)

return: to the parent it returns process id of child if good and -1 if error; to the child it returns 0 (thus your program can test the fork return code to determine whether it is running as the child or parent)

·         pid = fork();

·         if (pid <= 0)

·         {   printf ("The child code is running with fork response of %d\n",pid);

·         }

·         else

·         {   printf("The parent code is running with fork response of %d\n",pid);

·         }

·         wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/fork1.c

A parent can wait for its forked child to complete. Then, it can also examine the child's exit status. 

include <sys/wait.h>

pid_t wait (int *stat_loc) – for any child

pid_t waitpid (pid_t pid, int *stat_loc, int options) – for a particular child

possible status value tests examine stat_val (just an integer ):  credited to http://www.unix.org/version2/sample/wait.html

WIFEXITED(stat_val)

Evaluates to a non-zero value if status was returned for a child process that terminated normally.

WEXITSTATUS(stat_val)

If the value of WIFEXITED(stat_val) is non-zero, this macro evaluates to the low-order 8 bits of the status argument that the child process passed to _exit() or exit(), or the value the child process returned from main().

WIFSIGNALED(stat_val)

Evaluates to non-zero value if status was returned for a child process that terminated due to the receipt of a signal that was not caught (see <signal.h>).

WTERMSIG(stat_val)

If the value of WIFSIGNALED(stat_val) is non-zero, this macro evaluates to the number of the signal that caused the termination of the child process.

WIFSTOPPED(stat_val)

Evaluates to a non-zero value if status was returned for a child process that is currently stopped.

WSTOPSIG(stat_val)

If the value of WIFSTOPPED(stat_val) is non-zero, this macro evaluates to the number of the signal that caused the child process to stop.

WIFCONTINUED(stat_val)

Example: wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/fork1a.c

·         #include <sys/types.h>

·         #include <unistd.h>

·         #include <stdio.h>

·         #include <stdlib.h>

·         #include <sys/wait.h>

·         int main()

·         {

·         int stat_val;

·         pid_t  pid;

·         pid_t finished_pid;

·         char *message;

·         int n;

·         printf("fork program starting\n");

·         pid = fork();

·         if (pid > 0 || pid == -1) // parent

·         {

·         finished_pid = wait(&stat_val);

·         printf ("The parent code is running with fork response of %d\n",pid);

·         printf ("The child pid %d is finished now \n",finished_pid);

·         if (WIFEXITED(stat_val))

·         { printf("child exited with code %d\n", WEXITSTATUS(stat_val));

·         system ("ps -u PEPPER");

·         }

·         }

·         else // child

·         {   printf("The child code is running with fork response of %d\n",pid);

·         sleep(15);

·         system ("ps -u PEPPER");

·         exit(37);

·         }

·         exit(0);

·         }

Program Results in:

·         fork program starting

·         The child code is running with fork response of 0

·         Ps result with both processes

·         The parent code is running with fork response of 17962

·         The child pid 17962 is finished now

·         child exited with code 37

·         ps result without 17962

from http://www.cs.duke.edu/courses/spring01/cps110/slides/proc-ux/sld012.htm

Zombie Processes

Forked child that is done but waiting for the parent to exit. It keeps an entry in the process table with the return code in case the parent wants to call wait.  ps shows the child that is complete with <defunct> a

·         End the parent

·         Call wait

Handling signals your process receives using signal

Signal names are defined inside signal.h

some are: from http://unixhelp.ed.ac.uk/CGI/man-cgi?signal+7

       Signal      Value     Action   Comment
       -------------------------------------------------------------------------
       SIGHUP         1       Term    Hangup detected on controlling terminal
                              or death of controlling process
       SIGINT         2       Term    Interrupt from keyboard
       SIGQUIT        3       Core    Quit from keyboard
       SIGILL         4       Core    Illegal Instruction
       SIGABRT        6       Core    Abort signal from abort(3)
       SIGFPE         8       Core    Floating point exception
       SIGKILL        9       Term    Kill signal
       SIGSEGV       11       Core    Invalid memory reference
       SIGPIPE       13       Term    Broken pipe: write to pipe with no readers
       SIGALRM       14       Term    Timer signal from alarm(2)
       SIGTERM       15       Term    Termination signal
       SIGUSR1    30,10,16    Term    User-defined signal 1
       SIGUSR2    31,12,17    Term    User-defined signal 2
       SIGCHLD    20,17,18    Ign     Child stopped or terminated
       SIGCONT    19,18,25    Cont    Continue if stopped
       SIGSTOP    17,19,23    Stop    Stop process
       SIGTSTP    18,20,24    Stop    Stop typed at tty
       SIGTTIN    21,21,26    Stop    tty input for background process
       SIGTTOU    22,22,27    Stop    tty output for background process
 
 
       The  signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
 
 If a process receives a signal without arranging to catch it, it will die with a core dump.
 
 SIGCHLD is ignored by default 
 
 CTRL C sends SIGINT to the foreground process.
 
 To kill another process : kill –HUP 999 (will send SIGHUP to that process 999)
 
Programs handling signals using signal command:
void (*signal (int sig, void (*func) (int)))(int);
note: older programs use this, but sigaction is better.
·         signal takes 2 parms, sig and func. 
·         signal to be caught is sign
·         function to call when signal is received is func
·         func must take in one int argument, which is the signal and return nothing. 
 
·         Example: wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/ctrlc1.c
o  #include <signal.h>
o  #include <stdio.h>
o  #include <unistd.h>
o   
o  void ouch(int sig)
o  {
o      printf("OUCH! - I got signal %d\n", sig);
o      (void) signal(SIGINT, SIG_DFL); // put back default
o  }
o   
o  /*  The main function has to intercept the SIGINT signal generated when we type Ctrl-C .
o      For the rest of the time, it just sits in an infinite loop,
o      printing a message once a second.  */
o   
o  int main()
o  {
o      (void) signal(SIGINT, ouch); // set up a signal catcher function
o   
o      while(1) {
o          printf("Hello World!\n");
o          sleep(1);
o      }
o  }
 
Sending Signals:
 
 To send a signal to a process: int kill (pid_t  pid, int sig); (but does not have to be kill)
 To send an alarm at regular intervals to your own process: unsigned int alarm(unsigned int seconds); 
 To wait for a signal to be received: int pause(void);
 
  Example: wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/alarm.c
 
/*  In alarm.c, the first function, ding, simulates an alarm clock.  */
 
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
static int alarm_fired = 0;
 
void ding(int sig)
{
    alarm_fired = 1;
}
 
/*  In main, we tell the child process to wait for five seconds
    before sending a SIGALRM signal to its parent.  */
 
int main()
{
    pid_t pid;
 
    printf("alarm application starting\n");
 
    pid = fork();
    switch(pid) {
    case -1:
      /* Failure */
      perror("fork failed");
      exit(1);
    case 0:
      /* child */
        sleep(5);
        kill(getppid(), SIGALRM);
        exit(0);
    }
 
/*  The parent process arranges to catch SIGALRM with a call to signal
    and then waits for the inevitable.  */
 
    printf("waiting for alarm to go off\n");
    (void) signal(SIGALRM, ding);
 
    pause();
    if (alarm_fired)
        printf("Ding!\n");
 
    printf("done\n");
    exit(0);
}
 
Handling Signals using a more robust function sigaction:
 
sigaction command fills a sigaction structure:
int sigaction(int sig , const struct sigaction *act, struct sigaction * oact);
 
·         contains: 
·         sa_handler – the function to handle the signal or SIG_DFL (default) or SIG_IGN (ignore)
·         sa_mask – signals to block in sa_handler
·         sa_flags – signal action modifiers
Returns:
·         0 if successful
·         -1 if unsuccessful
      Example (same control c program but using sigaction)  
wget http://home.adelphi.edu/~pe16132/csc271/note/scripts/fileio/ctrlc2.c
·         #include <signal.h>
·         #include <stdio.h>
·         #include <unistd.h>
·         void ouch(int sig)
·         {
·         printf("OUCH! - I got signal %d\n", sig);
·         }
·         int main()
·         {
·         struct sigaction act;
·         act.sa_handler = ouch;
·         sigemptyset(&act.sa_mask);
·         act.sa_flags = 0;
·         sigaction(SIGINT, &act, 0);
·         while(1) {
·         printf("Hello World!\n");
·         sleep(1);
·         }
·         }