570 likes | 719 Views
Friday, June 09, 2006. “I think there is a world market for maybe five computers”. - Thomas Watson, Chairman of IBM, 1943. System Calls. Example : UNIX read system call Highly machine dependant (Assembly code) We can make system calls through C program using library procedures.
E N D
Friday, June 09, 2006 “I think there is a world market for maybe five computers”. - Thomas Watson, Chairman of IBM, 1943
System Calls Example : • UNIX read system call • Highly machine dependant (Assembly code) • We can make system calls through C program using library procedures.
System Calls • UNIX has an almost 1-1 relationship between system calls and library procedures • open • read • write • close POSIX defines about 100 procedure calls
Library procedures: • A procedure call may itself make a system call e.g. fopen malloc
In Windows the library calls and actual system calls are decoupled • Win32 API calls number in thousands. • Large number of calls or managing windows, menus, scroll bars, dialog boxes, fonts, text… • Not very clear which are system calls and which are user-space library calls
Process Management • fork creates a new process in Unix • It creates an exact duplicate of the original parent process including file descriptors, registers, etc (everything) • All variables have identical values at the time of fork • Remember: Parent’s data is copied • Subsequent changes do not affect each other
Process Management int pid = fork(); • pid contains zero in child process • pid contains the process id of child in parent
int main(void){ int counter=0, i, statloc, pid; pid=fork(); if (pid==-1){ perror("fork"); exit(1); } else if (pid==0){ counter=100; for(i=0;i<5; i++){ printf("Child counter is %d\n", counter); counter++; sleep(2); } }
else { counter=500; for(i=0;i<5; i++){ printf("Parent counter is %d\n", counter); counter++; sleep(2); } waitpid(pid, &statloc, 0); } return 0; }
One Possible Output Parent counter is 500 Child counter is 100 Child counter is 101 Parent counter is 501 Parent counter is 502 Child counter is 102 Child counter is 103 Parent counter is 503 Parent counter is 504 Child counter is 104
Another possible output Parent counter is 500 Child counter is 100 Child counter is 101 Parent counter is 501 Parent counter is 502 Child counter is 102 Parent counter is 503 Child counter is 103 Child counter is 104 Parent counter is 504
sleep suspends execution for an interval waitpid can wait for a specific child or any child by setting first parameter to -1 man sleep
int main(void){ int counter=0, i, statloc, pid; pid=fork(); if (pid==-1){ perror("fork"); exit(1); } else if (pid==0){ counter=100; for(i=0;i<5; i++){ printf("Child counter is %d\n", counter); counter++; sleep(2); } }
else { waitpid(pid, &statloc, 0); counter=500; for(i=0;i<5; i++){ printf("Parent counter is %d\n",counter); counter++; sleep(2); } } return 0; }
Child counter is 100 Child counter is 101 Child counter is 102 Child counter is 103 Child counter is 104 Parent counter is 500 Parent counter is 501 Parent counter is 502 Parent counter is 503 Parent counter is 504
int main(void){ int i; int* counter; int pid; counter=(int*) malloc(sizeof(int)); pid=fork(); if (pid==-1){ perror("fork"); exit(1); } else if (pid==0){ *counter=100; for(i=0;i<5; i++){ printf("Child counter is %d\n", *counter); (*counter)++; sleep(2); } }
else { *counter=500; for(i=0;i<5; i++){ printf("Parent counter is %d\n",*counter); (*counter)++; sleep(2); } waitpid(pid, &statloc, 0); } return 0; }
One Possible Output Parent counter is 500 Child counter is 100 Child counter is 101 Parent counter is 501 Parent counter is 502 Child counter is 102 Child counter is 103 Parent counter is 503 Parent counter is 504 Child counter is 104
exec system call replaces the current process image with a new process image.
int main(int argc, char *argv[]) { int i; int pid; int child_status; pid = fork(); if (pid<0){ printf("Fork Failed"); exit(-1); } else if (pid==0){ printf("Child first line\n"); execlp("/bin/ls","ls",”-l”,NULL); }
else { wait(&child_status); printf("Child Complete\n"); } return 0; }
Output Child first line -rwxr-xr-x 1 username group 9203 Jun 4 09:43 fork-ex -rw-r--r-- 1 username group 348 Jun 4 09:43 fork-ex.c -rw-r--r-- 1 username group 355 May 6 14:44 ex1.c -rw-r--r-- 1 username group 657 May 6 17:13 ex2.c -rw-r--r-- 1 username group 657 May 6 17:00 ex3.c Child Complete
int main(int argc, char *argv[]){ int i, pid, pid2; int child_status; pid = fork(); if (pid==0){ pid2=fork(); if (pid2==0){ printf("%d GChild first line\n", getpid()); } else{ printf("%d Child first line\n", getpid()); waitpid(pid2, &child_status, 0); } } else { printf("%d Parent first line\n", getpid()); waitpid(pid, &child_status, 0); } return 0;}
One Possible Output 13242 GChild first line 13240 Parent first line 13241 Child first line
Another Possible Output 13243 Parent first line 13244 Child first line 13245 GChild first line
int main(int argc, char *argv[]){ int pid; int child_status; pid = fork(); if (pid<0){ printf("Fork Failed"); exit(-1); } else if (pid==0){ printf("Child first line\n"); execlp("/bin/cal","cal",NULL); //what happens here? printf("Child second line\n"); printf("Child third line\n"); }
else { //what if we move wait statement down? wait(&child_status); printf("Parent line 1\n"); printf("Parent line 2\n"); printf("Parent line 3\n"); } return 0; }
OUTPUT Child first line June 2006 S M Tu W Th F S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Parent line 1 Parent line 2 Parent line 3
Simple shell while(1) { type_prompt(); read_command(command, parameters); if (fork()!=0){ waitpid(-1, &status, 0); } else { exec(command, parameters, 0); } }
Signals • Notification sent to a process in order to notify it of important events. • Each signal has an integer number (as well as symbolic name) that represents it
Signals • Why signals?
int main(int argc, char *argv[]) { int pid; int i; signal(SIGCHLD, catch_child); pid=fork(); if (pid==0){ execlp("/bin/ls", "ls", NULL); } for (i=0; i<10; i++){ printf("%d\n", i); sleep(1); } return 0; }
void catch_child(int sig_num) { int child_status; wait(&child_status); printf("child exited with code %d\n", child_status); }
int main(int argc, char *argv[]) { int i; int pid, pid2, pid3; int child_status; pid = fork(); //pid contains zero for child process if (pid==0){ pid2=fork(); if (pid2==0){ printf("hello"); } else{ printf("there"); wait(&child_status); } } else { pid3=fork(); if (pid3==0){ printf("Good"); } else{ printf("Luck"); wait(&child_status); } } return 0; }
Process Termination • Last instruction • exit() system call
After fork() call: • The child process inherits all files that were open in the parent process. If one of them reads from such an open file, the read/write pointer is advanced for both of them. • If one process closes a shared file, it is still kept open in the other process. • Files opened after the call to fork() are not shared by both processes.
Ctrl-C SIGINT • Ctrl-Z SIGTSTP • Default signal handlers • SIGSEGV – Segmentation violation – Core dumped
System Calls for I/O • 5 basic UNIX system calls for file I/O open close read write lseek • Different from regular procedure calls. How?
open System Call open ( path, mode flags) int fd = open("/dir1/file1", O_RDONLY); int fd = open("/dir1/file1", O_WRONLY | O_APPEND);
System Calls for I/O • Every process in Unix starts out with three file descriptors • file descriptor 0 is standard input • file descriptor 1 is standard output • file descriptor 2 is standard error • read(0, …) //read from standard input • write(1, …) //write to standard output
open System Call • O_RDONLY • Open the file in read-only mode. • O_WRONLY • Open the file in write-only mode. • O_RDWR • Open the file for both reading and writing. • In addition, any of the following flags may be OR-ed with the mode flag: • O_CREAT • If the file does not exist already - create it.
open System Call • O_EXCL • If used together with O_CREAT, the call will fail if the file already exists. • O_TRUNC • If the file already exists, truncate it (i.e. erase its contents). • O_APPEND • Open the file in append mode. Any data written to the file is appended at the end of the file.
close System Call close (filedescriptor) if (close(fd) == -1) { perror("close"); exit(1); }
read System Call int num_read = read(filedescriptor, buffer, nbytes); • num_read == 0 ? • num_read < 0 ?
write System Call int num = write(filedescriptor, buffer, nbytes); • num < 0 ?
File permissions access( “/dir1/file1”, R_OK) ==0 read access granted access( “/dir1/file1”, R_OK | W_OK ) ==0 read/ write access granted • R_OK Test for read permission. • W_OK Test for write permission. • X_OK Test for execute or search permission. • F_OK Check existence of file
File permissions chmod( “/dir1/file1”, S_IRGRP)
execlp("/bin/ls","ls","-l",”..”, NULL); man -s 2 read man –a read gcc -g -Wall fork-ex.c -o fork-ex It is good practice to always use the -Wall option ps -ef | grep yourusername ps -ef | grep init cat filea fileb filec | sort > /dev/lp &
lseek System Call Practice Homework int num = lseek( filedescriptor, offset, whence); • num < 0 ?