summaryrefslogtreecommitdiff
path: root/web/l1.html
blob: 98656019a3fb42fa239a10c5ea9ed4aaa2ac63b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<title>L1</title>
<html>
<head>
</head>
<body>

<h1>OS overview</h1>

<h2>Overview</h2>

<ul>
<li>Goal of course:

<ul>
<li>Understand operating systems in detail by designing and
implementing miminal OS
<li>Hands-on experience with building systems  ("Applying 6.033")
</ul>

<li>What is an operating system?
<ul>
<li>a piece of software that turns the hardware into something useful
<li>layered picture: hardware, OS, applications
<li>Three main functions: fault isolate applications, abstract hardware, 
manage hardware
</ul>

<li>Examples:
<ul>
<li>OS-X, Windows, Linux, *BSD, ... (desktop, server)
<li>PalmOS Windows/CE (PDA)
<li>Symbian, JavaOS (Cell phones)
<li>VxWorks, pSOS (real-time)
<li> ...
</ul>

<li>OS Abstractions
<ul>
<li>processes: fork, wait, exec, exit, kill, getpid, brk, nice, sleep,
trace
<li>files:  open, close, read, write, lseek, stat, sync
<li>directories: mkdir, rmdir, link, unlink, mount, umount
<li>users + security: chown, chmod, getuid, setuid
<li>interprocess communication: signals, pipe
<li>networking: socket, accept, snd, recv, connect
<li>time: gettimeofday
<li>terminal:
</ul>

<li>Sample Unix System calls (mostly POSIX)
<ul>
	<li> int read(int fd, void*, int)
	<li> int write(int fd, void*, int)
	<li> off_t lseek(int fd, off_t, int [012])
	<li> int close(int fd)
	<li> int fsync(int fd)
	<li> int open(const char*, int flags [, int mode])
	  <ul>
		<li> O_RDONLY, O_WRONLY, O_RDWR, O_CREAT
	  </ul>
	<li> mode_t umask(mode_t cmask)
	<li> int mkdir(char *path, mode_t mode);
	<li> DIR *opendir(char *dirname)
	<li> struct dirent *readdir(DIR *dirp)
	<li> int closedir(DIR *dirp)
	<li> int chdir(char *path)
	<li> int link(char *existing, char *new)
	<li> int unlink(char *path)
	<li> int rename(const char*, const char*)
	<li> int rmdir(char *path)
	<li> int stat(char *path, struct stat *buf)
	<li> int mknod(char *path, mode_t mode, dev_t dev)
	<li> int fork()
          <ul>
		<li> returns childPID in parent, 0 in child; only
		difference
           </ul>
	<li>int getpid()
	<li> int waitpid(int pid, int* stat, int opt)
           <ul>
		<li> pid==-1: any; opt==0||WNOHANG
		<li> returns pid or error
	   </ul>
	<li> void _exit(int status)
	<li> int kill(int pid, int signal)
	<li> int sigaction(int sig, struct sigaction *, struct sigaction *)
	<li> int sleep (int sec)
	<li> int execve(char* prog, char** argv, char** envp)
	<li> void *sbrk(int incr)
	<li> int dup2(int oldfd, int newfd)
	<li> int fcntl(int fd, F_SETFD, int val)
	<li> int pipe(int fds[2])
	  <ul>
		<li> writes on fds[1] will be read on fds[0]
		<li> when last fds[1] closed, read fds[0] retursn EOF
		<li> when last fds[0] closed, write fds[1] kills SIGPIPE/fails
		EPIPE
           </ul>
	<li> int fchown(int fd, uind_t owner, gid_t group)
	<li> int fchmod(int fd, mode_t mode)
	<li> int socket(int domain, int type, int protocol)
	<li> int accept(int socket_fd, struct sockaddr*, int* namelen)
	  <ul>
		<li> returns new fd
          </ul>
	<li> int listen(int fd, int backlog)
	<li> int connect(int fd, const struct sockaddr*, int namelen)
	<li> void* mmap(void* addr, size_t len, int prot, int flags, int fd,
	off_t offset)
	<li> int munmap(void* addr, size_t len)
	<li> int gettimeofday(struct timeval*)
</ul>
</ul>

<p>See the <a href="../reference.html">reference page</a> for links to
the early Unix papers.

<h2>Class structure</h2>

<ul>
<li>Lab: minimal OS for x86 in an exokernel style (50%)
<ul>
<li>kernel interface: hardware + protection
<li>libOS implements fork, exec, pipe, ...
<li>applications: file system, shell, ..
<li>development environment: gcc, bochs
<li>lab 1 is out
</ul>

<li>Lecture structure (20%)
<ul>
<li>homework
<li>45min lecture
<li>45min case study
</ul>

