/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- proc_create
- proc_destroy
- proc_bootstrap
- proc_create_runprogram
- proc_addthread
- proc_remthread
- curproc_getas
- curproc_setas
1 /*
2 * Copyright (c) 2013
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * Process support.
32 *
33 * There is (intentionally) not much here; you will need to add stuff
34 * and maybe change around what's already present.
35 *
36 * p_lock is intended to be held when manipulating the pointers in the
37 * proc structure, not while doing any significant work with the
38 * things they point to. Rearrange this (and/or change it to be a
39 * regular lock) as needed.
40 *
41 * Unless you're implementing multithreaded user processes, the only
42 * process that will have more than one thread is the kernel process.
43 */
44
45 #include <types.h>
46 #include <proc.h>
47 #include <current.h>
48 #include <addrspace.h>
49 #include <vnode.h>
50 #include <vfs.h>
51 #include <synch.h>
52 #include <kern/fcntl.h>
53
54 /*
55 * The process for the kernel; this holds all the kernel-only threads.
56 */
57 struct proc *kproc;
58
59 /*
60 * Mechanism for making the kernel menu thread sleep while processes are running
61 */
62 #ifdef UW
63 /* count of the number of processes, excluding kproc */
64 static unsigned int proc_count;
65 /* provides mutual exclusion for proc_count */
66 /* it would be better to use a lock here, but we use a semaphore because locks are not implemented in the base kernel */
67 static struct semaphore *proc_count_mutex;
68 /* used to signal the kernel menu thread when there are no processes */
69 struct semaphore *no_proc_sem;
70 #endif // UW
71
72
73
74 /*
75 * Create a proc structure.
76 */
77 static
78 struct proc *
79 proc_create(const char *name)
80 {
81 struct proc *proc;
82
83 proc = kmalloc(sizeof(*proc));
84 if (proc == NULL) {
85 return NULL;
86 }
87 proc->p_name = kstrdup(name);
88 if (proc->p_name == NULL) {
89 kfree(proc);
90 return NULL;
91 }
92
93 threadarray_init(&proc->p_threads);
94 spinlock_init(&proc->p_lock);
95
96 /* VM fields */
97 proc->p_addrspace = NULL;
98
99 /* VFS fields */
100 proc->p_cwd = NULL;
101
102 #ifdef UW
103 proc->console = NULL;
104 #endif // UW
105
106 return proc;
107 }
108
109 /*
110 * Destroy a proc structure.
111 */
112 void
113 proc_destroy(struct proc *proc)
114 {
115 /*
116 * note: some parts of the process structure, such as the address space,
117 * are destroyed in sys_exit, before we get here
118 *
119 * note: depending on where this function is called from, curproc may not
120 * be defined because the calling thread may have already detached itself
121 * from the process.
122 */
123
124 KASSERT(proc != NULL);
125 KASSERT(proc != kproc);
126
127 /*
128 * We don't take p_lock in here because we must have the only
129 * reference to this structure. (Otherwise it would be
130 * incorrect to destroy it.)
131 */
132
133 /* VFS fields */
134 if (proc->p_cwd) {
135 VOP_DECREF(proc->p_cwd);
136 proc->p_cwd = NULL;
137 }
138
139
140 #ifndef UW // in the UW version, space destruction occurs in sys_exit, not here
141 if (proc->p_addrspace) {
142 /*
143 * In case p is the currently running process (which
144 * it might be in some circumstances, or if this code
145 * gets moved into exit as suggested above), clear
146 * p_addrspace before calling as_destroy. Otherwise if
147 * as_destroy sleeps (which is quite possible) when we
148 * come back we'll be calling as_activate on a
149 * half-destroyed address space. This tends to be
150 * messily fatal.
151 */
152 struct addrspace *as;
153
154 as_deactivate();
155 as = curproc_setas(NULL);
156 as_destroy(as);
157 }
158 #endif // UW
159
160 #ifdef UW
161 if (proc->console) {
162 vfs_close(proc->console);
163 }
164 #endif // UW
165
166 threadarray_cleanup(&proc->p_threads);
167 spinlock_cleanup(&proc->p_lock);
168
169 kfree(proc->p_name);
170 kfree(proc);
171
172 #ifdef UW
173 /* decrement the process count */
174 /* note: kproc is not included in the process count, but proc_destroy
175 is never called on kproc (see KASSERT above), so we're OK to decrement
176 the proc_count unconditionally here */
177 P(proc_count_mutex);
178 KASSERT(proc_count > 0);
179 proc_count--;
180 /* signal the kernel menu thread if the process count has reached zero */
181 if (proc_count == 0) {
182 V(no_proc_sem);
183 }
184 V(proc_count_mutex);
185 #endif // UW
186
187
188 }
189
190 /*
191 * Create the process structure for the kernel.
192 */
193 void
194 proc_bootstrap(void)
195 {
196 kproc = proc_create("[kernel]");
197 if (kproc == NULL) {
198 panic("proc_create for kproc failed\n");
199 }
200 #ifdef UW
201 proc_count = 0;
202 proc_count_mutex = sem_create("proc_count_mutex",1);
203 if (proc_count_mutex == NULL) {
204 panic("could not create proc_count_mutex semaphore\n");
205 }
206 no_proc_sem = sem_create("no_proc_sem",0);
207 if (no_proc_sem == NULL) {
208 panic("could not create no_proc_sem semaphore\n");
209 }
210 #endif // UW
211 }
212
213 /*
214 * Create a fresh proc for use by runprogram.
215 *
216 * It will have no address space and will inherit the current
217 * process's (that is, the kernel menu's) current directory.
218 */
219 struct proc *
220 proc_create_runprogram(const char *name)
221 {
222 struct proc *proc;
223 char *console_path;
224
225 proc = proc_create(name);
226 if (proc == NULL) {
227 return NULL;
228 }
229
230 #ifdef UW
231 /* open the console - this should always succeed */
232 console_path = kstrdup("con:");
233 if (console_path == NULL) {
234 panic("unable to copy console path name during process creation\n");
235 }
236 if (vfs_open(console_path,O_WRONLY,0,&(proc->console))) {
237 panic("unable to open the console during process creation\n");
238 }
239 kfree(console_path);
240 #endif // UW
241
242 /* VM fields */
243
244 proc->p_addrspace = NULL;
245
246 /* VFS fields */
247
248 #ifdef UW
249 /* we do not need to acquire the p_lock here, the running thread should
250 have the only reference to this process */
251 /* also, acquiring the p_lock is problematic because VOP_INCREF may block */
252 if (curproc->p_cwd != NULL) {
253 VOP_INCREF(curproc->p_cwd);
254 proc->p_cwd = curproc->p_cwd;
255 }
256 #else // UW
257 spinlock_acquire(&curproc->p_lock);
258 if (curproc->p_cwd != NULL) {
259 VOP_INCREF(curproc->p_cwd);
260 proc->p_cwd = curproc->p_cwd;
261 }
262 spinlock_release(&curproc->p_lock);
263 #endif // UW
264
265 #ifdef UW
266 /* increment the count of processes */
267 /* we are assuming that all procs, including those created by fork(),
268 are created using a call to proc_create_runprogram */
269 P(proc_count_mutex);
270 proc_count++;
271 V(proc_count_mutex);
272 #endif // UW
273
274 return proc;
275 }
276
277 /*
278 * Add a thread to a process. Either the thread or the process might
279 * or might not be current.
280 */
281 int
282 proc_addthread(struct proc *proc, struct thread *t)
283 {
284 int result;
285
286 KASSERT(t->t_proc == NULL);
287
288 spinlock_acquire(&proc->p_lock);
289 result = threadarray_add(&proc->p_threads, t, NULL);
290 spinlock_release(&proc->p_lock);
291 if (result) {
292 return result;
293 }
294 t->t_proc = proc;
295 return 0;
296 }
297
298 /*
299 * Remove a thread from its process. Either the thread or the process
300 * might or might not be current.
301 */
302 void
303 proc_remthread(struct thread *t)
304 {
305 struct proc *proc;
306 unsigned i, num;
307
308 proc = t->t_proc;
309 KASSERT(proc != NULL);
310
311 spinlock_acquire(&proc->p_lock);
312 /* ugh: find the thread in the array */
313 num = threadarray_num(&proc->p_threads);
314 for (i=0; i<num; i++) {
315 if (threadarray_get(&proc->p_threads, i) == t) {
316 threadarray_remove(&proc->p_threads, i);
317 spinlock_release(&proc->p_lock);
318 t->t_proc = NULL;
319 return;
320 }
321 }
322 /* Did not find it. */
323 spinlock_release(&proc->p_lock);
324 panic("Thread (%p) has escaped from its process (%p)\n", t, proc);
325 }
326
327 /*
328 * Fetch the address space of the current process. Caution: it isn't
329 * refcounted. If you implement multithreaded processes, make sure to
330 * set up a refcount scheme or some other method to make this safe.
331 */
332 struct addrspace *
333 curproc_getas(void)
334 {
335 struct addrspace *as;
336 #ifdef UW
337 /* Until user processes are created, threads used in testing
338 * (i.e., kernel threads) have no process or address space.
339 */
340 if (curproc == NULL) {
341 return NULL;
342 }
343 #endif
344
345 spinlock_acquire(&curproc->p_lock);
346 as = curproc->p_addrspace;
347 spinlock_release(&curproc->p_lock);
348 return as;
349 }
350
351 /*
352 * Change the address space of the current process, and return the old
353 * one.
354 */
355 struct addrspace *
356 curproc_setas(struct addrspace *newas)
357 {
358 struct addrspace *oldas;
359 struct proc *proc = curproc;
360
361 spinlock_acquire(&proc->p_lock);
362 oldas = proc->p_addrspace;
363 proc->p_addrspace = newas;
364 spinlock_release(&proc->p_lock);
365 return oldas;
366 }