summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore1
-rw-r--r--src/Make.config4
-rw-r--r--src/devices/timer.c49
-rw-r--r--src/examples/Makefile10
-rw-r--r--src/examples/args.c12
-rw-r--r--src/examples/create.c29
-rw-r--r--src/examples/read.c22
-rw-r--r--src/examples/wait.c13
-rw-r--r--src/filesys/file.c7
-rw-r--r--src/filesys/filesys.c19
-rw-r--r--src/filesys/free-map.c10
-rw-r--r--src/filesys/inode.c45
-rw-r--r--src/lib/pid_t.h15
-rw-r--r--src/lib/user/syscall.h4
-rw-r--r--src/tests/Make.tests2
-rw-r--r--src/tests/userprog/Make.tests28
-rw-r--r--src/threads/synch.c40
-rw-r--r--src/threads/synch.h17
-rw-r--r--src/threads/thread.c4
-rw-r--r--src/threads/thread.h26
-rw-r--r--src/userprog/Make.vars2
-rw-r--r--src/userprog/process.c177
-rwxr-xr-x[-rw-r--r--]src/userprog/start_pfs.sh4
-rwxr-xr-x[-rw-r--r--]src/userprog/start_recursor.sh10
-rw-r--r--src/userprog/syscall.c334
-rwxr-xr-x[-rw-r--r--]src/utils/backtrace0
-rwxr-xr-x[-rw-r--r--]src/utils/pintos-gdb0
-rwxr-xr-x[-rw-r--r--]src/utils/pintos-mkdisk0
28 files changed, 822 insertions, 62 deletions
diff --git a/src/.gitignore b/src/.gitignore
index bea5755..89ff8ee 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1 +1,2 @@
TAGS
+*.o
diff --git a/src/Make.config b/src/Make.config
index f5c6705..1301180 100644
--- a/src/Make.config
+++ b/src/Make.config
@@ -11,12 +11,12 @@ VPATH = $(SRCDIR)
X86 = i.86\|pentium.*\|[pk][56]\|nexgen\|viac3\|6x86\|athlon.*\|i86pc
X86_64 = x86_64
ifneq (0, $(shell expr `uname -m` : '$(X86)'))
- CC = gcc
+ CC = gcc-4.8
LD = ld
OBJCOPY = objcopy
else
ifneq (0, $(shell expr `uname -m` : '$(X86_64)'))
- CC = gcc -m32
+ CC = gcc-4.8 -m32
LD = ld -melf_i386
OBJCOPY = objcopy
else
diff --git a/src/devices/timer.c b/src/devices/timer.c
index a4521de..aea6aa2 100644
--- a/src/devices/timer.c
+++ b/src/devices/timer.c
@@ -1,6 +1,7 @@
#include "devices/timer.h"
#include <debug.h>
#include <inttypes.h>
+#include <list.h>
#include <round.h>
#include <stdio.h>
#include "threads/interrupt.h"
@@ -17,6 +18,13 @@
#error TIMER_FREQ <= 1000 recommended
#endif
+struct waiting_thread
+ {
+ struct list_elem elem;
+ struct semaphore sema;
+ int64_t tick_target;
+ };
+
/* Number of timer ticks since OS booted. */
static int64_t ticks;
@@ -24,6 +32,8 @@ static int64_t ticks;
Initialized by timer_calibrate(). */
static unsigned loops_per_tick;
+static struct list waiting_threads;
+
static intr_handler_func timer_interrupt;
static bool too_many_loops (unsigned loops);
static void busy_wait (int64_t loops);
@@ -43,6 +53,8 @@ timer_init (void)
outb (0x40, count & 0xff);
outb (0x40, count >> 8);
+ list_init (&waiting_threads);
+
intr_register_ext (0x20, timer_interrupt, "8254 Timer");
}
@@ -98,9 +110,27 @@ timer_sleep (int64_t ticks)
{
int64_t start = timer_ticks ();
- ASSERT (intr_get_level () == INTR_ON);
- while (timer_elapsed (start) < ticks)
- thread_yield ();
+ struct waiting_thread new_waiting_thread;
+ new_waiting_thread.tick_target = start + ticks;
+ sema_init (&new_waiting_thread.sema, 0);
+
+ // disable interrupts so the timer interrupt handler can't modify the list
+ enum intr_level old_level = intr_disable ();
+
+ struct list_elem *before = list_begin (&waiting_threads);
+ while (before != list_end (&waiting_threads)) {
+ struct list_elem *next = list_next (before);
+ struct waiting_thread *waiting_thread = list_entry (before, struct waiting_thread, elem);
+ if (new_waiting_thread.tick_target < waiting_thread->tick_target) {
+ break;
+ }
+ before = next;
+ }
+ list_insert (before, &new_waiting_thread.elem);
+
+ intr_set_level (old_level);
+
+ sema_down (&new_waiting_thread.sema);
}
/* Suspends execution for approximately MS milliseconds. */
@@ -137,6 +167,19 @@ timer_interrupt (struct intr_frame *args UNUSED)
{
ticks++;
thread_tick ();
+
+ struct list_elem *e = list_begin (&waiting_threads);
+ while (e != list_end (&waiting_threads)) {
+ struct list_elem *next = list_next (e);
+ struct waiting_thread *waiting_thread = list_entry (e, struct waiting_thread, elem);
+ if (ticks >= waiting_thread->tick_target) {
+ sema_up (&waiting_thread->sema);
+ list_remove (e);
+ e = next;
+ } else {
+ break;
+ }
+ }
}
/* Returns true if LOOPS iterations waits for more than one timer
diff --git a/src/examples/Makefile b/src/examples/Makefile
index 8bd6ed2..6c7c09d 100644
--- a/src/examples/Makefile
+++ b/src/examples/Makefile
@@ -8,6 +8,16 @@ PROGS = cat cmp cp echo halt hex-dump ls mcat mcp mkdir pwd rm shell \
sumargv lab2test lab1test lab1test2 pfs pfs_reader pfs_writer dummy longrun \
child parent create-bad printf lab3test1 lab3test2 lab4test1
+PROGS += create read lab3test1 lab4test1 lab3test2 args wait
+
+create_SRC = create.c
+read_SRC = read.c
+lab3test1_SRC = lab3test1.c
+lab4test1_SRC = lab4test1.c
+lab3test2_SRC = lab3test2.c
+args_SRC = args.c
+wait_SRC = wait.c
+
# Added test programs
printf_SRC = printf.c
sumargv_SRC = sumargv.c
diff --git a/src/examples/args.c b/src/examples/args.c
new file mode 100644
index 0000000..643fb01
--- /dev/null
+++ b/src/examples/args.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ printf ("hello\n");
+ printf ("argc %p: %d\n", &argc, argc);
+ printf ("argv %p: %p\n", &argv, argv);
+ for (int i = 0; i < argc; i++) {
+ printf ("%d: %s\n", i, argv[i]);
+ }
+}
diff --git a/src/examples/create.c b/src/examples/create.c
new file mode 100644
index 0000000..65be47d
--- /dev/null
+++ b/src/examples/create.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <syscall.h>
+
+int
+main (int argc, char *argv[])
+{
+ if (create ("test", 1)) {
+ printf ("created file\n");
+ } else {
+ printf ("couldn't create file\n");
+ }
+ int fd = open ("test"); // open 2
+ printf ("opened file with fd %d\n", fd);
+ int fd2 = open ("test"); // open 3
+ printf ("opened file with fd %d\n", fd2);
+ close(fd); // close 2
+ int fd3 = open ("test"); // open 2
+ printf ("opened file with fd %d\n", fd3);
+ close(fd2); // close 3
+ int fd4 = open ("test"); // open 3
+ printf ("opened file with fd %d\n", fd4);
+ close(fd4); // close 3, valid
+ close(fd3); // close 2, valid
+ close(fd); // close closed 2, invalid
+ int fd5 = open ("test"); // open 2
+ printf ("opened file with fd %d\n", fd5);
+
+ halt ();
+}
diff --git a/src/examples/read.c b/src/examples/read.c
new file mode 100644
index 0000000..4b50bd8
--- /dev/null
+++ b/src/examples/read.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <syscall.h>
+
+int
+main (int argc, char *argv[])
+{
+ char read_buf[16] = {};
+
+ int fd = open ("readme");
+ if (fd == -1) {
+ halt ();
+ }
+ printf("opened file with fd %d\n", fd);
+
+ int n = read (fd, read_buf, 16);
+ printf("read %d bytes:\n", n);
+ printf("###############\n");
+ printf("%s\n", read_buf);
+
+ halt();
+ return 0;
+}
diff --git a/src/examples/wait.c b/src/examples/wait.c
new file mode 100644
index 0000000..ab0ea90
--- /dev/null
+++ b/src/examples/wait.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <syscall.h>
+
+int
+main (int argc, char **argv)
+{
+ printf ("hello\n");
+ if (argc != 1) {
+ int child = exec("wait");
+ printf("%d: %d\n", child, wait(child));
+ }
+ exit(1);
+}
diff --git a/src/filesys/file.c b/src/filesys/file.c
index d5fc10d..238806a 100644
--- a/src/filesys/file.c
+++ b/src/filesys/file.c
@@ -155,7 +155,12 @@ file_seek (struct file *file, off_t new_pos)
{
ASSERT (file != NULL);
ASSERT (new_pos >= 0);
- file->pos = new_pos;
+ off_t size = inode_length (file->inode);
+ if (new_pos < size) {
+ file->pos = new_pos;
+ } else {
+ file->pos = size;
+ }
}
/* Returns the current position in FILE as a byte offset from the
diff --git a/src/filesys/filesys.c b/src/filesys/filesys.c
index fedda08..d30f728 100644
--- a/src/filesys/filesys.c
+++ b/src/filesys/filesys.c
@@ -7,6 +7,11 @@
#include "filesys/inode.h"
#include "filesys/directory.h"
#include "devices/disk.h"
+#include "threads/synch.h"
+
+/* Locks filesys_create so the same file isn't
+ created twice with the same name. */
+static struct lock create_lock;
/* The disk that contains the file system. */
struct disk *filesys_disk;
@@ -22,6 +27,8 @@ filesys_init (bool format)
if (filesys_disk == NULL)
PANIC ("hd0:1 (hdb) not present, file system initialization failed");
+ lock_init (&create_lock);
+
inode_init ();
free_map_init ();
@@ -48,12 +55,14 @@ filesys_create (const char *name, off_t initial_size)
{
disk_sector_t inode_sector = 0;
struct dir *dir = dir_open_root ();
+ lock_acquire (&create_lock);
bool success = (dir != NULL
- && free_map_allocate (1, &inode_sector)
- && inode_create (inode_sector, initial_size)
- && dir_add (dir, name, inode_sector));
- if (!success && inode_sector != 0)
- free_map_release (inode_sector, 1);
+ && free_map_allocate (1, &inode_sector) // find sector
+ && inode_create (inode_sector, initial_size) // create inode pointing to sector
+ && dir_add (dir, name, inode_sector)); // add dir entry pointing to inode
+ lock_release (&create_lock);
+ if (!success && inode_sector != 0) // oops, we got a sector but file creation failed
+ free_map_release (inode_sector, 1); // so deallocate the sector
dir_close (dir);
return success;
diff --git a/src/filesys/free-map.c b/src/filesys/free-map.c
index 1cd9175..8b8aeae 100644
--- a/src/filesys/free-map.c
+++ b/src/filesys/free-map.c
@@ -4,8 +4,11 @@
#include "filesys/file.h"
#include "filesys/filesys.h"
#include "filesys/inode.h"
+#include "threads/synch.h"
static struct file *free_map_file; /* Free map file. */
+
+static struct lock free_map_lock;
static struct bitmap *free_map; /* Free map, one bit per disk sector. */
/* Initializes the free map. */
@@ -15,6 +18,7 @@ free_map_init (void)
free_map = bitmap_create (disk_size (filesys_disk));
if (free_map == NULL)
PANIC ("bitmap creation failed--disk is too large");
+ lock_init (&free_map_lock);
bitmap_mark (free_map, FREE_MAP_SECTOR);
bitmap_mark (free_map, ROOT_DIR_SECTOR);
}
@@ -26,6 +30,7 @@ free_map_init (void)
bool
free_map_allocate (size_t cnt, disk_sector_t *sectorp)
{
+ lock_acquire (&free_map_lock);
disk_sector_t sector = bitmap_scan_and_flip (free_map, 0, cnt, false);
if (sector != BITMAP_ERROR
&& free_map_file != NULL
@@ -34,6 +39,7 @@ free_map_allocate (size_t cnt, disk_sector_t *sectorp)
bitmap_set_multiple (free_map, sector, cnt, false);
sector = BITMAP_ERROR;
}
+ lock_release (&free_map_lock);
if (sector != BITMAP_ERROR)
*sectorp = sector;
return sector != BITMAP_ERROR;
@@ -43,9 +49,11 @@ free_map_allocate (size_t cnt, disk_sector_t *sectorp)
void
free_map_release (disk_sector_t sector, size_t cnt)
{
+ lock_acquire (&free_map_lock);
ASSERT (bitmap_all (free_map, sector, cnt));
bitmap_set_multiple (free_map, sector, cnt, false);
bitmap_write (free_map, free_map_file);
+ lock_release (&free_map_lock);
}
/* Opens the free map file and reads it from disk. */
@@ -55,8 +63,10 @@ free_map_open (void)
free_map_file = file_open (inode_open (FREE_MAP_SECTOR));
if (free_map_file == NULL)
PANIC ("can't open free map");
+ lock_acquire (&free_map_lock);
if (!bitmap_read (free_map, free_map_file))
PANIC ("can't read free map");
+ lock_release (&free_map_lock);
}
/* Writes the free map to disk and closes the free map file. */
diff --git a/src/filesys/inode.c b/src/filesys/inode.c
index cfdcb7b..dca5432 100644
--- a/src/filesys/inode.c
+++ b/src/filesys/inode.c
@@ -6,6 +6,7 @@
#include "filesys/filesys.h"
#include "filesys/free-map.h"
#include "threads/malloc.h"
+#include "threads/synch.h"
/* Identifies an inode. */
#define INODE_MAGIC 0x494e4f44
@@ -31,11 +32,14 @@ bytes_to_sectors (off_t size)
/* In-memory inode. */
struct inode
{
+ struct lock lock; /* Lock for inode metadata. */
struct list_elem elem; /* Element in inode list. */
disk_sector_t sector; /* Sector number of disk location. */
int open_cnt; /* Number of openers. */
bool removed; /* True if deleted, false otherwise. */
int deny_write_cnt; /* 0: writes ok, >0: deny writes. */
+
+ struct rwlock rwlock; /* RwLock for inode_disk data. */
struct inode_disk data; /* Inode content. */
};
@@ -53,6 +57,9 @@ byte_to_sector (const struct inode *inode, off_t pos)
return -1;
}
+/* Lock the open inode list since so inode_open doesn't race. */
+struct lock open_inodes_lock;
+
/* List of open inodes, so that opening a single inode twice
returns the same `struct inode'. */
static struct list open_inodes;
@@ -62,6 +69,7 @@ void
inode_init (void)
{
list_init (&open_inodes);
+ lock_init (&open_inodes_lock);
}
/* Initializes an inode with LENGTH bytes of data and
@@ -114,6 +122,7 @@ inode_open (disk_sector_t sector)
struct list_elem *e;
struct inode *inode;
+ lock_acquire (&open_inodes_lock);
/* Check whether this inode is already open. */
for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
e = list_next (e))
@@ -122,22 +131,30 @@ inode_open (disk_sector_t sector)
if (inode->sector == sector)
{
inode_reopen (inode);
+ lock_release (&open_inodes_lock);
return inode;
}
}
/* Allocate memory. */
inode = malloc (sizeof *inode);
- if (inode == NULL)
+ if (inode == NULL) {
+ lock_release (&open_inodes_lock);
return NULL;
+ }
/* Initialize. */
+ lock_init (&inode->lock);
+ lock_acquire (&inode->lock);
list_push_front (&open_inodes, &inode->elem);
+ lock_release (&open_inodes_lock);
inode->sector = sector;
inode->open_cnt = 1;
inode->deny_write_cnt = 0;
inode->removed = false;
+ rwlock_init (&inode->rwlock);
disk_read (filesys_disk, inode->sector, &inode->data);
+ lock_release (&inode->lock);
return inode;
}
@@ -147,8 +164,10 @@ inode_reopen (struct inode *inode)
{
if (inode != NULL)
{
+ lock_acquire (&inode->lock);
ASSERT(inode->open_cnt != 0);
inode->open_cnt++;
+ lock_release (&inode->lock);
}
return inode;
}
@@ -170,11 +189,17 @@ inode_close (struct inode *inode)
if (inode == NULL)
return;
+ lock_acquire (&inode->lock);
+
/* Release resources if this was the last opener. */
- if (--inode->open_cnt == 0)
+ if (--inode->open_cnt > 0)
{
- /* Remove from inode list and release lock. */
+ lock_release (&inode->lock);
+ } else {
+ /* Remove from inode list. */
+ lock_acquire (&open_inodes_lock);
list_remove (&inode->elem);
+ lock_release (&open_inodes_lock);
/* Deallocate blocks if removed. */
if (inode->removed)
@@ -194,7 +219,9 @@ void
inode_remove (struct inode *inode)
{
ASSERT (inode != NULL);
+ lock_acquire (&inode->lock);
inode->removed = true;
+ lock_release (&inode->lock);
}
/* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
@@ -207,6 +234,8 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
off_t bytes_read = 0;
uint8_t *bounce = NULL;
+ rwlock_read_p (&inode->rwlock);
+
while (size > 0)
{
/* Disk sector to read, starting byte offset within sector. */
@@ -247,6 +276,8 @@ inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
offset += chunk_size;
bytes_read += chunk_size;
}
+
+ rwlock_read_v (&inode->rwlock);
free (bounce);
return bytes_read;
@@ -268,6 +299,8 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
if (inode->deny_write_cnt)
return 0;
+ rwlock_write_p (&inode->rwlock);
+
while (size > 0)
{
/* Sector to write, starting byte offset within sector. */
@@ -315,6 +348,8 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
offset += chunk_size;
bytes_written += chunk_size;
}
+
+ rwlock_write_v (&inode->rwlock);
free (bounce);
return bytes_written;
@@ -325,8 +360,10 @@ inode_write_at (struct inode *inode, const void *buffer_, off_t size,
void
inode_deny_write (struct inode *inode)
{
+ lock_acquire (&inode->lock);
inode->deny_write_cnt++;
ASSERT (inode->deny_write_cnt <= inode->open_cnt);
+ lock_release (&inode->lock);
}
/* Re-enables writes to INODE.
@@ -335,9 +372,11 @@ inode_deny_write (struct inode *inode)
void
inode_allow_write (struct inode *inode)
{
+ lock_acquire (&inode->lock);
ASSERT (inode->deny_write_cnt > 0);
ASSERT (inode->deny_write_cnt <= inode->open_cnt);
inode->deny_write_cnt--;
+ lock_release (&inode->lock);
}
/* Returns the length, in bytes, of INODE's data. */
diff --git a/src/lib/pid_t.h b/src/lib/pid_t.h
new file mode 100644
index 0000000..c6d8e31
--- /dev/null
+++ b/src/lib/pid_t.h
@@ -0,0 +1,15 @@
+#ifndef LIB_PID_T_H
+#define LIB_PID_T_H
+
+/* Process identifier.
+ Moved from lib/user/syscall.h since both kernel-
+ and user-space want the same definition. */
+typedef int pid_t;
+
+#define PID_ERROR ((pid_t) -1)
+
+/* Format specifier for printf(), e.g.:
+ printf ("pid=%"PRPTd"\n", pid); */
+#define PRPTd d
+
+#endif /* lib/pid_t.h */
diff --git a/src/lib/user/syscall.h b/src/lib/user/syscall.h
index 8a9e0c0..a152dd1 100644
--- a/src/lib/user/syscall.h
+++ b/src/lib/user/syscall.h
@@ -4,9 +4,7 @@
#include <stdbool.h>
#include <debug.h>
-/* Process identifier. */
-typedef int pid_t;
-#define PID_ERROR ((pid_t) -1)
+#include "lib/pid_t.h"
/* Map region identifier. */
typedef int mapid_t;
diff --git a/src/tests/Make.tests b/src/tests/Make.tests
index 76d63f6..60f2c2d 100644
--- a/src/tests/Make.tests
+++ b/src/tests/Make.tests
@@ -14,7 +14,7 @@ ifdef PROGS
include ../../Makefile.userprog
endif
-TIMEOUT = 60
+TIMEOUT = 5
clean::
rm -f $(OUTPUTS) $(ERRORS) $(RESULTS)
diff --git a/src/tests/userprog/Make.tests b/src/tests/userprog/Make.tests
index c762af3..427f538 100644
--- a/src/tests/userprog/Make.tests
+++ b/src/tests/userprog/Make.tests
@@ -8,16 +8,18 @@ args-single args-multiple args-many args-dbl-space sc-bad-sp \
sc-bad-arg sc-boundary sc-boundary-2 halt exit create-normal \
create-empty create-null create-bad-ptr create-long create-exists \
create-bound open-normal open-missing open-boundary open-empty \
-open-null open-bad-ptr open-twice close-normal close-stdin \
-close-stdout close-bad-fd read-bad-ptr read-boundary \
+open-null open-bad-ptr open-twice close-normal close-twice close-stdin \
+close-stdout close-bad-fd read-normal read-bad-ptr read-boundary \
read-zero read-stdout read-bad-fd write-normal write-bad-ptr \
write-boundary write-zero write-stdin write-bad-fd exec-once exec-arg \
exec-multiple exec-missing exec-bad-ptr wait-simple wait-twice \
-wait-killed wait-bad-pid multi-recurse \
-)
+wait-killed wait-bad-pid multi-recurse multi-child-fd)
+
+
tests/userprog_PROGS = $(tests/userprog_TESTS) $(addprefix \
-tests/userprog/,child-simple child-args child-bad child-close child-rox)
+tests/userprog/,child-simple child-args child-bad child-close)
+
tests/userprog/args-none_SRC = tests/userprog/args.c
tests/userprog/args-single_SRC = tests/userprog/args.c
@@ -26,12 +28,7 @@ tests/userprog/args-many_SRC = tests/userprog/args.c
tests/userprog/args-dbl-space_SRC = tests/userprog/args.c
tests/userprog/sc-bad-sp_SRC = tests/userprog/sc-bad-sp.c tests/main.c
tests/userprog/sc-bad-arg_SRC = tests/userprog/sc-bad-arg.c tests/main.c
-tests/userprog/bad-read_SRC = tests/userprog/bad-read.c tests/main.c
-tests/userprog/bad-write_SRC = tests/userprog/bad-write.c tests/main.c
-tests/userprog/bad-jump_SRC = tests/userprog/bad-jump.c tests/main.c
-tests/userprog/bad-read2_SRC = tests/userprog/bad-read2.c tests/main.c
-tests/userprog/bad-write2_SRC = tests/userprog/bad-write2.c tests/main.c
-tests/userprog/bad-jump2_SRC = tests/userprog/bad-jump2.c tests/main.c
+
tests/userprog/sc-boundary_SRC = tests/userprog/sc-boundary.c \
tests/userprog/boundary.c tests/main.c
tests/userprog/sc-boundary-2_SRC = tests/userprog/sc-boundary-2.c \
@@ -86,16 +83,13 @@ tests/userprog/wait-bad-pid_SRC = tests/userprog/wait-bad-pid.c tests/main.c
tests/userprog/multi-recurse_SRC = tests/userprog/multi-recurse.c
tests/userprog/multi-child-fd_SRC = tests/userprog/multi-child-fd.c \
tests/main.c
-tests/userprog/rox-simple_SRC = tests/userprog/rox-simple.c tests/main.c
-tests/userprog/rox-child_SRC = tests/userprog/rox-child.c tests/main.c
-tests/userprog/rox-multichild_SRC = tests/userprog/rox-multichild.c \
-tests/main.c
+
tests/userprog/child-simple_SRC = tests/userprog/child-simple.c
tests/userprog/child-args_SRC = tests/userprog/args.c
tests/userprog/child-bad_SRC = tests/userprog/child-bad.c tests/main.c
tests/userprog/child-close_SRC = tests/userprog/child-close.c
-tests/userprog/child-rox_SRC = tests/userprog/child-rox.c
+
$(foreach prog,$(tests/userprog_PROGS),$(eval $(prog)_SRC += tests/lib.c))
@@ -128,5 +122,3 @@ tests/userprog/wait-twice_PUTFILES += tests/userprog/child-simple
tests/userprog/exec-arg_PUTFILES += tests/userprog/child-args
tests/userprog/multi-child-fd_PUTFILES += tests/userprog/child-close
tests/userprog/wait-killed_PUTFILES += tests/userprog/child-bad
-tests/userprog/rox-child_PUTFILES += tests/userprog/child-rox
-tests/userprog/rox-multichild_PUTFILES += tests/userprog/child-rox
diff --git a/src/threads/synch.c b/src/threads/synch.c
index 317c68a..e714ce0 100644
--- a/src/threads/synch.c
+++ b/src/threads/synch.c
@@ -336,3 +336,43 @@ cond_broadcast (struct condition *cond, struct lock *lock)
while (!list_empty (&cond->waiters))
cond_signal (cond, lock);
}
+
+void
+rwlock_init (struct rwlock *rwlock)
+{
+ sema_init (&rwlock->resource, 1);
+ lock_init (&rwlock->rmutex);
+ rwlock->readcount = 0;
+}
+
+void
+rwlock_write_p (struct rwlock *rwlock)
+{
+ sema_down (&rwlock->resource);
+}
+
+void
+rwlock_write_v (struct rwlock *rwlock)
+{
+ sema_up (&rwlock->resource);
+}
+
+void
+rwlock_read_p (struct rwlock *rwlock)
+{
+ lock_acquire (&rwlock->rmutex);
+ rwlock->readcount ++;
+ if (rwlock->readcount == 1)
+ sema_down (&rwlock->resource);
+ lock_release (&rwlock->rmutex);
+}
+
+void
+rwlock_read_v (struct rwlock *rwlock)
+{
+ lock_acquire (&rwlock->rmutex);
+ rwlock->readcount --;
+ if (rwlock->readcount == 0)
+ sema_up (&rwlock->resource);
+ lock_release (&rwlock->rmutex);
+}
diff --git a/src/threads/synch.h b/src/threads/synch.h
index a19e88b..a76eecc 100644
--- a/src/threads/synch.h
+++ b/src/threads/synch.h
@@ -41,6 +41,23 @@ void cond_wait (struct condition *, struct lock *);
void cond_signal (struct condition *, struct lock *);
void cond_broadcast (struct condition *, struct lock *);
+/* Readers-writers lock.
+
+ Implementation of "First readers-writers problem" from
+ https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem. */
+struct rwlock
+ {
+ struct semaphore resource;
+ struct lock rmutex;
+ unsigned readcount;
+ };
+
+void rwlock_init (struct rwlock *);
+void rwlock_write_p (struct rwlock *);
+void rwlock_write_v (struct rwlock *);
+void rwlock_read_p (struct rwlock *);
+void rwlock_read_v (struct rwlock *);
+
/* Optimization barrier.
The compiler will not reorder operations across an
diff --git a/src/threads/thread.c b/src/threads/thread.c
index 92d1aa8..3112a71 100644
--- a/src/threads/thread.c
+++ b/src/threads/thread.c
@@ -13,6 +13,7 @@
#include "threads/vaddr.h"
#ifdef USERPROG
#include "userprog/process.h"
+#include "threads/malloc.h"
#endif
/* Random value for struct thread's `magic' member.
@@ -435,6 +436,9 @@ init_thread (struct thread *t, const char *name, int priority)
strlcpy (t->name, name, sizeof t->name);
t->stack = (uint8_t *) t + PGSIZE;
t->priority = priority;
+#ifdef USERPROG
+ list_init (&t->children);
+#endif
t->magic = THREAD_MAGIC;
}
diff --git a/src/threads/thread.h b/src/threads/thread.h
index 0039560..a3bc814 100644
--- a/src/threads/thread.h
+++ b/src/threads/thread.h
@@ -4,6 +4,9 @@
#include <debug.h>
#include <list.h>
#include <stdint.h>
+#include "threads/synch.h"
+
+#define MAX_FDS 128 /* Max number of file descriptors per thread */
/* States in a thread's life cycle. */
enum thread_status
@@ -19,6 +22,23 @@ enum thread_status
typedef int tid_t;
#define TID_ERROR ((tid_t) -1) /* Error value for tid_t. */
+/* The relationship between a parent and child process.
+ The child reports its exit status by setting exit_status.
+ The parent places the parent_child element in its list of children.
+*/
+struct parent_child
+ {
+ struct list_elem elem; // owned by the parent
+
+ // exit_status is readable by the parent
+ struct semaphore exit_sema;
+ int exit_status;
+
+ struct lock l;
+ int alive_count;
+ tid_t child_tid;
+ };
+
/* Thread priorities. */
#define PRI_MIN 0 /* Lowest priority. */
#define PRI_DEFAULT 31 /* Default priority. */
@@ -80,6 +100,7 @@ typedef int tid_t;
only because they are mutually exclusive: only a thread in the
ready state is on the run queue, whereas only a thread in the
blocked state is on a semaphore wait list. */
+
struct thread
{
/* Owned by thread.c. */
@@ -95,6 +116,11 @@ struct thread
#ifdef USERPROG
/* Owned by userprog/process.c. */
uint32_t *pagedir; /* Page directory. */
+ struct file **fds; /* Pointer to array of file descriptors. */
+ bool load_success;
+
+ struct parent_child *parent; // one parent
+ struct list children; // multiple children
#endif
/* Owned by thread.c. */
diff --git a/src/userprog/Make.vars b/src/userprog/Make.vars
index eebac65..22aec79 100644
--- a/src/userprog/Make.vars
+++ b/src/userprog/Make.vars
@@ -2,6 +2,6 @@
os.dsk: DEFINES = -DUSERPROG -DFILESYS
KERNEL_SUBDIRS = threads devices lib lib/kernel userprog filesys
-TEST_SUBDIRS = tests/userprog #tests/userprog/no-vm tests/filesys/base
+TEST_SUBDIRS = tests/userprog tests/filesys/base
GRADING_FILE = $(SRCDIR)/tests/userprog/Grading
SIMULATOR = --qemu
diff --git a/src/userprog/process.c b/src/userprog/process.c
index b3e16bb..6170b53 100644
--- a/src/userprog/process.c
+++ b/src/userprog/process.c
@@ -14,10 +14,24 @@
#include "threads/flags.h"
#include "threads/init.h"
#include "threads/interrupt.h"
+#include "threads/malloc.h"
#include "threads/palloc.h"
+#include "threads/synch.h"
#include "threads/thread.h"
#include "threads/vaddr.h"
+struct start_process_args
+ {
+ struct semaphore sema;
+
+ // parent -> child
+ char *file_name;
+
+ // child -> parent
+ bool success;
+ struct parent_child *child;
+ };
+
static thread_func start_process NO_RETURN;
static bool load (const char *cmdline, void (**eip) (void), void **esp);
@@ -28,42 +42,75 @@ static bool load (const char *cmdline, void (**eip) (void), void **esp);
tid_t
process_execute (const char *file_name)
{
- char *fn_copy;
+ struct start_process_args args; // stack allocated since we know we wait for thread_create to finish reading
tid_t tid;
+ sema_init (&args.sema, 0);
+
/* Make a copy of FILE_NAME.
Otherwise there's a race between the caller and load(). */
- fn_copy = palloc_get_page (0);
- if (fn_copy == NULL)
+ args.file_name = palloc_get_page (0);
+ if (args.file_name == NULL)
return TID_ERROR;
- strlcpy (fn_copy, file_name, PGSIZE);
-
- /* Create a new thread to execute FILE_NAME. */
- tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
- if (tid == TID_ERROR)
- palloc_free_page (fn_copy);
+ strlcpy (args.file_name, file_name, PGSIZE);
+
+ /* Create a new thread to execute FILE_NAME.
+ If thread_create fails we free and return immediately since we know
+ that the thread didn't start.
+ Otherwise, the child thread can be scheduled freely so we explicitly
+ wait for the child to signal that it has read from and written to
+ the args. Only then can we free resources and return the tid. */
+ tid = thread_create (file_name, PRI_DEFAULT, start_process, &args);
+ if (tid != TID_ERROR) {
+ sema_down (&args.sema);
+
+ if (args.success) {
+ list_push_back (&thread_current ()->children, &args.child->elem);
+ } else {
+ tid = -1;
+ }
+ }
+ palloc_free_page (args.file_name);
return tid;
}
/* A thread function that loads a user process and starts it
running. */
static void
-start_process (void *file_name_)
+start_process (void *args_)
{
- char *file_name = file_name_;
+ struct start_process_args *args = args_;
struct intr_frame if_;
+ struct thread *t;
bool success;
+ t = thread_current ();
+
/* Initialize interrupt frame and load executable. */
memset (&if_, 0, sizeof if_);
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS;
- success = load (file_name, &if_.eip, &if_.esp);
+ success = load (args->file_name, &if_.eip, &if_.esp);
+ args->success = success;
+ t->load_success = success;
+
+ if (success) {
+ t->parent = malloc (sizeof (struct parent_child));
+
+ sema_init (&t->parent->exit_sema, 0);
+ lock_init (&t->parent->l);
+
+ t->parent->child_tid = t->tid;
+ t->parent->alive_count = 2;
+
+ args->child = t->parent;
+ }
+
+ sema_up (&args->sema);
/* If load failed, quit. */
- palloc_free_page (file_name);
- if (!success)
+ if (!success)
thread_exit ();
/* Start the user process by simulating a return from an
@@ -86,11 +133,39 @@ start_process (void *file_name_)
This function will be implemented in problem 2-2. For now, it
does nothing. */
int
-process_wait (tid_t child_tid UNUSED)
+process_wait (tid_t child_tid)
{
+ struct thread *t = thread_current ();
+ struct list_elem *e;
+ for (e = list_begin (&t->children); e != list_end (&t->children);
+ e = list_next (e))
+ {
+ struct parent_child *pc = list_entry (e, struct parent_child, elem);
+ if (child_tid == pc->child_tid) {
+ sema_down (&pc->exit_sema);
+ int exit_status = pc->exit_status;
+ pc->exit_status = -1;
+ sema_up (&pc->exit_sema); // a bit of a hack
+ // the child is killed so we can read again if we want to
+ return exit_status;
+ }
+ }
return -1;
}
+static void
+free_pc (struct parent_child *pc)
+{
+ lock_acquire (&pc->l);
+
+ pc->alive_count--;
+ if (pc->alive_count == 0) {
+ free (pc);
+ } else {
+ lock_release (&pc->l);
+ }
+}
+
/* Free the current process's resources. */
void
process_exit (void)
@@ -98,6 +173,20 @@ process_exit (void)
struct thread *cur = thread_current ();
uint32_t *pd;
+ if (cur->load_success) {
+ sema_up (&cur->parent->exit_sema);
+ free_pc (cur->parent);
+ printf("%s: exit(%d)\n", cur->name, cur->parent->exit_status);
+
+ struct list_elem *e;
+ struct parent_child *child;
+ while (!list_empty (&cur->children)) {
+ e = list_pop_front (&cur->children);
+ child = list_entry (e, struct parent_child, elem);
+ free_pc (child);
+ }
+ }
+
/* Destroy the current process's page directory and switch back
to the kernel-only page directory. */
pd = cur->pagedir;
@@ -226,10 +315,66 @@ load (const char *file_name, void (**eip) (void), void **esp)
goto done;
}
+ size_t cmd_len, word_alignment;
+ char *esp_cmd, **esp_argv_first, **esp_argv_entry, ***esp_argv;
+ int *esp_argc, argc = 0;
+
+ /* Copy passed command to start of user stack. */
+ cmd_len = strlen (file_name);
+ esp_cmd = *esp;
+ esp_cmd -= cmd_len + 1; // +1 makes room for '\0'
+ for (i = 0; i < cmd_len; i++) {
+ esp_cmd[i] = file_name[i];
+ }
+ esp_cmd[cmd_len] = '\0';
+
+ /* Tokenize passed command in-place. */
+ // esp_cmd still points to first character of passed command
+ char *token, *save_ptr;
+ for (token = strtok_r (esp_cmd, " ", &save_ptr); token != NULL;
+ token = strtok_r (NULL, " ", &save_ptr))
+ {
+ argc++;
+ }
+
+ file_name = esp_cmd;
+ strlcpy (thread_current ()->name, file_name, 16);
+
+ /* argv entries are pointers so they need to be aligned to the pointer size. */
+ size_t psize = sizeof (char *);
+ word_alignment = (cmd_len + psize) / psize;
+
+ /* Write argv entries. */
+ esp_argv_entry = *esp;
+ esp_argv_entry -= word_alignment + argc + 1; // +1 makes room for argv[argc] = NULL
+ esp_argv_first = esp_argv_entry; // save for later
+
+ // esp_cmd points to first entry so write directly
+ *esp_argv_entry = esp_cmd;
+ esp_argv_entry++;
+
+ for (i = 0; i < argc - 1; i++) {
+ // step until a \0 is found
+ while (*(++esp_cmd) != '\0') {}
+ // step over any ' '
+ while (*(++esp_cmd) == ' ') {}
+ *esp_argv_entry = esp_cmd; // point to next character
+ esp_argv_entry++;
+ }
+
+ esp_argv = esp_argv_first - 1;
+
+ *esp_argv = esp_argv_first;
+
+ esp_argc = esp_argv - 1;
+ *esp_argc = argc;
+
+ *esp = esp_argc - 1; // return address
+
/* Uncomment the following line to print some debug
information. This will be useful when you debug the program
stack.*/
-/*#define STACK_DEBUG*/
+// #define STACK_DEBUG
#ifdef STACK_DEBUG
printf("*esp is %p\nstack contents:\n", *esp);
diff --git a/src/userprog/start_pfs.sh b/src/userprog/start_pfs.sh
index 6ae76ad..26b9eb9 100644..100755
--- a/src/userprog/start_pfs.sh
+++ b/src/userprog/start_pfs.sh
@@ -1,4 +1,4 @@
-make -j4
+make -j12
cd build
pintos-mkdisk fs.dsk 800
dd if=/dev/urandom of=random bs=1 count=100
@@ -7,4 +7,4 @@ pintos --qemu -v -p random -a random -- -q
pintos --qemu -v -p ../../examples/pfs -a pfs -- -q
pintos --qemu -v -p ../../examples/pfs_writer -a pfs_writer -- -q
pintos --qemu -v -p ../../examples/pfs_reader -a pfs_reader -- -q
-pintos --qemu -v -- run pfs
+pintos --qemu -v -- -q run pfs
diff --git a/src/userprog/start_recursor.sh b/src/userprog/start_recursor.sh
index 22a69ac..6f5e99b 100644..100755
--- a/src/userprog/start_recursor.sh
+++ b/src/userprog/start_recursor.sh
@@ -1,6 +1,6 @@
-make -j4
-cd build
+make -j12
+cd build
pintos-mkdisk fs.dsk 400
-pintos --qemu -v -- -f -q
-pintos --qemu -v -p ../../examples/recursor_ng -a recursor_ng -- -q
-pintos --qemu -v -m 128 -- run "recursor_ng pintosmaster 6 1"
+pintos -v --qemu -- -f -q
+pintos -v --qemu -p ../../examples/recursor_ng -a recursor_ng -- -q
+pintos -v --qemu -m 128 -- run "recursor_ng pintosmaster 6 1"
diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c
index 370c89b..c1308ca 100644
--- a/src/userprog/syscall.c
+++ b/src/userprog/syscall.c
@@ -4,6 +4,17 @@
#include "threads/interrupt.h"
#include "threads/thread.h"
+#include "devices/input.h"
+#include "filesys/file.h"
+#include "filesys/filesys.h"
+#include "filesys/off_t.h"
+#include "lib/pid_t.h"
+#include "userprog/pagedir.h"
+#include "userprog/process.h"
+#include "threads/init.h"
+#include "threads/malloc.h"
+#include "threads/vaddr.h"
+
static void syscall_handler (struct intr_frame *);
void
@@ -13,8 +24,327 @@ syscall_init (void)
}
static void
-syscall_handler (struct intr_frame *f UNUSED)
+halt (void)
+{
+ power_off();
+}
+
+static bool
+create (const char *filename, off_t initial_size)
+{
+ return filesys_create (filename, initial_size);
+}
+
+static bool
+remove (const char *filename)
+{
+ return filesys_remove (filename);
+}
+
+static int
+open (const char *filename)
+{
+ struct thread *t = thread_current ();
+
+ if (!t->fds) {
+ t->fds = (struct file **) calloc (MAX_FDS, sizeof (struct file *));
+ }
+
+ struct file *file = filesys_open (filename);
+ if (!file) {
+ return -1;
+ }
+
+ for (int i = 0; i < MAX_FDS; i++) {
+ struct file **fd = t->fds + i;
+ if (*fd == NULL) {
+ *fd = file;
+ return i + 2; // 0 and 1 are reserved for stdin and stdout
+ }
+ }
+ free (file);
+ return -1;
+}
+
+static struct file **
+get_fd (struct thread *thread, int fd_i)
+{
+ if (!thread->fds) {
+ return NULL;
+ }
+
+ return thread->fds + fd_i - 2; // -2 since 0 and 1 are reserved and not present in the array
+}
+
+static void
+exit (int status)
{
- printf ("system call!\n");
+ struct thread *thread = thread_current ();
+
+ if (thread->fds) {
+ for (int i = 0; i < MAX_FDS; i++) {
+ struct file **fd = thread->fds + i;
+ if (fd && *fd) {
+ file_close (*fd);
+ *fd = NULL;
+ }
+ }
+ free (thread->fds);
+ }
+
+ lock_acquire (&thread->parent->l);
+ thread->parent->exit_status = status;
+ lock_release (&thread->parent->l);
+
thread_exit ();
}
+
+static int
+wait (tid_t child_tid)
+{
+ return process_wait (child_tid);
+}
+
+static int
+read (int fd_i, void *buf, unsigned size)
+{
+ struct thread *thread = thread_current ();
+
+ if (fd_i == 0) {
+ // stdin
+ unsigned i;
+ for (i = 0; i < size; i++) {
+ ((char *)buf)[i] = input_getc ();
+ }
+ return i;
+ } else if (fd_i == 1) {
+ // can't read from stdout
+ return -1;
+ }
+
+ struct file **fd = get_fd (thread, fd_i);
+ if (fd && *fd) {
+ return file_read (*fd, buf, size);
+ } else {
+ return -1;
+ }
+}
+
+static int
+write (int fd_i, const void *buf, unsigned size)
+{
+ struct thread *thread = thread_current ();
+
+ if (fd_i == 1) {
+ // stdout
+ putbuf ((const char *)buf, size);
+ return size;
+ } else if (fd_i == 0) {
+ // can't write to stdout
+ return -1;
+ }
+
+ struct file **fd = get_fd (thread, fd_i);
+ if (fd && *fd) {
+ return file_write (*fd, buf, size);
+ } else {
+ return -1;
+ }
+}
+
+static int
+filesize (int fd_i)
+{
+ struct thread *thread = thread_current ();
+ struct file **fd = get_fd (thread, fd_i);
+ if (fd && *fd) {
+ return file_length (*fd);
+ }
+ return -1;
+}
+
+static void
+seek (int fd_i, unsigned position)
+{
+ struct thread *thread = thread_current ();
+ struct file **fd = get_fd (thread, fd_i);
+ if (fd && *fd) {
+ file_seek (*fd, position);
+ }
+}
+
+static unsigned
+tell (int fd_i)
+{
+ struct thread *thread = thread_current ();
+ struct file **fd = get_fd (thread, fd_i);
+ if (fd && *fd) {
+ return file_tell (*fd);
+ }
+ return 0;
+}
+
+
+static void
+close (int fd_i)
+{
+ struct thread *thread = thread_current ();
+
+ struct file **fd = get_fd (thread, fd_i);
+ if (fd && *fd) {
+ file_close (*fd);
+ *fd = NULL;
+ }
+}
+
+static pid_t
+exec (const char *filename)
+{
+ return process_execute (filename);
+}
+
+static bool
+ptr_is_valid (const void *ptr)
+{
+ // uintptr_t ptr = _ptr;
+ if (!is_user_vaddr (ptr))
+ return false;
+
+ struct thread *t = thread_current ();
+
+ if (pagedir_get_page (t->pagedir, ptr) == NULL)
+ return false;
+
+ return true;
+}
+
+// cast argument N from f->esp to TYPE without dereferencing
+#define INTR_ESP(N, TYPE) (TYPE *)(f->esp+(4*(N)))
+
+#define CHECK_PTR_AND_MAYBE_EXIT(PTR) \
+ do { \
+ if (!ptr_is_valid (PTR)) { \
+ exit (-1); \
+ return; \
+ } \
+ } while (0)
+
+
+static void
+syscall_handler (struct intr_frame *f UNUSED)
+{
+ // check esp
+ int *syscall_number = INTR_ESP (0, int);
+
+ CHECK_PTR_AND_MAYBE_EXIT (syscall_number);
+
+ char **filename;
+ int *status, *fd_i;
+ off_t *initial_size;
+ tid_t *child_tid;
+ unsigned *size, *position;
+ void **buf;
+
+ switch (*syscall_number) {
+ case 0:
+ // halt
+ halt ();
+ break;
+ case 1:
+ // exit
+ status = INTR_ESP (1, int);
+ CHECK_PTR_AND_MAYBE_EXIT (status);
+ exit (*status);
+ break;
+ case 2:
+ // exec
+ filename = INTR_ESP (1, char *);
+ CHECK_PTR_AND_MAYBE_EXIT (filename);
+ CHECK_PTR_AND_MAYBE_EXIT (*filename);
+ f->eax = exec (*filename);
+ break;
+ case 3:
+ // wait
+ child_tid = INTR_ESP (1, tid_t);
+ CHECK_PTR_AND_MAYBE_EXIT (child_tid);
+ f->eax = wait (*child_tid);
+ break;
+ case 4:
+ // create
+ filename = INTR_ESP (1, char *);
+ initial_size = INTR_ESP (2, off_t);
+ CHECK_PTR_AND_MAYBE_EXIT (filename);
+ CHECK_PTR_AND_MAYBE_EXIT (*filename);
+ CHECK_PTR_AND_MAYBE_EXIT (initial_size);
+ f->eax = create (*filename, *initial_size);
+ break;
+ case 5:
+ // remove
+ filename = INTR_ESP (1, char *);
+ CHECK_PTR_AND_MAYBE_EXIT (filename);
+ CHECK_PTR_AND_MAYBE_EXIT (*filename);
+ f->eax = remove (*filename);
+ break;
+ case 6:
+ // open
+ filename = INTR_ESP (1, char *);
+ CHECK_PTR_AND_MAYBE_EXIT (filename);
+ CHECK_PTR_AND_MAYBE_EXIT (*filename);
+ f->eax = open (*filename);
+ break;
+ case 7:
+ // filesize
+ fd_i = INTR_ESP (1, int);
+ CHECK_PTR_AND_MAYBE_EXIT (fd_i);
+ f->eax = filesize (*fd_i);
+ break;
+ case 8:
+ // read
+ fd_i = INTR_ESP (1, int);
+ buf = INTR_ESP (2, void *);
+ size = INTR_ESP (3, unsigned);
+ CHECK_PTR_AND_MAYBE_EXIT (fd_i);
+ CHECK_PTR_AND_MAYBE_EXIT (buf);
+ CHECK_PTR_AND_MAYBE_EXIT (*buf);
+ CHECK_PTR_AND_MAYBE_EXIT (size);
+ CHECK_PTR_AND_MAYBE_EXIT (*buf + *size);
+ f->eax = read (*fd_i, *buf, *size);
+ break;
+ case 9:
+ // write
+ fd_i = INTR_ESP (1, int);
+ buf = INTR_ESP (2, void *);
+ size = INTR_ESP (3, unsigned);
+ CHECK_PTR_AND_MAYBE_EXIT (fd_i);
+ CHECK_PTR_AND_MAYBE_EXIT (buf);
+ CHECK_PTR_AND_MAYBE_EXIT (*buf);
+ CHECK_PTR_AND_MAYBE_EXIT (size);
+ CHECK_PTR_AND_MAYBE_EXIT (*buf + *size);
+ f->eax = write (*fd_i, *buf, *size);
+ break;
+ case 10:
+ // seek
+ fd_i = INTR_ESP (1, int);
+ position = INTR_ESP (2, unsigned);
+ CHECK_PTR_AND_MAYBE_EXIT (fd_i);
+ CHECK_PTR_AND_MAYBE_EXIT (position);
+ seek (*fd_i, *position);
+ break;
+ case 11:
+ // tell
+ fd_i = INTR_ESP (1, int);
+ CHECK_PTR_AND_MAYBE_EXIT (fd_i);
+ f->eax = tell (*fd_i);
+ break;
+ case 12:
+ // close
+ fd_i = INTR_ESP (1, int);
+ close (*fd_i);
+ break;
+ default:
+ printf ("kernel: unknown syscall '%d'\n", *syscall_number);
+ break;
+ }
+}
+
+#undef INTR_ESP
diff --git a/src/utils/backtrace b/src/utils/backtrace
index 95e422f..95e422f 100644..100755
--- a/src/utils/backtrace
+++ b/src/utils/backtrace
diff --git a/src/utils/pintos-gdb b/src/utils/pintos-gdb
index 4ef38d3..4ef38d3 100644..100755
--- a/src/utils/pintos-gdb
+++ b/src/utils/pintos-gdb
diff --git a/src/utils/pintos-mkdisk b/src/utils/pintos-mkdisk
index 662b2e5..662b2e5 100644..100755
--- a/src/utils/pintos-mkdisk
+++ b/src/utils/pintos-mkdisk