<li>Two quizzes (30%)
<ul>
<li>mid-term
<li>final's exam week
</ul>

</ul>

<h2>Case study: the shell (simplified)</h2>

<ul>
<li>interactive command execution and a programming language
<li>Nice example that uses various OS abstractions. See  <a
href="../readings/ritchie74unix.pdf">Unix
paper</a> if you are unfamiliar with the shell.
<li>Final lab is a simple shell.
<li>Basic structure:
<pre>
      
       while (1) {
	    printf ("$");
	    readcommand (command, args);   // parse user input
	    if ((pid = fork ()) == 0) {  // child?
	       exec (command, args, 0);
	    } else if (pid > 0) {   // parent?
	       wait (0);   // wait for child to terminate
	    } else {
	       perror ("Failed to fork\n");
            }
        }
</pre>
<p>The split of creating a process with a new program in fork and exec
is mostly a historical accident.  See the  <a
href="../readings/ritchie79evolution.html">assigned paper</a> for today.
<li>Example:
<pre>
        $ ls
</pre>
<li>why call "wait"?  to wait for the child to terminate and collect
its exit status.  (if child finishes, child becomes a zombie until
parent calls wait.)
<li>I/O: file descriptors.  Child inherits open file descriptors
from parent. By convention:
<ul>
<li>file descriptor 0 for input (e.g., keyboard). read_command: 
<pre>
     read (1, buf, bufsize)
</pre>
<li>file descriptor 1 for output (e.g., terminal)
<pre>
     write (1, "hello\n", strlen("hello\n")+1)
</pre>
<li>file descriptor 2 for error (e.g., terminal)
</ul>
<li>How does the shell implement:
<pre>
     $ls > tmp1
</pre>
just before exec insert:
<pre>
    	   close (1);
	   fd = open ("tmp1", O_CREAT|O_WRONLY);   // fd will be 1!
</pre>
<p>The kernel will return the first free file descriptor, 1 in this case.
<li>How does the shell implement sharing an output file:
<pre>
     $ls 2> tmp1 > tmp1
</pre>
replace last code with:
<pre>

	   close (1);
	   close (2);
	   fd1 = open ("tmp1", O_CREAT|O_WRONLY);   // fd will be 1!
	   fd2 = dup (fd1);
</pre>
both file descriptors share offset
<li>how do programs communicate?
<pre>
        $ sort file.txt | uniq | wc
</pre>
or
<pre>
	$ sort file.txt > tmp1
	$ uniq tmp1 > tmp2
	$ wc tmp2
	$ rm tmp1 tmp2
</pre>
or 
<pre>
        $ kill -9
</pre>
<li>A pipe is an one-way communication channel.  Here is an example
where the parent is the writer and the child is the reader:
<pre>

	int fdarray[2];
	
	if (pipe(fdarray) < 0) panic ("error");
	if ((pid = fork()) < 0) panic ("error");
	else if (pid > 0) {
	  close(fdarray[0]);
	  write(fdarray[1], "hello world\n", 12);
        } else {
	  close(fdarray[1]);
	  n = read (fdarray[0], buf, MAXBUF);
	  write (1, buf, n);
        }
</pre>
<li>How does the shell implement pipelines (i.e., cmd 1 | cmd 2 |..)?
We want to arrange that the output of cmd 1 is the input of cmd 2.
The way to achieve this goal is to manipulate stdout and stdin.
<li>The shell creates processes for each command in
the pipeline, hooks up their stdin and stdout correctly.  To do it
correct, and waits for the last process of the
pipeline to exit.  A sketch of the core modifications to our shell for
setting up a pipe is:
<pre>	    
	    int fdarray[2];

  	    if (pipe(fdarray) < 0) panic ("error");
	    if ((pid = fork ()) == 0) {  child (left end of pipe)
	       close (1);
	       tmp = dup (fdarray[1]);   // fdarray[1] is the write end, tmp will be 1
	       close (fdarray[0]);       // close read end
	       close (fdarray[1]);       // close fdarray[1]
	       exec (command1, args1, 0);
	    } else if (pid > 0) {        // parent (right end of pipe)
	       close (0);
	       tmp = dup (fdarray[0]);   // fdarray[0] is the read end, tmp will be 0
	       close (fdarray[0]);
	       close (fdarray[1]);       // close write end
	       exec (command2, args2, 0);
	    } else {
	       printf ("Unable to fork\n");
            }
</pre>
<li>Why close read-end and write-end? multiple reasons: maintain that
every process starts with 3 file descriptors and reading from an empty
pipe blocks reader, while reading from a closed pipe returns end of
file.
<li>How do you  background jobs?
<pre>
        $ compute &
</pre>
<li>How does the shell implement "&", backgrounding?  (Don't call wait
immediately).
<li>More details in the shell lecture later in the term.

</body>