Processes
• A process is a program in execution
• A process has (among other things) a number (pid) and a state. The pid enables the OS to distinguish between processes
• A process is a heavyweight process.
• A thread is a lightweight process.
Variable TypesBy Storage Class:• Static – Once allocated, static variables persist
throughout execution of the process. They are defined as:
– external variable names, – outside any function, or – defined inside a function with a static qualifier
• Automatic – Automatic variables come into existence when the block or function they are defined in begins execution and they cease to exist when the block or function exits. They are:
– local variable names or – parameters in a function that are not defined with a
static qualifier.
Variable TypesBy linkage class:
• Internal – Not visible to other files that are linked together. Variable names defined inside a function or outside a function with the static qualifier.
• External – Visible to other files that are linked together. Variable names defined outside a function and with no static qualifier.
Static Qualifier
Object Where Declared? Static Modifies Static Applied?
Storage Class
Linkage Class
variable
variable
variable
variable
function
function
inside a function
inside a function
outside any function
outside any function
outside any function
outside any function
storage class
storage class
linkage class
linkage class
linkage class
linkage class
yes
no
yes
no
yes
no
static
automatic
static
static
static
static
internal
internal
internal
external
internal
external
Program Layout
Command Line Arguments and Environment Variables
Stack
Heap
Un-initialized static data
Initialized static data
Program text
argc, argv, environment
Activation records for function calls
(return address, parameters, saved
registers, automatic variables)
allocations from malloc family
Static Variables
• If not explicitly initialized, they are initialized to 0 at runtime.
• Initialized and un-initialized occupy different sections of the program image.
• Initialized static variables are part of the executable module on disk, whereas un-initialized static variables are not.
Static Variable ExampleVersion 1:
int myarray[5000] = {1,2,3,4};void main(int argc, char *argv[]) { myarray[0] = 3; }
Version 2:int myarray[5000];void main(int argc, char *argv[]) { myarray[0] = 3;
Do an ls –l after compiling both versions. If integer is 4 bytes, version 1 executable is roughly 20,000 bytes larger.
Static Variables and Thread Safe
• Static variables can make a program unsafe for threaded execution.
• Readdir uses a static variable to hold return values.
• This strategy is also used for client/server stubs when marshaling/un-marshaling arguments for remote procedure calls.
• Therefore, avoid static variables in a threaded environment wherever possible.
Show History – list.h
/* Program 2.1 *//* list.h file */#include <sys/types.h>#include <time.h>
typedef struct data_struct { time_t time; char *string;} data_t;
int add_data(data_t data);data_t *get_data(void);int rewind_list(void);
listlib.c declarations
/* Program 2.2 */#include <stdlib.h>#include <string.h>#include "list.h"
typedef struct list_struct { data_t item; struct list_struct *next;} list_t;
static list_t *head_ptr = NULL;static list_t *tail_ptr = NULL;static list_t **trav_ptr = &head_ptr;static data_t temp;
listlib.c – add_data/* Allocate a node to hold data and add to end of list. Return 0 if successful or -1 if unsuccessful. */int add_data(data_t data){ list_t *newnode; if ((newnode = (list_t *)(malloc(sizeof(list_t) + strlen(data.string) + 1))) == NULL) return -1; newnode->item.time = data.time; newnode->item.string = (char *)(newnode + sizeof(list_t)); strcpy(newnode->item.string, data.string); newnode->next = NULL; if (head_ptr == NULL) head_ptr = newnode; else tail_ptr->next = newnode; tail_ptr = newnode; return 0;}
listlib.c – get_data /* Return a pointer in temp that has a copy of the data contained in the current node *trav_ptr. If at the end of the list return NULL. In any case, update trav_ptr. */data_t *get_data(void) { list_t *t; t = *trav_ptr; if (t == NULL) return NULL; if (temp.string != NULL) free (temp.string); if ( (temp.string = (char *) malloc(strlen(t->item.string) + 1)) == NULL) return NULL; temp.time = t->item.time; strcpy(temp.string, t->item.string); trav_ptr = &(t->next); return &temp; }
listlib.c – rewind_list
/* Set trav_ptr to contain the address of head_ptr. If head_ptr is NULL, return -1 indicating an empty list. Otherwise return 0. */
int rewind_list(void){ trav_ptr = &head_ptr; if (head_ptr == NULL) return -1; else return 0;}
keeploglib.c/* Program 2.4 */#include <stdio.h>#include <stdlib.h>#include "list.h" /* Execute cmd and store cmd and time of execution in history list. */int runproc(char *cmd){ data_t execute; time(&(execute.time)); execute.string = cmd; if (system(cmd) == -1) return -1; return add_data(execute);}/* Output the history list of the file f */void showhistory(FILE *f){ data_t *infop; rewind_list(); while ((infop = get_data()) != NULL) fprintf(f, "Command: %s\nTime: %s\n", infop->string, ctime(&(infop->time))); return;}
keeplog.c/* Program 2.3 */#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <string.h>#ifndef MAX_CANON#define MAX_CANON 8192#endif void showhistory(FILE *f);int runproc(char *cmd);void main(int argc, char *argv[]) { char cmd[MAX_CANON]; int history = 1; if (argc == 1) history = 0; else if ((argc > 2) || strcmp(argv[1], "history")) { fprintf(stderr, "Usage: %s [history]\n", argv[0]); exit(1); } while(fgets(cmd, MAX_CANON, stdin) != NULL) { if (*(cmd + strlen(cmd) - 1) == '\n') *(cmd + strlen(cmd) - 1) = 0; if (history && !strcmp(cmd, "history")) showhistory(stdout); else if (runproc(cmd)) break; } printf("\n\n>>>>>>The list of commands executed is:\n"); showhistory(stdout); exit(0); }
Process ID (pid)
• Parent Process
• Child Process
• getpid(void) – returns the pid of the currently running process.
• getppid(void) – returns the pid of the parent of the currently running process.
User ID (uid)
• Each process is identified with a particular user called the owner.
• Each user has a unique ID (uid).
• getuid(void) – returns the process uid.
• geteuid(void) – returns the process Effective User ID (euid).
euid
• Each process has an Effective User ID (euid) that determines the privileges a process has for accessing resources such as files.
• The euid can change during execution.
Process/User ID Example
/* Example 2.1 */#include <stdio.h>#include <sys/types.h>#include <unistd.h>
void main(void){ printf("Process ID: %ld\n", (long)getpid()); printf("Parent process ID: %ld\n", (long)getppid()); printf("Owner user ID: %ld\n", (long)getuid()); printf("Owner euser ID: %ld\n", (long)geteuid());}
ps -lheader MeaningF
S
UID
PID
PPID
C
PRI
NI
ADDR
SZ
WCHAN
TTY
TIME
COMMAND
Flags associated with the process
The process state
The user ID of the process owner
The process ID
The parent process ID
The processor utilization used for scheduling
The priority of the process
The nice value
The memory address of the process
The size of the process image
The address of the event if the process is sleeping
The controlling terminal
Cumulative execution time
Command name
fork(void) system call#include <sys/types.h>#include <unistd.h>
pid_t fork(void)_____________________________________Creates child process by copying parent’s memory image
Fork AttributesChild inherits:• Parent’s memory image • Most of the parent’s attributes including
environment and privilege.• Some of parent’s resources such as open files.
Child does not inherit:• Parent pid.• Parent time clock (child clock is set to 0).
fork Example#include <stdio.h>#include <unistd.h>#include <sys/types.h>void main(void){ pid_t childpid;
if ((childpid = fork()) == 0) { fprintf(stderr, "I am the child, ID = %ld\n", (long)getpid()); /* child code goes here */ } else if (childpid > 0) { fprintf(stderr, "I am the parent, ID = %ld\n", (long)getpid()); /* parent code goes here */ }}
fork (Chain)#include <stdio.h>#include <unistd.h>#include <sys/types.h>void main(void){ int i; int n; pid_t childpid; n = 4; for (i = 1; i < n; ++i) if (childpid = fork()) break; fprintf(stderr,"This is process %ld with parent %ld\n", (long)getpid(), (long)getppid()); sleep(1);}
fork (Fan)#include <stdio.h>#include <sys/types.h>#include <unistd.h>
void main(void){ int i; int n; pid_t childpid;
n = 4; for (i = 1; i < n; ++i) if ((childpid = fork()) <= 0) break; fprintf(stderr, "This is process %ld with parent %ld\n", (long)getpid(), (long)getppid()); sleep(1);}
fork (Tree)#include <stdio.h>#include <sys/types.h>#include <unistd.h>
void main(void){ int i; int n; pid_t childpid;
for (i = 1; i < n; ++i) if ((childpid = fork()) == -1) break; fprintf(stderr, "This is process %ld with parent %ld\n", (long)getpid(), (long)getppid()); sleep(1);}
pid_t wait(int *stat_loc)• Causes caller to pause until a child terminates, or stops
until the caller receives a signal.• If wait returns because a child terminates, the return value
(of type pid_t) is positive and is the pid of that child.• Otherwise wait returns –1 and sets errno.• stat_loc is a pointer to an integer variable.• If caller passes something other than NULL, wait stores
the return status (terminate status?) of the child.• POSIX specifies the following macros for testing the
return status: WIFEXITED, WEXITSTUS, WIFSIGNALED, WTERMSIG, WIFSTOPPED, and WSTOPSIG.
• Child returns status by calling exit, _exit, or return.
errno for wait
• ECHILD indicates there are no unwaited for child processes.
• EINTR indicates that the call was interrupted by a signal.
wait (Race Conditions)/* Program 2.5 */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h> void main (void) { pid_t childpid; int status; if ((childpid = fork()) == -1) { perror("The fork failed"); exit(1); } else if (childpid == 0) fprintf(stderr, "I am the child with pid = %ld\n", (long)getpid()); else if (wait(&status) != childpid) fprintf(stderr, "A signal must have interrupted the wait\n"); else fprintf(stderr, "I am the parent with pid = %ld and child pid = %ld\n", (long)getpid(), (long)childpid); exit(0); }
Wait for Child or Error#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.h>void main(void) { int status; pid_t childpid; pid_t waitreturn; childpid = fork(); if (childpid == 0) { fprintf(stderr,"Child %ld will sleep for 5 seconds\n",(long)getpid()); sleep(5); fprintf(stderr,"Child %ld will now exit\n",(long)getpid()); exit(0); } fprintf(stderr,"Parent %ld will wait for child %ld\n", (long)getpid(),(long)childpid); while(childpid != (waitreturn = wait(&status))) if ((waitreturn == -1) && (errno != EINTR)) break; }
waitpid – WNOHANG #include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.h>void main(void) { int status; pid_t childpid; pid_t waitreturnpid; childpid = fork(); if (childpid == 0) { fprintf(stderr,"Child %ld will sleep for 5 seconds\n",(long)getpid()); sleep(5); fprintf(stderr,"Child %ld will now exit\n",(long)getpid()); exit(0); } sleep(8); fprintf(stderr,"Parent %ld will wait for any child\n",(long)getpid()); while(waitreturnpid = waitpid(-1, &status, WNOHANG)) if (!((waitreturnpid == -1) && (errno != EINTR))) break; fprintf(stderr,"Parent will exit after receiving %ld from waitpid\n", waitreturnpid); }
Fan with wait#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <errno.h>void main(void) { int i; int n; pid_t childpid; int status; n = 4; for (i = 1; i < n; ++i) if ((childpid = fork()) <= 0) break; for( ; ; ) { childpid = wait(&status); if ((childpid == -1) && (errno != EINTR)) break; } fprintf(stderr, "I am process %ld, my parent is %ld\n", (long)getpid(), (long)getppid()); }
Chain with wait#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <errno.h> void main(void) { int i; int n; pid_t childpid; int status; pid_t waitreturn; n = 4; for (i = 1; i < n; ++i) if (childpid = fork()) break; while(childpid != (waitreturn = wait(&status))) if ((waitreturn == -1) && (errno != EINTR)) break; fprintf(stderr, "I am process %ld, my parent is %ld\n", (long)getpid(), (long)getppid()); }
Background Processes
• Child process becomes background process when it executes setsid().
• Child that becomes background process never returns to parent.
• Background processes cannot be interrupted with ctrl-c.
execl, execlp, execle“l” – Passes command directly as a parameter
in exec.
• execl searches for command in fully qualified pathname passed as exec parameter or in current directory
• execlp uses PATH environment variable to find command
• execle uses environment passed as exec parameter to find command
execv, execvp,execve“v” – Passes command as member of argument array
(i.e., argv[] or makeargv[])
• execv searches for arg array command in fully qualified pathname passed in exec or in current directory
• execvp uses PATH environment variable to find arg array command
• execve uses environment passed as exec parameter to find arg array command
execl Example/* Program 2.6 */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>void main(void) { pid_t childpid; int status; if ((childpid = fork()) == -1) { perror("Error in the fork"); exit(1); } else if (childpid == 0) { /* child code */ if (execl("/usr/bin/ls", "ls", "-l", NULL) < 0) { perror("Exec of ls failed"); exit(1); } } else if (childpid != wait(&status)) /* parent code */ perror("A signal occurred before the child exited"); exit(0); }
execvp Example/* Program 2.7 */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <errno.h>void main(int argc, char *argv[]) { pid_t childpid, waitreturn; int status; if ((childpid = fork()) == -1) { perror("The fork failed"); exit(1); } else if (childpid == 0) { /* child code */ if (execvp(argv[1], &argv[1]) < 0) { perror("The exec of command failed"); exit(1); } } else /* parent code */ while(childpid != (waitreturn = wait(&status))) if ((waitreturn == -1) && (errno != EINTR)) break; exit(0); }
Use of makeargv#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>int makeargv(char *s, char *delimiters, char ***argvp);void main(int argc, char *argv[]) { char **myargv; char delim[] = " \t"; pid_t childpid, waitreturn; int status; if (argc != 2) { fprintf(stderr, "Usage: %s string\n", argv[0]); exit(1); } if ((childpid = fork()) == -1) { perror("The fork failed"); exit(1); } else if (childpid == 0) { /* child code */ if (makeargv(argv[1], delim, &myargv) < 0) { fprintf(stderr, "Argument array could not be constructed\n"); exit(1); } else if (execvp(myargv[0], &myargv[0]) < 0) { perror("The exec of command failed"); exit(1); } } else /* parent code */ while(childpid != (waitreturn = wait(&status))) if ((waitreturn == -1) && (errno != EINTR)) break; exit(0); }
Attributes Preserved by Calls to execAttribute Relevant System Call
Process ID
Parent process ID
Process group ID
Session membership
Real user ID
Real group ID
Supplementary group IDs
Time left on alarm signal
Current working directory
Root directory
File mode creation mask
Process signal mask
Pending signals
Time elapsed
getpid()
getppid()
getpgid()
getsid()
getuid()
getgid()
getgroups()
alarm()
getcwd()
unmask()
sigprocmask()
sigpending()
times()
Daemon
A background process that runs indefinitely.
Examples:
• Solaris 2 pageout daemon
• Mailer daemon
Background Processes/* Program 2.9 */#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int makeargv(char *s, char *delimiters, char ***argvp);void main(int argc, char *argv[]) { char **myargv; char delim[] = " \t"; pid_t childpid; if (argc != 2) { fprintf(stderr, "Usage: %s string\n", argv[0]); exit(1); } if ((childpid = fork()) == -1) { perror("The fork failed"); exit(1); } else if (childpid == 0) { /* child becomes a background process */ if (setsid() == -1) perror("Could not become a session leader"); else if (makeargv(argv[1], delim, &myargv) < 0) fprintf(stderr, "Argument array could not be constructed\n"); else if (execvp(myargv[0], &myargv[0]) < 0) perror("The exec of command failed"); exit(1); } /* child should never return */ exit(0); } /* parent exits */
Biff
• Biff’s inventor had a dog that barked at mail carriers.
• Sends a ctrl-g (ASCII 7) to standard error.
• If there is mail:– The open succeeds.– Printing ASCII 7 causes a beep.
Biff
Environment List
• Array of pointers to strings of the form name = value.
• Name specifies an environment variable
• Value specifies a string of values.
Environment VariablesVariable Meaning
HOME
LANG
LC_ALL
LC-COLLATE
LC_CTYPE
LC_MONETARY
LC_NUMERIC
LC_TIME
LOGNAME
PATH
TERM
TZ
User’s initial working directory
Locale when not specified by LC_ALL or LC_*
Overriding name of locale
Name of locale for collating information
Name of locale for character classification
Name of locale for monetary editing
Name of locale for numeric editing
Name of locale for date/time information
Login name associated with a process
Path prefixes for finding the executable
Terminal type for output
Time zone information
Environment Variables (cont)
• In execl, execlp, execv, execvp child inherits environment parent has just prior to execution of exec.
• In execle and execve, child sets its own environment.
Process Termination
Normal or abnormal.
• Cancel pending timers and signals
• Release virtual memory resources
• Release other process-held system resources such as locks
• Close open files
Zombies
• If a parent process is not waiting for a child when it finishes, the child cannot be terminated by its parent. We call these child processes zombies.
• Orphaned child processes become zombies when they terminate.
• System init process (process whose ID is 1) gets rid of orphaned zombies.
Normal Termination
• Return from main.
• Call to C function exit
• Call to _exit system call.
(note that C function exit calls user-defined exit handlers that usually provides extra cleanup before calling on _exit).
exit and _exit
• Take an integer parameter status that indicates the status of the program.
• 0 normal termination.
• Programmer defined non-zero indicates error.
• At exit C function installs user-defined exit handler. Last-installed, first executed.
Top Related