Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/patches/ASST2.patch
734 views
1
diff --git a/.gitignore b/.gitignore
2
new file mode 100644
3
index 0000000..3caa328
4
--- /dev/null
5
+++ b/.gitignore
6
@@ -0,0 +1,5 @@
7
+kern/compile/*
8
+*.depend
9
+*.swp
10
+build/*
11
+
12
diff --git a/defs.mk b/defs.mk
13
new file mode 100644
14
index 0000000..9345229
15
--- /dev/null
16
+++ b/defs.mk
17
@@ -0,0 +1,20 @@
18
+# This file was generated by configure. Edits will disappear if you rerun
19
+# configure. If you find that you need to edit this file to make things
20
+# work, let the course staff know and we'll try to fix the configure script.
21
+#
22
+# The purpose of this file is to hold all the makefile definitions
23
+# needed to adjust the OS/161 build process to any particular
24
+# environment. If I've done it right, all you need to do is rerun the
25
+# configure script and make clean if you start working on a different
26
+# host OS. If I've done it mostly right, you may need to edit this
27
+# file but you still hopefully won't need to edit any of the
28
+# makefiles.
29
+#
30
+# The things that can be set here are documented in mk/os161.config.mk.
31
+#
32
+
33
+OSTREE=$(HOME)/root
34
+PLATFORM=sys161
35
+MACHINE=mips
36
+COMPAT_CFLAGS=
37
+COMPAT_TARGETS=
38
diff --git a/kern/arch/mips/locore/trap.c b/kern/arch/mips/locore/trap.c
39
index ff39633..42ed641 100644
40
--- a/kern/arch/mips/locore/trap.c
41
+++ b/kern/arch/mips/locore/trap.c
42
@@ -111,6 +111,10 @@ kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr)
43
/*
44
* You will probably want to change this.
45
*/
46
+
47
+ //simulate an exit call.
48
+ sys__exit( -1 );
49
+ return;
50
51
kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n",
52
code, sig, trapcodenames[code], epc, vaddr);
53
diff --git a/kern/arch/mips/syscall/syscall.c b/kern/arch/mips/syscall/syscall.c
54
index 0f773bd..4e99f50 100644
55
--- a/kern/arch/mips/syscall/syscall.c
56
+++ b/kern/arch/mips/syscall/syscall.c
57
@@ -32,10 +32,14 @@
58
#include <kern/syscall.h>
59
#include <lib.h>
60
#include <mips/trapframe.h>
61
+#include <copyinout.h>
62
#include <thread.h>
63
#include <current.h>
64
#include <syscall.h>
65
66
+#define MAKE_64BIT(x,y) (((int64_t)x) << 32 | y)
67
+#define GET_LO(x) ((int32_t) x & 0x00000000FFFFFFFF)
68
+#define GET_HI(x) ((int32_t) x & 0xFFFFFFFF00000000)
69
70
/*
71
* System call dispatcher.
72
@@ -80,7 +84,11 @@ syscall(struct trapframe *tf)
73
{
74
int callno;
75
int32_t retval;
76
+ int64_t retval64;
77
int err;
78
+ int nextra;
79
+ bool handle64;
80
+
81
82
KASSERT(curthread != NULL);
83
KASSERT(curthread->t_curspl == 0);
84
@@ -98,6 +106,10 @@ syscall(struct trapframe *tf)
85
*/
86
87
retval = 0;
88
+ handle64 = false;
89
+
90
+ //award points for the process that just called the systemcall.
91
+ curthread->td_proc->p_nsyscalls++;
92
93
switch (callno) {
94
case SYS_reboot:
95
@@ -109,6 +121,79 @@ syscall(struct trapframe *tf)
96
(userptr_t)tf->tf_a1);
97
break;
98
99
+ case SYS_open:
100
+ err = sys_open( (userptr_t) tf->tf_a0,
101
+ tf->tf_a1, &retval);
102
+ break;
103
+
104
+ case SYS_close:
105
+ err = sys_close( tf->tf_a0 );
106
+ break;
107
+
108
+ case SYS_write:
109
+ err = sys_write( tf->tf_a0,
110
+ (userptr_t) tf->tf_a1,
111
+ tf->tf_a2, &retval );
112
+ break;
113
+
114
+ case SYS_read:
115
+ err = sys_read( tf->tf_a0,
116
+ (userptr_t) tf->tf_a1,
117
+ tf->tf_a2, &retval);
118
+ break;
119
+
120
+ case SYS___getcwd:
121
+ err = sys___getcwd( (userptr_t)tf->tf_a0,
122
+ tf->tf_a1, &retval );
123
+ break;
124
+
125
+ case SYS_lseek:
126
+ //get the value of whence from sp+16
127
+ err = copyin( (userptr_t)(tf->tf_sp + 16),
128
+ &nextra, sizeof( int ) );
129
+ if( err )
130
+ break;
131
+
132
+ err = sys_lseek(
133
+ tf->tf_a0,
134
+ MAKE_64BIT( tf->tf_a2, tf->tf_a3 ),
135
+ nextra,
136
+ &retval64
137
+ );
138
+
139
+ //if no errors occurred, we must handle
140
+ //a 64-bit return value.
141
+ handle64 = true;
142
+ break;
143
+
144
+ case SYS_dup2:
145
+ err = sys_dup2( tf->tf_a0, tf->tf_a1, &retval );
146
+ break;
147
+
148
+ case SYS_chdir:
149
+ err = sys_chdir( (userptr_t)tf->tf_a0 );
150
+ break;
151
+
152
+ case SYS_getpid:
153
+ err = sys_getpid( &retval );
154
+ break;
155
+ case SYS__exit:
156
+ sys__exit( tf->tf_a0 );
157
+ err = 0;
158
+ break;
159
+
160
+ case SYS_waitpid:
161
+ err = sys_waitpid( tf->tf_a0, (userptr_t)tf->tf_a1, tf->tf_a2, &retval );
162
+ break;
163
+
164
+ case SYS_fork:
165
+ err = sys_fork( tf, &retval );
166
+ break;
167
+
168
+ case SYS_execv:
169
+ err = sys_execv( (userptr_t) tf->tf_a0, (userptr_t) tf->tf_a1 );
170
+ break;
171
+
172
/* Add stuff here */
173
174
default:
175
@@ -127,6 +212,11 @@ syscall(struct trapframe *tf)
176
tf->tf_v0 = err;
177
tf->tf_a3 = 1; /* signal an error */
178
}
179
+ else if( handle64 ) {
180
+ tf->tf_a3 = 0;
181
+ tf->tf_v0 = GET_HI( retval64 );
182
+ tf->tf_v1 = GET_LO( retval64 );
183
+ }
184
else {
185
/* Success. */
186
tf->tf_v0 = retval;
187
diff --git a/kern/conf/conf.kern b/kern/conf/conf.kern
188
index d527f61..190b6cf 100644
189
--- a/kern/conf/conf.kern
190
+++ b/kern/conf/conf.kern
191
@@ -368,6 +368,31 @@ file syscall/loadelf.c
192
file syscall/runprogram.c
193
file syscall/time_syscalls.c
194
195
+#IO SYSCALLS
196
+file syscall/open.c
197
+file syscall/write.c
198
+file syscall/close.c
199
+file syscall/read.c
200
+file syscall/__getcwd.c
201
+file syscall/lseek.c
202
+file syscall/dup2.c
203
+file syscall/chdir.c
204
+
205
+#PROC SYSCALLS
206
+file syscall/getpid.c
207
+file syscall/_exit.c
208
+file syscall/waitpid.c
209
+file syscall/fork.c
210
+file syscall/execv.c
211
+
212
+
213
+#IO
214
+file io/file.c
215
+file io/filedesc.c
216
+
217
+#PROC
218
+file proc/proc.c
219
+
220
#
221
# Startup and initialization
222
#
223
diff --git a/kern/include/file.h b/kern/include/file.h
224
new file mode 100644
225
index 0000000..803ec05
226
--- /dev/null
227
+++ b/kern/include/file.h
228
@@ -0,0 +1,35 @@
229
+#ifndef __FILEH__
230
+#define __FILEH__
231
+
232
+#include <vnode.h>
233
+#include <synch.h>
234
+#include <proc.h>
235
+
236
+#define MAX_FILE_NAME 32
237
+
238
+struct proc;
239
+
240
+struct file {
241
+ struct vnode *f_vnode; /* vnode associated with the file */
242
+ uint16_t f_oflags; /* open flags */
243
+ uint16_t f_refcount; /* reference count */
244
+ off_t f_offset; /* file offset */
245
+ struct lock *f_lk; /* lock for IO atomicity */
246
+};
247
+
248
+int file_get(struct proc *, int, struct file ** );
249
+int file_close_descriptor( struct proc *, int );
250
+int file_close( struct proc *, struct file * );
251
+int file_create( struct vnode *, int, struct file ** );
252
+bool file_descriptor_exists( struct proc *, int );
253
+void file_destroy( struct file * );
254
+int file_close_all( struct proc * );
255
+
256
+
257
+//helper function to open() files from inside the kernel.
258
+int ___open( struct proc *, char *, int, int *);
259
+
260
+#define F_LOCK(x) (lock_acquire((x)->f_lk))
261
+#define F_UNLOCK(x) (lock_release((x)->f_lk))
262
+
263
+#endif
264
diff --git a/kern/include/filedesc.h b/kern/include/filedesc.h
265
new file mode 100644
266
index 0000000..9129276
267
--- /dev/null
268
+++ b/kern/include/filedesc.h
269
@@ -0,0 +1,25 @@
270
+#ifndef __FILEDESCH__
271
+#define __FILEDESCH__
272
+
273
+#include <file.h>
274
+
275
+#define MAX_OPEN_FILES 16
276
+#define FD_RESERVED_SPOT 0xcafebabe
277
+
278
+struct filedesc {
279
+ struct file *fd_ofiles[MAX_OPEN_FILES]; /* array of open files */
280
+ struct lock *fd_lk; /* a lock protecting the file descriptor table */
281
+ uint16_t fd_nfiles; /* how many open files we have */
282
+};
283
+
284
+void fd_clone( struct filedesc *, struct filedesc * );
285
+int fd_create( struct filedesc ** );
286
+void fd_destroy( struct filedesc * );
287
+int fd_attach( struct filedesc *, struct file *, int * );
288
+void fd_detach( struct filedesc *, int );
289
+int fd_attach_into( struct filedesc *, struct file *, int );
290
+
291
+#define FD_LOCK(x) (lock_acquire((x)->fd_lk))
292
+#define FD_UNLOCK(x) (lock_release((x)->fd_lk))
293
+
294
+#endif
295
diff --git a/kern/include/proc.h b/kern/include/proc.h
296
new file mode 100644
297
index 0000000..09b9c4a
298
--- /dev/null
299
+++ b/kern/include/proc.h
300
@@ -0,0 +1,43 @@
301
+#ifndef __PROC__
302
+#define __PROC__
303
+
304
+#include <types.h>
305
+#include <filedesc.h>
306
+#include <synch.h>
307
+
308
+#define MAX_PROCESSES 64
309
+#define PROC_RESERVED_SPOT 0xcafebabe
310
+
311
+struct proc {
312
+ pid_t p_pid; /* pid of the process */
313
+ struct filedesc *p_fd; /* file descriptor table */
314
+ struct proc *p_proc; /* parent process */
315
+ bool p_is_dead; /* are we dead? */
316
+ int p_retval; /* our return code */
317
+
318
+ /* synchronization mechanisms */
319
+ struct lock *p_lk; /* lock to protect the structure */
320
+ struct semaphore *p_sem; /* sem used for wait/exit */
321
+
322
+ /* scheduler related */
323
+ uint64_t p_nsyscalls; /* how many system calls we called? */
324
+ int p_nice; /* our nice value */
325
+};
326
+
327
+extern struct proc *allproc[MAX_PROCESSES];
328
+extern struct lock *lk_allproc;
329
+extern struct lock *lk_exec;
330
+
331
+int proc_create( struct proc ** );
332
+int proc_clone(struct proc *, struct proc ** );
333
+void proc_destroy(struct proc *);
334
+int proc_get( pid_t, struct proc ** );
335
+void proc_system_init(void);
336
+
337
+//tests.
338
+void proc_test_pid_allocation(void);
339
+
340
+#define PROC_LOCK(x) (lock_acquire( (x)->p_lk ))
341
+#define PROC_UNLOCK(x) (lock_release( (x)->p_lk ))
342
+
343
+#endif
344
diff --git a/kern/include/synch.h b/kern/include/synch.h
345
index ac3714b..461eedc 100644
346
--- a/kern/include/synch.h
347
+++ b/kern/include/synch.h
348
@@ -74,8 +74,12 @@ void V(struct semaphore *);
349
*/
350
struct lock {
351
char *lk_name;
352
- // add what you need here
353
- // (don't forget to mark things volatile as needed)
354
+
355
+ // BEGIN SOLUTION
356
+ struct wchan *lk_wchan;
357
+ struct spinlock lk_lock;
358
+ volatile struct thread *lk_holder;
359
+ // END SOLUTION
360
};
361
362
struct lock *lock_create(const char *name);
363
@@ -113,8 +117,10 @@ void lock_destroy(struct lock *);
364
365
struct cv {
366
char *cv_name;
367
- // add what you need here
368
- // (don't forget to mark things volatile as needed)
369
+
370
+ // BEGIN SOLUTION
371
+ struct wchan *cv_wchan;
372
+ // END SOLUTION
373
};
374
375
struct cv *cv_create(const char *name);
376
diff --git a/kern/include/syscall.h b/kern/include/syscall.h
377
index befd3d8..851842a 100644
378
--- a/kern/include/syscall.h
379
+++ b/kern/include/syscall.h
380
@@ -58,4 +58,32 @@ void enter_new_process(int argc, userptr_t argv, vaddr_t stackptr,
381
int sys_reboot(int code);
382
int sys___time(userptr_t user_seconds, userptr_t user_nanoseconds);
383
384
+/*
385
+ * I/O syscalls
386
+ */
387
+
388
+int sys_open( userptr_t, int, int *);
389
+int sys_close( int );
390
+int sys_write( int, userptr_t, size_t, int * );
391
+int sys_read( int, userptr_t, size_t, int * );
392
+int sys___getcwd( userptr_t, size_t, int * );
393
+int sys_lseek( int, off_t, int, int64_t * );
394
+int sys_dup2( int, int, int * );
395
+int sys_chdir( userptr_t );
396
+
397
+/**
398
+ * Process System Calls
399
+ */
400
+
401
+int sys_getpid( int * );
402
+void sys__exit( int );
403
+int sys_waitpid( int, userptr_t, int, int * );
404
+int sys_fork( struct trapframe *, int * );
405
+int sys_execv( userptr_t, userptr_t );
406
+
407
+/**
408
+ * Kernel versions of the system calls.
409
+ */
410
+int ___waitpid( int, int *, int );
411
+
412
#endif /* _SYSCALL_H_ */
413
diff --git a/kern/include/thread.h b/kern/include/thread.h
414
index 86706ca..373453d 100644
415
--- a/kern/include/thread.h
416
+++ b/kern/include/thread.h
417
@@ -38,6 +38,7 @@
418
419
#include <spinlock.h>
420
#include <threadlist.h>
421
+#include <proc.h>
422
423
struct addrspace;
424
struct cpu;
425
@@ -111,7 +112,8 @@ struct thread {
426
/* VFS */
427
struct vnode *t_cwd; /* current working directory */
428
429
- /* add more here as needed */
430
+ /* modifications for ASST2 */
431
+ struct proc *td_proc; /* process associated with this thread */
432
};
433
434
/* Call once during system startup to allocate data structures. */
435
diff --git a/kern/include/version.h b/kern/include/version.h
436
index 9fec0e8..4734a98 100644
437
--- a/kern/include/version.h
438
+++ b/kern/include/version.h
439
@@ -35,6 +35,7 @@
440
* code we gave you.
441
*/
442
#define BASE_VERSION "1.99.05"
443
+#define ASST1SOL_VERSION "1.0"
444
445
/*
446
* Change this as you see fit in the course of hacking the system.
447
diff --git a/kern/io/file.c b/kern/io/file.c
448
new file mode 100644
449
index 0000000..299773c
450
--- /dev/null
451
+++ b/kern/io/file.c
452
@@ -0,0 +1,144 @@
453
+#include <types.h>
454
+#include <lib.h>
455
+#include <kern/errno.h>
456
+#include <file.h>
457
+#include <vfs.h>
458
+
459
+/*
460
+ * create a new file associated with the given vnode/flags
461
+ */
462
+int
463
+file_create( struct vnode *vn, int flags, struct file **f ) {
464
+ struct file *res;
465
+
466
+ res = kmalloc( sizeof( struct file ) );
467
+ if( res == NULL )
468
+ return ENOMEM;
469
+
470
+ //fill the basic fields
471
+ res->f_oflags = flags;
472
+ res->f_refcount = 0;
473
+ res->f_vnode = vn;
474
+ res->f_offset = 0;
475
+
476
+ //attempt to create the lock
477
+ res->f_lk = lock_create( "f_lk" );
478
+ if( res->f_lk == NULL ) {
479
+ kfree( res );
480
+ return ENOMEM;
481
+ }
482
+
483
+ *f = res;
484
+ return 0;
485
+}
486
+
487
+/*
488
+ * destroy the given file.
489
+ * otherwise, lock_destroy will fail.
490
+ */
491
+void
492
+file_destroy( struct file *f ) {
493
+ //make sure we are not destroying something that is being used
494
+ KASSERT( f->f_refcount == 0 );
495
+
496
+ //close the associated vnode
497
+ vfs_close( f->f_vnode );
498
+
499
+ //release and destroy the lock
500
+ lock_destroy( f->f_lk );
501
+
502
+ //free the memory
503
+ kfree( f );
504
+}
505
+
506
+/**
507
+ * close the file given by the descriptor
508
+ */
509
+int
510
+file_close_descriptor( struct proc *p, int fd ) {
511
+ struct file *f = NULL;
512
+ int err = 0;
513
+
514
+ err = file_get( p, fd, &f );
515
+ if( err )
516
+ return err;
517
+
518
+ //make sure there are programs using it
519
+ KASSERT( f->f_refcount > 0 );
520
+
521
+ //detach from the file descriptor table
522
+ fd_detach( p->p_fd, fd );
523
+
524
+ //decrease both refcounts
525
+ f->f_refcount--;
526
+ VOP_DECREF( f->f_vnode );
527
+
528
+ //destroy if we are the only ones using it
529
+ if( f->f_refcount == 0 ) {
530
+ F_UNLOCK( f );
531
+ file_destroy( f );
532
+ return 0;
533
+ }
534
+
535
+ //unlock the file
536
+ F_UNLOCK( f );
537
+ return 0;
538
+}
539
+
540
+
541
+/**
542
+ * find and return the file associated with the filedescriptor
543
+ * inside the process. it will be returned locked.
544
+ */
545
+int
546
+file_get(struct proc *p, int fd, struct file **f ) {
547
+ if( fd >= MAX_OPEN_FILES || fd < 0 )
548
+ return EBADF;
549
+
550
+ FD_LOCK( p->p_fd );
551
+ if( p->p_fd->fd_ofiles[fd] != NULL ) {
552
+ *f = p->p_fd->fd_ofiles[fd];
553
+ FD_UNLOCK( p->p_fd );
554
+ return 0;
555
+ }
556
+
557
+ FD_UNLOCK( p->p_fd );
558
+ return EBADF;
559
+}
560
+
561
+/**
562
+ * Checks whether the given file descriptor exists in the table.
563
+ */
564
+bool
565
+file_descriptor_exists( struct proc *p, int fd ) {
566
+ bool exists = false;
567
+
568
+ FD_LOCK( p->p_fd );
569
+ if( p->p_fd->fd_ofiles[fd] != NULL )
570
+ exists = true;
571
+ FD_UNLOCK( p->p_fd );
572
+
573
+ return exists;
574
+}
575
+
576
+/**
577
+ * close all open files associated with the given process.
578
+ */
579
+int
580
+file_close_all( struct proc *p ) {
581
+ int i = 0;
582
+ int err;
583
+
584
+ FD_LOCK( p->p_fd );
585
+ for( i = 0; i < MAX_OPEN_FILES; ++i ) {
586
+ if( p->p_fd->fd_ofiles[i] != NULL ) {
587
+ FD_UNLOCK( p->p_fd );
588
+ err = file_close_descriptor( p, i );
589
+ if( err )
590
+ return -1;
591
+ FD_LOCK( p->p_fd );
592
+ }
593
+ }
594
+ FD_UNLOCK( p->p_fd );
595
+ return 0;
596
+}
597
diff --git a/kern/io/filedesc.c b/kern/io/filedesc.c
598
new file mode 100644
599
index 0000000..2e59a07
600
--- /dev/null
601
+++ b/kern/io/filedesc.c
602
@@ -0,0 +1,133 @@
603
+#include <types.h>
604
+#include <lib.h>
605
+#include <kern/errno.h>
606
+#include <filedesc.h>
607
+
608
+//scan over the given file descriptor table
609
+//and store the file in a free location, if possible
610
+int
611
+fd_attach( struct filedesc *fdesc, struct file *f, int *fd ) {
612
+ int i = 0;
613
+
614
+ //lock the file descriptor table
615
+ FD_LOCK( fdesc );
616
+
617
+ //for each possible spot
618
+ for( i = 0; i < MAX_OPEN_FILES; ++i ) {
619
+ if( fdesc->fd_ofiles[i] == NULL ) {
620
+ fdesc->fd_ofiles[i] = f;
621
+ fdesc->fd_nfiles++;
622
+ *fd = i;
623
+ FD_UNLOCK( fdesc );
624
+ return 0;
625
+ }
626
+ }
627
+ FD_UNLOCK( fdesc );
628
+ return ENFILE;
629
+}
630
+
631
+//detaches the given filedescriptor from the given filetable
632
+void
633
+fd_detach( struct filedesc *fdesc, int fd ) {
634
+ FD_LOCK( fdesc );
635
+ fdesc->fd_ofiles[fd] = NULL;
636
+ fdesc->fd_nfiles--;
637
+ FD_UNLOCK( fdesc );
638
+}
639
+
640
+//destroy the given filedescriptor table
641
+void
642
+fd_destroy( struct filedesc *fdesc ) {
643
+ KASSERT( fdesc->fd_nfiles == 0 );
644
+ lock_destroy( fdesc->fd_lk );
645
+ kfree( fdesc );
646
+}
647
+
648
+//create a new filedescriptor tabke
649
+int
650
+fd_create( struct filedesc **fdesc ) {
651
+ struct filedesc *fd = NULL;
652
+ int i = 0;
653
+
654
+ fd = kmalloc( sizeof( struct filedesc ) );
655
+ if( fd == NULL )
656
+ return ENOMEM;
657
+
658
+ //create the lock
659
+ fd->fd_lk = lock_create( "fd_lk" );
660
+ if( fd->fd_lk == NULL ) {
661
+ kfree( fd );
662
+ return ENOMEM;
663
+ }
664
+
665
+ //initialize all open files
666
+ for( i = 0; i < MAX_OPEN_FILES; ++i )
667
+ fd->fd_ofiles[i] = NULL;
668
+
669
+ //initially we have no open files.
670
+ fd->fd_nfiles = 0;
671
+
672
+ //we are good to go
673
+ *fdesc = fd;
674
+ return 0;
675
+}
676
+
677
+/**
678
+ * attaches a given filehandle inside a specific location
679
+ * on the filetable.
680
+ */
681
+int
682
+fd_attach_into( struct filedesc *fdesc, struct file *f, int fd ) {
683
+ FD_LOCK( fdesc );
684
+
685
+ //if the file-table already contains something
686
+ //inside the desired spot, we cannot continue.
687
+ if( fdesc->fd_ofiles[fd] != NULL ) {
688
+ FD_UNLOCK( fdesc );
689
+ return EMFILE;
690
+ }
691
+
692
+ fdesc->fd_ofiles[fd] = f;
693
+ fdesc->fd_nfiles++;
694
+
695
+ FD_UNLOCK( fdesc );
696
+ return 0;
697
+}
698
+
699
+/**
700
+ * clone a filedescriptor table into another.
701
+ */
702
+void
703
+fd_clone( struct filedesc *source, struct filedesc *fdesc ) {
704
+ struct file *f = NULL;
705
+ int i = 0;
706
+
707
+ //lock the source file-descriptor table.
708
+ //and for each file, we copy its pointer into the new table.
709
+ FD_LOCK( source );
710
+ for( i = 0; i < MAX_OPEN_FILES; ++i ) {
711
+ if( source->fd_ofiles[i] != NULL ) {
712
+ //lock the file for atomicity.
713
+ //this ensures nobody is writing things out while we are transfering.
714
+ f = source->fd_ofiles[i];
715
+ F_LOCK( f );
716
+ fdesc->fd_ofiles[i] = f;
717
+ fdesc->fd_nfiles++;
718
+
719
+ //at this point we also update the file's
720
+ //reference count.
721
+ f->f_refcount++;
722
+ VOP_INCREF( f->f_vnode );
723
+
724
+ //we are done with it.
725
+ F_UNLOCK( f );
726
+ }
727
+ }
728
+
729
+ //for sakeness, both file-descriptor tables
730
+ //must have the same number of open files.
731
+ KASSERT( source->fd_nfiles == fdesc->fd_nfiles );
732
+
733
+ //unlock.
734
+ FD_UNLOCK( source );
735
+}
736
diff --git a/kern/proc/proc.c b/kern/proc/proc.c
737
new file mode 100644
738
index 0000000..66b354e
739
--- /dev/null
740
+++ b/kern/proc/proc.c
741
@@ -0,0 +1,285 @@
742
+#include <types.h>
743
+#include <lib.h>
744
+#include <kern/errno.h>
745
+#include <proc.h>
746
+
747
+struct proc *allproc[MAX_PROCESSES];
748
+struct lock *lk_allproc;
749
+struct lock *lk_exec;
750
+int next_pid;
751
+
752
+/**
753
+ * add the given function to the allproc array.
754
+ */
755
+static
756
+void
757
+proc_add_to_allproc( struct proc *p, int spot ) {
758
+ lock_acquire( lk_allproc );
759
+
760
+ KASSERT( allproc[spot] == (void *)PROC_RESERVED_SPOT );
761
+ allproc[spot] = p;
762
+ lock_release( lk_allproc );
763
+}
764
+
765
+/**
766
+ * quick function that simply a spot as reserved,
767
+ * stores the index of the spot inside the pid
768
+ * and unlocks allproc.
769
+ */
770
+static
771
+void
772
+proc_found_spot( pid_t *pid, int spot ) {
773
+ //if we are being called, allproc[spot] must be null.
774
+ KASSERT( allproc[spot] == NULL );
775
+
776
+ //mark it as reserved.
777
+ allproc[spot] = (void *)PROC_RESERVED_SPOT;
778
+ *pid = spot;
779
+
780
+ //adjust next_pid to be the one just given.
781
+ next_pid = spot + 1;
782
+
783
+ //release the lock
784
+ lock_release( lk_allproc );
785
+}
786
+
787
+/**
788
+ * attempts to allocate a new pid by looping
789
+ * through allproc, starting from next_pid, until finding an empty spot.
790
+ * once a spot is given, it is marked as reserved.
791
+ */
792
+static
793
+int
794
+proc_alloc_pid( pid_t *pid ) {
795
+ int i = 0;
796
+
797
+ //lock allproc, to guarantee atomicity
798
+ lock_acquire( lk_allproc );
799
+
800
+ //if the next_pid is greater than the maximum number of processes
801
+ //we need to start failing pid allocations.
802
+ if( next_pid >= MAX_PROCESSES )
803
+ next_pid = 0;
804
+
805
+
806
+ //first we loop until the end, starting from lastpid.
807
+ for( i = next_pid; i < MAX_PROCESSES; ++i ) {
808
+ if( allproc[i] == NULL ) {
809
+ proc_found_spot( pid, i );
810
+ return 0;
811
+ }
812
+ }
813
+
814
+ //now we loop from the beginning until next_pid
815
+ for( i = 0; i < next_pid; ++i ) {
816
+ if( allproc[i] == NULL ) {
817
+ proc_found_spot( pid, i );
818
+ return 0;
819
+ }
820
+ }
821
+
822
+ //we couldn't find a spot, so we have to fail.
823
+ lock_release( lk_allproc );
824
+ return ENPROC;
825
+}
826
+
827
+/**
828
+ * de-allocates the given pid.
829
+ */
830
+static
831
+void
832
+proc_dealloc_pid( pid_t pid ) {
833
+ //lock for atomicity.
834
+ lock_acquire( lk_allproc );
835
+
836
+ //it cannot be null, it must be either reserved or fulfilled.
837
+ KASSERT( allproc[pid] != NULL );
838
+ allproc[pid] = NULL;
839
+
840
+ //unlock and be done.
841
+ lock_release( lk_allproc );
842
+}
843
+
844
+int
845
+proc_create( struct proc **res ) {
846
+ struct proc *p = NULL;
847
+ int err = 0;
848
+ pid_t pid;
849
+
850
+ //first, attempt to allocate a pid.
851
+ err = proc_alloc_pid( &pid );
852
+ if( err )
853
+ return err;
854
+
855
+ //alloc memory for the structure
856
+ p = kmalloc( sizeof( struct proc ) );
857
+ if( p == NULL ) {
858
+ proc_dealloc_pid( pid );
859
+ return ENOMEM;
860
+ }
861
+
862
+ //associcate it with the pid.
863
+ p->p_pid = pid;
864
+
865
+ //create the filedescriptor table
866
+ err = fd_create( &p->p_fd );
867
+ if( err ) {
868
+ kfree( p );
869
+ proc_dealloc_pid( pid );
870
+ return err;
871
+ }
872
+
873
+ //create the lock
874
+ p->p_lk = lock_create( "p_lk" );
875
+ if( p->p_lk == NULL ) {
876
+ fd_destroy( p->p_fd );
877
+ kfree( p );
878
+ proc_dealloc_pid( pid );
879
+ return ENOMEM;
880
+ }
881
+
882
+ //create the semaphore
883
+ p->p_sem = sem_create( "p_sem", 0 );
884
+ if( p->p_sem == NULL ) {
885
+ lock_destroy( p->p_lk );
886
+ fd_destroy( p->p_fd );
887
+ kfree( p );
888
+ proc_dealloc_pid( pid );
889
+ return ENOMEM;
890
+ }
891
+
892
+ //adjust static information
893
+ p->p_retval = 0;
894
+ p->p_is_dead = false;
895
+ p->p_nsyscalls = 0;
896
+ p->p_nice = 0;
897
+ p->p_proc = NULL;
898
+
899
+ //add to the list of allproc
900
+ proc_add_to_allproc( p, pid );
901
+
902
+ *res = p;
903
+ return 0;
904
+}
905
+
906
+/**
907
+ * clone a process into a new process.
908
+ */
909
+int
910
+proc_clone( struct proc *source, struct proc **target ) {
911
+ struct proc *p = NULL;
912
+ int err;
913
+
914
+ //try to create the process.
915
+ err = proc_create( &p );
916
+ if( err )
917
+ return err;
918
+
919
+ //clone all the files from the source file-descriptor table
920
+ //into the childs file-descriptor table.
921
+ fd_clone( source->p_fd, p->p_fd );
922
+
923
+ //we are done, simply copy the new proc
924
+ //into the given pointer.
925
+ *target = p;
926
+
927
+ return 0;
928
+}
929
+/**
930
+ * destroy a given process.
931
+ */
932
+void
933
+proc_destroy( struct proc *p ) {
934
+ pid_t pid;
935
+
936
+ //copy the pid for later used.
937
+ pid = p->p_pid;
938
+
939
+ //destroy the cv
940
+ sem_destroy( p->p_sem );
941
+
942
+ //destroy the lock associated with it.
943
+ lock_destroy( p->p_lk );
944
+
945
+ //destroy the filedescriptor table
946
+ fd_destroy( p->p_fd );
947
+
948
+ //free the memory.
949
+ kfree( p );
950
+
951
+ //deallocate the pid.
952
+ proc_dealloc_pid( pid );
953
+}
954
+
955
+/**
956
+ * initialize the proc-system
957
+ */
958
+void
959
+proc_system_init( void ) {
960
+ int i = 0;
961
+
962
+ //initialize the array
963
+ for( i = 0; i < MAX_PROCESSES; ++i ) {
964
+ allproc[i] = NULL;
965
+ }
966
+
967
+ //create the lock
968
+ lk_allproc = lock_create( "lk_allproc" );
969
+ if( lk_allproc == NULL )
970
+ panic( "could not initialize proc system." );
971
+
972
+ //create the lock protecting exec args
973
+ lk_exec = lock_create( "lk_exec" );
974
+ if( lk_exec == NULL ) {
975
+ lock_destroy( lk_allproc );
976
+ panic( "could not create lk_exec." );
977
+ }
978
+ //set last pid to be 0.
979
+ next_pid = 0;
980
+}
981
+
982
+/**
983
+ * find a process inside allproc.
984
+ * if it exists, return it locked.
985
+ */
986
+int
987
+proc_get( pid_t pid, struct proc **res ) {
988
+ //invalid pid.
989
+ if( pid >= MAX_PROCESSES || pid <= 0 )
990
+ return EINVAL;
991
+
992
+ //lock allproc.
993
+ lock_acquire( lk_allproc );
994
+
995
+ //if the requested pid is associated with a valid process
996
+ if( allproc[pid] != NULL && allproc[pid] != (void *)PROC_RESERVED_SPOT ) {
997
+ PROC_LOCK( allproc[pid] );
998
+ *res = allproc[pid];
999
+ lock_release( lk_allproc );
1000
+ return 0;
1001
+ }
1002
+
1003
+ //the requested pid is actually invalid.
1004
+ lock_release( lk_allproc );
1005
+ return ESRCH;
1006
+
1007
+}
1008
+/**
1009
+ * stress tests.
1010
+ */
1011
+void
1012
+proc_test_pid_allocation() {
1013
+ pid_t pid;
1014
+ int err;
1015
+ int i;
1016
+
1017
+ for( i = 0; i < 100; ++i ) {
1018
+ err = proc_alloc_pid( &pid );
1019
+ if( err )
1020
+ panic( "failed to allocate a pid. pid allocation is broken.\n" );
1021
+
1022
+ kprintf( "awarded PID = %d\n", pid );
1023
+ proc_dealloc_pid( pid );
1024
+ }
1025
+}
1026
+
1027
diff --git a/kern/startup/main.c b/kern/startup/main.c
1028
index be4c4b8..535a864 100644
1029
--- a/kern/startup/main.c
1030
+++ b/kern/startup/main.c
1031
@@ -96,7 +96,7 @@ boot(void)
1032
*/
1033
1034
kprintf("\n");
1035
- kprintf("OS/161 base system version %s\n", BASE_VERSION);
1036
+ kprintf("OS/161 base version %s ASST1 solution version %s\n", BASE_VERSION, ASST1SOL_VERSION);
1037
kprintf("%s", harvard_copyright);
1038
kprintf("\n");
1039
1040
diff --git a/kern/startup/menu.c b/kern/startup/menu.c
1041
index 6c71551..ec02bc3 100644
1042
--- a/kern/startup/menu.c
1043
+++ b/kern/startup/menu.c
1044
@@ -39,11 +39,23 @@
1045
#include <vfs.h>
1046
#include <sfs.h>
1047
#include <syscall.h>
1048
+#include <kern/fcntl.h>
1049
#include <test.h>
1050
+#include <proc.h>
1051
+#include <file.h>
1052
+#include <current.h>
1053
+
1054
#include "opt-synchprobs.h"
1055
#include "opt-sfs.h"
1056
#include "opt-net.h"
1057
1058
+struct proc *p0;
1059
+
1060
+struct cmd_progthread_args {
1061
+ char **args;
1062
+ struct proc *p;
1063
+};
1064
+
1065
/*
1066
* In-kernel menu and command dispatcher.
1067
*/
1068
@@ -66,6 +78,40 @@ getinterval(time_t s1, uint32_t ns1, time_t s2, uint32_t ns2,
1069
*rs = s2 - s1;
1070
}
1071
1072
+//open the standard files.
1073
+static
1074
+int
1075
+open_standard_files( struct proc *p ) {
1076
+ int err = 0;
1077
+ int retval;
1078
+ char buf[32];
1079
+
1080
+ KASSERT( p != NULL );
1081
+
1082
+ strcpy( buf, "con:" );
1083
+ err = ___open( p, buf, O_RDONLY, &retval );
1084
+ if( err )
1085
+ return err;
1086
+
1087
+ strcpy( buf, "con:" );
1088
+ err = ___open( p, buf, O_WRONLY, &retval );
1089
+ if( err ) {
1090
+ file_close_all( p );
1091
+ return err;
1092
+ }
1093
+
1094
+ strcpy( buf, "con:" );
1095
+ err = ___open( p, buf, O_WRONLY, &retval );
1096
+ if( err ) {
1097
+ file_close_all( p );
1098
+ return err;
1099
+ }
1100
+
1101
+ return 0;
1102
+}
1103
+
1104
+
1105
+
1106
////////////////////////////////////////////////////////////
1107
//
1108
// Command menu functions
1109
@@ -85,10 +131,11 @@ static
1110
void
1111
cmd_progthread(void *ptr, unsigned long nargs)
1112
{
1113
- char **args = ptr;
1114
+ struct cmd_progthread_args *cargs = ptr;
1115
+ char **args = cargs->args;
1116
char progname[128];
1117
int result;
1118
-
1119
+
1120
KASSERT(nargs >= 1);
1121
1122
if (nargs > 2) {
1123
@@ -99,11 +146,20 @@ cmd_progthread(void *ptr, unsigned long nargs)
1124
KASSERT(strlen(args[0]) < sizeof(progname));
1125
1126
strcpy(progname, args[0]);
1127
+
1128
+ //attach the process to the current thread
1129
+ curthread->td_proc = cargs->p;
1130
+
1131
+ //destroy the cargs struct
1132
+ kfree( cargs );
1133
1134
result = runprogram(progname);
1135
if (result) {
1136
kprintf("Running program %s failed: %s\n", args[0],
1137
strerror(result));
1138
+
1139
+ //exit with a failure.
1140
+ sys__exit( -1 );
1141
return;
1142
}
1143
1144
@@ -127,21 +183,62 @@ int
1145
common_prog(int nargs, char **args)
1146
{
1147
int result;
1148
+ struct proc *p = NULL;
1149
+ struct cmd_progthread_args *cargs = NULL;
1150
+ pid_t pid;
1151
+ int err;
1152
1153
#if OPT_SYNCHPROBS
1154
kprintf("Warning: this probably won't work with a "
1155
"synchronization-problems kernel.\n");
1156
#endif
1157
+
1158
+ //attempt to create the first process.
1159
+ result = proc_create( &p );
1160
+ if( result ) {
1161
+ kprintf( "common_prog: failed creating the first process." );
1162
+ return result;
1163
+ }
1164
+
1165
+ //store the pid.
1166
+ pid = p->p_pid;
1167
+
1168
+ //open the standard files.
1169
+ err = open_standard_files( p );
1170
+ if( err ) {
1171
+ proc_destroy( p );
1172
+ return err;
1173
+ }
1174
+
1175
+ //create the arguments
1176
+ cargs = kmalloc( sizeof( struct cmd_progthread_args ) );
1177
+ if( cargs == NULL ) {
1178
+ file_close_all( p );
1179
+ proc_destroy( p );
1180
+ return ENOMEM;
1181
+ }
1182
+
1183
+ //adjust the parent to reflect p0.
1184
+ p->p_proc = p0;
1185
+
1186
+ cargs->args = args;
1187
+ cargs->p = p;
1188
1189
result = thread_fork(args[0] /* thread name */,
1190
cmd_progthread /* thread function */,
1191
- args /* thread arg */, nargs /* thread arg */,
1192
+ cargs /* thread arg */, nargs /* thread arg */,
1193
NULL);
1194
if (result) {
1195
kprintf("thread_fork failed: %s\n", strerror(result));
1196
+
1197
+ file_close_all( p );
1198
+ proc_destroy( p );
1199
return result;
1200
}
1201
1202
+ //wait for our chid to die.
1203
+ ___waitpid( pid, &result, 0 );
1204
+
1205
return 0;
1206
}
1207
1208
@@ -652,6 +749,32 @@ menu_execute(char *line, int isargs)
1209
}
1210
}
1211
1212
+static
1213
+int
1214
+proc0( struct proc **p0 ) {
1215
+ struct proc *p = NULL;
1216
+ int err;
1217
+
1218
+ //create the new process.
1219
+ err = proc_create( &p );
1220
+ if( err )
1221
+ return err;
1222
+
1223
+ //open the standard files.
1224
+ err = open_standard_files( p );
1225
+ if( err ) {
1226
+ proc_destroy( p );
1227
+ return err;
1228
+ }
1229
+
1230
+ //associate it with the current thread.
1231
+ curthread->td_proc = p;
1232
+
1233
+ //we are good to go.
1234
+ *p0 = p;
1235
+ return 0;
1236
+}
1237
+
1238
/*
1239
* Command menu main loop.
1240
*
1241
@@ -673,8 +796,20 @@ void
1242
menu(char *args)
1243
{
1244
char buf[64];
1245
+ int err;
1246
1247
menu_execute(args, 1);
1248
+
1249
+ //initialize the proc system
1250
+ proc_system_init();
1251
+
1252
+ //kickstart proc0.
1253
+ err = proc0( &p0 );
1254
+ if( err )
1255
+ panic( "failed creating proc0." );
1256
+
1257
+ //test the proc allocation mechanism.
1258
+ //proc_test_pid_allocation();
1259
1260
while (1) {
1261
kprintf("OS/161 kernel [? for menu]: ");
1262
diff --git a/kern/syscall/__getcwd.c b/kern/syscall/__getcwd.c
1263
new file mode 100644
1264
index 0000000..90bf9eb
1265
--- /dev/null
1266
+++ b/kern/syscall/__getcwd.c
1267
@@ -0,0 +1,45 @@
1268
+#include <types.h>
1269
+#include <lib.h>
1270
+#include <vfs.h>
1271
+#include <kern/iovec.h>
1272
+#include <uio.h>
1273
+#include <kern/fcntl.h>
1274
+#include <kern/errno.h>
1275
+#include <vnode.h>
1276
+#include <current.h>
1277
+#include <syscall.h>
1278
+
1279
+int
1280
+sys___getcwd( userptr_t ubuf, size_t ulen, int *retval ) {
1281
+ struct uio ruio;
1282
+ struct iovec iov;
1283
+ int err;
1284
+
1285
+ KASSERT( curthread != NULL );
1286
+ KASSERT( curthread->td_proc != NULL );
1287
+
1288
+ //prepare the uio
1289
+ uio_kinit(
1290
+ &iov,
1291
+ &ruio,
1292
+ ubuf,
1293
+ ulen,
1294
+ 0,
1295
+ UIO_READ
1296
+ );
1297
+
1298
+ //the given pointer lives in userland
1299
+ ruio.uio_space = curthread->t_addrspace;
1300
+ ruio.uio_segflg = UIO_USERSPACE;
1301
+
1302
+ //forward the call to vfs_getcwd
1303
+ err = vfs_getcwd( &ruio );
1304
+ if( err )
1305
+ return err;
1306
+
1307
+ //set the return value to be the length of the
1308
+ //data that was just read
1309
+ *retval = ulen - ruio.uio_resid;
1310
+ return 0;
1311
+}
1312
+
1313
diff --git a/kern/syscall/_exit.c b/kern/syscall/_exit.c
1314
new file mode 100644
1315
index 0000000..ca1a787
1316
--- /dev/null
1317
+++ b/kern/syscall/_exit.c
1318
@@ -0,0 +1,53 @@
1319
+#include <types.h>
1320
+#include <lib.h>
1321
+#include <proc.h>
1322
+#include <file.h>
1323
+#include <filedesc.h>
1324
+#include <thread.h>
1325
+#include <current.h>
1326
+#include <syscall.h>
1327
+
1328
+/**
1329
+ * exit will perform the following tasks:
1330
+ * 1. close all open files (through file_close_all())
1331
+ * 2. set the given exit code inside the proc structure.
1332
+ * 3. mark each child process as orphan.
1333
+ * 4. if orphan, will destroy the proc associated with the current thread.
1334
+ * 4.1 if not orphan, will signal the parent regarding our death.
1335
+ * 5. call thread_exit() so we become a zombie.
1336
+ */
1337
+void
1338
+sys__exit( int code ) {
1339
+ struct proc *p = NULL;
1340
+ int err;
1341
+
1342
+ KASSERT( curthread != NULL );
1343
+ KASSERT( curthread->td_proc != NULL );
1344
+
1345
+ p = curthread->td_proc;
1346
+
1347
+ //close all open files.
1348
+ err = file_close_all( p );
1349
+ if( err )
1350
+ panic( "problem closing a file." );
1351
+
1352
+ //lock so we can adjust the return value.
1353
+ PROC_LOCK( p );
1354
+ p->p_retval = code;
1355
+ p->p_is_dead = true;
1356
+
1357
+ //if we are orphans ourselves, no one is interested
1358
+ //in our return code, so we simply destroy ourselves.
1359
+ if( p->p_proc == NULL ) {
1360
+ PROC_UNLOCK( p );
1361
+ proc_destroy( p );
1362
+ }
1363
+ else {
1364
+ //signal that we are done.
1365
+ V( p->p_sem );
1366
+ PROC_UNLOCK( p );
1367
+ }
1368
+
1369
+ //all that is left now is to kill our thread.
1370
+ thread_exit();
1371
+}
1372
diff --git a/kern/syscall/chdir.c b/kern/syscall/chdir.c
1373
new file mode 100644
1374
index 0000000..db7d113
1375
--- /dev/null
1376
+++ b/kern/syscall/chdir.c
1377
@@ -0,0 +1,43 @@
1378
+#include <types.h>
1379
+#include <lib.h>
1380
+#include <copyinout.h>
1381
+#include <kern/iovec.h>
1382
+#include <kern/fcntl.h>
1383
+#include <uio.h>
1384
+#include <vfs.h>
1385
+#include <thread.h>
1386
+#include <current.h>
1387
+#include <syscall.h>
1388
+
1389
+#define MAX_DIR_LEN 128
1390
+
1391
+int
1392
+sys_chdir( userptr_t ubuf ) {
1393
+ char kbuf[MAX_DIR_LEN];
1394
+ int err;
1395
+ struct vnode *v_dir = NULL;
1396
+
1397
+ KASSERT( curthread != NULL );
1398
+ KASSERT( curthread->td_proc != NULL );
1399
+
1400
+ //copy the buffer from userland into kernel land.
1401
+ err = copyinstr( ubuf, kbuf, sizeof( kbuf ), NULL );
1402
+ if( err )
1403
+ return err;
1404
+
1405
+ //try to open the directory pointed by the path.
1406
+ err = vfs_open( kbuf, O_RDONLY, 0644, &v_dir );
1407
+ if( err )
1408
+ return err;
1409
+
1410
+ //change the current directory.
1411
+ err = vfs_setcurdir( v_dir );
1412
+
1413
+ //close the vnode.
1414
+ vfs_close( v_dir );
1415
+
1416
+ if( err )
1417
+ return err;
1418
+
1419
+ return 0;
1420
+}
1421
diff --git a/kern/syscall/close.c b/kern/syscall/close.c
1422
new file mode 100644
1423
index 0000000..aba47a3
1424
--- /dev/null
1425
+++ b/kern/syscall/close.c
1426
@@ -0,0 +1,21 @@
1427
+#include <types.h>
1428
+#include <lib.h>
1429
+#include <kern/errno.h>
1430
+#include <syscall.h>
1431
+#include <file.h>
1432
+#include <copyinout.h>
1433
+#include <current.h>
1434
+
1435
+/**
1436
+ * close() system call
1437
+ */
1438
+int
1439
+sys_close( int fd ) {
1440
+ struct proc *p = NULL;
1441
+
1442
+ KASSERT( curthread != NULL );
1443
+ KASSERT( curthread->td_proc != NULL );
1444
+
1445
+ p = curthread->td_proc;
1446
+ return file_close_descriptor( p, fd );
1447
+}
1448
diff --git a/kern/syscall/dup2.c b/kern/syscall/dup2.c
1449
new file mode 100644
1450
index 0000000..311b47d
1451
--- /dev/null
1452
+++ b/kern/syscall/dup2.c
1453
@@ -0,0 +1,61 @@
1454
+#include <types.h>
1455
+#include <lib.h>
1456
+#include <kern/errno.h>
1457
+#include <filedesc.h>
1458
+#include <file.h>
1459
+#include <current.h>
1460
+#include <syscall.h>
1461
+
1462
+int
1463
+sys_dup2( int oldfd, int newfd, int *retval ) {
1464
+ struct proc *p = NULL;
1465
+ struct file *f_old = NULL;
1466
+ struct file *f_new = NULL;
1467
+ int err;
1468
+
1469
+ KASSERT( curthread != NULL );
1470
+ KASSERT( curthread->td_proc != NULL );
1471
+
1472
+ p = curthread->td_proc;
1473
+
1474
+ //make sure both file handles are valid
1475
+ if( (oldfd < 0 || newfd < 0) || (newfd >= MAX_OPEN_FILES) )
1476
+ return EBADF;
1477
+
1478
+ //get the old file
1479
+ err = file_get( p, oldfd, &f_old );
1480
+ if( err )
1481
+ return EBADF;
1482
+
1483
+ //if the new-file already exists
1484
+ //we must close it.
1485
+ if( file_descriptor_exists( p, newfd ) ) {
1486
+ err = file_close_descriptor( p, newfd );
1487
+ //if we had a problem closing, dup2()
1488
+ //cannot continue running.
1489
+ if( err ) {
1490
+ F_UNLOCK( f_old );
1491
+ return err;
1492
+ }
1493
+ }
1494
+
1495
+ //at this point, we simply copy the pointers.
1496
+ f_new = f_old;
1497
+
1498
+ //attach f_new into newfd
1499
+ err = fd_attach_into( p->p_fd, f_new, newfd );
1500
+ if( err ) {
1501
+ F_UNLOCK( f_old );
1502
+ return err;
1503
+ }
1504
+
1505
+ //increase the reference count.
1506
+ f_old->f_refcount++;
1507
+ VOP_INCREF(f_old->f_vnode);
1508
+
1509
+ //unlock and return
1510
+ F_UNLOCK( f_old );
1511
+ *retval = newfd;
1512
+
1513
+ return 0;
1514
+}
1515
diff --git a/kern/syscall/execv.c b/kern/syscall/execv.c
1516
new file mode 100644
1517
index 0000000..0d3e7d7
1518
--- /dev/null
1519
+++ b/kern/syscall/execv.c
1520
@@ -0,0 +1,295 @@
1521
+#include <types.h>
1522
+#include <lib.h>
1523
+#include <copyinout.h>
1524
+#include <proc.h>
1525
+#include <thread.h>
1526
+#include <current.h>
1527
+#include <filedesc.h>
1528
+#include <addrspace.h>
1529
+#include <kern/fcntl.h>
1530
+#include <limits.h>
1531
+#include <kern/errno.h>
1532
+#include <machine/trapframe.h>
1533
+#include <synch.h>
1534
+#include <vfs.h>
1535
+#include <syscall.h>
1536
+
1537
+#ifndef NARG_MAX
1538
+#define NARG_MAX 1024
1539
+#endif
1540
+
1541
+static char karg[ARG_MAX];
1542
+static unsigned char kargbuf[ARG_MAX];
1543
+
1544
+#define MAX_PROG_NAME 32
1545
+
1546
+/**
1547
+ * given a string, and an align parameter
1548
+ * this function will align its length (by appending zero) to match the required alignment.
1549
+ */
1550
+static
1551
+int
1552
+align_arg( char arg[ARG_MAX], int align ) {
1553
+ char *p = arg;
1554
+ int len = 0;
1555
+ int diff;
1556
+
1557
+ while( *p++ != '\0' )
1558
+ ++len;
1559
+
1560
+ if( ++len % align == 0 )
1561
+ return len;
1562
+
1563
+ diff = align - ( len % align );
1564
+ while( diff-- ) {
1565
+ *(++p) = '\0';
1566
+ ++len;
1567
+ }
1568
+
1569
+ return len;
1570
+}
1571
+
1572
+/**
1573
+ * return the nearest length aligned to alignment.
1574
+ */
1575
+static
1576
+int
1577
+get_aligned_length( char arg[ARG_MAX], int alignment ) {
1578
+ char *p = arg;
1579
+ int len = 0;
1580
+
1581
+ while( *p++ != '\0' )
1582
+ ++len;
1583
+
1584
+ if( ++len % 4 == 0 )
1585
+ return len;
1586
+
1587
+ return len + (alignment - ( len % alignment ) );
1588
+}
1589
+
1590
+static
1591
+int
1592
+copy_args( userptr_t uargs, int *nargs, int *buflen ) {
1593
+ int i = 0;
1594
+ int err;
1595
+ int nlast = 0;
1596
+ char *ptr;
1597
+ unsigned char *p_begin = NULL;
1598
+ unsigned char *p_end = NULL;
1599
+ uint32_t offset;
1600
+ uint32_t last_offset;
1601
+
1602
+ //check whether we got a valid pointer.
1603
+ if( uargs == NULL )
1604
+ return EFAULT;
1605
+
1606
+ //initialize the numbe of arguments and the buffer size
1607
+ *nargs = 0;
1608
+ *buflen = 0;
1609
+
1610
+ //copy-in kargs.
1611
+ i = 0;
1612
+ while( ( err = copyin( (userptr_t)uargs + i * 4, &ptr, sizeof( ptr ) ) ) == 0 ) {
1613
+ if( ptr == NULL )
1614
+ break;
1615
+ err = copyinstr( (userptr_t)ptr, karg, sizeof( karg ), NULL );
1616
+ if( err )
1617
+ return err;
1618
+
1619
+ ++i;
1620
+ *nargs += 1;
1621
+ *buflen += get_aligned_length( karg, 4 ) + sizeof( char * );
1622
+ }
1623
+
1624
+ //if there is a problem, and we haven't read a single argument
1625
+ //that means the given user argument pointer is invalid.
1626
+ if( i == 0 && err )
1627
+ return err;
1628
+
1629
+ //account for NULL also.
1630
+ *nargs += 1;
1631
+ *buflen += sizeof( char * );
1632
+
1633
+
1634
+ //loop over the arguments again, building karbuf.
1635
+ i = 0;
1636
+ p_begin = kargbuf;
1637
+ p_end = kargbuf + (*nargs * sizeof( char * ));
1638
+ nlast = 0;
1639
+ last_offset = *nargs * sizeof( char * );
1640
+ while( ( err = copyin( (userptr_t)uargs + i * 4, &ptr, sizeof( ptr ) ) ) == 0 ) {
1641
+ if( ptr == NULL )
1642
+ break;
1643
+ err = copyinstr( (userptr_t)ptr, karg, sizeof( karg ), NULL );
1644
+ if( err )
1645
+ return err;
1646
+
1647
+ offset = last_offset + nlast;
1648
+ nlast = align_arg( karg, 4 );
1649
+
1650
+ //copy the integer into 4 bytes.
1651
+ *p_begin = offset & 0xff;
1652
+ *(p_begin + 1) = (offset >> 8) & 0xff;
1653
+ *(p_begin + 2) = (offset >> 16) & 0xff;
1654
+ *(p_begin + 3) = (offset >> 24) & 0xff;
1655
+
1656
+ //copy the string the buffer.
1657
+ memcpy( p_end, karg, nlast );
1658
+ p_end += nlast;
1659
+
1660
+ //advance p_begin by 4 bytes.
1661
+ p_begin += 4;
1662
+
1663
+ //adjust last offset
1664
+ last_offset = offset;
1665
+ ++i;
1666
+ }
1667
+
1668
+ //set the NULL pointer (i.e., it takes 4 zero bytes.)
1669
+ *p_begin = 0;
1670
+ *(p_begin+1) = 0;
1671
+ *(p_begin+2) = 0;
1672
+ *(p_begin+3) = 0;
1673
+
1674
+ return 0;
1675
+}
1676
+
1677
+static
1678
+int
1679
+adjust_kargbuf( int nparams, vaddr_t stack_ptr ) {
1680
+ int i;
1681
+ uint32_t new_offset = 0;
1682
+ uint32_t old_offset = 0;
1683
+ int index;
1684
+
1685
+ for( i = 0; i < nparams-1; ++i ) {
1686
+ index = i * sizeof( char * );
1687
+ //read the old offset.
1688
+ old_offset = (( 0xFF & kargbuf[index+3] ) << 24) | (( 0xFF & kargbuf[index+2]) << 16) |
1689
+ (( 0xFF & kargbuf[index+1]) << 8) | (0xFF & kargbuf[index]);
1690
+
1691
+ //calculate the new offset
1692
+ new_offset = stack_ptr + old_offset;
1693
+
1694
+ //store it instead of the old one.
1695
+ memcpy( kargbuf + index, &new_offset, sizeof( int ) );
1696
+ }
1697
+
1698
+ return 0;
1699
+}
1700
+
1701
+int
1702
+sys_execv( userptr_t upname, userptr_t uargs ) {
1703
+ struct addrspace *as_new = NULL;
1704
+ struct addrspace *as_old = NULL;
1705
+ struct vnode *vn = NULL;
1706
+ vaddr_t entry_ptr;
1707
+ vaddr_t stack_ptr;
1708
+ int err;
1709
+ char kpname[MAX_PROG_NAME];
1710
+ int nargs;
1711
+ int buflen;
1712
+
1713
+ KASSERT( curthread != NULL );
1714
+ KASSERT( curthread->td_proc != NULL );
1715
+
1716
+ (void)uargs;
1717
+
1718
+ //lock the execv args
1719
+ lock_acquire( lk_exec );
1720
+
1721
+ //copy the old addrspace just in case.
1722
+ as_old = curthread->t_addrspace;
1723
+
1724
+ //copyin the program name.
1725
+ err = copyinstr( upname, kpname, sizeof( kpname ), NULL );
1726
+ if( err ) {
1727
+ lock_release( lk_exec );
1728
+ return err;
1729
+ }
1730
+
1731
+ //try to open the given executable.
1732
+ err = vfs_open( kpname, O_RDONLY, 0, &vn );
1733
+ if( err ) {
1734
+ lock_release( lk_exec );
1735
+ return err;
1736
+ }
1737
+
1738
+ //copy the arguments into the kernel buffer.
1739
+ err = copy_args( uargs, &nargs, &buflen );
1740
+ if( err ) {
1741
+ lock_release( lk_exec );
1742
+ vfs_close( vn );
1743
+ return err;
1744
+ }
1745
+
1746
+ //create the new addrspace.
1747
+ as_new = as_create();
1748
+ if( as_new == NULL ) {
1749
+ lock_release( lk_exec );
1750
+ vfs_close( vn );
1751
+ return ENOMEM;
1752
+ }
1753
+
1754
+ //activate the new addrspace.
1755
+ as_activate( as_new );
1756
+
1757
+ //temporarily switch the addrspaces.
1758
+ curthread->t_addrspace = as_new;
1759
+
1760
+ //load the elf executable.
1761
+ err = load_elf( vn, &entry_ptr );
1762
+ if( err ) {
1763
+ curthread->t_addrspace = as_old;
1764
+ as_destroy( as_new );
1765
+ vfs_close( vn );
1766
+ lock_release( lk_exec );
1767
+ return err;
1768
+ }
1769
+
1770
+ //create a stack for the new addrspace.
1771
+ err = as_define_stack( as_new, &stack_ptr );
1772
+ if( err ) {
1773
+ curthread->t_addrspace = as_old;
1774
+ as_destroy( as_new );
1775
+ vfs_close( vn );
1776
+ lock_release( lk_exec );
1777
+ return err;
1778
+ }
1779
+
1780
+ //adjust the stackptr to reflect the change
1781
+ stack_ptr -= buflen;
1782
+ err = adjust_kargbuf( nargs, stack_ptr );
1783
+ if( err ) {
1784
+ curthread->t_addrspace = as_old;
1785
+ as_destroy( as_new );
1786
+ vfs_close( vn );
1787
+ lock_release( lk_exec );
1788
+ return err;
1789
+ }
1790
+
1791
+ //copy the arguments into the new user stack.
1792
+ err = copyout( kargbuf, (userptr_t)stack_ptr, buflen );
1793
+ if( err ) {
1794
+ curthread->t_addrspace = as_old;
1795
+ as_destroy( as_new );
1796
+ vfs_close( vn );
1797
+ lock_release( lk_exec );
1798
+ return err;
1799
+ }
1800
+
1801
+ //reelase lk_exec
1802
+ lock_release( lk_exec );
1803
+
1804
+ //no need for it anymore.
1805
+ vfs_close( vn );
1806
+
1807
+ //we are good to go.
1808
+ as_destroy( as_old );
1809
+
1810
+ //off we go to userland.
1811
+ enter_new_process( nargs-1, (userptr_t)stack_ptr, stack_ptr, entry_ptr );
1812
+
1813
+ panic( "execv: we should not be here." );
1814
+ return EINVAL;
1815
+}
1816
diff --git a/kern/syscall/fork.c b/kern/syscall/fork.c
1817
new file mode 100644
1818
index 0000000..043f740
1819
--- /dev/null
1820
+++ b/kern/syscall/fork.c
1821
@@ -0,0 +1,170 @@
1822
+#include <types.h>
1823
+#include <lib.h>
1824
+#include <copyinout.h>
1825
+#include <proc.h>
1826
+#include <thread.h>
1827
+#include <current.h>
1828
+#include <filedesc.h>
1829
+#include <addrspace.h>
1830
+#include <kern/errno.h>
1831
+#include <machine/trapframe.h>
1832
+#include <synch.h>
1833
+#include <syscall.h>
1834
+
1835
+/**
1836
+ * structure containings all the information
1837
+ * necessary for the child fork thread.
1838
+ */
1839
+struct child_fork_args {
1840
+ struct addrspace *as_source;
1841
+ struct proc *td_proc;
1842
+ struct trapframe *tf;
1843
+};
1844
+
1845
+
1846
+/**
1847
+ * this is the first function that gets executed
1848
+ * when the child thread runs.
1849
+ */
1850
+static
1851
+void
1852
+fork_child_return( void *v_args, unsigned long not_used ) {
1853
+ struct child_fork_args *args = NULL;
1854
+ struct trapframe tf;
1855
+
1856
+ (void)not_used;
1857
+
1858
+ //cast to something we can work with.
1859
+ args = v_args;
1860
+
1861
+ //the return value of fork() for the child is 0.
1862
+ args->tf->tf_v0 = 0;
1863
+ args->tf->tf_a3 = 0;
1864
+
1865
+ //skip to the next instruction to avoid fork()ing again.
1866
+ args->tf->tf_epc += 4;
1867
+
1868
+ //make the current thread aware of its process.
1869
+ curthread->td_proc = args->td_proc;
1870
+
1871
+ //set the current addrspace.
1872
+ curthread->t_addrspace = args->as_source;
1873
+
1874
+ //active its addrspace.
1875
+ as_activate( curthread->t_addrspace );
1876
+
1877
+ //copy from kernel stack into user stack.
1878
+ memcpy( &tf, args->tf, sizeof( struct trapframe ) );
1879
+
1880
+ //clean-up the arguments passed by fork().
1881
+ kfree( args->tf );
1882
+ kfree( args );
1883
+
1884
+ //tell our parent we are OK.
1885
+ V( curthread->td_proc->p_sem );
1886
+
1887
+ //off we go to usermode.
1888
+ mips_usermode( &tf );
1889
+}
1890
+
1891
+/**
1892
+ * helper function to clone a trapframe.
1893
+ */
1894
+static
1895
+int
1896
+trapframe_clone( struct trapframe *tf, struct trapframe **newtf ) {
1897
+ *newtf = kmalloc( sizeof( struct trapframe ) );
1898
+ if( *newtf == NULL )
1899
+ return ENOMEM;
1900
+
1901
+ memcpy( *newtf, tf, sizeof( struct trapframe ) );
1902
+ return 0;
1903
+}
1904
+
1905
+int
1906
+sys_fork( struct trapframe *tf, int *retval ) {
1907
+ struct proc *p_new = NULL;
1908
+ struct trapframe *tf_new = NULL;
1909
+ int err;
1910
+ struct child_fork_args *args;
1911
+ pid_t pid;
1912
+
1913
+ KASSERT( curthread != NULL );
1914
+ KASSERT( curthread->td_proc != NULL );
1915
+ KASSERT( tf != NULL );
1916
+
1917
+ //attempt to create a clone.
1918
+ err = proc_clone( curthread->td_proc, &p_new );
1919
+ if( err )
1920
+ return err;
1921
+
1922
+ //hold on to the pid.
1923
+ pid = p_new->p_pid;
1924
+
1925
+ //set the parent process of the new process to be us.
1926
+ p_new->p_proc = curthread->td_proc;
1927
+
1928
+ //clone the trapframe.
1929
+ err = trapframe_clone( tf, &tf_new );
1930
+ if( err ) {
1931
+ file_close_all( p_new );
1932
+ proc_destroy( p_new );
1933
+ return err;
1934
+ }
1935
+
1936
+ //prepare the arguments for the fork child thread.
1937
+ args = kmalloc( sizeof( struct child_fork_args ) );
1938
+ if( args == NULL ) {
1939
+ kfree( tf_new );
1940
+ file_close_all( p_new );
1941
+ proc_destroy( p_new );
1942
+ return ENOMEM;
1943
+ }
1944
+
1945
+ //copy the trapframe and wrapping proc
1946
+ //into the args structure.
1947
+ args->tf = tf_new;
1948
+ args->td_proc = p_new;
1949
+
1950
+ //copy the addresspace.
1951
+ err = as_copy( curthread->t_addrspace, &args->as_source );
1952
+ if( err ) {
1953
+ //clean after ourselves.
1954
+ kfree( args->tf );
1955
+ kfree( args );
1956
+
1957
+ file_close_all( p_new );
1958
+ proc_destroy( p_new );
1959
+ return err;
1960
+ }
1961
+
1962
+ //finalize the creation of the thread.
1963
+ err = thread_fork(
1964
+ curthread->t_name,
1965
+ fork_child_return,
1966
+ args,
1967
+ 0,
1968
+ NULL
1969
+ );
1970
+
1971
+ //oh well, thread creation failed.
1972
+ //make sure we clean-up after ourselves.
1973
+ if( err ) {
1974
+ as_destroy( args->as_source );
1975
+ kfree( args->tf );
1976
+ kfree( args );
1977
+
1978
+ //close all possible files open by the proc.
1979
+ file_close_all( p_new );
1980
+ proc_destroy( p_new );
1981
+ return err;
1982
+ }
1983
+
1984
+
1985
+ //wait for the child to tell us things are ok.
1986
+ P( p_new->p_sem );
1987
+
1988
+ //parent returns with no errors.
1989
+ *retval = pid;
1990
+ return 0;
1991
+}
1992
diff --git a/kern/syscall/getpid.c b/kern/syscall/getpid.c
1993
new file mode 100644
1994
index 0000000..ba52560
1995
--- /dev/null
1996
+++ b/kern/syscall/getpid.c
1997
@@ -0,0 +1,19 @@
1998
+#include <types.h>
1999
+#include <lib.h>
2000
+#include <proc.h>
2001
+#include <thread.h>
2002
+#include <current.h>
2003
+#include <syscall.h>
2004
+
2005
+int
2006
+sys_getpid( int *retval ) {
2007
+ KASSERT( curthread != NULL );
2008
+ KASSERT( curthread->td_proc != NULL );
2009
+
2010
+ PROC_LOCK( curthread->td_proc );
2011
+ *retval = curthread->td_proc->p_pid;
2012
+ PROC_UNLOCK( curthread->td_proc );
2013
+
2014
+ return 0;
2015
+}
2016
+
2017
diff --git a/kern/syscall/lseek.c b/kern/syscall/lseek.c
2018
new file mode 100644
2019
index 0000000..5b26e8a
2020
--- /dev/null
2021
+++ b/kern/syscall/lseek.c
2022
@@ -0,0 +1,72 @@
2023
+#include <types.h>
2024
+#include <lib.h>
2025
+#include <proc.h>
2026
+#include <file.h>
2027
+#include <vnode.h>
2028
+#include <vfs.h>
2029
+#include <stat.h>
2030
+#include <kern/fcntl.h>
2031
+#include <kern/seek.h>
2032
+#include <kern/errno.h>
2033
+#include <current.h>
2034
+#include <syscall.h>
2035
+
2036
+int
2037
+sys_lseek( int fd, off_t offset, int whence, int64_t *retval ) {
2038
+ struct proc *p = NULL;
2039
+ struct file *f = NULL;
2040
+ int err;
2041
+ struct stat st;
2042
+ off_t new_offset;
2043
+
2044
+ KASSERT( curthread != NULL );
2045
+ KASSERT( curthread->td_proc != NULL );
2046
+
2047
+ p = curthread->td_proc;
2048
+
2049
+ //try to open the file
2050
+ err = file_get( p, fd, &f );
2051
+ if( err )
2052
+ return err;
2053
+
2054
+ //depending on whence, seek to appropriate location
2055
+ switch( whence ) {
2056
+ case SEEK_SET:
2057
+ new_offset = offset;
2058
+ break;
2059
+
2060
+ case SEEK_CUR:
2061
+ new_offset = f->f_offset + offset;
2062
+ break;
2063
+
2064
+ case SEEK_END:
2065
+ //if it is SEEK_END, we use VOP_STAT to figure out
2066
+ //the size of the file, and set the offset to be that size.
2067
+ err = VOP_STAT( f->f_vnode, &st );
2068
+ if( err ) {
2069
+ F_UNLOCK( f );
2070
+ return err;
2071
+ }
2072
+
2073
+ //set the offet to the filesize.
2074
+ new_offset = st.st_size + offset;
2075
+ break;
2076
+ default:
2077
+ F_UNLOCK( f );
2078
+ return EINVAL;
2079
+ }
2080
+
2081
+ //use VOP_TRYSEEK to verify whether the desired
2082
+ //seeking location is proper.
2083
+ err = VOP_TRYSEEK( f->f_vnode, new_offset );
2084
+ if( err ) {
2085
+ F_UNLOCK( f );
2086
+ return err;
2087
+ }
2088
+
2089
+ //adjust the seek.
2090
+ f->f_offset = new_offset;
2091
+ *retval = new_offset;
2092
+ F_UNLOCK( f );
2093
+ return 0;
2094
+}
2095
diff --git a/kern/syscall/open.c b/kern/syscall/open.c
2096
new file mode 100644
2097
index 0000000..42d0d66
2098
--- /dev/null
2099
+++ b/kern/syscall/open.c
2100
@@ -0,0 +1,116 @@
2101
+#include <types.h>
2102
+#include <lib.h>
2103
+#include <kern/errno.h>
2104
+#include <syscall.h>
2105
+#include <file.h>
2106
+#include <filedesc.h>
2107
+#include <copyinout.h>
2108
+#include <kern/fcntl.h>
2109
+#include <stat.h>
2110
+#include <vfs.h>
2111
+#include <current.h>
2112
+
2113
+//check to see if the given flags are valid.
2114
+//valid flags consist of exactly one of O_RDONLY/O_WRONLY/O_RDWR.
2115
+static
2116
+bool
2117
+valid_flags( int flags ) {
2118
+ int count = 0;
2119
+ int accmode = flags & O_ACCMODE;
2120
+
2121
+ if( accmode == O_RDWR )
2122
+ ++count;
2123
+
2124
+ if( accmode == O_RDONLY )
2125
+ ++count;
2126
+
2127
+ if( accmode == O_WRONLY )
2128
+ ++count;
2129
+
2130
+ return count == 1;
2131
+}
2132
+
2133
+//kernel version of the open() systemcall.
2134
+int
2135
+___open( struct proc *p, char *path, int flags, int *retval ) {
2136
+ struct vnode *vn = NULL;
2137
+ int err;
2138
+ struct file *f = NULL;
2139
+ struct stat st;
2140
+
2141
+ //attempt to open the file
2142
+ err = vfs_open( path, flags, 0, &vn );
2143
+ if( err )
2144
+ return err;
2145
+
2146
+ //atempt to create the file object
2147
+ err = file_create( vn, flags, &f );
2148
+ if( err ) {
2149
+ vfs_close( vn );
2150
+ return err;
2151
+ }
2152
+
2153
+ //if we have O_APPEND, we must set the offset
2154
+ //to be the file size.
2155
+ if( flags & O_APPEND ) {
2156
+ err = VOP_STAT( f->f_vnode, &st );
2157
+ if( err ) {
2158
+ vfs_close( vn );
2159
+ file_destroy( f );
2160
+ return err;
2161
+ }
2162
+
2163
+ f->f_offset = st.st_size;
2164
+ }
2165
+
2166
+ //lock the file so we can safely modify
2167
+ F_LOCK( f );
2168
+
2169
+ //we now need to find a spot inside the process' filetable
2170
+ //so we can store our new file
2171
+ err = fd_attach( p->p_fd, f, retval );
2172
+ if( err ) {
2173
+ F_UNLOCK( f );
2174
+ vfs_close( vn );
2175
+ file_destroy( f );
2176
+ return err;
2177
+ }
2178
+
2179
+ //increase both references counts
2180
+ f->f_refcount++;
2181
+ VOP_INCREF( f->f_vnode );
2182
+
2183
+ //we are done if the file, unlock it
2184
+ F_UNLOCK( f );
2185
+ return 0;
2186
+
2187
+}
2188
+
2189
+int
2190
+sys_open( userptr_t upath, int flags, int *retval ) {
2191
+ char k_filename[MAX_FILE_NAME];
2192
+ int err;
2193
+ struct proc *p;
2194
+
2195
+ //make sure the current thread is not null
2196
+ //and that we have a process associated with it
2197
+ KASSERT( curthread != NULL );
2198
+ KASSERT( curthread->td_proc != NULL );
2199
+
2200
+ p = curthread->td_proc;
2201
+
2202
+ //check if we have valid flags
2203
+ if( !valid_flags( flags ) )
2204
+ return EINVAL;
2205
+
2206
+ //copy the path from userland into kernel-land
2207
+ err = copyinstr( upath, k_filename, sizeof( k_filename ), NULL );
2208
+
2209
+ //if we couldn't copy the file name, we probably have an I/O error
2210
+ //simply return that error code
2211
+ if( err )
2212
+ return err;
2213
+
2214
+ //delegate the actual opening to another function.
2215
+ return ___open( p, k_filename, flags, retval );
2216
+}
2217
diff --git a/kern/syscall/read.c b/kern/syscall/read.c
2218
new file mode 100644
2219
index 0000000..7a61ff7
2220
--- /dev/null
2221
+++ b/kern/syscall/read.c
2222
@@ -0,0 +1,68 @@
2223
+#include <types.h>
2224
+#include <lib.h>
2225
+#include <copyinout.h>
2226
+#include <proc.h>
2227
+#include <kern/iovec.h>
2228
+#include <uio.h>
2229
+#include <file.h>
2230
+#include <kern/fcntl.h>
2231
+#include <kern/errno.h>
2232
+#include <vnode.h>
2233
+#include <current.h>
2234
+#include <syscall.h>
2235
+
2236
+int
2237
+sys_read( int fd, userptr_t ubuf, size_t ulen, int *retval ) {
2238
+ struct proc *p = NULL;
2239
+ struct file *f = NULL;
2240
+ struct uio ruio;
2241
+ struct iovec iov;
2242
+ int err;
2243
+
2244
+ KASSERT( curthread != NULL );
2245
+ KASSERT( curthread->td_proc != NULL );
2246
+
2247
+ p = curthread->td_proc;
2248
+
2249
+ //attempt to open the file
2250
+ err = file_get( p, fd, &f );
2251
+ if( err )
2252
+ return err;
2253
+
2254
+ //check whether we have reading permissions
2255
+ if( f->f_oflags & O_WRONLY ) {
2256
+ F_UNLOCK( f );
2257
+ return EBADF;
2258
+ }
2259
+
2260
+ //prepare the uio for read
2261
+ uio_kinit (
2262
+ &iov,
2263
+ &ruio,
2264
+ ubuf,
2265
+ ulen,
2266
+ f->f_offset,
2267
+ UIO_READ
2268
+ );
2269
+
2270
+ ruio.uio_space = curthread->t_addrspace;
2271
+ ruio.uio_segflg = UIO_USERSPACE;
2272
+
2273
+ //perform the read
2274
+ err = VOP_READ( f->f_vnode, &ruio );
2275
+
2276
+ if( err ) {
2277
+ F_UNLOCK( f );
2278
+ return err;
2279
+ }
2280
+
2281
+ //advance the offset
2282
+ f->f_offset = ruio.uio_offset;
2283
+
2284
+ //set the number of bytes read to be retval
2285
+ *retval = ulen - ruio.uio_resid;
2286
+
2287
+ //unlock and quit
2288
+ F_UNLOCK( f );
2289
+ return 0;
2290
+}
2291
diff --git a/kern/syscall/waitpid.c b/kern/syscall/waitpid.c
2292
new file mode 100644
2293
index 0000000..1b67cd5
2294
--- /dev/null
2295
+++ b/kern/syscall/waitpid.c
2296
@@ -0,0 +1,86 @@
2297
+#include <types.h>
2298
+#include <lib.h>
2299
+#include <kern/errno.h>
2300
+#include <kern/wait.h>
2301
+#include <proc.h>
2302
+#include <copyinout.h>
2303
+#include <file.h>
2304
+#include <filedesc.h>
2305
+#include <thread.h>
2306
+#include <current.h>
2307
+#include <syscall.h>
2308
+
2309
+int
2310
+___waitpid( int pid, int *retval, int options ) {
2311
+ struct proc *p = NULL;
2312
+ int err;
2313
+
2314
+ KASSERT( curthread != NULL );
2315
+ KASSERT( curthread->td_proc != NULL );
2316
+
2317
+ //we only support WNOHANG and nothing else.
2318
+ if( options != 0 && options != WNOHANG )
2319
+ return EINVAL;
2320
+
2321
+ //get the process associated with the given pid
2322
+ err = proc_get( pid, &p );
2323
+ if( err )
2324
+ return err;
2325
+
2326
+ //make sure that we are the parent of that process
2327
+ //otherwise we are collecting an the exit code of a process
2328
+ //whose parent might still be interested in.
2329
+ if( p->p_proc != curthread->td_proc ) {
2330
+ PROC_UNLOCK( p );
2331
+ return ECHILD;
2332
+ }
2333
+
2334
+ //if WNOHANG was given, and said process is not yet dead
2335
+ //we immediately, (successfully) return with a value of 0.
2336
+ if( !p->p_is_dead && (options == WNOHANG) ) {
2337
+ PROC_UNLOCK( p );
2338
+ *retval = 0;
2339
+ return 0;
2340
+ }
2341
+
2342
+ //unlock the process, so the child potentially makes progress.
2343
+ //then, consume a signal from the child's semaphore.
2344
+ PROC_UNLOCK( p );
2345
+ P( p->p_sem );
2346
+ PROC_LOCK( p );
2347
+
2348
+ //at this point the child should be certainly dead.
2349
+ KASSERT( p->p_is_dead );
2350
+
2351
+ //copy its exit code to the userland.
2352
+ *retval = _MKWAIT_EXIT(p->p_retval);
2353
+
2354
+ //unlock and destroy.
2355
+ PROC_UNLOCK( p );
2356
+ proc_destroy( p );
2357
+
2358
+ return 0;
2359
+
2360
+}
2361
+
2362
+int
2363
+sys_waitpid( int pid, userptr_t uret, int options, int *retval ) {
2364
+ int kstatus;
2365
+ int err;
2366
+
2367
+ err = ___waitpid( pid, &kstatus, options );
2368
+ if( err )
2369
+ return err;
2370
+
2371
+ //copy its exit code to the userland.
2372
+ err = copyout( &kstatus, uret, sizeof( int ) );
2373
+
2374
+ //if we had an error copying out, we will return
2375
+ //an efault, but we still must destroy the associated
2376
+ //proc since the child is essentially dead.
2377
+ if( err )
2378
+ return err;
2379
+
2380
+ *retval = pid;
2381
+ return 0;
2382
+}
2383
diff --git a/kern/syscall/write.c b/kern/syscall/write.c
2384
new file mode 100644
2385
index 0000000..881ef4c
2386
--- /dev/null
2387
+++ b/kern/syscall/write.c
2388
@@ -0,0 +1,68 @@
2389
+#include <types.h>
2390
+#include <lib.h>
2391
+#include <copyinout.h>
2392
+#include <kern/errno.h>
2393
+#include <file.h>
2394
+#include <filedesc.h>
2395
+#include <kern/iovec.h>
2396
+#include <kern/fcntl.h>
2397
+#include <uio.h>
2398
+#include <proc.h>
2399
+#include <current.h>
2400
+#include <syscall.h>
2401
+
2402
+int
2403
+sys_write( int fd, userptr_t ubuf, size_t ulen, int *retval ) {
2404
+ int err = 0;
2405
+ struct file *f = NULL;
2406
+ struct proc *p = NULL;
2407
+ char kbuf[ulen];
2408
+ struct uio wuio;
2409
+ struct iovec iov;
2410
+
2411
+ KASSERT( curthread != NULL );
2412
+ KASSERT( curthread->td_proc != NULL );
2413
+
2414
+ p = curthread->td_proc;
2415
+
2416
+ //attempt to get a hold of the file
2417
+ err = file_get( p, fd, &f );
2418
+ if( err )
2419
+ return err;
2420
+
2421
+ //make sure it is not readony
2422
+ if( f->f_oflags & O_RDONLY )
2423
+ return EBADF;
2424
+
2425
+ //copy the data from userland into kernel
2426
+ err = copyin( ubuf, kbuf, sizeof( kbuf ) );
2427
+ if( err ) {
2428
+ F_UNLOCK( f );
2429
+ return err;
2430
+ }
2431
+
2432
+ //prepare the iovec/uio
2433
+ uio_kinit(
2434
+ &iov,
2435
+ &wuio,
2436
+ kbuf,
2437
+ sizeof( kbuf ),
2438
+ f->f_offset,
2439
+ UIO_WRITE
2440
+ );
2441
+
2442
+ //perform the IO
2443
+ err = VOP_WRITE( f->f_vnode, &wuio );
2444
+ if( err ) {
2445
+ F_UNLOCK( f );
2446
+ return err;
2447
+ }
2448
+
2449
+ //update the offset
2450
+ f->f_offset = wuio.uio_offset;
2451
+ F_UNLOCK( f );
2452
+
2453
+ //number of bytes written
2454
+ *retval = ulen - wuio.uio_resid;
2455
+ return 0;
2456
+}
2457
diff --git a/kern/thread/synch.c b/kern/thread/synch.c
2458
index 9a7468c..c5f8ef3 100644
2459
--- a/kern/thread/synch.c
2460
+++ b/kern/thread/synch.c
2461
@@ -163,7 +163,14 @@ lock_create(const char *name)
2462
return NULL;
2463
}
2464
2465
- // add stuff here as needed
2466
+ lock->lk_wchan = wchan_create(lock->lk_name);
2467
+ if (lock->lk_wchan == NULL) {
2468
+ kfree(lock->lk_name);
2469
+ kfree(lock);
2470
+ return NULL;
2471
+ }
2472
+ spinlock_init(&lock->lk_lock);
2473
+ lock->lk_holder = NULL;
2474
2475
return lock;
2476
}
2477
@@ -171,9 +178,11 @@ lock_create(const char *name)
2478
void
2479
lock_destroy(struct lock *lock)
2480
{
2481
- KASSERT(lock != NULL);
2482
+ DEBUGASSERT(lock != NULL);
2483
+ DEBUGASSERT(lock->lk_holder == NULL);
2484
2485
- // add stuff here as needed
2486
+ spinlock_cleanup(&lock->lk_lock);
2487
+ wchan_destroy(lock->lk_wchan);
2488
2489
kfree(lock->lk_name);
2490
kfree(lock);
2491
@@ -182,27 +191,44 @@ lock_destroy(struct lock *lock)
2492
void
2493
lock_acquire(struct lock *lock)
2494
{
2495
- // Write this
2496
+ DEBUGASSERT(lock != NULL);
2497
+ DEBUGASSERT(!(lock_do_i_hold(lock)));
2498
+ KASSERT(curthread->t_in_interrupt == false);
2499
+
2500
+ spinlock_acquire(&lock->lk_lock);
2501
+ while (lock->lk_holder != NULL) {
2502
+ wchan_lock(lock->lk_wchan);
2503
+ spinlock_release(&lock->lk_lock);
2504
+ wchan_sleep(lock->lk_wchan);
2505
+ spinlock_acquire(&lock->lk_lock);
2506
+ }
2507
2508
- (void)lock; // suppress warning until code gets written
2509
+ lock->lk_holder = curthread;
2510
+ spinlock_release(&lock->lk_lock);
2511
}
2512
2513
void
2514
lock_release(struct lock *lock)
2515
{
2516
- // Write this
2517
+ DEBUGASSERT(lock_do_i_hold(lock));
2518
2519
- (void)lock; // suppress warning until code gets written
2520
+ spinlock_acquire(&lock->lk_lock);
2521
+ lock->lk_holder = NULL;
2522
+ wchan_wakeone(lock->lk_wchan);
2523
+ spinlock_release(&lock->lk_lock);
2524
}
2525
2526
bool
2527
lock_do_i_hold(struct lock *lock)
2528
{
2529
- // Write this
2530
+ bool ret;
2531
+ DEBUGASSERT(lock != NULL);
2532
2533
- (void)lock; // suppress warning until code gets written
2534
+ spinlock_acquire(&lock->lk_lock);
2535
+ ret = (lock->lk_holder == curthread);
2536
+ spinlock_release(&lock->lk_lock);
2537
2538
- return true; // dummy until code gets written
2539
+ return ret;
2540
}
2541
2542
////////////////////////////////////////////////////////////
2543
@@ -226,7 +252,12 @@ cv_create(const char *name)
2544
return NULL;
2545
}
2546
2547
- // add stuff here as needed
2548
+ cv->cv_wchan = wchan_create(cv->cv_name);
2549
+ if (cv->cv_wchan == NULL) {
2550
+ kfree(cv->cv_name);
2551
+ kfree(cv);
2552
+ return NULL;
2553
+ }
2554
2555
return cv;
2556
}
2557
@@ -236,8 +267,7 @@ cv_destroy(struct cv *cv)
2558
{
2559
KASSERT(cv != NULL);
2560
2561
- // add stuff here as needed
2562
-
2563
+ wchan_destroy(cv->cv_wchan);
2564
kfree(cv->cv_name);
2565
kfree(cv);
2566
}
2567
@@ -245,23 +275,26 @@ cv_destroy(struct cv *cv)
2568
void
2569
cv_wait(struct cv *cv, struct lock *lock)
2570
{
2571
- // Write this
2572
- (void)cv; // suppress warning until code gets written
2573
- (void)lock; // suppress warning until code gets written
2574
-}
2575
+ DEBUGASSERT(lock_do_i_hold(lock));
2576
2577
+ wchan_lock(cv->cv_wchan);
2578
+ lock_release(lock);
2579
+ wchan_sleep(cv->cv_wchan);
2580
+ lock_acquire(lock);
2581
+}
2582
+
2583
void
2584
cv_signal(struct cv *cv, struct lock *lock)
2585
{
2586
- // Write this
2587
- (void)cv; // suppress warning until code gets written
2588
- (void)lock; // suppress warning until code gets written
2589
-}
2590
+ DEBUGASSERT(lock_do_i_hold(lock));
2591
2592
+ wchan_wakeone(cv->cv_wchan);
2593
+}
2594
+
2595
void
2596
cv_broadcast(struct cv *cv, struct lock *lock)
2597
{
2598
- // Write this
2599
- (void)cv; // suppress warning until code gets written
2600
- (void)lock; // suppress warning until code gets written
2601
+ DEBUGASSERT(lock_do_i_hold(lock));
2602
+
2603
+ wchan_wakeall(cv->cv_wchan);
2604
}
2605
diff --git a/kern/thread/synch.c.orig b/kern/thread/synch.c.orig
2606
new file mode 100644
2607
index 0000000..9a7468c
2608
--- /dev/null
2609
+++ b/kern/thread/synch.c.orig
2610
@@ -0,0 +1,267 @@
2611
+/*
2612
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
2613
+ * The President and Fellows of Harvard College.
2614
+ *
2615
+ * Redistribution and use in source and binary forms, with or without
2616
+ * modification, are permitted provided that the following conditions
2617
+ * are met:
2618
+ * 1. Redistributions of source code must retain the above copyright
2619
+ * notice, this list of conditions and the following disclaimer.
2620
+ * 2. Redistributions in binary form must reproduce the above copyright
2621
+ * notice, this list of conditions and the following disclaimer in the
2622
+ * documentation and/or other materials provided with the distribution.
2623
+ * 3. Neither the name of the University nor the names of its contributors
2624
+ * may be used to endorse or promote products derived from this software
2625
+ * without specific prior written permission.
2626
+ *
2627
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
2628
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2629
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2630
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
2631
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2632
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2633
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2634
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2635
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2636
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2637
+ * SUCH DAMAGE.
2638
+ */
2639
+
2640
+/*
2641
+ * Synchronization primitives.
2642
+ * The specifications of the functions are in synch.h.
2643
+ */
2644
+
2645
+#include <types.h>
2646
+#include <lib.h>
2647
+#include <spinlock.h>
2648
+#include <wchan.h>
2649
+#include <thread.h>
2650
+#include <current.h>
2651
+#include <synch.h>
2652
+
2653
+////////////////////////////////////////////////////////////
2654
+//
2655
+// Semaphore.
2656
+
2657
+struct semaphore *
2658
+sem_create(const char *name, int initial_count)
2659
+{
2660
+ struct semaphore *sem;
2661
+
2662
+ KASSERT(initial_count >= 0);
2663
+
2664
+ sem = kmalloc(sizeof(struct semaphore));
2665
+ if (sem == NULL) {
2666
+ return NULL;
2667
+ }
2668
+
2669
+ sem->sem_name = kstrdup(name);
2670
+ if (sem->sem_name == NULL) {
2671
+ kfree(sem);
2672
+ return NULL;
2673
+ }
2674
+
2675
+ sem->sem_wchan = wchan_create(sem->sem_name);
2676
+ if (sem->sem_wchan == NULL) {
2677
+ kfree(sem->sem_name);
2678
+ kfree(sem);
2679
+ return NULL;
2680
+ }
2681
+
2682
+ spinlock_init(&sem->sem_lock);
2683
+ sem->sem_count = initial_count;
2684
+
2685
+ return sem;
2686
+}
2687
+
2688
+void
2689
+sem_destroy(struct semaphore *sem)
2690
+{
2691
+ KASSERT(sem != NULL);
2692
+
2693
+ /* wchan_cleanup will assert if anyone's waiting on it */
2694
+ spinlock_cleanup(&sem->sem_lock);
2695
+ wchan_destroy(sem->sem_wchan);
2696
+ kfree(sem->sem_name);
2697
+ kfree(sem);
2698
+}
2699
+
2700
+void
2701
+P(struct semaphore *sem)
2702
+{
2703
+ KASSERT(sem != NULL);
2704
+
2705
+ /*
2706
+ * May not block in an interrupt handler.
2707
+ *
2708
+ * For robustness, always check, even if we can actually
2709
+ * complete the P without blocking.
2710
+ */
2711
+ KASSERT(curthread->t_in_interrupt == false);
2712
+
2713
+ spinlock_acquire(&sem->sem_lock);
2714
+ while (sem->sem_count == 0) {
2715
+ /*
2716
+ * Bridge to the wchan lock, so if someone else comes
2717
+ * along in V right this instant the wakeup can't go
2718
+ * through on the wchan until we've finished going to
2719
+ * sleep. Note that wchan_sleep unlocks the wchan.
2720
+ *
2721
+ * Note that we don't maintain strict FIFO ordering of
2722
+ * threads going through the semaphore; that is, we
2723
+ * might "get" it on the first try even if other
2724
+ * threads are waiting. Apparently according to some
2725
+ * textbooks semaphores must for some reason have
2726
+ * strict ordering. Too bad. :-)
2727
+ *
2728
+ * Exercise: how would you implement strict FIFO
2729
+ * ordering?
2730
+ */
2731
+ wchan_lock(sem->sem_wchan);
2732
+ spinlock_release(&sem->sem_lock);
2733
+ wchan_sleep(sem->sem_wchan);
2734
+
2735
+ spinlock_acquire(&sem->sem_lock);
2736
+ }
2737
+ KASSERT(sem->sem_count > 0);
2738
+ sem->sem_count--;
2739
+ spinlock_release(&sem->sem_lock);
2740
+}
2741
+
2742
+void
2743
+V(struct semaphore *sem)
2744
+{
2745
+ KASSERT(sem != NULL);
2746
+
2747
+ spinlock_acquire(&sem->sem_lock);
2748
+
2749
+ sem->sem_count++;
2750
+ KASSERT(sem->sem_count > 0);
2751
+ wchan_wakeone(sem->sem_wchan);
2752
+
2753
+ spinlock_release(&sem->sem_lock);
2754
+}
2755
+
2756
+////////////////////////////////////////////////////////////
2757
+//
2758
+// Lock.
2759
+
2760
+struct lock *
2761
+lock_create(const char *name)
2762
+{
2763
+ struct lock *lock;
2764
+
2765
+ lock = kmalloc(sizeof(struct lock));
2766
+ if (lock == NULL) {
2767
+ return NULL;
2768
+ }
2769
+
2770
+ lock->lk_name = kstrdup(name);
2771
+ if (lock->lk_name == NULL) {
2772
+ kfree(lock);
2773
+ return NULL;
2774
+ }
2775
+
2776
+ // add stuff here as needed
2777
+
2778
+ return lock;
2779
+}
2780
+
2781
+void
2782
+lock_destroy(struct lock *lock)
2783
+{
2784
+ KASSERT(lock != NULL);
2785
+
2786
+ // add stuff here as needed
2787
+
2788
+ kfree(lock->lk_name);
2789
+ kfree(lock);
2790
+}
2791
+
2792
+void
2793
+lock_acquire(struct lock *lock)
2794
+{
2795
+ // Write this
2796
+
2797
+ (void)lock; // suppress warning until code gets written
2798
+}
2799
+
2800
+void
2801
+lock_release(struct lock *lock)
2802
+{
2803
+ // Write this
2804
+
2805
+ (void)lock; // suppress warning until code gets written
2806
+}
2807
+
2808
+bool
2809
+lock_do_i_hold(struct lock *lock)
2810
+{
2811
+ // Write this
2812
+
2813
+ (void)lock; // suppress warning until code gets written
2814
+
2815
+ return true; // dummy until code gets written
2816
+}
2817
+
2818
+////////////////////////////////////////////////////////////
2819
+//
2820
+// CV
2821
+
2822
+
2823
+struct cv *
2824
+cv_create(const char *name)
2825
+{
2826
+ struct cv *cv;
2827
+
2828
+ cv = kmalloc(sizeof(struct cv));
2829
+ if (cv == NULL) {
2830
+ return NULL;
2831
+ }
2832
+
2833
+ cv->cv_name = kstrdup(name);
2834
+ if (cv->cv_name==NULL) {
2835
+ kfree(cv);
2836
+ return NULL;
2837
+ }
2838
+
2839
+ // add stuff here as needed
2840
+
2841
+ return cv;
2842
+}
2843
+
2844
+void
2845
+cv_destroy(struct cv *cv)
2846
+{
2847
+ KASSERT(cv != NULL);
2848
+
2849
+ // add stuff here as needed
2850
+
2851
+ kfree(cv->cv_name);
2852
+ kfree(cv);
2853
+}
2854
+
2855
+void
2856
+cv_wait(struct cv *cv, struct lock *lock)
2857
+{
2858
+ // Write this
2859
+ (void)cv; // suppress warning until code gets written
2860
+ (void)lock; // suppress warning until code gets written
2861
+}
2862
+
2863
+void
2864
+cv_signal(struct cv *cv, struct lock *lock)
2865
+{
2866
+ // Write this
2867
+ (void)cv; // suppress warning until code gets written
2868
+ (void)lock; // suppress warning until code gets written
2869
+}
2870
+
2871
+void
2872
+cv_broadcast(struct cv *cv, struct lock *lock)
2873
+{
2874
+ // Write this
2875
+ (void)cv; // suppress warning until code gets written
2876
+ (void)lock; // suppress warning until code gets written
2877
+}
2878
diff --git a/kern/thread/thread.c b/kern/thread/thread.c
2879
index 5b8099e..cb76f07 100644
2880
--- a/kern/thread/thread.c
2881
+++ b/kern/thread/thread.c
2882
@@ -852,7 +852,58 @@ schedule(void)
2883
{
2884
// 28 Feb 2012 : GWA : Implement your scheduler that prioritizes
2885
// "interactive" threads here.
2886
+
2887
+ /*
2888
+ * the idea behind the new scheduler
2889
+ * is that interactive threads call system-calls more often
2890
+ * then cpu-bound threads, therefore we will give preference to those.
2891
+ */
2892
+
2893
+ struct cpu *cpu = NULL;
2894
+ struct thread *it = NULL;
2895
+ struct thread *t_max = NULL;
2896
+
2897
+ //get the current cpu.
2898
+ cpu = curcpu;
2899
+
2900
+ //lock its running queue.
2901
+ spinlock_acquire( &cpu->c_runqueue_lock );
2902
+
2903
+ //loop over all the threads, and choose the one that has the
2904
+ //maximum syscalls number. once chosen, we remove that thread and
2905
+ //add it to the front of the runqueue.
2906
+ for ( it = cpu->c_runqueue.tl_head.tln_next->tln_self;
2907
+ it != NULL && it->t_listnode.tln_next != NULL;
2908
+ it = it->t_listnode.tln_next->tln_self) {
2909
+
2910
+ //if we're in the first iteration ...
2911
+ if( t_max == NULL ) {
2912
+ t_max = it;
2913
+ continue;
2914
+ }
2915
+
2916
+ if( t_max->td_proc != NULL && it->td_proc != NULL ) {
2917
+ if( t_max->td_proc->p_nsyscalls < it->td_proc->p_nsyscalls ) {
2918
+ t_max = it;
2919
+ continue;
2920
+ }
2921
+ }
2922
+ }
2923
+
2924
+ //remove t_max from the runqueue.
2925
+ if( t_max != NULL ) {
2926
+ threadlist_remove( &cpu->c_runqueue, t_max );
2927
+
2928
+ //add it to the head.
2929
+ threadlist_addhead( &cpu->c_runqueue, t_max );
2930
+ }
2931
+
2932
+ KASSERT( t_max->t_state == S_READY );
2933
+ //release the lock
2934
+ spinlock_release( &cpu->c_runqueue_lock );
2935
+
2936
}
2937
+
2938
#endif
2939
2940
/*
2941
diff --git a/patches/ASST1-sol.tgz b/patches/ASST1-sol.tgz
2942
new file mode 100644
2943
index 0000000..b56c5e7
2944
Binary files /dev/null and b/patches/ASST1-sol.tgz differ
2945
diff --git a/patches/ASST1-sol/README b/patches/ASST1-sol/README
2946
new file mode 100644
2947
index 0000000..7cfed18
2948
--- /dev/null
2949
+++ b/patches/ASST1-sol/README
2950
@@ -0,0 +1,58 @@
2951
+01 Mar 2012 : GWA : This is ASST1 solution v. 1.0.
2952
+05 Mar 2012 : GWA : This is ASST1 solution v. 1.1.
2953
+
2954
+It contains:
2955
+ 1) Working locks.
2956
+ 2) Working CVs.
2957
+
2958
+It does not contain:
2959
+ 1) Working reader-writer locks.
2960
+ 2) Solutions to the synchronization problems.
2961
+
2962
+Reader-writer locks may be included in a future ASST1 solution archive, but
2963
+for now neither of the things that it does *not* contain should prevent you
2964
+from making forward progress on ASST2.
2965
+
2966
+There are two ways to bring your Git repository into line with your solution.
2967
+The first thing to do is commit anything you have uncommitted and make sure
2968
+that your git status shows a clean directory. After that, here are the two
2969
+options:
2970
+
2971
+1) git revert + patch
2972
+
2973
+The sol10.patch file is against commit 02a93045, or the same one that starts
2974
+ASST2. If you have not received this commit yet do a git pull to do so. It's
2975
+probably a good idea to do a git pull anyway, just in case.
2976
+
2977
+The sol11.path is against the sol10.path, so you should apply them in order.
2978
+
2979
+The first thing you have to do is locate the commit that contains your ASST0
2980
+changes: adding your username and debug messages. You may have tagged this
2981
+commit to begin ASST1. Use git log to locate the appropriate commit tag.
2982
+
2983
+Once you have located it, ask git to revert your ASST1 changes and then apply
2984
+our patches.
2985
+
2986
+$ git revert <ASST1 start tag>
2987
+$ patch -p1 sol10.patch
2988
+$ patch -p1 sol11.patch
2989
+$ git commit -a
2990
+
2991
+If you have previously applied the sol10.patch you should be able to simply
2992
+apply the sol11.patch on top of your current source tree.
2993
+
2994
+2) copy files
2995
+
2996
+The other option is to do the merge by hand starting with your current
2997
+working tree. All the files we changed are included in this archive. Several
2998
+can be copied; for others, you will need to do the merge by hand, but the
2999
+changes are very limited.
3000
+
3001
+ 1) synch.c, synch.h: solution primitives. These files can be copied.
3002
+ 2) version.h, main.c: add solution set version to kernel boot messages.
3003
+ These files must be merged by hand or you will break changes you made for
3004
+ ASST0. (Specifically, making sure that your group or username prints during
3005
+ bootup, which our grading scripts will check.)
3006
+
3007
+After committing any changes, simply move these files into place and commit
3008
+the resulting changes.
3009
diff --git a/patches/ASST1-sol/files/main.c b/patches/ASST1-sol/files/main.c
3010
new file mode 100644
3011
index 0000000..535a864
3012
--- /dev/null
3013
+++ b/patches/ASST1-sol/files/main.c
3014
@@ -0,0 +1,211 @@
3015
+/*
3016
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3017
+ * The President and Fellows of Harvard College.
3018
+ *
3019
+ * Redistribution and use in source and binary forms, with or without
3020
+ * modification, are permitted provided that the following conditions
3021
+ * are met:
3022
+ * 1. Redistributions of source code must retain the above copyright
3023
+ * notice, this list of conditions and the following disclaimer.
3024
+ * 2. Redistributions in binary form must reproduce the above copyright
3025
+ * notice, this list of conditions and the following disclaimer in the
3026
+ * documentation and/or other materials provided with the distribution.
3027
+ * 3. Neither the name of the University nor the names of its contributors
3028
+ * may be used to endorse or promote products derived from this software
3029
+ * without specific prior written permission.
3030
+ *
3031
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
3032
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3033
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3034
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
3035
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3036
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3037
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3038
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3039
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3040
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3041
+ * SUCH DAMAGE.
3042
+ */
3043
+
3044
+/*
3045
+ * Main.
3046
+ */
3047
+
3048
+#include <types.h>
3049
+#include <kern/errno.h>
3050
+#include <kern/reboot.h>
3051
+#include <kern/unistd.h>
3052
+#include <lib.h>
3053
+#include <spl.h>
3054
+#include <clock.h>
3055
+#include <thread.h>
3056
+#include <current.h>
3057
+#include <synch.h>
3058
+#include <vm.h>
3059
+#include <mainbus.h>
3060
+#include <vfs.h>
3061
+#include <device.h>
3062
+#include <syscall.h>
3063
+#include <test.h>
3064
+#include <version.h>
3065
+#include "autoconf.h" // for pseudoconfig
3066
+
3067
+
3068
+/*
3069
+ * These two pieces of data are maintained by the makefiles and build system.
3070
+ * buildconfig is the name of the config file the kernel was configured with.
3071
+ * buildversion starts at 1 and is incremented every time you link a kernel.
3072
+ *
3073
+ * The purpose is not to show off how many kernels you've linked, but
3074
+ * to make it easy to make sure that the kernel you just booted is the
3075
+ * same one you just built.
3076
+ */
3077
+extern const int buildversion;
3078
+extern const char buildconfig[];
3079
+
3080
+/*
3081
+ * Copyright message for the OS/161 base code.
3082
+ */
3083
+static const char harvard_copyright[] =
3084
+ "Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009\n"
3085
+ " President and Fellows of Harvard College. All rights reserved.\n";
3086
+
3087
+
3088
+/*
3089
+ * Initial boot sequence.
3090
+ */
3091
+static
3092
+void
3093
+boot(void)
3094
+{
3095
+ /*
3096
+ * The order of these is important!
3097
+ * Don't go changing it without thinking about the consequences.
3098
+ *
3099
+ * Among other things, be aware that console output gets
3100
+ * buffered up at first and does not actually appear until
3101
+ * mainbus_bootstrap() attaches the console device. This can
3102
+ * be remarkably confusing if a bug occurs at this point. So
3103
+ * don't put new code before mainbus_bootstrap if you don't
3104
+ * absolutely have to.
3105
+ *
3106
+ * Also note that the buffer for this is only 1k. If you
3107
+ * overflow it, the system will crash without printing
3108
+ * anything at all. You can make it larger though (it's in
3109
+ * dev/generic/console.c).
3110
+ */
3111
+
3112
+ kprintf("\n");
3113
+ kprintf("OS/161 base version %s ASST1 solution version %s\n", BASE_VERSION, ASST1SOL_VERSION);
3114
+ kprintf("%s", harvard_copyright);
3115
+ kprintf("\n");
3116
+
3117
+ kprintf("Put-your-group-name-here's system version %s (%s #%d)\n",
3118
+ GROUP_VERSION, buildconfig, buildversion);
3119
+ kprintf("\n");
3120
+
3121
+ /* Early initialization. */
3122
+ ram_bootstrap();
3123
+ thread_bootstrap();
3124
+ hardclock_bootstrap();
3125
+ vfs_bootstrap();
3126
+
3127
+ /* Probe and initialize devices. Interrupts should come on. */
3128
+ kprintf("Device probe...\n");
3129
+ KASSERT(curthread->t_curspl > 0);
3130
+ mainbus_bootstrap();
3131
+ KASSERT(curthread->t_curspl == 0);
3132
+ /* Now do pseudo-devices. */
3133
+ pseudoconfig();
3134
+ kprintf("\n");
3135
+
3136
+ /* Late phase of initialization. */
3137
+ vm_bootstrap();
3138
+ kprintf_bootstrap();
3139
+ thread_start_cpus();
3140
+
3141
+ /* Default bootfs - but ignore failure, in case emu0 doesn't exist */
3142
+ vfs_setbootfs("emu0");
3143
+
3144
+
3145
+ /*
3146
+ * Make sure various things aren't screwed up.
3147
+ */
3148
+ COMPILE_ASSERT(sizeof(userptr_t) == sizeof(char *));
3149
+ COMPILE_ASSERT(sizeof(*(userptr_t)0) == sizeof(char));
3150
+}
3151
+
3152
+/*
3153
+ * Shutdown sequence. Opposite to boot().
3154
+ */
3155
+static
3156
+void
3157
+shutdown(void)
3158
+{
3159
+
3160
+ kprintf("Shutting down.\n");
3161
+
3162
+ vfs_clearbootfs();
3163
+ vfs_clearcurdir();
3164
+ vfs_unmountall();
3165
+
3166
+ thread_shutdown();
3167
+
3168
+ splhigh();
3169
+}
3170
+
3171
+/*****************************************/
3172
+
3173
+/*
3174
+ * reboot() system call.
3175
+ *
3176
+ * Note: this is here because it's directly related to the code above,
3177
+ * not because this is where system call code should go. Other syscall
3178
+ * code should probably live in the "syscall" directory.
3179
+ */
3180
+int
3181
+sys_reboot(int code)
3182
+{
3183
+ switch (code) {
3184
+ case RB_REBOOT:
3185
+ case RB_HALT:
3186
+ case RB_POWEROFF:
3187
+ break;
3188
+ default:
3189
+ return EINVAL;
3190
+ }
3191
+
3192
+ shutdown();
3193
+
3194
+ switch (code) {
3195
+ case RB_HALT:
3196
+ kprintf("The system is halted.\n");
3197
+ mainbus_halt();
3198
+ break;
3199
+ case RB_REBOOT:
3200
+ kprintf("Rebooting...\n");
3201
+ mainbus_reboot();
3202
+ break;
3203
+ case RB_POWEROFF:
3204
+ kprintf("The system is halted.\n");
3205
+ mainbus_poweroff();
3206
+ break;
3207
+ }
3208
+
3209
+ panic("reboot operation failed\n");
3210
+ return 0;
3211
+}
3212
+
3213
+/*
3214
+ * Kernel main. Boot up, then fork the menu thread; wait for a reboot
3215
+ * request, and then shut down.
3216
+ */
3217
+void
3218
+kmain(char *arguments)
3219
+{
3220
+ boot();
3221
+
3222
+ menu(arguments);
3223
+
3224
+ /* Should not get here */
3225
+}
3226
diff --git a/patches/ASST1-sol/files/synch.c b/patches/ASST1-sol/files/synch.c
3227
new file mode 100644
3228
index 0000000..c5f8ef3
3229
--- /dev/null
3230
+++ b/patches/ASST1-sol/files/synch.c
3231
@@ -0,0 +1,300 @@
3232
+/*
3233
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3234
+ * The President and Fellows of Harvard College.
3235
+ *
3236
+ * Redistribution and use in source and binary forms, with or without
3237
+ * modification, are permitted provided that the following conditions
3238
+ * are met:
3239
+ * 1. Redistributions of source code must retain the above copyright
3240
+ * notice, this list of conditions and the following disclaimer.
3241
+ * 2. Redistributions in binary form must reproduce the above copyright
3242
+ * notice, this list of conditions and the following disclaimer in the
3243
+ * documentation and/or other materials provided with the distribution.
3244
+ * 3. Neither the name of the University nor the names of its contributors
3245
+ * may be used to endorse or promote products derived from this software
3246
+ * without specific prior written permission.
3247
+ *
3248
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
3249
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3250
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3251
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
3252
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3253
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3254
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3255
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3256
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3257
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3258
+ * SUCH DAMAGE.
3259
+ */
3260
+
3261
+/*
3262
+ * Synchronization primitives.
3263
+ * The specifications of the functions are in synch.h.
3264
+ */
3265
+
3266
+#include <types.h>
3267
+#include <lib.h>
3268
+#include <spinlock.h>
3269
+#include <wchan.h>
3270
+#include <thread.h>
3271
+#include <current.h>
3272
+#include <synch.h>
3273
+
3274
+////////////////////////////////////////////////////////////
3275
+//
3276
+// Semaphore.
3277
+
3278
+struct semaphore *
3279
+sem_create(const char *name, int initial_count)
3280
+{
3281
+ struct semaphore *sem;
3282
+
3283
+ KASSERT(initial_count >= 0);
3284
+
3285
+ sem = kmalloc(sizeof(struct semaphore));
3286
+ if (sem == NULL) {
3287
+ return NULL;
3288
+ }
3289
+
3290
+ sem->sem_name = kstrdup(name);
3291
+ if (sem->sem_name == NULL) {
3292
+ kfree(sem);
3293
+ return NULL;
3294
+ }
3295
+
3296
+ sem->sem_wchan = wchan_create(sem->sem_name);
3297
+ if (sem->sem_wchan == NULL) {
3298
+ kfree(sem->sem_name);
3299
+ kfree(sem);
3300
+ return NULL;
3301
+ }
3302
+
3303
+ spinlock_init(&sem->sem_lock);
3304
+ sem->sem_count = initial_count;
3305
+
3306
+ return sem;
3307
+}
3308
+
3309
+void
3310
+sem_destroy(struct semaphore *sem)
3311
+{
3312
+ KASSERT(sem != NULL);
3313
+
3314
+ /* wchan_cleanup will assert if anyone's waiting on it */
3315
+ spinlock_cleanup(&sem->sem_lock);
3316
+ wchan_destroy(sem->sem_wchan);
3317
+ kfree(sem->sem_name);
3318
+ kfree(sem);
3319
+}
3320
+
3321
+void
3322
+P(struct semaphore *sem)
3323
+{
3324
+ KASSERT(sem != NULL);
3325
+
3326
+ /*
3327
+ * May not block in an interrupt handler.
3328
+ *
3329
+ * For robustness, always check, even if we can actually
3330
+ * complete the P without blocking.
3331
+ */
3332
+ KASSERT(curthread->t_in_interrupt == false);
3333
+
3334
+ spinlock_acquire(&sem->sem_lock);
3335
+ while (sem->sem_count == 0) {
3336
+ /*
3337
+ * Bridge to the wchan lock, so if someone else comes
3338
+ * along in V right this instant the wakeup can't go
3339
+ * through on the wchan until we've finished going to
3340
+ * sleep. Note that wchan_sleep unlocks the wchan.
3341
+ *
3342
+ * Note that we don't maintain strict FIFO ordering of
3343
+ * threads going through the semaphore; that is, we
3344
+ * might "get" it on the first try even if other
3345
+ * threads are waiting. Apparently according to some
3346
+ * textbooks semaphores must for some reason have
3347
+ * strict ordering. Too bad. :-)
3348
+ *
3349
+ * Exercise: how would you implement strict FIFO
3350
+ * ordering?
3351
+ */
3352
+ wchan_lock(sem->sem_wchan);
3353
+ spinlock_release(&sem->sem_lock);
3354
+ wchan_sleep(sem->sem_wchan);
3355
+
3356
+ spinlock_acquire(&sem->sem_lock);
3357
+ }
3358
+ KASSERT(sem->sem_count > 0);
3359
+ sem->sem_count--;
3360
+ spinlock_release(&sem->sem_lock);
3361
+}
3362
+
3363
+void
3364
+V(struct semaphore *sem)
3365
+{
3366
+ KASSERT(sem != NULL);
3367
+
3368
+ spinlock_acquire(&sem->sem_lock);
3369
+
3370
+ sem->sem_count++;
3371
+ KASSERT(sem->sem_count > 0);
3372
+ wchan_wakeone(sem->sem_wchan);
3373
+
3374
+ spinlock_release(&sem->sem_lock);
3375
+}
3376
+
3377
+////////////////////////////////////////////////////////////
3378
+//
3379
+// Lock.
3380
+
3381
+struct lock *
3382
+lock_create(const char *name)
3383
+{
3384
+ struct lock *lock;
3385
+
3386
+ lock = kmalloc(sizeof(struct lock));
3387
+ if (lock == NULL) {
3388
+ return NULL;
3389
+ }
3390
+
3391
+ lock->lk_name = kstrdup(name);
3392
+ if (lock->lk_name == NULL) {
3393
+ kfree(lock);
3394
+ return NULL;
3395
+ }
3396
+
3397
+ lock->lk_wchan = wchan_create(lock->lk_name);
3398
+ if (lock->lk_wchan == NULL) {
3399
+ kfree(lock->lk_name);
3400
+ kfree(lock);
3401
+ return NULL;
3402
+ }
3403
+ spinlock_init(&lock->lk_lock);
3404
+ lock->lk_holder = NULL;
3405
+
3406
+ return lock;
3407
+}
3408
+
3409
+void
3410
+lock_destroy(struct lock *lock)
3411
+{
3412
+ DEBUGASSERT(lock != NULL);
3413
+ DEBUGASSERT(lock->lk_holder == NULL);
3414
+
3415
+ spinlock_cleanup(&lock->lk_lock);
3416
+ wchan_destroy(lock->lk_wchan);
3417
+
3418
+ kfree(lock->lk_name);
3419
+ kfree(lock);
3420
+}
3421
+
3422
+void
3423
+lock_acquire(struct lock *lock)
3424
+{
3425
+ DEBUGASSERT(lock != NULL);
3426
+ DEBUGASSERT(!(lock_do_i_hold(lock)));
3427
+ KASSERT(curthread->t_in_interrupt == false);
3428
+
3429
+ spinlock_acquire(&lock->lk_lock);
3430
+ while (lock->lk_holder != NULL) {
3431
+ wchan_lock(lock->lk_wchan);
3432
+ spinlock_release(&lock->lk_lock);
3433
+ wchan_sleep(lock->lk_wchan);
3434
+ spinlock_acquire(&lock->lk_lock);
3435
+ }
3436
+
3437
+ lock->lk_holder = curthread;
3438
+ spinlock_release(&lock->lk_lock);
3439
+}
3440
+
3441
+void
3442
+lock_release(struct lock *lock)
3443
+{
3444
+ DEBUGASSERT(lock_do_i_hold(lock));
3445
+
3446
+ spinlock_acquire(&lock->lk_lock);
3447
+ lock->lk_holder = NULL;
3448
+ wchan_wakeone(lock->lk_wchan);
3449
+ spinlock_release(&lock->lk_lock);
3450
+}
3451
+
3452
+bool
3453
+lock_do_i_hold(struct lock *lock)
3454
+{
3455
+ bool ret;
3456
+ DEBUGASSERT(lock != NULL);
3457
+
3458
+ spinlock_acquire(&lock->lk_lock);
3459
+ ret = (lock->lk_holder == curthread);
3460
+ spinlock_release(&lock->lk_lock);
3461
+
3462
+ return ret;
3463
+}
3464
+
3465
+////////////////////////////////////////////////////////////
3466
+//
3467
+// CV
3468
+
3469
+
3470
+struct cv *
3471
+cv_create(const char *name)
3472
+{
3473
+ struct cv *cv;
3474
+
3475
+ cv = kmalloc(sizeof(struct cv));
3476
+ if (cv == NULL) {
3477
+ return NULL;
3478
+ }
3479
+
3480
+ cv->cv_name = kstrdup(name);
3481
+ if (cv->cv_name==NULL) {
3482
+ kfree(cv);
3483
+ return NULL;
3484
+ }
3485
+
3486
+ cv->cv_wchan = wchan_create(cv->cv_name);
3487
+ if (cv->cv_wchan == NULL) {
3488
+ kfree(cv->cv_name);
3489
+ kfree(cv);
3490
+ return NULL;
3491
+ }
3492
+
3493
+ return cv;
3494
+}
3495
+
3496
+void
3497
+cv_destroy(struct cv *cv)
3498
+{
3499
+ KASSERT(cv != NULL);
3500
+
3501
+ wchan_destroy(cv->cv_wchan);
3502
+ kfree(cv->cv_name);
3503
+ kfree(cv);
3504
+}
3505
+
3506
+void
3507
+cv_wait(struct cv *cv, struct lock *lock)
3508
+{
3509
+ DEBUGASSERT(lock_do_i_hold(lock));
3510
+
3511
+ wchan_lock(cv->cv_wchan);
3512
+ lock_release(lock);
3513
+ wchan_sleep(cv->cv_wchan);
3514
+ lock_acquire(lock);
3515
+}
3516
+
3517
+void
3518
+cv_signal(struct cv *cv, struct lock *lock)
3519
+{
3520
+ DEBUGASSERT(lock_do_i_hold(lock));
3521
+
3522
+ wchan_wakeone(cv->cv_wchan);
3523
+}
3524
+
3525
+void
3526
+cv_broadcast(struct cv *cv, struct lock *lock)
3527
+{
3528
+ DEBUGASSERT(lock_do_i_hold(lock));
3529
+
3530
+ wchan_wakeall(cv->cv_wchan);
3531
+}
3532
diff --git a/patches/ASST1-sol/files/synch.h b/patches/ASST1-sol/files/synch.h
3533
new file mode 100644
3534
index 0000000..461eedc
3535
--- /dev/null
3536
+++ b/patches/ASST1-sol/files/synch.h
3537
@@ -0,0 +1,162 @@
3538
+/*
3539
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3540
+ * The President and Fellows of Harvard College.
3541
+ *
3542
+ * Redistribution and use in source and binary forms, with or without
3543
+ * modification, are permitted provided that the following conditions
3544
+ * are met:
3545
+ * 1. Redistributions of source code must retain the above copyright
3546
+ * notice, this list of conditions and the following disclaimer.
3547
+ * 2. Redistributions in binary form must reproduce the above copyright
3548
+ * notice, this list of conditions and the following disclaimer in the
3549
+ * documentation and/or other materials provided with the distribution.
3550
+ * 3. Neither the name of the University nor the names of its contributors
3551
+ * may be used to endorse or promote products derived from this software
3552
+ * without specific prior written permission.
3553
+ *
3554
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
3555
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3556
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3557
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
3558
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3559
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3560
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3561
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3562
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3563
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3564
+ * SUCH DAMAGE.
3565
+ */
3566
+
3567
+#ifndef _SYNCH_H_
3568
+#define _SYNCH_H_
3569
+
3570
+/*
3571
+ * Header file for synchronization primitives.
3572
+ */
3573
+
3574
+
3575
+#include <spinlock.h>
3576
+
3577
+/*
3578
+ * Dijkstra-style semaphore.
3579
+ *
3580
+ * The name field is for easier debugging. A copy of the name is made
3581
+ * internally.
3582
+ */
3583
+struct semaphore {
3584
+ char *sem_name;
3585
+ struct wchan *sem_wchan;
3586
+ struct spinlock sem_lock;
3587
+ volatile int sem_count;
3588
+};
3589
+
3590
+struct semaphore *sem_create(const char *name, int initial_count);
3591
+void sem_destroy(struct semaphore *);
3592
+
3593
+/*
3594
+ * Operations (both atomic):
3595
+ * P (proberen): decrement count. If the count is 0, block until
3596
+ * the count is 1 again before decrementing.
3597
+ * V (verhogen): increment count.
3598
+ */
3599
+void P(struct semaphore *);
3600
+void V(struct semaphore *);
3601
+
3602
+
3603
+/*
3604
+ * Simple lock for mutual exclusion.
3605
+ *
3606
+ * When the lock is created, no thread should be holding it. Likewise,
3607
+ * when the lock is destroyed, no thread should be holding it.
3608
+ *
3609
+ * The name field is for easier debugging. A copy of the name is
3610
+ * (should be) made internally.
3611
+ */
3612
+struct lock {
3613
+ char *lk_name;
3614
+
3615
+ // BEGIN SOLUTION
3616
+ struct wchan *lk_wchan;
3617
+ struct spinlock lk_lock;
3618
+ volatile struct thread *lk_holder;
3619
+ // END SOLUTION
3620
+};
3621
+
3622
+struct lock *lock_create(const char *name);
3623
+void lock_acquire(struct lock *);
3624
+
3625
+/*
3626
+ * Operations:
3627
+ * lock_acquire - Get the lock. Only one thread can hold the lock at the
3628
+ * same time.
3629
+ * lock_release - Free the lock. Only the thread holding the lock may do
3630
+ * this.
3631
+ * lock_do_i_hold - Return true if the current thread holds the lock;
3632
+ * false otherwise.
3633
+ *
3634
+ * These operations must be atomic. You get to write them.
3635
+ */
3636
+void lock_release(struct lock *);
3637
+bool lock_do_i_hold(struct lock *);
3638
+void lock_destroy(struct lock *);
3639
+
3640
+
3641
+/*
3642
+ * Condition variable.
3643
+ *
3644
+ * Note that the "variable" is a bit of a misnomer: a CV is normally used
3645
+ * to wait until a variable meets a particular condition, but there's no
3646
+ * actual variable, as such, in the CV.
3647
+ *
3648
+ * These CVs are expected to support Mesa semantics, that is, no
3649
+ * guarantees are made about scheduling.
3650
+ *
3651
+ * The name field is for easier debugging. A copy of the name is
3652
+ * (should be) made internally.
3653
+ */
3654
+
3655
+struct cv {
3656
+ char *cv_name;
3657
+
3658
+ // BEGIN SOLUTION
3659
+ struct wchan *cv_wchan;
3660
+ // END SOLUTION
3661
+};
3662
+
3663
+struct cv *cv_create(const char *name);
3664
+void cv_destroy(struct cv *);
3665
+
3666
+/*
3667
+ * Operations:
3668
+ * cv_wait - Release the supplied lock, go to sleep, and, after
3669
+ * waking up again, re-acquire the lock.
3670
+ * cv_signal - Wake up one thread that's sleeping on this CV.
3671
+ * cv_broadcast - Wake up all threads sleeping on this CV.
3672
+ *
3673
+ * For all three operations, the current thread must hold the lock passed
3674
+ * in. Note that under normal circumstances the same lock should be used
3675
+ * on all operations with any particular CV.
3676
+ *
3677
+ * These operations must be atomic. You get to write them.
3678
+ */
3679
+void cv_wait(struct cv *cv, struct lock *lock);
3680
+void cv_signal(struct cv *cv, struct lock *lock);
3681
+void cv_broadcast(struct cv *cv, struct lock *lock);
3682
+
3683
+/*
3684
+ * 13 Feb 2012 : GWA : Reader-writer locks.
3685
+ */
3686
+
3687
+struct rwlock {
3688
+ char *rwlock_name;
3689
+};
3690
+
3691
+struct rwlock * rwlock_create(const char *);
3692
+void rwlock_destroy(struct rwlock *);
3693
+
3694
+void rwlock_acquire_read(struct rwlock *);
3695
+void rwlock_release_read(struct rwlock *);
3696
+void rwlock_acquire_write(struct rwlock *);
3697
+void rwlock_release_write(struct rwlock *);
3698
+
3699
+#endif /* _SYNCH_H_ */
3700
diff --git a/patches/ASST1-sol/files/version.h b/patches/ASST1-sol/files/version.h
3701
new file mode 100644
3702
index 0000000..4734a98
3703
--- /dev/null
3704
+++ b/patches/ASST1-sol/files/version.h
3705
@@ -0,0 +1,46 @@
3706
+/*
3707
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3708
+ * The President and Fellows of Harvard College.
3709
+ *
3710
+ * Redistribution and use in source and binary forms, with or without
3711
+ * modification, are permitted provided that the following conditions
3712
+ * are met:
3713
+ * 1. Redistributions of source code must retain the above copyright
3714
+ * notice, this list of conditions and the following disclaimer.
3715
+ * 2. Redistributions in binary form must reproduce the above copyright
3716
+ * notice, this list of conditions and the following disclaimer in the
3717
+ * documentation and/or other materials provided with the distribution.
3718
+ * 3. Neither the name of the University nor the names of its contributors
3719
+ * may be used to endorse or promote products derived from this software
3720
+ * without specific prior written permission.
3721
+ *
3722
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
3723
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3724
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3725
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
3726
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3727
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3728
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3729
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3730
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3731
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3732
+ * SUCH DAMAGE.
3733
+ */
3734
+
3735
+#ifndef _VERSION_H_
3736
+#define _VERSION_H_
3737
+
3738
+/*
3739
+ * Leave this alone, so we can tell what version of the OS/161 base
3740
+ * code we gave you.
3741
+ */
3742
+#define BASE_VERSION "1.99.05"
3743
+#define ASST1SOL_VERSION "1.0"
3744
+
3745
+/*
3746
+ * Change this as you see fit in the course of hacking the system.
3747
+ */
3748
+#define GROUP_VERSION "0"
3749
+
3750
+
3751
+#endif /* _VERSION_H_ */
3752
diff --git a/patches/ASST1-sol/sol10.patch b/patches/ASST1-sol/sol10.patch
3753
new file mode 100644
3754
index 0000000..6dea880
3755
--- /dev/null
3756
+++ b/patches/ASST1-sol/sol10.patch
3757
@@ -0,0 +1,220 @@
3758
+diff --git a/kern/include/synch.h b/kern/include/synch.h
3759
+index ac3714b..461eedc 100644
3760
+--- a/kern/include/synch.h
3761
++++ b/kern/include/synch.h
3762
+@@ -74,8 +74,12 @@ void V(struct semaphore *);
3763
+ */
3764
+ struct lock {
3765
+ char *lk_name;
3766
+- // add what you need here
3767
+- // (don't forget to mark things volatile as needed)
3768
++
3769
++ // BEGIN SOLUTION
3770
++ struct wchan *lk_wchan;
3771
++ struct spinlock lk_lock;
3772
++ volatile struct thread *lk_holder;
3773
++ // END SOLUTION
3774
+ };
3775
+
3776
+ struct lock *lock_create(const char *name);
3777
+@@ -113,8 +117,10 @@ void lock_destroy(struct lock *);
3778
+
3779
+ struct cv {
3780
+ char *cv_name;
3781
+- // add what you need here
3782
+- // (don't forget to mark things volatile as needed)
3783
++
3784
++ // BEGIN SOLUTION
3785
++ struct wchan *cv_wchan;
3786
++ // END SOLUTION
3787
+ };
3788
+
3789
+ struct cv *cv_create(const char *name);
3790
+diff --git a/kern/include/version.h b/kern/include/version.h
3791
+index 9fec0e8..4734a98 100644
3792
+--- a/kern/include/version.h
3793
++++ b/kern/include/version.h
3794
+@@ -35,6 +35,7 @@
3795
+ * code we gave you.
3796
+ */
3797
+ #define BASE_VERSION "1.99.05"
3798
++#define ASST1SOL_VERSION "1.0"
3799
+
3800
+ /*
3801
+ * Change this as you see fit in the course of hacking the system.
3802
+diff --git a/kern/startup/main.c b/kern/startup/main.c
3803
+index be4c4b8..535a864 100644
3804
+--- a/kern/startup/main.c
3805
++++ b/kern/startup/main.c
3806
+@@ -96,7 +96,7 @@ boot(void)
3807
+ */
3808
+
3809
+ kprintf("\n");
3810
+- kprintf("OS/161 base system version %s\n", BASE_VERSION);
3811
++ kprintf("OS/161 base version %s ASST1 solution version %s\n", BASE_VERSION, ASST1SOL_VERSION);
3812
+ kprintf("%s", harvard_copyright);
3813
+ kprintf("\n");
3814
+
3815
+diff --git a/kern/thread/synch.c b/kern/thread/synch.c
3816
+index 9a7468c..fb983b4 100644
3817
+--- a/kern/thread/synch.c
3818
++++ b/kern/thread/synch.c
3819
+@@ -163,7 +163,16 @@ lock_create(const char *name)
3820
+ return NULL;
3821
+ }
3822
+
3823
+- // add stuff here as needed
3824
++ // BEGIN SOLUTION
3825
++ lock->lk_wchan = wchan_create(lock->lk_name);
3826
++ if (lock->lk_wchan == NULL) {
3827
++ kfree(lock->lk_name);
3828
++ kfree(lock);
3829
++ return NULL;
3830
++ }
3831
++ spinlock_init(&lock->lk_lock);
3832
++ lock->lk_holder = NULL;
3833
++ // END SOLUTION
3834
+
3835
+ return lock;
3836
+ }
3837
+@@ -173,7 +182,11 @@ lock_destroy(struct lock *lock)
3838
+ {
3839
+ KASSERT(lock != NULL);
3840
+
3841
+- // add stuff here as needed
3842
++ // BEGIN SOLUTION
3843
++ KASSERT(lock->lk_holder == NULL);
3844
++ spinlock_cleanup(&lock->lk_lock);
3845
++ wchan_destroy(lock->lk_wchan);
3846
++ // END SOLUTION
3847
+
3848
+ kfree(lock->lk_name);
3849
+ kfree(lock);
3850
+@@ -182,27 +195,52 @@ lock_destroy(struct lock *lock)
3851
+ void
3852
+ lock_acquire(struct lock *lock)
3853
+ {
3854
+- // Write this
3855
++ // BEGIN SOLUTION
3856
++ DEBUGASSERT(lock != NULL);
3857
++ KASSERT(curthread->t_in_interrupt == false);
3858
++
3859
++ spinlock_acquire(&lock->lk_lock);
3860
++ while (lock->lk_holder != NULL) {
3861
++ /* As in the semaphore. */
3862
++ wchan_lock(lock->lk_wchan);
3863
++ spinlock_release(&lock->lk_lock);
3864
++ wchan_sleep(lock->lk_wchan);
3865
++
3866
++ spinlock_acquire(&lock->lk_lock);
3867
++ }
3868
+
3869
+- (void)lock; // suppress warning until code gets written
3870
++ lock->lk_holder = curthread;
3871
++ spinlock_release(&lock->lk_lock);
3872
++ // END SOLUTION
3873
+ }
3874
+
3875
+ void
3876
+ lock_release(struct lock *lock)
3877
+ {
3878
+- // Write this
3879
+-
3880
+- (void)lock; // suppress warning until code gets written
3881
++ // BEGIN SOLUTION
3882
++ DEBUGASSERT(lock != NULL);
3883
++
3884
++ spinlock_acquire(&lock->lk_lock);
3885
++ lock->lk_holder = NULL;
3886
++ wchan_wakeone(lock->lk_wchan);
3887
++ spinlock_release(&lock->lk_lock);
3888
++ // END SOLUTION
3889
+ }
3890
+
3891
+ bool
3892
+ lock_do_i_hold(struct lock *lock)
3893
+ {
3894
+- // Write this
3895
++ // BEGIN SOLUTION
3896
++ bool ret;
3897
+
3898
+- (void)lock; // suppress warning until code gets written
3899
++ DEBUGASSERT(lock != NULL);
3900
+
3901
+- return true; // dummy until code gets written
3902
++ spinlock_acquire(&lock->lk_lock);
3903
++ ret = (lock->lk_holder == curthread);
3904
++ spinlock_release(&lock->lk_lock);
3905
++
3906
++ return ret;
3907
++ // END SOLUTION
3908
+ }
3909
+
3910
+ ////////////////////////////////////////////////////////////
3911
+@@ -226,7 +264,14 @@ cv_create(const char *name)
3912
+ return NULL;
3913
+ }
3914
+
3915
+- // add stuff here as needed
3916
++ // BEGIN SOLUTION
3917
++ cv->cv_wchan = wchan_create(cv->cv_name);
3918
++ if (cv->cv_wchan == NULL) {
3919
++ kfree(cv->cv_name);
3920
++ kfree(cv);
3921
++ return NULL;
3922
++ }
3923
++ // END SOLUTION
3924
+
3925
+ return cv;
3926
+ }
3927
+@@ -236,7 +281,9 @@ cv_destroy(struct cv *cv)
3928
+ {
3929
+ KASSERT(cv != NULL);
3930
+
3931
+- // add stuff here as needed
3932
++ // BEGIN SOLUTION
3933
++ wchan_destroy(cv->cv_wchan);
3934
++ // END SOLUTION
3935
+
3936
+ kfree(cv->cv_name);
3937
+ kfree(cv);
3938
+@@ -245,23 +292,28 @@ cv_destroy(struct cv *cv)
3939
+ void
3940
+ cv_wait(struct cv *cv, struct lock *lock)
3941
+ {
3942
+- // Write this
3943
+- (void)cv; // suppress warning until code gets written
3944
+- (void)lock; // suppress warning until code gets written
3945
++ // BEGIN SOLUTION
3946
++ wchan_lock(cv->cv_wchan);
3947
++ lock_release(lock);
3948
++ wchan_sleep(cv->cv_wchan);
3949
++ lock_release(lock);
3950
++ // END SOLUTION
3951
+ }
3952
+-
3953
++
3954
+ void
3955
+ cv_signal(struct cv *cv, struct lock *lock)
3956
+ {
3957
+- // Write this
3958
+- (void)cv; // suppress warning until code gets written
3959
+- (void)lock; // suppress warning until code gets written
3960
++ // BEGIN SOLUTION
3961
++ (void)lock;
3962
++ wchan_wakeone(cv->cv_wchan);
3963
++ // END SOLUTION
3964
+ }
3965
+-
3966
++
3967
+ void
3968
+ cv_broadcast(struct cv *cv, struct lock *lock)
3969
+ {
3970
+- // Write this
3971
+- (void)cv; // suppress warning until code gets written
3972
+- (void)lock; // suppress warning until code gets written
3973
++ // BEGIN SOLUTION
3974
++ (void)lock;
3975
++ wchan_wakeall(cv->cv_wchan);
3976
++ // END SOLUTION
3977
+ }
3978
diff --git a/user/testbin/Makefile b/user/testbin/Makefile
3979
index c3b97a8..d02221f 100644
3980
--- a/user/testbin/Makefile
3981
+++ b/user/testbin/Makefile
3982
@@ -6,10 +6,10 @@ TOP=../..
3983
.include "$(TOP)/mk/os161.config.mk"
3984
3985
SUBDIRS=add argtest badcall bigfile conman crash ctest dirconc dirseek \
3986
- dirtest f_test farm faulter filetest forkbomb forktest guzzle \
3987
+ dirtest f_test farm faulter fileonlytest filetest forkbomb forktest guzzle \
3988
hash hog huge kitchen malloctest matmult palin parallelvm psort \
3989
randcall rmdirtest rmtest sink sort sty tail tictac triplehuge \
3990
- triplemat triplesort
3991
+ triplemat triplesort ft1 ft2 ft3 ft4 pt1 pt2 pt3 pt4 pt5
3992
3993
# But not:
3994
# userthreads (no support in kernel API in base system)
3995
diff --git a/user/testbin/badcall/bad_execv.c b/user/testbin/badcall/bad_execv.c
3996
index 287a678..2312381 100644
3997
--- a/user/testbin/badcall/bad_execv.c
3998
+++ b/user/testbin/badcall/bad_execv.c
3999
@@ -34,6 +34,7 @@
4000
#include <sys/types.h>
4001
#include <stdlib.h>
4002
#include <unistd.h>
4003
+#include <stdio.h>
4004
#include <errno.h>
4005
#include <err.h>
4006
4007
@@ -62,6 +63,7 @@ exec_common_fork(void)
4008
warn("UH-OH: waitpid failed");
4009
return -1;
4010
}
4011
+
4012
if (!WIFEXITED(status) || WEXITSTATUS(status) != MAGIC_STATUS) {
4013
warnx("FAILURE: wrong exit code of subprocess");
4014
}
4015
diff --git a/user/testbin/fileonlytest/Makefile b/user/testbin/fileonlytest/Makefile
4016
new file mode 100644
4017
index 0000000..156fc41
4018
--- /dev/null
4019
+++ b/user/testbin/fileonlytest/Makefile
4020
@@ -0,0 +1,11 @@
4021
+# Makefile for fileonlytest
4022
+
4023
+TOP=../../..
4024
+.include "$(TOP)/mk/os161.config.mk"
4025
+
4026
+PROG=fileonlytest
4027
+SRCS=fileonlytest.c
4028
+BINDIR=/testbin
4029
+
4030
+.include "$(TOP)/mk/os161.prog.mk"
4031
+
4032
diff --git a/user/testbin/fileonlytest/fileonlytest.c b/user/testbin/fileonlytest/fileonlytest.c
4033
new file mode 100644
4034
index 0000000..b807ff6
4035
--- /dev/null
4036
+++ b/user/testbin/fileonlytest/fileonlytest.c
4037
@@ -0,0 +1,167 @@
4038
+/*
4039
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
4040
+ * The President and Fellows of Harvard College.
4041
+ *
4042
+ * Redistribution and use in source and binary forms, with or without
4043
+ * modification, are permitted provided that the following conditions
4044
+ * are met:
4045
+ * 1. Redistributions of source code must retain the above copyright
4046
+ * notice, this list of conditions and the following disclaimer.
4047
+ * 2. Redistributions in binary form must reproduce the above copyright
4048
+ * notice, this list of conditions and the following disclaimer in the
4049
+ * documentation and/or other materials provided with the distribution.
4050
+ * 3. Neither the name of the University nor the names of its contributors
4051
+ * may be used to endorse or promote products derived from this software
4052
+ * without specific prior written permission.
4053
+ *
4054
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
4055
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4056
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4057
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
4058
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4059
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4060
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4061
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4062
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4063
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4064
+ * SUCH DAMAGE.
4065
+ */
4066
+
4067
+/*
4068
+ * rmtest.c
4069
+ *
4070
+ * Tests file system synchronization by deleting an open file and
4071
+ * then attempting to read it.
4072
+ *
4073
+ * This should run correctly when the file system assignment is complete.
4074
+ */
4075
+
4076
+#include <stdlib.h>
4077
+#include <stdio.h>
4078
+#include <string.h>
4079
+#include <unistd.h>
4080
+#include <err.h>
4081
+
4082
+// 23 Mar 2012 : GWA : BUFFER_COUNT must be even.
4083
+
4084
+#define BUFFER_COUNT 128
4085
+#define BUFFER_SIZE 128
4086
+
4087
+static int writebuf[BUFFER_SIZE];
4088
+static int readbuf[BUFFER_SIZE];
4089
+
4090
+int
4091
+main(int argc, char **argv)
4092
+{
4093
+
4094
+ // 23 Mar 2012 : GWA : Assume argument passing is *not* supported.
4095
+
4096
+ (void) argc;
4097
+ (void) argv;
4098
+ int i, j;
4099
+ int fh, len;
4100
+ off_t pos, target;
4101
+
4102
+ const char * filename = "fileonlytest.dat";
4103
+
4104
+ // 23 Mar 2012 : GWA : Test that open works.
4105
+
4106
+ printf("Opening %s\n", filename);
4107
+
4108
+ fh = open(filename, O_RDWR|O_CREAT|O_TRUNC);
4109
+ if (fh < 0) {
4110
+ err(1, "create failed");
4111
+ }
4112
+
4113
+ printf("Writing %d bytes.\n", BUFFER_SIZE * BUFFER_COUNT);
4114
+
4115
+ // 23 Mar 2012 : GWA : Do the even-numbered writes. Test read() and
4116
+ // lseek(SEEK_END).
4117
+
4118
+ for (i = 0; i < BUFFER_COUNT / 2; i++) {
4119
+ for (j = 0; j < BUFFER_SIZE; j++) {
4120
+ writebuf[j] = i * 2 * j;
4121
+ }
4122
+ len = write(fh, writebuf, sizeof(writebuf));
4123
+ if (len != sizeof(writebuf)) {
4124
+ err(1, "write failed");
4125
+ }
4126
+
4127
+ // 23 Mar 2012 : GWA : Use lseek() to skip the odd guys.
4128
+
4129
+ target = (i + 1) * 2 * sizeof(writebuf);
4130
+ pos = lseek(fh, sizeof(writebuf), SEEK_END);
4131
+ if (pos != target) {
4132
+ err(1, "(even) lseek failed: %llu != %llu", pos, target);
4133
+ }
4134
+ }
4135
+
4136
+ target = 0;
4137
+ pos = lseek(fh, target, SEEK_SET);
4138
+ if (pos != target) {
4139
+ err(1, "(reset) lseek failed: %llu != %llu", pos, target);
4140
+ }
4141
+
4142
+ // 23 Mar 2012 : GWA : Do the odd-numbered writes. Test write() and
4143
+ // lseek(SEEK_CUR).
4144
+
4145
+ for (i = 0; i < BUFFER_COUNT / 2; i++) {
4146
+
4147
+ // 23 Mar 2012 : GWA : Use lseek() to skip the even guys.
4148
+
4149
+ target = ((i * 2) + 1) * sizeof(writebuf);
4150
+ pos = lseek(fh, sizeof(writebuf), SEEK_CUR);
4151
+ if (pos != target) {
4152
+ err(1, "(odd) lseek failed: %llu != %llu", pos, target);
4153
+ }
4154
+
4155
+ for (j = 0; j < BUFFER_SIZE; j++) {
4156
+ writebuf[j] = ((i * 2) + 1) * j;
4157
+ }
4158
+ len = write(fh, writebuf, sizeof(writebuf));
4159
+ if (len != sizeof(writebuf)) {
4160
+ err(1, "write failed");
4161
+ }
4162
+ }
4163
+
4164
+ // 23 Mar 2012 : GWA : Read the test data back and make sure what we wrote
4165
+ // ended up where we wrote it. Tests read() and lseek(SEEK_SET).
4166
+
4167
+ printf("Verifying write.\n");
4168
+
4169
+ for (i = BUFFER_COUNT - 1; i >= 0; i--) {
4170
+ target = i * sizeof(writebuf);
4171
+ pos = lseek(fh, target, SEEK_SET);
4172
+ if (pos != target) {
4173
+ err(1, "(verify) lseek failed: %llu != %llu", pos, target);
4174
+ }
4175
+ len = read(fh, readbuf, sizeof(readbuf));
4176
+ if (len != sizeof(readbuf)) {
4177
+ err(1, "read failed");
4178
+ }
4179
+ for (j = BUFFER_SIZE - 1; j >= 0; j--) {
4180
+ if (readbuf[j] != i * j) {
4181
+ err(1, "read mismatch: pos=%llu, readbuf[j]=%d, i*j=%d, i=%d, j=%d", pos, readbuf[j], i * j, i, j);
4182
+ }
4183
+ }
4184
+ }
4185
+
4186
+ // 23 Mar 2012 : GWA : Close the file.
4187
+
4188
+ printf("Closing %s\n", filename);
4189
+ close(fh);
4190
+
4191
+ // 23 Mar 2012 : GWA : Make sure the file is actually closed.
4192
+
4193
+ pos = lseek(fh, (off_t) 0, SEEK_SET);
4194
+ if (pos == 0) {
4195
+ err(1, "seek after close succeeded");
4196
+ }
4197
+
4198
+ // 23 Mar 2012 : GWA : FIXME : Spin until exit() works.
4199
+
4200
+ printf("Spinning in case exit() doesn't work.\n");
4201
+ while (1) {};
4202
+
4203
+ return 0;
4204
+}
4205
diff --git a/user/testbin/ft1/Makefile b/user/testbin/ft1/Makefile
4206
new file mode 100644
4207
index 0000000..318ed15
4208
--- /dev/null
4209
+++ b/user/testbin/ft1/Makefile
4210
@@ -0,0 +1,11 @@
4211
+# Makefile for tail
4212
+
4213
+TOP=../../..
4214
+.include "$(TOP)/mk/os161.config.mk"
4215
+
4216
+PROG=ft1
4217
+SRCS=ft1.c
4218
+BINDIR=/testbin
4219
+
4220
+.include "$(TOP)/mk/os161.prog.mk"
4221
+
4222
diff --git a/user/testbin/ft1/ft1.c b/user/testbin/ft1/ft1.c
4223
new file mode 100644
4224
index 0000000..17b110a
4225
--- /dev/null
4226
+++ b/user/testbin/ft1/ft1.c
4227
@@ -0,0 +1,24 @@
4228
+#include <unistd.h>
4229
+#include <stdio.h>
4230
+#include <stdlib.h>
4231
+
4232
+int main( int argc, char *argv[] ) {
4233
+ int fd_stdout = 0;
4234
+
4235
+ (void)argc;
4236
+ (void)argv;
4237
+
4238
+ //attempt to open stdout
4239
+ fd_stdout = open( "con:", O_WRONLY );
4240
+ if( fd_stdout == -1 )
4241
+ return -1;
4242
+
4243
+ //now we can write
4244
+ char message[] = "Hello World!";
4245
+ write( fd_stdout, message, sizeof( message ) );
4246
+
4247
+ //close the file
4248
+ close( fd_stdout );
4249
+
4250
+ return 0;
4251
+}
4252
diff --git a/user/testbin/ft2/Makefile b/user/testbin/ft2/Makefile
4253
new file mode 100644
4254
index 0000000..8662011
4255
--- /dev/null
4256
+++ b/user/testbin/ft2/Makefile
4257
@@ -0,0 +1,11 @@
4258
+# Makefile for tail
4259
+
4260
+TOP=../../..
4261
+.include "$(TOP)/mk/os161.config.mk"
4262
+
4263
+PROG=ft2
4264
+SRCS=ft2.c
4265
+BINDIR=/testbin
4266
+
4267
+.include "$(TOP)/mk/os161.prog.mk"
4268
+
4269
diff --git a/user/testbin/ft2/ft2.c b/user/testbin/ft2/ft2.c
4270
new file mode 100644
4271
index 0000000..c9f8020
4272
--- /dev/null
4273
+++ b/user/testbin/ft2/ft2.c
4274
@@ -0,0 +1,37 @@
4275
+#include <unistd.h>
4276
+#include <stdio.h>
4277
+#include <stdlib.h>
4278
+
4279
+#define BUF_SIZE 128
4280
+
4281
+int main( int argc, char *argv[] ) {
4282
+ int fd_stdout;
4283
+ int fd_in;
4284
+ char buf[BUF_SIZE];
4285
+ int nread;
4286
+
4287
+ (void)argc;
4288
+ (void)argv;
4289
+
4290
+ //attempt to open stdout
4291
+ fd_stdout = open( "con:", O_WRONLY );
4292
+ if( fd_stdout == -1 )
4293
+ return -1;
4294
+
4295
+ //attempt to open input file
4296
+ fd_in = open( "/hello.txt", O_RDONLY );
4297
+ if( fd_in == -1 ) {
4298
+ close( fd_stdout );
4299
+ return -1;
4300
+ }
4301
+
4302
+ //read and output to stdout
4303
+ while( ( nread = read( fd_in, buf, sizeof( buf ) ) ) > 0 )
4304
+ write( fd_stdout, buf, nread );
4305
+
4306
+ //close the files
4307
+ close( fd_in );
4308
+ close( fd_stdout );
4309
+
4310
+ return 0;
4311
+}
4312
diff --git a/user/testbin/ft3/Makefile b/user/testbin/ft3/Makefile
4313
new file mode 100644
4314
index 0000000..0ba365b
4315
--- /dev/null
4316
+++ b/user/testbin/ft3/Makefile
4317
@@ -0,0 +1,11 @@
4318
+# Makefile for tail
4319
+
4320
+TOP=../../..
4321
+.include "$(TOP)/mk/os161.config.mk"
4322
+
4323
+PROG=ft3
4324
+SRCS=ft3.c
4325
+BINDIR=/testbin
4326
+
4327
+.include "$(TOP)/mk/os161.prog.mk"
4328
+
4329
diff --git a/user/testbin/ft3/ft3.c b/user/testbin/ft3/ft3.c
4330
new file mode 100644
4331
index 0000000..8a96c0e
4332
--- /dev/null
4333
+++ b/user/testbin/ft3/ft3.c
4334
@@ -0,0 +1,42 @@
4335
+#include <unistd.h>
4336
+#include <stdio.h>
4337
+#include <stdlib.h>
4338
+
4339
+#define BUF_SIZE 128
4340
+
4341
+int main( int argc, char *argv[] ) {
4342
+ int fd_out;
4343
+ int err;
4344
+
4345
+ (void)argc;
4346
+ (void)argv;
4347
+
4348
+ //try to open a sample output file.
4349
+ fd_out = open( "/hello.txt", O_WRONLY );
4350
+ if( fd_out < 0 ) {
4351
+ printf( "open: error opening the file." );
4352
+ return -1;
4353
+ }
4354
+
4355
+ //close stdout.
4356
+ err = close( STDOUT_FILENO );
4357
+ if( err ) {
4358
+ printf( "close: could not close stdout." );
4359
+ return -1;
4360
+ }
4361
+
4362
+ //route stdout to fd_out.
4363
+ dup2( fd_out, STDOUT_FILENO );
4364
+
4365
+ //print a sample message to STDOUT.
4366
+ //this should end up inside the file.
4367
+ printf( "I should be seeing this message inside hello.txt\n" );
4368
+
4369
+ //close fd_out
4370
+ err = close( fd_out );
4371
+ if( err )
4372
+ return err;
4373
+
4374
+ //stdout will be closed by exit().
4375
+ return 0;
4376
+}
4377
diff --git a/user/testbin/ft4/Makefile b/user/testbin/ft4/Makefile
4378
new file mode 100644
4379
index 0000000..6d532e4
4380
--- /dev/null
4381
+++ b/user/testbin/ft4/Makefile
4382
@@ -0,0 +1,11 @@
4383
+# Makefile for tail
4384
+
4385
+TOP=../../..
4386
+.include "$(TOP)/mk/os161.config.mk"
4387
+
4388
+PROG=ft4
4389
+SRCS=ft4.c
4390
+BINDIR=/testbin
4391
+
4392
+.include "$(TOP)/mk/os161.prog.mk"
4393
+
4394
diff --git a/user/testbin/ft4/ft4.c b/user/testbin/ft4/ft4.c
4395
new file mode 100644
4396
index 0000000..3b18e6a
4397
--- /dev/null
4398
+++ b/user/testbin/ft4/ft4.c
4399
@@ -0,0 +1,37 @@
4400
+#include <unistd.h>
4401
+#include <stdio.h>
4402
+#include <stdlib.h>
4403
+
4404
+#define BUF_SIZE 128
4405
+
4406
+static
4407
+int
4408
+test_chdir( const char *path ) {
4409
+ int err;
4410
+
4411
+ putchar( '\n' );
4412
+
4413
+ printf( "attempting to switch directories to %s\n", path );
4414
+ err = chdir( path );
4415
+ if( err ) {
4416
+ printf( "failed to switch directories to %s\n", path );
4417
+ return -1;
4418
+ }
4419
+
4420
+ printf( "successfully switched to %s\n", path );
4421
+ return 0;
4422
+}
4423
+
4424
+int main( int argc, char *argv[] ) {
4425
+ (void)argc;
4426
+ (void)argv;
4427
+
4428
+ if( test_chdir( "/testbin" ) )
4429
+ return -1;
4430
+
4431
+ if( test_chdir( "/" ) )
4432
+ return -1;
4433
+
4434
+
4435
+ return 0;
4436
+}
4437
diff --git a/user/testbin/pt1/Makefile b/user/testbin/pt1/Makefile
4438
new file mode 100644
4439
index 0000000..6ba378a
4440
--- /dev/null
4441
+++ b/user/testbin/pt1/Makefile
4442
@@ -0,0 +1,11 @@
4443
+# Makefile for tail
4444
+
4445
+TOP=../../..
4446
+.include "$(TOP)/mk/os161.config.mk"
4447
+
4448
+PROG=pt1
4449
+SRCS=pt1.c
4450
+BINDIR=/testbin
4451
+
4452
+.include "$(TOP)/mk/os161.prog.mk"
4453
+
4454
diff --git a/user/testbin/pt1/pt1.c b/user/testbin/pt1/pt1.c
4455
new file mode 100644
4456
index 0000000..edae1a7
4457
--- /dev/null
4458
+++ b/user/testbin/pt1/pt1.c
4459
@@ -0,0 +1,11 @@
4460
+#include <unistd.h>
4461
+#include <stdio.h>
4462
+#include <stdlib.h>
4463
+
4464
+int main( int argc, char *argv[] ) {
4465
+ (void)argc;
4466
+ (void)argv;
4467
+
4468
+ printf( "my pid is %d\n", getpid() );
4469
+ return 0;
4470
+}
4471
diff --git a/user/testbin/pt2/Makefile b/user/testbin/pt2/Makefile
4472
new file mode 100644
4473
index 0000000..515e24e
4474
--- /dev/null
4475
+++ b/user/testbin/pt2/Makefile
4476
@@ -0,0 +1,11 @@
4477
+# Makefile for tail
4478
+
4479
+TOP=../../..
4480
+.include "$(TOP)/mk/os161.config.mk"
4481
+
4482
+PROG=pt2
4483
+SRCS=pt2.c
4484
+BINDIR=/testbin
4485
+
4486
+.include "$(TOP)/mk/os161.prog.mk"
4487
+
4488
diff --git a/user/testbin/pt2/pt2.c b/user/testbin/pt2/pt2.c
4489
new file mode 100644
4490
index 0000000..5b0a41e
4491
--- /dev/null
4492
+++ b/user/testbin/pt2/pt2.c
4493
@@ -0,0 +1,23 @@
4494
+#include <unistd.h>
4495
+#include <sys/wait.h>
4496
+#include <stdio.h>
4497
+#include <stdlib.h>
4498
+
4499
+int main( int argc, char *argv[] ) {
4500
+ pid_t pid;
4501
+ int res;
4502
+
4503
+ (void)argc;
4504
+ (void)argv;
4505
+
4506
+ pid = fork();
4507
+ if( pid == 0 ) {
4508
+ printf( "Hi. I'm the child. My PID is: %d\n", getpid() );
4509
+ }
4510
+ else {
4511
+ waitpid( pid, &res, 0 );
4512
+ printf( "Hi. I'm the parent. My child returned: %d\n", res );
4513
+ }
4514
+
4515
+ return 0;
4516
+}
4517
diff --git a/user/testbin/pt3/Makefile b/user/testbin/pt3/Makefile
4518
new file mode 100644
4519
index 0000000..2cc84f9
4520
--- /dev/null
4521
+++ b/user/testbin/pt3/Makefile
4522
@@ -0,0 +1,11 @@
4523
+# Makefile for tail
4524
+
4525
+TOP=../../..
4526
+.include "$(TOP)/mk/os161.config.mk"
4527
+
4528
+PROG=pt3
4529
+SRCS=pt3.c
4530
+BINDIR=/testbin
4531
+
4532
+.include "$(TOP)/mk/os161.prog.mk"
4533
+
4534
diff --git a/user/testbin/pt3/pt3.c b/user/testbin/pt3/pt3.c
4535
new file mode 100644
4536
index 0000000..07da59f
4537
--- /dev/null
4538
+++ b/user/testbin/pt3/pt3.c
4539
@@ -0,0 +1,30 @@
4540
+#include <unistd.h>
4541
+#include <sys/wait.h>
4542
+#include <stdio.h>
4543
+#include <stdlib.h>
4544
+
4545
+int main( int argc, char *argv[] ) {
4546
+ pid_t pid;
4547
+ int res;
4548
+ const char *args[] = { "hello", "world", NULL };
4549
+
4550
+ (void)argc;
4551
+ (void)argv;
4552
+
4553
+ pid = fork();
4554
+ if( pid == 0 ) {
4555
+ printf( "Hi. I'm the child. My PID is: %d\n", getpid() );
4556
+ printf( "I'm about to call exec ....\n" );
4557
+ res = execv( "/testbin/pt1", (char **)args );
4558
+ if( res ) {
4559
+ printf( "execv failed." );
4560
+ return -1;
4561
+ }
4562
+ }
4563
+ else {
4564
+ waitpid( pid, &res, 0 );
4565
+ printf( "Hi. I'm the parent. My child returned: %d\n", res );
4566
+ }
4567
+
4568
+ return 0;
4569
+}
4570
diff --git a/user/testbin/pt4/Makefile b/user/testbin/pt4/Makefile
4571
new file mode 100644
4572
index 0000000..9ac3773
4573
--- /dev/null
4574
+++ b/user/testbin/pt4/Makefile
4575
@@ -0,0 +1,11 @@
4576
+# Makefile for tail
4577
+
4578
+TOP=../../..
4579
+.include "$(TOP)/mk/os161.config.mk"
4580
+
4581
+PROG=pt4
4582
+SRCS=pt4.c
4583
+BINDIR=/testbin
4584
+
4585
+.include "$(TOP)/mk/os161.prog.mk"
4586
+
4587
diff --git a/user/testbin/pt4/pt4.c b/user/testbin/pt4/pt4.c
4588
new file mode 100644
4589
index 0000000..60867c8
4590
--- /dev/null
4591
+++ b/user/testbin/pt4/pt4.c
4592
@@ -0,0 +1,16 @@
4593
+#include <unistd.h>
4594
+#include <sys/wait.h>
4595
+#include <stdio.h>
4596
+#include <stdlib.h>
4597
+
4598
+int main( int argc, char *argv[] ) {
4599
+ const char *args[] = { "foo", "os161", "execv", NULL };
4600
+
4601
+ (void) argc;
4602
+ (void) argv;
4603
+
4604
+ printf( "about to call execv\n" );
4605
+ execv( "/testbin/pt5", (char **)args );
4606
+
4607
+ return 0;
4608
+}
4609
diff --git a/user/testbin/pt5/Makefile b/user/testbin/pt5/Makefile
4610
new file mode 100644
4611
index 0000000..8fc5a80
4612
--- /dev/null
4613
+++ b/user/testbin/pt5/Makefile
4614
@@ -0,0 +1,11 @@
4615
+# Makefile for tail
4616
+
4617
+TOP=../../..
4618
+.include "$(TOP)/mk/os161.config.mk"
4619
+
4620
+PROG=pt5
4621
+SRCS=pt5.c
4622
+BINDIR=/testbin
4623
+
4624
+.include "$(TOP)/mk/os161.prog.mk"
4625
+
4626
diff --git a/user/testbin/pt5/pt5.c b/user/testbin/pt5/pt5.c
4627
new file mode 100644
4628
index 0000000..2e25a4f
4629
--- /dev/null
4630
+++ b/user/testbin/pt5/pt5.c
4631
@@ -0,0 +1,16 @@
4632
+#include <unistd.h>
4633
+#include <sys/wait.h>
4634
+#include <stdio.h>
4635
+#include <stdlib.h>
4636
+
4637
+int main( int argc, char *argv[] ) {
4638
+ int i;
4639
+
4640
+ printf( "\ngot %d arguments\n", argc );
4641
+ printf( "the address of argv is: %p\n", argv );
4642
+
4643
+ for( i = 0; i < argc; ++i )
4644
+ printf( "argv[%d] = %s\n", i, argv[i] );
4645
+
4646
+ return 0;
4647
+}
4648
4649