Scribe notes by: Joey Gomez-Benito, Patrick Killian Jackson, and Justin Jordan

OS Organization

Goals of an OS:

3 fundamental abstractions for systems

  1. Memory API Issues:
  2. Interpreters API
    high level:
    interpreter f, program p
    v = f(p) where v is the answer

    ip = instruction pointer
    ep = environment pointer

    need:
  3. Link API
    send (linkname, bufferofdata)
    receive (linkname, bufferofdata)
    e.g., I/O bus
    examples of message passing.
    Upsides: Downsides:

if students were asked to write an OS in CS 32, they would write is as an Object Oriented Program. they would implement it with classes for I/O bus, memory, interpreter...
(the road not taken)

CPU
||
-------------||-------------||------------------------ bus
               RAM          I/O Controllers

(resources below are decreasing in performance order)
Core of the CPU: (User code access actual ALU + registers at full speed)
ALU;
Registers;
Cache; (Shouldn't make the program run any different besides speed)

RAM:
primary RAM <--- want full-speed access to some physical memory

I/O <--- typically no access in interpreted program

One Other Resource:
time (operating system has to manage system resources)

Method of Implementing Interpreters:

Layering



GO




Building New Machines on top of old ones.

OS + virtualizable processor
let you support a process
process = program running in isolation(on a virtual interpreter)

To create a process in linux:
     pid_t fork(void); //pid_t - process ID. It's a 32 bit int

To destroy a process:
     you can't, processes destroy themselves
noreturn void exit(int)
the argument is the exit status


pid_t p = fork();

1 physical CPU
>1 Processes

process table:
indexed by process_IDs

GO

suppose a process does a read(fd, buf, 1000);
save the process's registers and resume some other process

the register values of a running process are junk because they show what the instructions were at a previous point

Accessing Memory
each process has its own view of memory

Process table is a table indexing processes by process_ID


each process will have its own view of memory



GO


Things that are cloned are mapped to the same part of physical memory

The _exit() system call
pid_t p = fork();

_exit(2); <--- doesn't flush the output buffers

true.c
int main(void)
{
       return 0;
}

cat executable

--------------
   glue === exit(main()) to put exit status in process table
--------------
code from cats
main program
-------------


The waitpid() system call
pid_t waitpid(pid_t, int*, int);
pid_t: pid of waited-for process
int *: location to store its status
int: flags(0)

name for an exited process: zombie
zombies are still in the process table.
To reclaim the entry in the process table you must call waitpid() on
the process that is in a zombie state. This will give its exit status and put
the process into an empty state.

process table
---------------
---------------
---------------
---------------
56 *zombie* | exit status| <--- exited process
---------------
---------------
---------------
---------------

while(fork()==0) //each iteration you get a parent to fork into a child
       continue;
this will load up the process table to 100%;
called a fork bomb;

most systems have a limit on the amount of processes



Limited Isolation - the pipe() system call
Sometimes processes need ways to communicate with each other:
solution = a pipe

pipe = bounded buffer that sits inside the kernel that acts like a queue of bytes

int pipe(int fd[2]);

each entry in the fd array correspond to file descriptors:
1 for reading the pipe
1 for writing into the pipe

Pipe issues:
Reading an empty pipe = hanging
Writing to an empty pipe = hanging