summaryrefslogtreecommitdiffstats
path: root/pintos-progos/notes/3.txt
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/notes/3.txt')
-rw-r--r--pintos-progos/notes/3.txt241
1 files changed, 241 insertions, 0 deletions
diff --git a/pintos-progos/notes/3.txt b/pintos-progos/notes/3.txt
new file mode 100644
index 0000000..bc64f88
--- /dev/null
+++ b/pintos-progos/notes/3.txt
@@ -0,0 +1,241 @@
1Project 2
2=========
3
4Working with Disks
5------------------
6
7Assumes 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
29Putting 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
34Getting 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
45This should be enough to see 'system call!' when executing
46the 'halt' example.
47
48Next, we need to implement user memory access and the
49the system call dispatcher, as well as the basic
50system calls halt, exit and write.
51
52A simple implementation of user memory access first checks
53whether the address is in user space, and the calls load_page.
54
55For an initial system call dispatcher, we convert the stack pointer
56saved by the processor during the interrupt to kernel space, and
57then dispatch to halt, exit and write. For now, exit just terminates
58the process, and write uses printf, ignoring the fd argument.
59The return value is stored into %eax.
60
61Notes:
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
99Stat:
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
108Argument Passing
109----------------
110First, we tokenize the command using strtok_r, and then setup
111the stack.
112
113Notes:
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
128Stat:
129 pintos/src/userprog/process.c | 116 +++++++++++++++++++++++++++++++++--------
130
131 Design and Implementation Time: 4 hours
132
133
134Process Management: exec, wait and exit
135---------------------------------------
136The wait system call requires that all children
137of a process are known, that the exit code of
138a process is stored until collected by the parent,
139and that the parent can block until the child
140process terminates.
141
142One difficult aspect in the design is that kernel
143threads are not processes, and that child threads
144may exit after their parent. It is important to
145note that threads do not need to wait for their
146children, but that we need to keep the exit status
147until the parent exits.
148
149In the original design, a thread is cleaned up when
150in the scheduler right after it died. In our design
151we delay the cleanup if the parent thread is still alive.
152
153Another issue is that thread_create needs to block
154until the load process of the child thread has finished.
155
156Notes:
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
175Stats:
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
183File I/O System Calls
184---------------------
185For file I/O we need to implement synchronization (filesys is not thread safe).
186The documentation states that it is not recommended to modify the code in
187the filesys directory for now. A very simple solution is to use one lock for all filesystem operations, including process.c#load.
188Furthermore, we need to deny writes to a a file currently running as a user
189space process.
190
191Notes:
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
206Stats:
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
217Improved User Memory Access
218---------------------------
219Looking at Project 3, it is a much better idea to not check whether a user
220space page is valid, but just let the page fault handler do the job.
221I decided to exit the process in the page fault handler if the address
222is in user space. One needs to take care of temporary memory allocated
223by the syscall handler, to avoid memory leaks. To this end, temporary kernel
224pages allocated in the handler are recorded and either freed at the end
225of the syscall or the end of the process.
226
227Notes:
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
233Stats:
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