Omar Sheikh

Karapet Shaginyan

CS111 Lecture 5

Professor Eggert

10/8/09 10:00AM 

Orthogonality

      -decisions on each axis are independent, and (ideally) result in a useful design. This is out goal in OS design.

      - Example: making changes in the file system should not result in having to rewrite the way processes are handled.

      - In OS design, our three main issues are files, processes, and memory. You can think of these as the labels on the axes of a 3-D plane and the orthogonality analogy should make sense. 

How to model O.S. resources in a user program.  (mechanism) 

O.S. data structure

      (process descriptor)

      (file descriptor) 

  1. give application a pointer(or special values)
    • fast, easy to explain
    • no protection against bad apps
    • brittle->change O.S. -> rebuild applications (non-orthogonal design)
    • race conditions galore
  2. Hand out handles
    • a bad pointer. - opaque identifiers for system data

      Struct pte {int pid; int vid; ______;};

      O.S. struct pte *p = return (struct pte foolya*) ~ (int) p;

struct foolya;
 

3) an int (very common)

       OS table

 
 
 
 
 
 

table itself is in memory

application sees the table

memory is invisible to application 

Passing out ints is a very common approach in Unix, here are some examples:

pid_t, fd(int), uid_t, gid_t, IP ports, ino_t, dev_t 

The drawback of this method: ints are easily forged. Anyone can guess a number. 

int main (void) {

      kill (1, SIG_KILL);

} 

We get around this drawback by forcing out OS to check if an application has authority of certain ints. 

int main (void) {

      char buf[512];

      read(27, buf, sizeof(buf));

}

returns EBADF - bad file descriptors 

int main(int argc, char **argv) {

      kill(atoi(argv[1]), SIGTERM));

      return 0;

} 

how to kill yourself in shell

$ kill $$ 

kill(getpid(), SIGTERM); 

Files and Processes

creating/destroying file descriptors

      int open(char const *filename, int flags[, mode_t mode]); 

If a syscall fails (returns with -1, you can examine the variable errno to get more information about the failure. On a successful syscall, errno is garbage. Errno is special because it is a thread local variable. 
 

When opening a file use one either O_RDONLY, O_WRONLY, O_RDWR for either read-only, write-only, or read-and-write respectively. Use O_CREAT if you want the OS to create the file if it doesn't already exist. 

Example: open(“/tmp/foo”, O_RDONLY|O_CREAT, 0666) 

0666 specifies the permissions. These are 9 bits that are used to specifiy the owner's, group's, and other's permissions for a file or directory. The first 3 bits represent the permissions for the owner, the next 3 bits for the group, and the final 3 bits for others. In each category, if the first bit is on, then read permissions are available. If the second second bit is on, it represents write permissions, if the third bit is on, it represents execute permissions. 

a side note on permissions:

101 111 110 100
5 7 6 4
sticky bit user group other
 

arg to open for a created file

=> mask it with the process’s umask (in process descriptor) 

m&~u is file’s actual mode 

program: open(“foo”, O_WRONLY, 0666);

users says umask 022 

0666

0022

0644 

Too much orthogonality? 167 --x rw- rwx is possible. This means others can read, write, execute, but the owner can only execute. This is strange, but allowable. 
 

creating/destroying fds fd= open(--)

                              close(fd); 

creating/destroying processes.   pid_t   fork(void);

      clone process

            parent are identical except

                                          parent: fork return child pid

                                          child:  fork returns 0

multiple versions of exit:

int or void exit(int(exit status));  <--C library cleanup

void  _exit(int);    <--syscall 

int printdate(void){  ---char args [2] = {“date”, NULL};

      pid_t p=fork();

      switch(p){

            case -1:  return -1;

            case 0: execup(“/usr/bin/date”, args);

            default: int status;

                        if (waitpid(p, &status, 0 <0) return -1;

                  return status; 

int execup(char const *filename, char *const *args);

      change program to filename, run it’s main function

always returns -1 (if it returns) settings errno 
 

date.c

      int main(int argc, char **argv){

            decode_options(argv);

            gettimeofday(-);

            int n = printf(---);

            int o = fflush(stdout);

            if (ok(n,o)) return 0;

            else return 1;

} 

O.S. does this:

      exit(main(argc, argv)); 

race conditions

      behavior goes bad if processes are scheduled in a certain way:

      does waitpid get called in parent before or after -exit is called in child?

open

exit => closes all open fds

fd = open (“foo”, o_RDWR, _ )

remove(“foo”);

read(fd, _) a nameless file: sticks around, until file is closed.

write(___) 

while (exists(n)) n = n+ “x”;

p1: open(n, O_RDWR, O_CREAT, 0666);

p2: