diff options
| author | manuel <manuel@mausz.at> | 2012-03-27 11:51:08 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2012-03-27 11:51:08 +0200 |
| commit | 4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b (patch) | |
| tree | 868c52e06f207b5ec8a3cc141f4b8b2bdfcc165c /notes | |
| parent | eae0bd57f0a26314a94785061888d193d186944a (diff) | |
| download | progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.tar.gz progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.tar.bz2 progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.zip | |
reorganize file structure to match the upstream requirements
Diffstat (limited to 'notes')
| -rw-r--r-- | notes/1.txt | 81 | ||||
| -rw-r--r-- | notes/2.txt | 164 | ||||
| -rw-r--r-- | notes/3.txt | 241 |
3 files changed, 486 insertions, 0 deletions
diff --git a/notes/1.txt b/notes/1.txt new file mode 100644 index 0000000..9d478f7 --- /dev/null +++ b/notes/1.txt | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | Getting Started with PINTOS | ||
| 2 | =========================== | ||
| 3 | |||
| 4 | Building Project 1 | ||
| 5 | ------------------ | ||
| 6 | |||
| 7 | pintos $ cd src/threads | ||
| 8 | threads $ make | ||
| 9 | |||
| 10 | |||
| 11 | Building Bochs | ||
| 12 | -------------- | ||
| 13 | You should have a patched bochs install available. | ||
| 14 | |||
| 15 | See | ||
| 16 | |||
| 17 | http://courses.mpi-sws.org/os-ss11/assignments/pintos/pintos_12.html#SEC160 | ||
| 18 | |||
| 19 | There is a build script src/misc/bochs-2.3.7-build.sh in the pintos fork from Saarland, | ||
| 20 | which (after small modifications) works on a modern Ubuntu x86. | ||
| 21 | |||
| 22 | For Ubuntu 11 with a Linux 3.0 kernel, you need to: | ||
| 23 | |||
| 24 | * Regenerate the configure script (autoconf configure.in) | ||
| 25 | * Patch the test for Linux 2.4 or 2.6 | ||
| 26 | |||
| 27 | After building, copy bochs and bochs-gdb to the pintos/src/utils directory | ||
| 28 | |||
| 29 | Running | ||
| 30 | ------- | ||
| 31 | |||
| 32 | # [pintos/src] | ||
| 33 | PATH=`pwd`/utils:$PATH | ||
| 34 | |||
| 35 | cd threads/build | ||
| 36 | # [pintos/src/threads/build] | ||
| 37 | pintos run alarm-multiple > logfile | ||
| 38 | |||
| 39 | |||
| 40 | ### Reproducability | ||
| 41 | |||
| 42 | This command line flags to pintos influence reproducability. | ||
| 43 | Remember: you need the patched bochs build. | ||
| 44 | |||
| 45 | -j seed ... Reproducible behavior | ||
| 46 | -r ... Real-Time behavior | ||
| 47 | |||
| 48 | Running with qemu | ||
| 49 | ----------------- | ||
| 50 | |||
| 51 | # [pintos/src] | ||
| 52 | vim utils/pintos # comment line with -no-kqemu flag | ||
| 53 | |||
| 54 | cd threads/build | ||
| 55 | # [pintos/src/threads/build] | ||
| 56 | pintos --qemu -- run alarm-multiple | ||
| 57 | |||
| 58 | Debugging | ||
| 59 | --------- | ||
| 60 | |||
| 61 | pintos $ vim utils/pintos-gdb | ||
| 62 | |||
| 63 | GDBMACROS=${PINTOS_SRC}/misc/gdb-macros | ||
| 64 | |||
| 65 | [pts/0 build] $ pintos --gdb -- run alarm-multiple | ||
| 66 | [pts/1 build] $ pintos-gdb kernel.o | ||
| 67 | (gdb) debugpintos | ||
| 68 | |||
| 69 | Testing | ||
| 70 | ------- | ||
| 71 | |||
| 72 | * Running all tests | ||
| 73 | |||
| 74 | build $ make check | ||
| 75 | |||
| 76 | * Running a single test | ||
| 77 | |||
| 78 | build $ rm tests/threads/alarm-multiple.result | ||
| 79 | build $ make tests/threads/alarm-multiple.result | ||
| 80 | |||
| 81 | |||
diff --git a/notes/2.txt b/notes/2.txt new file mode 100644 index 0000000..c81b980 --- /dev/null +++ b/notes/2.txt | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | Projekt 1 - Threads | ||
| 2 | =================== | ||
| 3 | |||
| 4 | alarm clock | ||
| 5 | ----------- | ||
| 6 | The simplest strategy is to maintain a wait list for | ||
| 7 | all threads blocked for sleep. | ||
| 8 | |||
| 9 | * In 'timer_interrupt', check for threads which can be | ||
| 10 | unblocked from sleeping | ||
| 11 | * In 'sleep', set sleep timeout in thread, block the | ||
| 12 | thread and put it on the sleep list | ||
| 13 | |||
| 14 | Notes: | ||
| 15 | |||
| 16 | * There are three places where a thread is added to the | ||
| 17 | ready list: | ||
| 18 | - thread_init | ||
| 19 | - thread_yield | ||
| 20 | - thread_unblock | ||
| 21 | * Iterate list with removal: | ||
| 22 | for (e = list_begin (&list); e != list_end (&list); ) | ||
| 23 | if(...) | ||
| 24 | e = list_remove(e)->prev; | ||
| 25 | /* Unblock must be called AFTER removing, as thread.elem is reused */ | ||
| 26 | else | ||
| 27 | e = list_next(e); | ||
| 28 | |||
| 29 | Stats: | ||
| 30 | |||
| 31 | pintos/src/devices/timer.c | 40 ++++++++++++++++++++++++++++++++++++++-- | ||
| 32 | pintos/src/threads/thread.h | 3 +++ | ||
| 33 | 2 files changed, 41 insertions(+), 2 deletions(-) | ||
| 34 | |||
| 35 | Design & Implementation time: 4 hours | ||
| 36 | |||
| 37 | Priority Scheduler | ||
| 38 | ------------------ | ||
| 39 | |||
| 40 | A simple implementation of the priority scheduler (64 priority levels, round robin within | ||
| 41 | one priority group). | ||
| 42 | |||
| 43 | * If a new task arrives with a higher priority, switch to this group | ||
| 44 | * If the currently active group is empty, search for the group with the next highest priority | ||
| 45 | |||
| 46 | Notes: | ||
| 47 | |||
| 48 | * thread_{init,unblock,yield} now call thread_ready, which updates the lowest ready priority | ||
| 49 | * The thread_unblock operation does not yield a new thread immediately. Therefore, we need to check | ||
| 50 | later whether we need to switch to a higher priority thread (via thread_yield). | ||
| 51 | As thread_unblock is called with interrupts off, it seemed best to perform | ||
| 52 | this check when interrupts are enabled. This is only necessary if a higher priority task | ||
| 53 | is ready. | ||
| 54 | * First attempt passed alarm-priority, but failed to pass the priority-preempt test. | ||
| 55 | But the debugging facilities are fantastic, so it was easy to spot the problem | ||
| 56 | * Wolfgang suggested to yield a software interrupt when unblocking instead of modifying | ||
| 57 | interrupt_enable. | ||
| 58 | |||
| 59 | Stats: | ||
| 60 | |||
| 61 | pintos/src/threads/interrupt.c | 3 +- | ||
| 62 | pintos/src/threads/thread.c | 60 ++++++++++++++++++++++++++++++++-------- | ||
| 63 | pintos/src/threads/thread.h | 1 + | ||
| 64 | 3 files changed, 51 insertions(+), 13 deletions(-) | ||
| 65 | |||
| 66 | Design and implementation time: 3 hours | ||
| 67 | |||
| 68 | Priority Locks | ||
| 69 | -------------- | ||
| 70 | |||
| 71 | We also need to select higher priority task first from locks, semaphores and condition variables. | ||
| 72 | This easiest implementation searches for the thread with the highest priority in the wait queue. | ||
| 73 | |||
| 74 | Notes: | ||
| 75 | |||
| 76 | * It is sufficient to implement the priority based selection twice, for sema_up and | ||
| 77 | cond_signal. cond_signal is a little bit harder, as we need to store the priority | ||
| 78 | (or the waiting thread) in the semaphore_elem type | ||
| 79 | * There are some handy list utility functions; in this case, list_max does a fine job | ||
| 80 | for both sema_up and cond_signal | ||
| 81 | * It is difficult to implement this in an efficient (sublinear) way, because priority donation | ||
| 82 | may boost a thread at any time! | ||
| 83 | |||
| 84 | Stats: | ||
| 85 | |||
| 86 | pintos/src/threads/synch.c | 40 ++++++++++++++++++++++++++++++++++------ | ||
| 87 | 1 files changed, 34 insertions(+), 6 deletions(-) | ||
| 88 | |||
| 89 | Design and Implementation time: 1 hour | ||
| 90 | |||
| 91 | Priority Donation | ||
| 92 | ----------------- | ||
| 93 | If a thread aquires a lock, the lock holder needs to be boosted to the donated priority. | ||
| 94 | We need to deal with nesting and chaining: | ||
| 95 | |||
| 96 | * Lock/Thread correspondence: Each lock is associated with at most one thread that holds it. | ||
| 97 | Therefore, donated priority can be associated with a lock. | ||
| 98 | * If a thread t wants to obtain a lock L, and a thread with a lower priority holds it, | ||
| 99 | the thread holding the lock is boosted to the priority of the requesting thread | ||
| 100 | * Chaining: If the boosted thread is also blocked on a lock, than we also need to donate | ||
| 101 | the priority to that lock, in a transitive way. | ||
| 102 | * Nesting: If a thread may hold more than one lock, we need to keep track of the donation | ||
| 103 | to each lock. When a lock is released or the static priority changes, the highest priority | ||
| 104 | donated to other locks is assigned to the thread. | ||
| 105 | |||
| 106 | With this information, the following rules seem suitable (without proof of correctness): | ||
| 107 | |||
| 108 | * If thread T tries to aquire lock L | ||
| 109 | |||
| 110 | ==> if(L.owner) | ||
| 111 | T.locked_on = L | ||
| 112 | donate_priority (L, T.priority) | ||
| 113 | end | ||
| 114 | donate_priority (L ,p) := | ||
| 115 | L.priority v= p | ||
| 116 | L.holder.priority v= p | ||
| 117 | donate_priority( L.holder.locked_on, p) | ||
| 118 | end | ||
| 119 | |||
| 120 | * If a thread T aquires a lock L | ||
| 121 | |||
| 122 | ==> L.holder = T | ||
| 123 | T.locks += L | ||
| 124 | T.lock_on = none | ||
| 125 | |||
| 126 | |||
| 127 | * If a thread T releases a lock L | ||
| 128 | |||
| 129 | ==> L.holder = none | ||
| 130 | T.locks -= L | ||
| 131 | T.priority = max (T.locks.priority, static_priority) | ||
| 132 | |||
| 133 | To implement this, each thread needs to maintain a list of locks, a static priority, | ||
| 134 | and a reference to the lock blocking it. | ||
| 135 | |||
| 136 | Notes: | ||
| 137 | |||
| 138 | * Difficult to design, really a challenge. | ||
| 139 | Literature (short paper) could be helpful. | ||
| 140 | Maybe it would be interesting to ask for correctness proof sketches? | ||
| 141 | |||
| 142 | * First design was wrong, because I assumed locks are aquired in FIFO fashion | ||
| 143 | * First implementation failed to pass donate tests, due to a typo. Debugging | ||
| 144 | facilities are fantastic, no problem to spot this one. | ||
| 145 | * Next try, priority-donate-lower failed. Looking at the source code revealed that | ||
| 146 | we need to recompute the priority at the end of thread_set_priority. | ||
| 147 | * Next try, priority-donate-chain failed. Chaining is tricky to get right; | ||
| 148 | in my implementation, chained donations were lost after one lock was released. | ||
| 149 | |||
| 150 | * It would be an interesting option to ask for new test cases from the students | ||
| 151 | * I think it would also be a cool task to write a test for a RMS scheduling | ||
| 152 | scenario with blocking. | ||
| 153 | |||
| 154 | Stats: | ||
| 155 | |||
| 156 | pintos/src/threads/synch.c | 15 ++++++++++++ | ||
| 157 | pintos/src/threads/synch.h | 6 +++- | ||
| 158 | pintos/src/threads/thread.c | 53 +++++++++++++++++++++++++++++++++++++++++- | ||
| 159 | pintos/src/threads/thread.h | 9 ++++++- | ||
| 160 | pintos/src/utils/pintos | 2 +- | ||
| 161 | |||
| 162 | Design: 5h | ||
| 163 | Implementation: 3h | ||
| 164 | |||
diff --git a/notes/3.txt b/notes/3.txt new file mode 100644 index 0000000..bc64f88 --- /dev/null +++ b/notes/3.txt | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | Project 2 | ||
| 2 | ========= | ||
| 3 | |||
| 4 | Working with Disks | ||
| 5 | ------------------ | ||
| 6 | |||
| 7 | Assumes you ran make in src/userprog and src/examples. | ||
| 8 | |||
| 9 | * Create a 2 MB hard disk for pintos | ||
| 10 | |||
| 11 | # [src/userprog/build] | ||
| 12 | pintos-mkdisk filesys.dsk --filesys-size=2 | ||
| 13 | |||
| 14 | * Format Disk | ||
| 15 | |||
| 16 | # -f ... format virtual disk | ||
| 17 | pintos -f -q | ||
| 18 | |||
| 19 | * Copy file to filesystem | ||
| 20 | |||
| 21 | # -p FILE ... file to put on virtual disk | ||
| 22 | # -a FILE ... newname on virtual disk | ||
| 23 | pintos -p ../../examples/echo -a echo -- -q | ||
| 24 | |||
| 25 | * Execute echo, and get file 'echo' from the virtual disk | ||
| 26 | |||
| 27 | pintos -g echo -- -q run 'echo x' | ||
| 28 | |||
| 29 | Putting all together, we can run an minimal example like that: | ||
| 30 | |||
| 31 | # [src/userprog/build] | ||
| 32 | pintos --filesys-size=2 -p ../../examples/halt -a halt -- -f -q run 'halt' | ||
| 33 | |||
| 34 | Getting Started | ||
| 35 | --------------- | ||
| 36 | |||
| 37 | * Fix the problem with the .note.gnu.build-id segment | ||
| 38 | |||
| 39 | * Change the stack setup in process.c#setup_stack() to | ||
| 40 | |||
| 41 | *esp = PHYS_BASE - 12; | ||
| 42 | |||
| 43 | * Change process_wait() to an infinite loop | ||
| 44 | |||
| 45 | This should be enough to see 'system call!' when executing | ||
| 46 | the 'halt' example. | ||
| 47 | |||
| 48 | Next, we need to implement user memory access and the | ||
| 49 | the system call dispatcher, as well as the basic | ||
| 50 | system calls halt, exit and write. | ||
| 51 | |||
| 52 | A simple implementation of user memory access first checks | ||
| 53 | whether the address is in user space, and the calls load_page. | ||
| 54 | |||
| 55 | For an initial system call dispatcher, we convert the stack pointer | ||
| 56 | saved by the processor during the interrupt to kernel space, and | ||
| 57 | then dispatch to halt, exit and write. For now, exit just terminates | ||
| 58 | the process, and write uses printf, ignoring the fd argument. | ||
| 59 | The return value is stored into %eax. | ||
| 60 | |||
| 61 | Notes: | ||
| 62 | * halt(): There is no function shutdown() in init.h, only | ||
| 63 | shutdown_poweroff in shutdown.h | ||
| 64 | |||
| 65 | * When accessing data from user space in kernel space, we need to be | ||
| 66 | sure that the entire address ranged accessed is in user space. | ||
| 67 | Note that pointers are not necessarily aligned, and thus might | ||
| 68 | involve two user pages. | ||
| 69 | Furthermore, buffers need to be copied to kernel space; | ||
| 70 | otherwise, concurrent user space operations could corrupt the kernel. | ||
| 71 | Linux allows at most one kernel page for such buffers; we follow | ||
| 72 | the same route. | ||
| 73 | |||
| 74 | * Debugging: the function hex_dump() is useful; no need to | ||
| 75 | reimplement it. | ||
| 76 | |||
| 77 | * Something went wrong with the write system call, and this | ||
| 78 | is rather tricky to debug. | ||
| 79 | I invoked the system call directly, using inline | ||
| 80 | assembly; this worked fine? | ||
| 81 | Then I tried to debug the user space program; to this | ||
| 82 | end, lookup the code address you are interested in, | ||
| 83 | and use gdb together with objdump for debugging: | ||
| 84 | |||
| 85 | Debugging 'write(1,"USA\n",4)' | ||
| 86 | |||
| 87 | break *0x0804820e # break at <write> | ||
| 88 | cont # pushl 0xc(%esp) | ||
| 89 | info registers # esp = 0xbfffffbc | ||
| 90 | x/1w (0xbfffffbc+0xc) # ==> 4 (length) | ||
| 91 | stepi # pushl 0x8(%esp) | ||
| 92 | info registers # esp = 0x......b8 | ||
| 93 | x/1w 0xbfffffb8 # ==> 4 (TOS) | ||
| 94 | x/1w (0xbfffffb8+8) # ==> 1 (wrong) !!! | ||
| 95 | |||
| 96 | Apparently, the inline assembler in pintos does not use | ||
| 97 | the right constraints. | ||
| 98 | |||
| 99 | Stat: | ||
| 100 | pintos/src/lib/user/syscall.c | 6 +- | ||
| 101 | pintos/src/userprog/process.c | 5 ++- | ||
| 102 | pintos/src/userprog/syscall.c | 92 ++++++++++++++++++++++++++++++++++++++-- | ||
| 103 | |||
| 104 | Reading and Implementation Time: 6 hours | ||
| 105 | Debugging Syscalls: 5 hours | ||
| 106 | |||
| 107 | |||
| 108 | Argument Passing | ||
| 109 | ---------------- | ||
| 110 | First, we tokenize the command using strtok_r, and then setup | ||
| 111 | the stack. | ||
| 112 | |||
| 113 | Notes: | ||
| 114 | * As noted in the doc, just using strtok_r seems fine. | ||
| 115 | However, as strtok_r modifies the string even if only | ||
| 116 | the first token is needed, some copying is involved | ||
| 117 | if it is used to obtain the filename. | ||
| 118 | * Due to the detailed description in the documentation, | ||
| 119 | setting up the stack is mostly implementation work. | ||
| 120 | * One of the trickier implementation aspects is that we | ||
| 121 | modify the stack in kernel space, but need to convert | ||
| 122 | pointers to user space before pushing them on the stack. | ||
| 123 | * Debugging: Optimizations were really troublesome debugging | ||
| 124 | this task; making setup_stack non-static at least helped | ||
| 125 | to set a suitable breakpoint. In the end, printf was the | ||
| 126 | better debugging aid for this task. | ||
| 127 | |||
| 128 | Stat: | ||
| 129 | pintos/src/userprog/process.c | 116 +++++++++++++++++++++++++++++++++-------- | ||
| 130 | |||
| 131 | Design and Implementation Time: 4 hours | ||
| 132 | |||
| 133 | |||
| 134 | Process Management: exec, wait and exit | ||
| 135 | --------------------------------------- | ||
| 136 | The wait system call requires that all children | ||
| 137 | of a process are known, that the exit code of | ||
| 138 | a process is stored until collected by the parent, | ||
| 139 | and that the parent can block until the child | ||
| 140 | process terminates. | ||
| 141 | |||
| 142 | One difficult aspect in the design is that kernel | ||
| 143 | threads are not processes, and that child threads | ||
| 144 | may exit after their parent. It is important to | ||
| 145 | note that threads do not need to wait for their | ||
| 146 | children, but that we need to keep the exit status | ||
| 147 | until the parent exits. | ||
| 148 | |||
| 149 | In the original design, a thread is cleaned up when | ||
| 150 | in the scheduler right after it died. In our design | ||
| 151 | we delay the cleanup if the parent thread is still alive. | ||
| 152 | |||
| 153 | Another issue is that thread_create needs to block | ||
| 154 | until the load process of the child thread has finished. | ||
| 155 | |||
| 156 | Notes: | ||
| 157 | * I wanted to use the same semaphore for startup and wait. | ||
| 158 | This works, but we need one additional variable (or bit) | ||
| 159 | to distinguish failure at load time from failure at | ||
| 160 | runtime. | ||
| 161 | * Ugly 1: thread_create only gives back a tid, | ||
| 162 | so it is not possible to directly access the semaphore | ||
| 163 | in process_execute. Therefore we need to iterate over the | ||
| 164 | child list (which is not that bad, because if loading failed, | ||
| 165 | the child needs to be removed from the list anyway). | ||
| 166 | * Ugly 2: We up the semaphore used to synchronize | ||
| 167 | with process_execute and process_wait in thread.c, for | ||
| 168 | all threads. | ||
| 169 | * As also noted by rene, it is important to identifiy memory leaks, | ||
| 170 | as early as possible. To this end, first add debug messages to | ||
| 171 | page_alloc/page_free, and then run test programs to identify leaking | ||
| 172 | pages. Then debug, add conditional breakpoints to stop when a leaking | ||
| 173 | page is allocated, and inspect the stacktrace to find the culprit. | ||
| 174 | |||
| 175 | Stats: | ||
| 176 | pintos/src/threads/thread.c | 31 +++++++++++++++++--- | ||
| 177 | pintos/src/threads/thread.h | 8 +++++ | ||
| 178 | pintos/src/userprog/process.c | 60 ++++++++++++++++++++++++++++++++-------- | ||
| 179 | pintos/src/userprog/syscall.c | 19 +++++++++--- | ||
| 180 | |||
| 181 | Design and Implementation Time: 7 hours | ||
| 182 | |||
| 183 | File I/O System Calls | ||
| 184 | --------------------- | ||
| 185 | For file I/O we need to implement synchronization (filesys is not thread safe). | ||
| 186 | The documentation states that it is not recommended to modify the code in | ||
| 187 | the filesys directory for now. A very simple solution is to use one lock for all filesystem operations, including process.c#load. | ||
| 188 | Furthermore, we need to deny writes to a a file currently running as a user | ||
| 189 | space process. | ||
| 190 | |||
| 191 | Notes: | ||
| 192 | * init_thread() must not aquire locks, and thus not allocate pages. | ||
| 193 | Otherwise, the initialization of the init thread fails. | ||
| 194 | * The {lg,sm}-full tests failed in the initial implementation; | ||
| 195 | apparently, the read/write system calls should always read/write the | ||
| 196 | full amount of bytes specified to pass this tests. This was not | ||
| 197 | clear from the assignment. | ||
| 198 | * It is not obvious that file_close calls file_allow_write. But an | ||
| 199 | executable should not be writeable during its execution. Therefore, | ||
| 200 | one needs to make sure that it stays write protected after loading | ||
| 201 | has finished. I solve this by keeping the executable open during | ||
| 202 | execution. | ||
| 203 | * The multi-oom test failed again; debugging revealed that I forgot | ||
| 204 | to close all files at process_exit. | ||
| 205 | |||
| 206 | Stats: | ||
| 207 | |||
| 208 | pintos/src/threads/thread.c | 1 + | ||
| 209 | pintos/src/threads/thread.h | 6 +- | ||
| 210 | pintos/src/userprog/process.c | 53 ++++- | ||
| 211 | pintos/src/userprog/process.h | 2 + | ||
| 212 | pintos/src/userprog/syscall.c | 435 +++++++++++++++++++++++++++++++----- | ||
| 213 | pintos/src/userprog/syscall.h | 1 + | ||
| 214 | 6 files changed, 381 insertions(+), 117 deletions(-) | ||
| 215 | Design and Implementation Time: 8 hours | ||
| 216 | |||
| 217 | Improved User Memory Access | ||
| 218 | --------------------------- | ||
| 219 | Looking at Project 3, it is a much better idea to not check whether a user | ||
| 220 | space page is valid, but just let the page fault handler do the job. | ||
| 221 | I decided to exit the process in the page fault handler if the address | ||
| 222 | is in user space. One needs to take care of temporary memory allocated | ||
| 223 | by the syscall handler, to avoid memory leaks. To this end, temporary kernel | ||
| 224 | pages allocated in the handler are recorded and either freed at the end | ||
| 225 | of the syscall or the end of the process. | ||
| 226 | |||
| 227 | Notes: | ||
| 228 | * When using this approach, it is vital to copy user buffers | ||
| 229 | before reading or writing. With virtual memory, a page fault may | ||
| 230 | require to access the file system, and thus may cause race | ||
| 231 | conditions during access to the file system | ||
| 232 | |||
| 233 | Stats: | ||
| 234 | pintos/src/threads/thread.h | 5 +- | ||
| 235 | pintos/src/userprog/exception.c | 17 ++- | ||
| 236 | pintos/src/userprog/process.c | 2 +- | ||
| 237 | pintos/src/userprog/syscall.c | 314 +++++++++++++++++++-------------------- | ||
| 238 | pintos/src/userprog/syscall.h | 2 +- | ||
| 239 | 5 files changed, 173 insertions(+), 167 deletions(-) | ||
| 240 | |||
| 241 | Implementation Time: 3 hours | ||
