unix system programming - ucy · unix system programming • objectives look at how to program unix...
TRANSCRIPT
UNIX System Programming
• Objectives ▫ look at how to program UNIX processes ▫ fork( ), wait( )
Processes
Overview
1. What is a Process? 2. fork() 3. wait() 4. Process Data
1. What is a Process?
A process is the context (the information/data) maintained for an executing program. Intuitively, a process is the abstraction of a physical
processor. Exists because it is difficult for the OS to otherwise coordinate many concurrent
activities, such as incoming network data, multiple users, etc.
IMPORTANT: A process is sequential
What makes up a Process?
program code machine registers global data stack open files (file descriptors) an environment (environment variables;
credentials for security)
Some of the Context Information
▫ Process ID (pid) unique integer ▫ Parent process ID (ppid) ▫ Real User ID ID of user/process
which started this process
▫ Effective User ID ID of user who wrote the process’ program
continued
Important System Processes
init – Mother of all processes. init is started at boot time and is responsible for starting other processes. init uses file inittab & directories: /etc/rc?.d getty – login process that manages login
sessions.
Unix Start Up Processes Diagram OS kernel
Process 0 (sched)
Process 1 (init)
getty getty getty
login
csh
login
bash
Pid and Parentage
A process ID or pid is a positive integer that uniquely identifies a running process, and is stored in a variable of type pid_t. You can get the process pid or parent’s pid #include <sys/types> main() { pid_t pid, ppid; printf( "My PID is:%d\n\n",(pid = getpid()) ); printf( "Par PID is:%d\n\n",(ppid = getppid()) ); }
2. fork()
#include <sys/types.h> #include <unistd.h> pid_t fork( void );
Creates a child process by making a copy of the
parent process --- an exact duplicate. Implicitly specifies code, registers, stack, data,
files Both the child and the parent continue running.
fork() as a diagram
Parent
pid = fork()
Returns a new PID: e.g. pid == 5
Data
Shared Program Data
Copied
Child
pid == 0
Process IDs (pids revisited)
pid = fork(); In the child: pid == 0;
In the parent: pid == the process ID of the child. A program almost always uses this pid
difference to do different things in the parent and child.
fork() Example (parchld.c)
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() {
pid_t pid; /* could be int */ int i; pid = fork(); if( pid > 0 )
{ /* parent */ for( i=0; i < 1000; i++ ) printf(“\t\t\tPARENT %d\n”, i); }
else { /* child */ for( i=0; I < 1000; i++ )
printf( “CHILD %d\n”, i ); } return 0; }
Possible Output
CHILD 0 CHILD 1 CHILD 2 PARENT 0 PARENT 1 PARENT 2 PARENT 3 CHILD 3 CHILD 4 PARENT 4 :
Things to Note
i is copied between parent and child. The switching between the parent and child
depends on many factors: machine load, system process scheduling
I/O buffering effects amount of output shown.
Output interleaving is nondeterministic cannot determine output by looking at code
3. wait() #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *statloc); Suspends the calling process until one of its child processes
ends. If the system already has information about a terminated child process when wait is called, the return from wait occurs immediately.
Status information for the terminating child process is usually stored at the location pointed to by *statloc. if wait is called with NULL as the *statloc value, no status information is returned.
If successful, wait returns the process ID of the child process. If unsuccessful, a -1 is returned.
wait() Actions
A process that calls wait() can: suspend (block) if all of its children are still
running, or return immediately with the termination status of
a child, or return immediately with an error if there are no
child processes.
4. Process Data
Since a child process is a copy of the parent, it has copies of the parent’s data. A change to a variable in the child will not
change that variable in the parent.
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = -1, errno = ENOMEM
-1
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = -1, errno = ENOMEM
-1
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = -1, errno = ENOMEM
-1
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = -1, errno = ENOMEM
-1
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
0
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
0
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
0
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
0
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
9870
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
9870
PID=981
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
987
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
p = 987
PID=987
Δεδομένα :p = ? mypid = ?
Κείμενο:
pid_t p, mypid;…p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {mypid = getpid();child();
} else {father();
}
p = 0
9870
ΔημιουργίαΔημιουργία στοστο μοντέλομοντέλο τουτου UNIX: fork()UNIX: fork()
� Όλες οι διεργασίες προκύπτουν με fork() [σχεδόν όλες]� Ίδιο πρόγραμμα με γονική διεργασία, αντίγραφο χώρου μνήμης,
κληρονομεί ανοιχτά αρχεία, συνδέσεις, δικαιώματα πρόσβασης� Αντικατάσταση προγράμματος διεργασίας: execve()� Η γονική διεργασία ενημερώνεται για το θάνατο του
παιδιού με wait() → συλλογή τιμής τερματισμού (exit status)� Μέχρι τότε, παιδί που έχει καλέσει την exit() είναι zombie� Αν ο γονέας πεθάνει πρώτα, η διεργασία γίνεται παιδί της
init (PID = 1), που κάνει συνεχώς wait()
prog-A981
Prog-A981
fork
Prog-A 987
execveProg-B
987 exit
Prog-B 987 (zombie)
wait
wait() / wait() / waitpidwaitpid()()
� Για κάθε fork() πρέπει να γίνει ένα wait()� wait(&status)
� Μπλοκάρει έως οποιοδήποτε παιδί πεθάνει� Το status κωδικοποιεί πώς πέθανε η διεργασία
� Κανονικά (exit()), λόγω κάποιου σήματος (SIGTERM, SIGKILL)� Χρήσιμες μακροεντολές για την ερμηνεία του status
� WIFEXITED(), WEXITSTATUS(), WIFSIGNALED(), WTERMSIG()� σας δίνεται η explain_wait_status()
� Μια πιο ευέλικτη wait(): waitpid()� Περιμένει για αλλαγή κατάστασης συγκεκριμένου ή
οποιουδήποτε PID διεργασίας-παιδιού� Συμπεριφορά ελεγχόμενη από flags (WNOHANG, WUNTRACED)
explain_wait_statusexplain_wait_status()()
void explain_wait_status(pid_t pid, int status){if (WIFEXITED(status))
fprintf(stderr, "Child with PID = %ld terminated normally, exit status = %d\n",(long)pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))fprintf(stderr, "Child with PID = %ld was terminated by a signal, signo = %d\n",
(long)pid, WTERMSIG(status));else if (WIFSTOPPED(status))
fprintf(stderr, "Child with PID = %ld has been stopped by a signal, signo = %d\n",(long)pid, WSTOPSIG(status));
else {fprintf(stderr, "%s: Internal error: Unhandled case, PID = %ld, status = %d\n",
__func__, (long)pid, status);exit(1);
}fflush(stderr);
}
explain_wait_statusexplain_wait_status()()
void explain_wait_status(pid_t pid, int status){if (WIFEXITED(status))
fprintf(stderr, "Child with PID = %ld terminated normally, exit status = %d\n",(long)pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))fprintf(stderr, "Child with PID = %ld was terminated by a signal, signo = %d\n",
(long)pid, WTERMSIG(status));else if (WIFSTOPPED(status))
fprintf(stderr, "Child with PID = %ld has been stopped by a signal, signo = %d\n",(long)pid, WSTOPSIG(status));
else {fprintf(stderr, "%s: Internal error: Unhandled case, PID = %ld, status = %d\n",
__func__, (long)pid, status);exit(1);
}fflush(stderr);
}
Παράδειγμα:
pid = wait(&status);explain_wait_status(pid, status);if (WIFEXITED(status) || WIFSIGNALED(status))
--processes_alive;
ΚώδικαςΚώδικας: : παράδειγμαπαράδειγμα fork() / wait()fork() / wait()
void child(void){
compute(10000);exit(7);
}
int main(void){
pid_t p;int status;
p = fork();if (p < 0) {
perror("fork");exit(1);
}if (p == 0) {
child(); exit(1);}
p = wait(&status);explain_wait_status(p, status);return 0;
}
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (1)(1)
� Ένας από τους βασικότερους μηχανισμούς στο UNIX� Μονόδρομη μεταφορά δεδομένων� Από το άκρο εγγραφής στο άκρο ανάγνωσης
� Δημιουργία με pipe(), επικοινωνία με write() και read()� Αν η σωλήνωση είναι άδεια; → η read() μπλοκάρει
M
write fd[1]
readfd[0]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασία
άκροεγγραφής
άκροανάγνωσης
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (1)(1)
int fd[2];
int num1, num2;
pipe(fd);
write(fd[1], &num1, sizeof(num1));
read(fd[0], &num2, sizeof(num2));
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασία
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (1)(1)
int fd[2];
int num1, num2;
pipe(fd);
write(fd[1], &num1, sizeof(num1));
read(fd[0], &num2, sizeof(num2));
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασία
άκροεγγραφής
άκροανάγνωσης
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (1)(1)
int fd[2];
int num1, num2;
pipe(fd);
write(fd[1], &num1, sizeof(num1));
read(fd[0], &num2, sizeof(num2));
M
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασία
άκροεγγραφής
άκροανάγνωσης
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (1)(1)
int fd[2];
int num1, num2;
pipe(fd);
write(fd[1], &num1, sizeof(num1));
read(fd[0], &num2, sizeof(num2));
M
write fd[1]
readfd[0]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασία
άκροεγγραφής
άκροανάγνωσης
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (1)(1)
int fd[2];
int num1, num2;
pipe(fd);
write(fd[1], &num1, sizeof(num1));
read(fd[0], &num2, sizeof(num2));
write fd[1]
readfd[0]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασία
άκροεγγραφής
άκροανάγνωσης
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
readfd[0]
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
readfd[0]
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
Διεργασίαπαιδί
readfd[0]
write fd[1]
readfd[0]
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
Διεργασίαπαιδί
write fd[1]
readfd[0]
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
Διεργασίαπαιδί
readfd[0]
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
M
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
Διεργασίαπαιδί
readfd[0]
ΣωληνώσειςΣωληνώσεις στοστο UNIXUNIX (2)(2)
pipe(fd);
fork();
… ο πατέρας κλείνει το άκρο ανάγνωσης
…το παιδί κλείνει το άκρο εγγραφής
write fd[1]
Χώρος Χρήστη
Χώρος Πυρήνα
Διεργασίαπατέρας
άκροεγγραφής
άκροανάγνωσης
Διεργασίαπαιδί
readfd[0]
ΚώδικαςΚώδικας: : παράδειγμαπαράδειγμα IPCIPC μεμε UNIX pipesUNIX pipes
ΚώδικαςΚώδικας: : παράδειγμαπαράδειγμα IPCIPC μεμε UNIX pipesUNIX pipesdouble value;int pfd[2];pid_t p;
if (pipe(pfd) < 0) {perror(“pipe”);exit(1);
}
p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {if (read(pfd[0], &value, sizeof(value)) != sizeof(value)) {
perror(“read from pipe”);exit(1);
}printf(“child received value: value = %f\n”, value);exit(0);
} else {compute_value(&value);if (write(pfd[1], &value, sizeof(value)) != sizeof(value)) {
perror(“write to pipe”);exit(1);
}exit(0);
}
ΚώδικαςΚώδικας: : παράδειγμαπαράδειγμα IPCIPC μεμε UNIX pipesUNIX pipesdouble value;int pfd[2];pid_t p;
if (pipe(pfd) < 0) {perror(“pipe”);exit(1);
}
p = fork();if (p < 0) {
perror(“fork”);exit(1);
} else if (p == 0) {if (read(pfd[0], &value, sizeof(value)) != sizeof(value)) {
perror(“read from pipe”);exit(1);
}printf(“child received value: value = %f\n”, value);exit(0);
} else {compute_value(&value);if (write(pfd[1], &value, sizeof(value)) != sizeof(value)) {
perror(“write to pipe”);exit(1);
}exit(0);
}