-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathcs111-eggert
1756 lines (1299 loc) · 51.8 KB
/
cs111-eggert
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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
CS111: Operating System Principles (Paul Eggert)
http://web.cs.ucla.edu/classes/winter16/cs111
=============
Jan. 6, 2016
=============
A bit more OS philosophy
-------------------------
tradeoffs
scaling
these issues are not inherently new, occur in traditional systems
been with us for a long time already
complexity
new to our entineering operating systems
getting worse with time
inconsmemorate scaling
Moore's Law (transistors, #bits/chip)
--------------------------------------
exponential growth
but looking at the most recent dots, the exponential growth seems to tail off
the graph [!] talks only about the economic sweet spot (mass produced chips)
Kryder's Law (secondary storage capacity, bytes/drive)
-------------------------------------------------------
disk size per unit price grows (0.0001TB -> 4TB)
how about avg seek time?
we are not good at making fast machines as we are with making complex objects
Why exponential growth?
------------------------
UNIVAC I (hand designed, slow, safe)
used this to design UNIVAC II
d(technology)/dt = K * technology (current)
Thus according to this bogus argument
technology is an exponential function of time
How not to do an OS
--------------------
Why not to use an OS
---------------------
- simplicity
- performance
speed
memory
- reliability
as a consequence of simplicity
- security
paranoia
Application: Word Processor
----------------------------
count of words in an ASCII text file
all bytes in range '\001' - '\177'
~ 10 year old desktop
Core 13-4160 (3 MiB cache, 3.6 GHz)
4GiB dual channel DDR3, 1600 MUSDRAM
1TB hard drive, SAIA, 2700
Intel 4400 graphics
assume file is in congiguous array of sectors
traditional disk drive with 512 byte each sector
running an old BIOS (Basic Input Output System)
where's the program
where's the data (file)
BIOS
-----
cycling power -> CPU resets, clears the RAM and cache
bootstrapping problem
ip = 0xffff0 (2^20 - 16)
Physical RAM
0 4GB
+---+---+--------------------------------------------------------------+
| * | * | |
+-|-+-|-+--------------------------------------------------------------+
| +---> 0xffff0
+---------------------> EEPROM region <- hardwired by manufactured
electronic erasable programmable read-only memory
+---> non-volatile memory
word count program is on disk, we need to read it into RAM to execute it
in EEPROM we give location on disk and size of WC + loading program
after loading we jump to its loaded location on RAM
conventional desktop: read-only constants on EEPROM
manufactures will specify location where they will
run the programs and the size they will run
convention
+---+-------------------------------------------------------------------+
| | |
+-|-+-------------------------------------------------------------------+
|
|
|
+-+--> 1st sector Master Boot Record (MBR) partition table
| |
| +-------------------------------------------------------+---|--+-+
+> | x86 code | 64 |*|
+-------------------------------------------------------+------+|+
446 bytes |
0xAA55
copy this sector to 0x7c00
do hardware sanity check
checks for devices (CPU is attached via bus to many devices)
looks for 1st device with MBR
how to differentiate with random data and MBR
last two bytes of MBR has: 0x55 0xAA
still a chance to find non-MBR with same pattern
put MBR before all devices to eliminate this option
partition table
+---------------------------------------------+----+----+----+----+---+
| | | |
+---------------------------------------------+-|--+----+----+----+---+
446 bytes | 64 bytes 2
|
32-bit
type byte/bootable
size of partitions
origin
+---+-----------------------------------------------------------------+
+--> | |
| +---+-----------------------------------------------------------------+
| origin + size
|
+-- 0 (MBR)
chain loading
firmware -> MBR ---------> VBR---------> kernel -> run many programs
OS-agnostic OS-specific many
sectors
subroutine to read data from disk (omit error checking due to time problem)
void read_ide_sector(int sector_no, char *address_into)
4 byte 4 byte (x86 mode)
{
// 0x1f7: status register
// +-+-+-+-+-+-+-+-+
// |0|1| | | | | | |
// +-+-+-+-+-+-+-+-+
// +---------------------> this pattern '01' means ready
//
while ((inb(0xif7) & 0xc0) != 0x40)
continue;
outb(0x1f2, 1);
outb(0x1f3, sector_no); // outputs low order 8 bits
outb(0x1f4, sector_no >> 8);
outb(0x1f5, sector_no >> 16);
outb(0x1f6, sector_no >> 24);
outb(0x1f7, 0x20);
while((inb(0x1f7) & 0x20) != 0x40)
continue; // wait
insl(0x1f0, address_into, 128); // 128 = 512/sizeof(int)
}
'inb' subroutine: CPU send signal to disk controller via bus
disk controller sends back data from disk
retrieve address 'a' (bus address) from disk
this instruction is slow because signals travel on bus
static inline inb(int a)
{
asm("...");
}
1f0: actual data
1f2: sector count
1f3: low order byte
1f4: sector number
1f5
1f6: high order byte
1f7: write : issue command
read : returns status
+------------+----------+--------------+------+
| status/cmd | sector # | sector count | data |
+------------+----------+--------------+------+
1f7 1f6 ~ 1f3 1f2 1f1 ~ 1f0
where to put this subroutine?
compile and put into RAM
copy and put in firmware (BIOS) at 0xffff07
copy into MBR at 0x7c21
copy into WC program
problem: have 3 copies of the same code
keep in firmware (BIOS) and discard the others
nowadays we keep the copies since memory is not that of an issue
==============
Jan. 11, 2016
==============
To output to screen, we use memory-mapped I/O, not programmed I/O (PIO)
Use movb to move byte to particular region in memory to display on screen
+----+---+-------------------------+
movb | | * | |
+----+-|-+-------------------------+
|
+----> not RAM in ordinary sense, but displayed
display CPU: read bytes from display RAM and display on screen (60 times/sec)
screen = 80 x 25 grid of chars
0xb8000
4000 bytes
|<------ 80 ------>|
+------------------+ -+
| +--+ | |
| +-> | | | 25
| | +--+ | |
+------|-----------+ -+
|
|
16 bits to represent
low order 8 bits in ASCII
high order bits, graphical appearance
want grey on black (7 in higher bits)
void output_to_screen(long n)
{
short *p = (short *)0xb8000 + (80*25/2 - 80/2);
do {
*p-- = (7 << 8) | (n % 10 + '0');
n /= 10;
} while (n != 0);
}
run the program
void main(void)
{
int s = 1000; // choose arbitrary sector to read from
// '\0' = 0, means EOF
long nwords = 0;
bool inword = 0;
char buf[512];
for (;;) {
read_ide_sector(s++, buf);
for (int j = 0; j < sizeof(buf); j++) {
if (!buf[j])
done(nwords);
bool isletter = ((buf[j] >= 'a' && buf[j] <= 'z') ||
(buf[j] >= 'A' && buf[j] <= 'Z'));
nwords += isletter & ~inword; // 1 if and only if at start of word
inword = isletter;
}
}
}
void done(long nwords) {
output_to_screen(nwords);
halt();
}
Issues in this program
-----------------------
(1) we are getting data inefficiently from disk
we transfer data from disk controller to CPU then from CPU to RAM
we would like to copy data directly from disk controller to RAM
Could use DMA (directory memory access)
+-----+
| CPU |
+-----+
============================================ BUS
+-----+ +-----------------+
| RAM | | Disk Controller |
+-----+ +-----------------+
catch: CPU must ask the controller 'done yet?'
CPU can be notified somehow
Crypto App, lots of CPU
------------------------ 0 1 2 | 0 1 2 3
I/O --- --- --- | ------------
(wait for disk to become ready) |
0 1 2 | 0 1 2 3
ECC --- --- --- | ------------
|
time ------------------------------------------------|-------------------------->
| double buffering
want to utilize CPU better, use double buffering
could use multitasking and run I/O in parallel
How to scale up these programs
-------------------------------
* fancier performance tricks without rewriting apps
* multitasking
Modularity
-----------
split up program into pieces so that each piece becomes more manageable
cost of maintaining a module of N lines of code is O(N^2)
How do you measure quality of modularity & abstraction in an OS?
-----------------------------------------------------------------
Simplicity ease of use
ease of learning
short manual for the OS
Robustness tolerance of errors, large inputs
under harsh conditions, should still work
Performance modularity is going cost some performance
have to build module interfaces (design cost)
costs when jumping between modules at runtime
minor costs are inevitable
major costs are avoidable
Flexibility
Lack of assumptions
Neutrality
Unix/Linux: '\n' is not a special case in a file
Designing an interface for reading a line from input
-----------------------------------------------------
read a line from the input
1. char *readline(FILE *f)
BAD DESIGN for an OS
---------------------
1. Performance unbounded work - may take forever for big lines
unbatched work - overhead for small lines
2. Robustness apps crash with big lines
3. Neutrality forces line ending convention
4. Simplicity good simplicity :)
2. size_t read(int fd, void *buf, size_t bufsize)
int return value for indicating error values or failures
-> ssize_t (64-bit long) for number bytes read, -1 for all errors
bufsize for not assuming 512 byte sector, more general interface
void *buf turns off type checking on C compiler for any pointer
int bufsize 2^31 = 2GiB --> size_t for size
size_t: x86_64 -> unsigned long 64-bit
x86 -> unsigned long 32-bit
int byte_offset -> off_t (64-bit signed)
int fd specifies which file to read from (opaque file handle)
[!] removed byte_offset
BIG IDEA OF UNIX: everything outside the program is a file
random access stream devices
--------------------------------------------
disk network mouse keyboard
flash display
added new system call: lseek(int fd, off_t where, int flag)
corallary: OS records current file position on read, lseek sets position
3. pread(...)
has extra argument for random access with a 'byte_offset' argument
Mechanisms for modularity
--------------------------
1. function (or method) calls
call a function in another module and wait for return
+ simple, well understood
+ fast
- robustness, things can go wrong
run out of stack space
functions stepping on each other's stack space
infinite loops
2. client-server
+ not as simple, well understood
+ things do not go wrong as easily
- way too slow, client -> server -> client
works if clients are human beings
does not work for high-performance applications
3. virtualization
==============
Jan. 13, 2016
==============
OS Organization
----------------
Booting
--------
get good interfaces between modules
UEFI
want to organize booting process and split up what firmware (BIOS) does
and what's on the disk with better line between the two
GUID (Globally Unique Idendifier for disk partition)
128-bit quantity
without these IDs, firmware won't know if it changed or not
GUID partition table (GPT)
Standard layout in partition
-----------------------------
File system formats FAT12
FAT16
FAT32
Firmware is in EEPROM
Firmware can understand file format on disk
Have a kernel with well-known name sitting as a file
Firmware will load kernel into memory and run it
Firmware --> configuration variables, nvram
If firmware does not like config, may not boot
Once booted, OS is in charge
We could put OS in read-only memory, does not work because we may want to
change it before we boot
How to enforce modularity after booting?
-----------------------------------------
use function calls as the way of interfacing into OS
char buf[2000];
read(3, buf, 1000);
why is this terrible?
use toy function
-----------------
int fact(int n) {
if (!n)
return 1;
return n * fact(n-1);
}
gcc compiled this into a loop with optimization
after turning off optimization
fact: pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
cmpl $0, -4(%rbp)
jne .L2
movl $1, %eax
jmp .L3
.L2: movl -4(%rbp), %eax # move 'n' into %eax
subl $1, %eax # 'n-1'
movl %eax, %edi # %edi holds first argument
call fact # calls the 'fact' function
imull -4(%rbp), %eax # have fact(n-1) in %eax
# n * fact(n-1), store in %eax
.L3: leave # rsp = rbp; rbp = *rsp++;
ret # rip = *rsp++;
[!] things that chould go wrong
fact(-1) # negative numbers
fact(10000000) # same logic as INT_MAX
# stack will grow inifinitely
# stack overflow, dump core if lucky
# may mess with other structures
fact(INT_MIN) # will compute fact(INT_MAX)
fact(50) # will do 50 multiplications
# get bottom 32 bits of correct answer
what to do with stack overflow?
--------------------------------
(1) we could check stack everytime we grow the stack
fact: # check for stack overflow here
pushq %rbp
(2) use virtual memory with guard page on stack
trap when encounters guard page
suppose the 'fact' calls 'fact2', what can 'fact2' do to mess up 'fact'
------------------------------------------------------------------------
(1) can modify 'fact's activation record
modify return address -> return to wrong place
can make 'fact' multiply wrong number
can loop forever
jump to any other location in program
how can fact mess up fact2?
----------------------------
(1) put a random number value into %edi
(2) movl $0, %esp
jmp fact2
set stack pointer to 0, which is a forbidden region
WE HAVE SOFT MODULARITY HERE
-----------------------------
requires that program trusts each other
does not scale to large applciations
[!] WE WANT HARD MODULARITY
----------------------------
(1) virtualization
+ cheaper modularity
- unidirectional hard modularity
kernel is protected against application
application is not protected against kernel
- not as reliable as client-server approach
(2) client server (hard modularity in both directions)
+ client and server are both insulated from each other
not allowed to look into each others' memory
- expensive for small software, need something cheaper
How to get virtualization to work?
-----------------------------------
operating system is the master program
wants to run application under the kernel's control
simplest way to get virtualization to work
-------------------------------------------
write simulator for machine the applciation runs on
simulator can execute instructions under it controls
it carefully checks the instructions
refuses to execute any dangerous instructions
we could count instructions, when it reaches a limit --> return
simulators cane be useful for debugging programs on machines that
are not available or does not exist yet
THIS IS USUALLY TOO SLOW FOR PRODUCTION!
[!] We need a virtualizable processor
run in sandbox
Second way of doing virtualization
-----------------------------------
throw application out and let it run
but stop the program before it causes trouble
app: kernel:
+---------+ +----------+
| could | | |
| cause | | reliable |
| trouble | | |
+----|----+ +-----^----+
| | -----> not allowed
+----------------+
kernel can mess around the application
but application cannot mess around with the kernel
divide instructions into safe and dangerous instructions
---------------------------------------------------------
safe instructions can be executed by application
but if an application wants to execute dangerous (privileged) instruciton
hardware executes a 'protected transfer of control'
%rip becomes in the kernel!
need extra bit in processor that tells if in kernel or not (privileged bit)
privileged instructions should be rare
if they are rare enough, then we will run at almost full speed
we have to protect memory with virtual memory techniques
'movl' should work in most circumstances, unless it accesses privileged memory
Layered architecture
---------------------
+-------------+
| application |
+--------+ |
| kernel | |
+--------+----+
| hardware |
+-------------+
Classic way to enter the kernel
--------------------------------
execute a privileged instruction with a standard convention
int 128 # interrupt function
# execute system call
x86 version
------------
push ss # stack segment
push esp
push eflags
push cs # code segment
push eip
push error code
trap vector : contains the value 128
kernel
trap vec +------+
+-----+ | |
| | | |
| | +------+
| 128 ----> | | <-- ip
| | +------+
| | | |
| | | |
| | | |
| | | |
+-----+ | |
+------+
rti # return from interrupt
nowadays with x86 & x86-64
---------------------------
syscall instruction
enters kernel
returns
looks as if we have new instruction to do wonderful stuff
each system call has unique system call number
we have no system call with more than 6 arguments
6 arguments to system call: rax rdi rsi rdx r10 r8 r9
syscall #
destroys rcx, r11
result in rax
returns a number between [-4095, -1] to indicate failure
ssize_t read(int fd, void *buf, size_t s) { ... }
Assume mechanism works, now what does user app developer see?
--------------------------------------------------------------
Model
processes: applications running in virtual machine atop operating system
each process thinks it has control of the whole computer
Operating systems need to support this notion of processes
how to create processes and how to destroy them?
-----------------------------------------------------------
create pid_t fork(void);
clones current process
returns 0 to the child
returns child process id in the parent
returns -1 on failure (not enough resources)
while(1) fork(); // fork bombs
// everybody starts creating
// children as fast they can
void _Noreturn _exit(int);
this bypasses cleanup methods with 'void exit(int)'
_Noreturn specifies that this method does not return
changes calling convention, goes faster
process object
+--------------+
| pid |
| fd-table |
| exit status |
+--------------+
destroy pid_t waitpid(pid_t pid, int *status, int flags)
0
WNOHANG
==============
Jan. 20, 2016
==============
OS goals
---------
protection
robustness
utilization
performance
flexibility
simplicity
apply modularity
split into pieces
apply abstraction
layered modularity
simple layers
kernel can access privileged instructions --> hardware
invoke kernel through system calls
can have more layers
apps
paging
I/O drivers
kernel
x86 supports 4 levels of abstraction in hardware!
Linux supports 2 layers, for simplicity and performance
OS X supports more than 2 layers
microkernel small and efficient
build abstractions atop of that
Unix applications
+------+ +------+ +------+
| app1 | | app2 | | app3 |
+------+ +------+ +------+
+------------------------+
| kernel |
+------------------------+
Some types of system calls
---------------------------
fork() clone a process
copy of process identical to original EXCEPT FOR
1. two processes have different process IDs
use pid_t getpid(void) to get the pid
2. they have different parent pids
use pit_t getppid(void) to get the parent pid
3. have different file descriptor tables
process has file descriptor table (maintained by kernel)
containing pointers to other parts of system
/dev/urandom not exactly random
keeps entropy pool (scarce resource)
random bits seed psuedo-random number generator
somewhere in system contains file description
file description is shared
4. accumulated execution time, CPU time info
counter of CPU time is reset to 0
$time make
5. pending signals are not cloned
the pending signal belongs to the original process
child does not get the signal
6. file locks
file locks are advisory not mandatorily enforced
execvp(char const *, char *const*)
file to execute arguments
destroy/reuse a process
destroy everything except the above listed
destroy all variables, all program, instruction pointer, registers
we also have to destroy signal handlers
sample program
---------------
bool printable(void) {
// run /bin/date
pid_t pid = fork();
switch (pid)
{
case -1: error(); // fork() fails, OS out of resources
case 0: {
static char const date[] = "/bin/date";
if (execvp(date, (char const *){date, NULL})) {
error();
}
}
default: {
int status;
if (waitpid(p, &status, 0) != p)
error();
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
}
}
}
what if we pass in a file that we want the date to be printed in
-----------------------------------------------------------------
bool printable(char const *outfile) {
pid_t pid = fork();
switch (pid)
{
case -1: error(); // fork() fails, OS out of resources
case 0: {
int fd = open(outfile, OWRONLY);
if (fd < 0)
error();
if (dup2(fd, 1) < 0)
error();
if (fd != 1)
close(fd);
static char const date[] = "/bin/date";
if (execvp(date, (char const *){date, NULL})) {
error();
}
}
default: {
int status;
if (waitpid(p, &status, 0) != p)
error();
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
}
}
}
other system call to spawn process
-----------------------------------
This idea was put into POSIX because fork and cloning processes take too much
overhead beacause people think that we do not need to copy all data from a
process for a simple operation.
POSIX spawning processes are fast on Windows system POSIX emulator
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 attr,
char * const * restrict envp)
nice(3) : 3 degrees nicer, less greedy, less CPU time, important for scheduling
restrict keyword all pointers have to point into different parts
of memory in order to prevent aliasing
char *strcpy(char * restrict dest,
char const * restrict src)
Fun thing to try on SEASnet
----------------------------
# on one shell
$echo $$
9731
$kill -STOP $$
# on another shell
$kill -CONT 9731
Orthogonality
--------------
system calls should be orthogonal to each other
meaning that system calls should not be dependent to each other
posix_spawnvp violates this on the grounds that there are two ways to
set niceness, namely the call will do that and we could
manually call nice();
Files are slow & unreliable
robustness & performance are essential
network
mouse vs. flash
keyboard disk
---------------------------------------------------------------
strean random access
spontaneous data generation request/response quickly
infinite finite
Unix BIG IDEA everything is a file
use same system calls to access file
less operations that apply to wide range of applications
open open("/dev/tty", O_RDONLY)
open("dev/rdisk/b", O_WRONLY)
close
read
write
dup2
lseek lseek(fd, 27000, SEEK_SET)
this does not make sense for stream devices
this will return -1 and set errno
locking
Inter-Process Communication (IPC)
----------------------------------
want IPC that doesn't store data on files
Pipes bounded buffers
kernel allocates 4KiB buffer
process A write("xyz");
+-----+---+---+---+-----------+
| | x | y | z | |
+-----+---+---+---+-----------+
process B read()
read/write directly from/to buffer, not involving disk
buffer is bounded so we do not need to worry about memory
Race conditions
----------------
race conditions can occur when the behavoir of program can be dependent on
when things get scheduled
inside sort.c
--------------
int create_temp_file(void) {
while (1) {
char name[1000];
sprintf(name, "/tmp/sort.%d", random());
if (open(name, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600) > 0)
return ;
}