1 / 59

System Programming

System Programming. Operating Systems Level 4. OS defines an abstract machine Provides environment for programming Allocates resources efficiently. Operating Systems. Resources of a typical computer system: CPU time Main Memory Secondary Storage (disk, etc.)

dayton
Download Presentation

System Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. System Programming

  2. Operating SystemsLevel 4 • OS defines an abstract • machine • Provides environment • for programming • Allocates resources • efficiently.

  3. Operating Systems • Resources of a typical computer system: • CPU time • Main Memory • Secondary Storage (disk, etc.) • Chapter 8: how OS allocates CPU time. • Chapter 9: how OS allocates MM and Disk.

  4. Three types of operating systems • Single-user • Example: PCs, Pep/7 • Multiuser • Real-time • Usually video or hardware control • Examples: auto engines, nuclear power plants, etc.

  5. Processes in UNIX Process Management: #include <sys/wait.h> fork():Create another process in the same address space beginning execution at instruction label exit(int): Terminate the process. The int parameter indicates termination status. pid_t wait(int *stat_loc): waits until the next child process stops. Returns the PID of the child process. The variable stat_loc contains the exit status of the child. int getpid( ): Returns the processes PID

  6. fork() • creates another process • the second process starts execution in the same place in the code. main() …… y = fork() …. fork call creates a new process, the new process begins execution with the return from the fork() call main() …… y = fork() ….

  7. y contains 16250 y contains 0 fork() • fork() returns a different value to the parent process and the child process • parent gets pid of child • child gets 0 main() …… y = fork() …. y gets value childPID in parent process main() …… y = fork() …. y gets value 0 in child process

  8. y != 0 in parent process so execute parent code y == 0 in child process so execute child code fork() • To create different code, must examine the value that was returned by fork() main() …… y = fork() if (y == 0){ /* child code */ exit(0); } /* parent code */ …. child main() …… y = fork() if (y == 0){ /* child code */ exit(0); } /* parent code */ …. parent

  9. create a child process if x is 0, then this must be the child process child sleeps for 5 seconds child dies and becomes a zombie Only the parent process will reach this code since x != 0 in the parent process parent waits until the child terminates paramter is NULL because we don’t care how the child terminates. gets and prints its own PID fork() example #include <sys/wait.h> #include <stdio.h> #define NULL 0 int main(){ int y,x; printf("Process[%d]: Parent in execution ... \n", getpid() ); x = fork(); if (x == 0){ /* this is child */ fprintf(stderr,"Process[%d]: child in execution....\n",getpid() ); sleep(5); fprintf(stderr,"Process[%d]: child terminating....\n",getpid() ); exit(0); } /* Parent code here */ printf("Process[%d]: Parent in execution ... \n", getpid() ); sleep(2); if (wait(NULL) > 0) /* Child terminating */ printf("Process[%d]: Parent detects terminating child \n", getpid() ); printf("Process[%d]: Parent terminating....\n", getpid() ); }

  10. fork() example bash-2.03$ fork1 Process[16299]: Parent in execution ... Process[16301]: child in execution.... Process[16301]: child terminating.... Process[16299]: Parent detects terminating child Process[16299]: Parent terminating.... bash-2.03$

  11. wait() • pid_t wait(int *stat_loc) • pid_tis the PID of the process that wakes up this process • stat_locis an integer that represents the reason for the child terminating. • See Beginning Linux Programming book for termination codes.

  12. Request Wait by parent Done Running zombie Schedule Request Sleeping I/O Request Start Allocate Runnable I/O Complete Resume Traced or Stopped Uninterruptible Sleep Unix Transition Diagram

  13. Two forks Only check for one of the children! Who executes the parent code?? complicated fork() example 6 int main(){ 7 int y,x; 8 printf("Process[%d]: Parent in execution ... \n", getpid() ); 9 x = fork(); 10 y = fork(); 11 if (x == 0){ /* this is child */ 12 fprintf(stderr,"Process[%d]: child in execution....\n",getpid() ); 13 sleep(5); 14 fprintf(stderr,"Process[%d]: child terminating....\n",getpid() ); 15 exit(0); 16 } 17 18 /* Parent code here */ 19 printf("Process[%d]: Parent in execution ... \n", getpid() ); 20 sleep(2); 21 if (wait(NULL) > 0) /* Child terminating */ 22 printf("Process[%d]: Parent detects terminating child \n", getpid() ); 23 printf("Process[%d]: Parent terminating....\n", getpid() ); 24 }

  14. Why two children? Why two parents? Parent terminates, so get the prompt back. Later second and third children terminates. fork() example Note that we cannot predict the order of execution because the OS must schedule this bash-2.03$ fork1.2 Process[16750]: Parent in execution ... Process[16752]: child in execution.... Process[16751]: child in execution.... Process[16753]: Parent in execution ... Process[16750]: Parent in execution ... Process[16753]: Parent terminating.... Process[16750]: Parent detects terminating child Process[16750]: Parent terminating.... bash-2.03$ Process[16751]: child terminating.... Process[16752]: child terminating.... bash-2.03$

  15. execl() • int execl(const char *path, const char *arg0, … (char *)0); • execl is used to replace code. • the process code is replaced by the program given in the path parameter. • Can have as many the arg0, arg1, … arguments as you like. Each is passed to the child program (as a command line argument). • the last argument must be (char*)0 or NULL.

  16. 1. creates a copy of the parent process 2. replaces the child process code with the executable code for myProg main() …… x = fork(); if (x == 0){ execl(“myProg”, NULL) …. Process 2 Process 2 execl() • the “child” reference must be a compiled program main() …… x = fork(); if (x == 0){ execl(“myProg”, NULL) …. Process 1 /* this is the main function for the myProg.c program */ main() …… ……

  17. execl() 1 #include <sys/wait.h> 2 3 #define NULL 0 4 5 int main(){ 6 if (fork() == 0){ /* this is child */ 7 execl("child",0); 8 exit(1); /* should never get here; terminate */ 9 } 10 11 /* Parent code here */ 12 printf("Process[%d]: Parent in execution ... \n", getpid() ); 13 sleep(2); 14 if (wait(NULL) > 0) /* Child terminating */ 15 printf("Process[%d]: Parent detects terminating child \n", getpid() ); 16 printf("Process[%d]: Parent terminating....\n", getpid() ); 17 }

  18. child.c 1 #include <stdio.h> 2 3 main () { 4 /* The child process's new program 5 This program replaces the parent's program */ 6 7 fprintf(stderr,"Process[%d]: child in execution....\n",getpid() ); 8 sleep(5); 9 fprintf(stderr,"Process[%d]: child terminating....\n",getpid() ); 10 }

  19. Three arguments passed to the new child code. fork3.c 1 #include <sys/wait.h> 2 3 #define NULL 0 4 5 int main(){ 6 if (fork() == 0){ /* this is child */ 7 execl("child2","first","second","third",0); 8 exit(1); /* should never get here; terminate */ 9 } 10 11 /* Parent code here */ 12 printf("Process[%d]: Parent in execution ... \n", getpid() ); 13 sleep(2); 14 if (wait(NULL) > 0) /* Child terminating */ 15 printf("Process[%d]: Parent detects terminating child \n ", getpid() ); 16 printf("Process[%d]: Parent terminating....\n", getpid() ); 17 }

  20. Print all passed arguments fork3.c 1 #include <stdio.h> 2 3 int main (int argc, char *argv[]) { 4 int i; 5 6 7 /* The child process's new program 8 This program replaces the parent's program */ 9 10 fprintf(stderr,"Process[%d]: child in execution....\n",getpid() ); 11 for (i = 0; i < argc; i++) 12 fprintf(stderr,"Argument[%d]: %s\n",i, argv[i]); 13 14 fprintf(stderr, "\n"); 15 16 sleep(5); 17 fprintf(stderr,"Process[%d]: child terminating....\n",getpid() ); 18 }

  21. Pipes • A pipe is a communications channel between two processes (and only two). • a pipe has two parts, a read part and a write part. P1 P2

  22. File Descriptors • Every process has a file descriptor table • Table contains an entry for every file that the process has opened. • Each entry contains all the info that the OS needs to access that file. • Every process has 3 entries by default: stdin, stdout, stderr. Index File 0 stdin stdout 1 stderr 2

  23. File Descriptors • Every process has a file descriptor table • opening a file adds a file descriptor to the table. • the file descriptor returned is the index into the file descriptor table. • OS always assigns the next available entry in the table. • closing a file causes its entry in the table to be removed. fd = fopen(“myFile”, “r”); Index File 0 stdin fd has value 3 stdout 1 stderr 2 3 myFile (r)

  24. Pipes • Syntax: #include <unistd.h> int file_pipes[2]; int pipe(file_pipes); int write(file_pipes[1], some_data, strlen(some_data)); int read(file_pipes[0], buffer, BUFSIZ); Must include the unistd.h header The pipe file descriptor must be an int array of 2 elements. Element 0 is the read descriptor, Element 1 is the write descriptor. The pipe( ) system call takes a pipe file descriptor as an argument and returns 0 if the pipe is successfully opened, and error code otherwise (see BLP for error codes) The write( ) system call takes a file descriptor, a string of bytes, and the number of bytes to write. It returns the number of bytes that was actually written. The read( ) system call takes a file descriptor, a pointer to character array, and the number of bytes to read. It returns the number of bytes that were actually read (may be less than requested).

  25. File Descriptors • The pipe system call creates two file descriptors. int file_pipes[2]; x =pipe(file_pipes) Index File 0 stdin stdout 1 After the pipe call: x contains 0 file_pipes[0] contains 3 file_pipes[1] contains 4 stderr 2 3 file_pipes[0] (r) 4 file_pipes[1] (w)

  26. Pipes #include <unistd.h> #include <stdio.h> #define BUFSIZ 30 int main( ){ int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; if (pipe(file_pipes) == 0) { data_processed = write(file_pipes[1], some_data, strlen(some_data)); printf("Wrote %d bytes\n", data_processed); data_processed = read(file_pipes[0], buffer, BUFSIZ); printf("Read %d bytes: %s\n", data_processed, buffer); exit(0); } exit(1); } creates a pipe writes to the write end of the pipe reads from the read end of the pipe

  27. Pipes #include <unistd.h> #include <all the other headers needed> #define BUFSIZ 30 int main () { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; int fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == -1) { fprintf(stderr, "Fork failure"); exit(1); } creates a pipe forks a child parent: writes to the write end of the pipe child: reads from the read end of the pipe

  28. Pipes if (fork_result == 0) { /* This is the child process */ data_processed = read(file_pipes[0], buffer, BUFSIZ); printf("Read %d bytes: %s\n", data_processed, buffer); exit(0); } else { /* This is the parent process */ data_processed = write(file_pipes[1], some_data, strlen(some_data)); printf("Wrote %d bytes\n", data_processed); } } exit(0); }

  29. Pipes and execl • Problem: • when do an execl, the new child program will not know of the variables that the old child program contained • the new child program will have the same fd table that the old child had. • but the new child program will not know of the pipe because it has lost its variables.

  30. Pipes and execl • Solution: • Since we know that the fd is really just an integer, we can pass the fd as a command line argument.

  31. Pipes and execl #include <unistd.h> #include <other libraries> #define BUFSIZ 30 int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; char buffer[BUFSIZ + 1]; int fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == -1) { fprintf(stderr, "Fork failure"); exit(1); }

  32. Copy the read file descriptor into the string “buffer” Pass the string containing the fd number as a command line argument Pipes and execl if (fork_result == 0) { /* This is the child process */ sprintf(buffer, "%d", file_pipes[0]); execl("pipe4", "pipe4", buffer, (char *)0); exit(1); } else { /* This is the parent process */ data_processed = write(file_pipes[1], some_data, strlen(some_data)); printf("%d - wrote %d bytes\n", getpid(), data_processed); } } exit(0); }

  33. Change the string containing the file descriptor into an integer. Pipe4.c #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #define BUFSIZ 30 int main(int argc, char *argv[]) { int data_processed; char buffer[BUFSIZ + 1]; int file_descriptor; memset(buffer, '\0', sizeof(buffer)); sscanf(argv[1], "%d", &file_descriptor); data_processed = read(file_descriptor, buffer, BUFSIZ); printf("%d - read %d bytes: %s\n", getpid(), data_processed, buffer); exit(0); }

  34. Pipes: changing stdin • What if the new child program reads from stdin? • Since a new child from an exec retains the fd table, must trick the child into thinking that the pipe is stdin

  35. Pipes: changing stdin • Method: • close standard in. • frees up the 0th entry in the fd table • use the dup system call to duplicate the read fd of the pipe. • dup(fd) will create a duplicate of fd and place it in the first available entry of the fd table. • in this case, the first available entry is the 0th entry • close the pipe • do an exec call

  36. pipes and stdin int main() { int data_processed; int file_pipes[2]; const char some_data[] = "123"; int fork_result; if (pipe(file_pipes) == 0) { fork_result = fork(); if (fork_result == -1) { fprintf(stderr, "Fork failure"); exit(1); }

  37. close stdin duplicate the read end of the pipe in fd 0 close the pipe exec the “od” program. execlp searches the PATH environmental variable to find the program. pipes and stdin if (fork_result == 0) { /* This is the child process */ close(0); dup(file_pipes[0]); close(file_pipes[0]); close(file_pipes[1]); execlp("od", "od", "-c", (char *)0); exit(1); } else { /* This is the parent process */ close(file_pipes[0]); data_processed = write(file_pipes[1], some_data, strlen(some_data)); close(file_pipes[1]); printf("%d - wrote %d bytes\n", getpid(), data_processed); } } exit(0); } The od program takes its input (in this case the od program itself) and converts it to octal.

  38. Semaphores • Semaphores in Unix are complex. • binSem.h • library that simplifies semaphores • provides functions for binary semaphores • use by including the file in any program that uses binary semaphores: #include binSem.h

  39. Semaphores • binSem.h int start_semvalue(int sem_num) creates the binary semaphore sem_num int set_semvalue(int sem_id,int semVal) initializes the semaphore sem_id with the value semVal void del_semvalue(int sem_id) deletes the semaphore represented by sem_id

  40. Semaphores • more functions provided by binSem.h: int semaphore_p(int sem_id) wait on semaphore sem_id int semaphore_v(int sem_id) signal semaphore sem_id

  41. sem1.c • Compile into the executable file sem1 • To run two copies: bash > sem1 x & bash > sem1 • The first command puts the process into the background • immediately get the prompt back. • Result is that two copies of sem1 are running concurrently

  42. A semaphore identifier is just an int. If semaphore 1234 does not exist, start_semvalue will create it. O.w. it returns the identifier associated with semaphore 1234 semaphore example #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "binSem.h" static int sem_id; int main(int argc, char *argv[]) { int i; int pause_time; char op_char = 'O'; srand((unsigned int)getpid()); sem_id = start_semvalue(1234);

  43. set_semvalue will initialize the value of the semaphore sem_id in this case to 1. Only the process that gets the command line argument will initialize the semaphore. It returns 1 if successful, 0 o.w. sempahore_p is the wait call. It returns 1 if successful, 0 o.w. sempahore_v is the signal call. It returns 1 if successful, 0 o.w. semaphore example if (argc > 1) { if (!set_semvalue(sem_id,1)) { fprintf(stderr, "Failed to initialize semaphore\n"); exit(EXIT_FAILURE); } op_char = 'X'; sleep(2); } for(i = 0; i < 10; i++) { if (!semaphore_p(sem_id)) exit(EXIT_FAILURE); /* start of critical section */ printf("%c", op_char); fflush(stdout); pause_time = rand() % 3; sleep(pause_time); printf("%c", op_char); fflush(stdout); /* end of critical section */ if (!semaphore_v(sem_id)) exit(EXIT_FAILURE);

  44. del_semvalue deletes the semaphore. Only the process that gets the command line argument will delete the semaphore. semaphore example pause_time = rand() % 2; sleep(pause_time); } /* end of for loop */ printf("\n%d - finished\n", getpid()); if (argc > 1) { sleep(10); del_semvalue(sem_id); } exit(EXIT_SUCCESS); }

  45. sem2.c • Same as previous example, but writes to a file instead of stdout #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "binSem.h" static int sem_id; int main(int argc, char *argv[]) { int i; int pause_time; char op_char = 'O'; FILE *fd; char name[]="temp.txt"; srand((unsigned int)getpid()); sem_id = start_semvalue(1234);

  46. sem2.c if (argc > 1) { if (!set_semvalue(sem_id,1)) { fprintf(stderr, "Failed to initialize semaphore\n"); exit(EXIT_FAILURE); } op_char = 'X'; sleep(2); }

  47. sem2.c for(i = 0; i < 10; i++) { if (!semaphore_p(sem_id)) exit(EXIT_FAILURE); /* start of critical section */ fd = fopen(name, "a"); fprintf(fd, "%c", op_char); pause_time = rand() % 3; sleep(pause_time); fprintf(fd, "%c", op_char); fclose(fd); /* end of critical section */ if (!semaphore_v(sem_id)) exit(EXIT_FAILURE); pause_time = rand() % 2; sleep(pause_time); } /* end of for */

  48. sem2.c printf("\n%d - finished\n", getpid()); if (argc > 1) { sleep(10); del_semvalue(sem_id); } exit(EXIT_SUCCESS); }

  49. sem3.c • sem3.c forks off a child and then uses a semaphore to coordinate parent and child access to a file. • Note that a child will inherit all of a parent’s variables, including the semaphore id.

  50. sem3.c #include <all appropriate headers> #include "binSem.h" static int sem_id; int main(int argc, char *argv[]) { int i; int pause_time; char op_char = 'C'; FILE *fd; char name[]="temp2.txt"; srand((unsigned int)getpid()); sem_id = start_semvalue(1234); if (!set_semvalue(sem_id,1)) { fprintf(stderr, "Failed to initialize semaphore\n"); exit(EXIT_FAILURE); }

More Related