Operating Systems - Processes PDF
Document Details
Tags
Summary
This document provides an overview of operating systems processes and various concepts like process API, process creation, and process states. It also covers data structures related to processes.
Full Transcript
Operating Systems 4. The Abstraction: The Process 2 How to provide the illusion of many CPUs? CPU virtualizing The OS can promote the illusion that many virtual CPUs exist. Time sharing: Running one process, then stopping it and running anothe...
Operating Systems 4. The Abstraction: The Process 2 How to provide the illusion of many CPUs? CPU virtualizing The OS can promote the illusion that many virtual CPUs exist. Time sharing: Running one process, then stopping it and running another The potential cost is performance. 3 A Process A process is a running program. Comprising of a process: Memory (address space) Instructions Data section Registers Program counter Stack pointer 4 Process API These APIs are available on any modern OS. Create Create a new process to run a program Destroy Halt a runaway process Wait Wait for a process to stop running Miscellaneous Control Some kind of method to suspend a process and then resume it Status Get some status info about a process 5 Process Creation 1. Load a program code into memory, into the address space of the process. Programs initially reside on disk in executable format. OS perform the loading process lazily. Loading pieces of code or data only as they are needed during program execution. 2. The program’s run-time stack is allocated. Use the stack for local variables, function parameters, and return address. Initialize the stack with arguments argc and the argv array of main() function 6 Process Creation (Cont.) 3. The program’s heap is created. Used for explicitly requested dynamically allocated data. Program request such space by calling malloc() and free it by calling free(). 4. The OS do some other initialization tasks. input/output (I/O) setup Each process by default has three open file descriptors. Standard input, output and error 5. Start the program running at the entry point, namely main(). The OS transfers control of the CPU to the newly-created process. 7 Loading: From Program To Process CPU Memory code static data heap stack Process Loading: code Takes on-disk program static data and reads it into the heap address space of Program process Disk 8 Process States A process can be one of three states. Running A process is running on a processor. Ready A process is ready to run but for some reason the OS has chosen not to run it at this given moment. Blocked A process has performed some kind of operation. When a process initiates an I/O request to a disk, it becomes blocked and thus some other process can use the processor. 9 Process State Transition Descheduled Running Ready Scheduled I/O: initiate I/O: done Blocked 10 Data structures PCB(Process Control Block) A C-structure that contains information about each process. Register context: a set of registers that define the state of a process Process list Ready processes Blocked processes Current running processx 11 Example) thread structure in Pintos struct thread{ tid_t tid; enum thread_status status char name; uint8_t *stack; int priority; struct list_elem allelem; struct list_elem elem; #ifdef USERPROG uint32_t *pagedir; #endif unsigned magic; }; 12 Example) The xv6 kernel Proc Structure (Cont.) // the information xv6 tracks about each process // including its register context and state struct proc { char *mem; // Start of process memory uint sz; // Size of process memory char *kstack; // Bottom of kernel stack // for this process enum proc_state state; // Process state int pid; // Process ID struct proc *parent; // Parent process void *chan; // If non-zero, sleeping on chan int killed; // If non-zero, have been killed struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory struct context context; // Switch here to run process struct trapframe *tf; // Trap frame for the // current interrupt }; 13 Example) Register Context in xv6 // the registers xv6 will save and restore // to stop and subsequently restart a process struct context { int eip; // Index pointer register int esp; // Stack pointer register int ebx; // Called the base register int ecx; // Called the counter register int edx; // Called the data register int esi; // Source index register int edi; // Destination index register int ebp; // Stack base pointer register }; // the different states a process can be in enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE }; 14 Process API 15 Overview fork() exec() wait() Separation of fork() and exec() IO redirection pipe 16 Creating a child process fork() Create a child process child process is allocated separate memory space from the process. The child pro cess has the same memory contents as the parents. The child process has its own registers, and program counter register(PC). The newly created process becomes independent after it is created. for parent, fork() returns PID of child process; for child process, fork() returns 0. 17 Usage of fork() p1.c #include #include #include int main(int argc, char *argv[]){ printf("hello world (pid:%d)\n", (int) getpid()); int rc = fork(); if (rc < 0) { // fork failed; exit fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { // child (new process) printf("hello, I am child (pid:%d)\n", (int) getpid()); } else { // parent goes down this path (main) printf("hello, I am parent of %d (pid:%d)\n", rc, (int) getpid()); } return 0; } 18 1 9 fork(): parent vs. child 20 Let’s run it. prompt>./p1 hello world (pid:29146) hello, I am parent of 29147 (pid:29146) hello, I am child (pid:29147) prompt> or prompt>./p1 hello world (pid:29146) hello, I am child (pid:29147) hello, I am parent of 29147 (pid:29146) prompt> 21 Create the dependency between bewteen the processes wait() When the child process is created, wait() in the parent process won’t return until the child has run and exited. The parent and the child does not have any dependency. In some cases, the application wants to enforce the order in which they are executed, e.g. the parent exits only after the child finishes. 22 The usage of wait() System Call p2.c #include #include #include #include int main(int argc, char *argv[]){ printf("hello world (pid:%d)\n", (int) getpid()); int rc = fork(); if (rc < 0) { // fork failed; exit fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { // child (new process) printf("hello, I am child (pid:%d)\n", (int) getpid()); } else { // parent goes down this path (main) int wc = wait(NULL); printf("hello, I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid()); } return 0; } 23 2 4 The wait() System Call (Cont.) Result (Deterministic) prompt>./p2 hello world (pid:29266) hello, I am child (pid:29267) hello, I am parent of 29267 (wc:29267) (pid:29266) prompt> 25 Running a new program exec() The caller wants to run a program that is different from the caller itself. Launch an editor % ls –l OS needs to load a new binary image, initialize a new stack, initialize a new heap for the new program. two parameters The name of the binary file The array of arguemtns 26 char *argv; argv = “echo”; argv = “hello”; argv = 0; exec(“/bin/echo”, argv); printf(“exec error\n”); 2 7 Usage of exec() p3.c #include #include #include #include #include int main(int argc, char *argv[]){ printf("hello world (pid:%d)\n", (int) getpid()); int rc = fork(); if (rc < 0) { // fork failed; exit fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { // child (new process) printf("hello, I am child (pid:%d)\n", (int) getpid()); char *myargs; myargs = strdup("wc"); // program: "wc" (word count) myargs = strdup("p3.c"); // argument: file to count myargs = NULL; // marks end of array execvp(myargs, myargs); // runs word count printf("this shouldn’t print out"); } else { // parent goes down this path (main) int wc = wait(NULL); printf("hello, I am parent of %d (wc:%d) (pid:%d)\n", rc, wc, (int) getpid()); } return 0; } 28 When exec() is called,… Replace the existing contents of the memory with the new memory contents from the new binary file. exec() does not return. It starts to execute the new program. 29 Usage of exec() Result prompt>./p3 hello world (pid:29383) hello, I am child (pid:29384) 29 107 1030 p3.c hello, I am parent of 29384 (wc:29384) (pid:29383) prompt> 30 Why separating fork() and exec()? Why don’t we just use something like “forkandexec(“ls”, “ls –l”)”? Via separating fork() and exec(), we can manipulate various settings just before executing a new program and make the IO rediction and pipe possible. IO redirection % cat w3.c > newfile.txt pipe % echo hello world | wc ‘pipe’ is the heart of the shell programming. 31 IO redirection % wc w3.c > newfile.txt Save the result of ’wc w3.c‘ to newfile.txt. How? Shell is a program that fork() and exec() the command with argument. % ls –l shell calls fork() and exec(“ls”, “ls—l”) ; Before calling exec(“wc”, “wc w3.c”), the shell closes STDOUT (close(1)) and opens newfile.txt (open(“newfile.txt)). 32 Details of IO redirection p4.c #include #include #include #include #include #include int main(int argc, char *argv[]){ int rc = fork(); if (rc < 0) { // fork failed; exit fprintf(stderr, "fork failed\n"); exit(1); } else if (rc == 0) { // child: redirect standard output to a file close(STDOUT_FILENO); open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU); // now exec "wc"... char *myargs; myargs = strdup("wc"); // program: "wc" (word count) myargs = strdup("p4.c"); // argument: file to count myargs = NULL; // marks end of array execvp(myargs, myargs); // runs word count } else { // parent goes down this path (main) int wc = wait(NULL); } return 0; } 33 IO redirection Result prompt>./p4 prompt> cat p4.output 32 109 846 p4.c prompt> 34 File descriptor and file descriptor table File descriptor an integer that represents a file, a pipe, a directory and a device A process uses a file descriptor to open a file and directory. each process has its own file descriptor table. File descriptor 0 (Standard Input), 1 (Standard Output), 2 (Standard Error) 3 5 File offset 3 6 File structure (struct file in Linux) 37 file descriptor and system calls open() Allocate a new file object, allocate new file descriptor and set the newly allocated file descript or to point to the new file object. When allocating the new file descriptor, it uses the smallest ‘free’ file descriptor from the file descriptor table. close() deallocate the file descriptor ‘fd’. Deallocate the file object if there is no file descriptor associated with it. fork() copies the file descriptor table from the parent to child process. exec() retains the file descriptor table. 38 fork() and file descriptors if(fork() == 0) { write(1, “hello “, 6); exit(); } else { wait(); write(1, “world\n”, 6); } 39 40 41 cat and IO redirection % cat input.txt char *argv; char buf; argv = “cat”; int n; argv = 0; if(fork() == 0) { for(;;) { Standard Input close(0); n = read(0, buf, sizeof(buf)); open(“input.txt”, O_RDONLY); if(n == 0) exec(“cat”, argv); break; } if(n < 0) { Standard Error fprintf(2, “read error\n”); exit(); } Standard Output if(write(1, buf, n) != n) { fprintf(2, “write error\n”); exit(); } } 4 2 pipe: ‘|’ % echo hello world | wc pipe Output to STDOUT of one process is fed to STDIN of another process. Implemented with dup() and pipe(). Key innovation of UNIX shell. 4 3 dup(fd) duplicate file descriptor: dup() system call fd = dup(1); write(1, “hello “, 6); write(fd, “world\n”, 6); 4 4 pipe() special type of file, a kernel buffer that is exposed to a process via a pair of file de scriptors: p for read end and p for write end. The reader blocks when there is no data to read. 4 5 pipe int p; char *argv; argv = “wc”; argv = 0; pipe(p); if(fork() == 0) { close(0); dup(p); close(p); close(p); exec(“/bin/wc”, argv); } else { close(p); write(p, “hello world\n”, 12); % echo hello world | wc close(p); } 46 pipe int p; char *argv; argv = “wc”; argv = 0; pipe(p); if(fork() == 0) { close(0); dup(p); close(p); close(p); exec(“/bin/wc”, argv); } else { close(p); write(p, “hello world\n”, 12); % echo hello world | wc close(p); } 47 pipe int p; char *argv; argv = “wc”; argv = 0; pipe(p); if(fork() == 0) { close(0); dup(p); close(p); close(p); exec(“/bin/wc”, argv); } else { close(p); write(p, “hello world\n”, 12); close(p); % echo hello world | wc } 48 pipe int p; char *argv; argv = “wc”; argv = 0; pipe(p); if(fork() == 0) { close(0); dup(p); close(p); close(p); exec(“/bin/wc”, argv); } else { close(p); write(p, “hello world\n”, 12); % echo hello world | wc close(p); } 49 pipe vs. IO redirection advantages of pipes over using redirection with temporary files echo hello world | wc vs. echo hello world > ttmp/xyz ; wc