Lecture 5: Orthogonality, Processes, and Races |
CS111: Operating Systems |
Scribes: Yuhuang Chen, Jianan Li and Chuchu Ding |
1. Recap of Previous Lectures
Different operating systems deploy different schemes when it comes to kernel abstraction
Examples:
2. Processes
|
Code example: program that prints out the time of the day
//Program that prints out the time of the day bool printdate() { pid_t p = fork(); switch(p) { case -1: error(); case 0: { static char const date[] = "/bin/date"; execvp("/bin/date", (char const *){date,0}); error(); //execvp doesn't return if succeed } default: { int status; if (waitpid(p,&status,0) != p) error(); } } //WIFEXITED: if child terminated normally, returns ture //WEXITSTATUS(status) prints out the real exit status return WIFEXITED(status) && WEXITSTATUS(status) == 0; } //Program that prints out the time of the day to a file bool printdate(char const *outfile) { pid_t p = fork(); switch(p) { case -1: error(); case 0: { static char const date[] = "/bin/date"; int fd = open(outfile, O_WRONLY); if (fd < 0) error(); if (dup2(fd,1) < 0) error(); if (fd != 1) close(fd); execvp("/bin/date", (char const *){date,0}); error(); //execvp doesn't return if succeed } default: { int status; if (waitpid(p,&status,0) != p) error(); } } return WIFEXITED(status) && WEXITSTATUS(status) == 0; }
Usual pattern for executing a program:
if(fork() == 0) { //Housekeeping; execvp(...); }
Another school of thought, which is simpler and does all jobs in one system call:
int posix_spawnvp( pid_t * restrict pid, char const *restrict file, posix_spawn_file_actions_t const * restrict file_acts, posix_spawn_attr_t const * restrict attrp, char * const * restrict argv, char * const * restrict envp );
posix_spawnvp doesn't copy all that memory(imagine you copied 8GB memory only to do an execvp), so it is very efficient and fast and cheap.
3. Orthogonality
Comparison of Linux’s files:
4. IPC (Interprocess Communication)
Buffers are located in kernel memory
5. Race Conditions
Code example: creating a temporary file that stores sorted data.
// create_temp_file returns the new file descriptor, or -1 if an error occurred //Proposal: int create_temp_file(void) { return open("/tmp/sort.tmp",O_RDWR|O_CREAT|O_TRUNC,0600); } //Problem: when two sort programs are running at the same time, one will trash the other's temp file! //Fix: int create_temp_file(void) { char name[1000]; sprintf(name, "/tmp/sort.%d", getpid()); return open(name, O_RDWR|O_CREAT|O_TRUNC,0600); } //name[1000] is an char array big enough to hold our temp file's name //sprintf() puts "/temp/sort." and our process ID into name[1000]. (e.g. "/temp/sort.30149", where 30149 is our process ID) Thus, no two sort programs running at the same time can trash each other's temp files because each process has a unique process ID! //Problem: what if someone else has already created the same file and you don't have the access to open it? //Fix: int create_temp_file(void) { char name[1000]; int fd; while (1) { sprintf(name, "/tmp/sort.%d", random()); if((fd = open(name, O_RDWR|O_CREAT|O_TRUNC|O_EXCL,0600)) > 0) return fd; } } //now we have a loop, and a random name generator. O_EXCl flag ensures that when the file with the same name already exists, open() should fail. //Simplified version: int create_temp_file(void) { for(;;) { sprintf(name, some_random_string()); if(open(name, O_RDONLY|O_CREAT|O_TRUNC|O_EXCL)) return open(name, O_WRONLY, 0600); } } //Problem: now race condition arises! What if two sort call open() on the same file at the same time?