root/Whitix/trunk/kernel/process.c

Revision 2055, 9.8 KB (checked in by mwhitworth, 3 years ago)

Convert SysWaitForProcessFinish to Thr*, add syscall wrapper.

Line 
1#include <fs/icfs.h>
2#include <sched.h>
3#include <module.h>
4#include <slab.h>
5#include <task.h>
6#include <sys.h>
7#include <i386/process.h>
8#include <malloc.h>
9#include <keobject.h>
10#include <user_acc.h>
11
12LIST_HEAD(processList);
13extern struct ListHead threadList;
14Spinlock procListLock;
15struct Cache* processCache;
16int pid=0;
17
18struct IcAttribute processAttributes[]=
19{
20        IC_STRING(struct Process, name, IC_READ), /* Could be RW? */
21        IC_INT(struct Process, state, IC_READ),
22        IC_INT(struct Process, numFds, IC_READ),
23        IC_STRING(struct Process, cmdLine, IC_READ),
24        IC_END(),
25};
26
27KE_OBJECT_TYPE(processType, ThrFreeProcess);
28struct KeSet processSet;
29
30/***********************************************************************
31 *
32 * FUNCTION: ThrFindProcessById
33 *
34 * DESCRIPTION: Returns process information for a given process id.
35 *
36 * PARAMETERS: pid - the id for the process.
37 *
38 * RETURNS: process with pid's value.
39 *
40 ***********************************************************************/
41
42struct Process* ThrFindProcessById(DWORD pid)
43{
44        struct Process* curr;
45        int found=0;
46
47        /*
48         * Don't want a process removed from underneath us while traversing
49         * the list.
50         */
51
52        PreemptDisable();
53
54        ListForEachEntry(curr,&processList,next)
55                if (curr->pid == pid)
56                {
57                        found=1;
58                        break;
59                }
60
61        PreemptEnable();
62       
63        if (!found)
64                return NULL;
65
66        return curr;
67}
68
69/***********************************************************************
70 *
71 * FUNCTION: ThrCreateProcess
72 *
73 * DESCRIPTION: Create a new user process with the given name. However,
74 *              no threads are created with it, so it is not scheduled
75 *              until then.
76 *
77 * PARAMETERS: name - the name of the new process.
78 *
79 ***********************************************************************/
80
81struct Process* ThrCreateProcess(char* name)
82{
83        struct Process* process;
84
85        if (!name)
86                return NULL;
87
88        process=(struct Process*)MemCacheAlloc(processCache);
89       
90        if (!process)
91                return NULL;
92
93        /* Set up the new process' address space. */
94        if (VirtMemManagerSetup(process))
95        {
96                MemCacheFree(processCache, process);
97               
98                process = NULL;
99               
100                goto out;
101        }
102
103        /* Allocate the process's name - used when listing processes or when faulting. */
104        process->name=(char*)MemAlloc(strlen(name)+1);
105        strncpy(process->name, name, strlen(name));
106
107        process->pid = pid++;
108        process->cId = 0; /* Used to give IDs to threads. */
109
110        process->state = THR_RUNNING;
111
112        SpinLockIrq(&procListLock);
113
114        /* Add to parent's children list. Used for notify when a parent disappears. */
115        process->parent = current;
116
117        if (current)
118        {
119                ThrGetProcess(process);
120                ListAddTail(&process->sibling, &current->children);
121        }
122
123        /* Create the process kernel object, and add it to /Processes.
124         * KeObjectInit is called in the slab constructor. */
125        if (KeObjectAttach(&process->object, "%d", process->pid))
126        {
127                ListRemove(&process->sibling);
128                MemCacheFree(processCache, process);
129                process = NULL;
130                goto out;
131        }
132       
133        IcAddAttributes(&process->object, processAttributes, OffsetOf(struct Process, object));
134
135        ListAddTail(&process->next,&processList);
136       
137out:
138
139        SpinUnlockIrq(&procListLock);
140        return process;
141}
142
143SYMBOL_EXPORT(ThrCreateProcess);
144
145/***********************************************************************
146 *
147 * FUNCTION: ThrFreeProcess
148 *
149 * DESCRIPTION: Free all resources associated with a process that haven't
150 *                              already been freed in ThrProcessExit.
151 *
152 * PARAMETERS: process - the process to be freed.
153 *
154 * RETURNS: Nothing.
155 *
156 ***********************************************************************/
157
158void ThrFreeProcess(struct KeObject* object)
159{
160        DWORD flags;
161        struct Process* process;
162        IrqSaveFlags(flags);
163
164        process = ContainerOf(object, struct Process, object);
165       
166        PreemptDisable();
167
168        /* Remove process from the parent's list of children. */
169        if (process->parent)
170                ListRemove(&process->sibling);
171
172        ListRemove(&process->next);
173
174        PreemptEnable();
175
176        MemFree(process->cmdLine);
177        MemFree(process->name);
178        MemCacheFree(processCache, process);
179
180        IrqRestoreFlags(flags);
181}
182
183SYMBOL_EXPORT(ThrFreeProcess);
184
185/***********************************************************************
186 *
187 * FUNCTION: ThrGetProcName
188 *
189 * DESCRIPTION: Returns the process name of the given process id.
190 *
191 * PARAMETERS: pid - the process's id.
192 *
193 * RETURNS: the process name.
194 *
195 ***********************************************************************/
196
197char* ThrGetProcName(DWORD pid)
198{
199        struct Process* curr;
200        char* name = "<none>";
201
202        PreemptDisable();
203
204        ListForEachEntry(curr,&processList,next)
205                if (curr->pid == pid)
206                {
207                        name = curr->name;
208                        break;
209                }
210       
211        PreemptEnable();
212
213        return name;
214}
215
216int ThrWaitForProcessFinish(int pid, int* finishStatus)
217{
218        struct Process* curr;
219        int retVal=0, shouldWait;
220       
221repeat:
222        PreemptDisable();
223        shouldWait = 0;         
224        ListForEachEntry(curr, &current->children, sibling)
225        {
226                if (pid >= 0 && curr->pid != pid)
227                                continue;
228               
229                shouldWait = 1;
230                               
231                if (curr->state == THR_DYING)
232                {
233                        if (finishStatus)
234                                *finishStatus = (curr->exitCode << 8);
235                               
236                        retVal = curr->pid;
237                        PreemptEnable();
238                        ThrPutProcess(curr);
239                        goto out;
240                }
241        }
242
243        PreemptFastEnable();
244
245        if (shouldWait)
246        {
247                retVal = 0;
248                SLEEP_ON(&current->waitQueue);
249                goto repeat;
250        }
251       
252        retVal = -ENOENT;
253
254out:
255        return retVal;
256}
257
258/***********************************************************************
259 *
260 * FUNCTION:    SysWaitForProcessFinish
261 *
262 * DESCRIPTION: Waits on a certain process exiting.
263 *
264 * PARAMETERS:  pid - the process id to wait on.
265 *
266 * RETURNS:             0 if success, -ETIMEOUT if wait timed out.
267 *
268 ***********************************************************************/
269
270/* In future, add time to timeout */
271
272int SysWaitForProcessFinish(int pid,int* finishStatus)
273{
274        if (finishStatus)
275                if (VirtCheckArea(finishStatus,sizeof(int),VER_WRITE))
276                        return -EFAULT;
277                       
278        return ThrWaitForProcessFinish(pid, finishStatus);
279}
280
281/***********************************************************************
282 *
283 * FUNCTION:    SysGetCurrentProcessId
284 *
285 * DESCRIPTION: Get the pid of the current process.
286 *
287 * PARAMETERS:  None.
288 *
289 * RETURNS:             Process id of the current process.
290 *
291 ***********************************************************************/
292
293int SysGetCurrentProcessId()
294{
295        return current->pid;
296}
297
298void ThrProcessConstructor(void* obj)
299{
300        struct Process* process=(struct Process*)obj;
301
302        ZeroMemory(process,sizeof(struct Process));
303
304        INIT_WAITQUEUE_HEAD(&process->waitQueue);
305        INIT_LIST_HEAD(&process->areaList);
306        INIT_LIST_HEAD(&process->children);
307        KeObjectInit(&process->object, &processSet);
308}
309
310/***********************************************************************
311 *
312 * FUNCTION: ThrRelativeAlert
313 *
314 * DESCRIPTION: Alerts relatives of the process that the process is
315 *                              exiting.
316 *
317 * PARAMETERS: None.
318 *
319 * RETURNS: Nothing.
320 *
321 ***********************************************************************/
322
323static void ThrRelativeAlert()
324{
325        struct Process* currProc, *currProc2;
326
327        /* Go through all the children and abandon them. */
328        ListForEachEntrySafe(currProc, currProc2, &current->children, sibling)
329        {
330                ThrPutProcess(currProc);
331                currProc->parent=NULL;
332        }
333       
334        /* Signify to parent that process has finished. (if waiting in
335           SysWaitForProcessFinish. */
336
337        if (current->parent)
338                WakeUpAll(&current->parent->waitQueue);
339}
340
341/***********************************************************************
342 *
343 * FUNCTION: ThrProcessExit
344 *
345 * DESCRIPTION: Exit the current process
346 *
347 * PARAMETERS: returnCode - value to give to parent process.
348 *
349 * RETURNS: Nothing.
350 *
351 ***********************************************************************/
352
353void ThrProcessExit(int returnCode)
354{
355        struct Thread* curr,*curr2;
356
357        SpinLockIrq(&procListLock);
358
359        current->state = THR_DYING;
360        current->exitCode = returnCode;
361
362        /* Release all vmm areas. TODO: Should probably do this after other threads have
363         * been ended. */
364        MmapProcessRemove(current);
365        LoadReleaseFsContext();
366
367        /* Now get rid of the memory manager - leaving kernel memory pages intact */
368        VirtDestroyMemManager(current->memManager);
369        current->memManager=NULL;
370
371        /*
372         * Alert the relatives of the process. For example, the parent may be
373         * waiting in SysWaitForProcessFinish for the process to exit.
374         */
375
376        ThrRelativeAlert();
377
378        /* Get a reference to the current thread, as it still has to continue on. */
379        ThrGetThread(currThread);
380
381        ListForEachEntrySafe(curr,curr2,&threadList,list)
382        {
383                if (curr->parent == current)
384                {
385//                      if (curr->state != THR_RUNNING)
386//                              ThrResumeThread(curr); /* FIXME: Need to resume? */
387                                               
388                        curr->state=THR_DYING;
389                       
390                        /* General destruction. */
391                        TimerThreadExit(curr);
392                       
393                        ThrReleaseThread(curr); /* A waitqueue might still have a reference to this thread, so might not be freed */
394                        ThrArchDestroyThread(curr);
395                }
396        }
397
398        ThrPutProcess(current);
399       
400        current = NULL; /* Will reschedule as soon as possible - so no big deal,
401                                        the parent has a reference to the process anyway. */
402
403        SpinUnlockIrq(&procListLock);
404
405        ThrSchedule();
406}
407
408SYMBOL_EXPORT(ThrProcessExit);
409
410/***********************************************************************
411 *
412 * FUNCTION:    SysExit
413 *
414 * DESCRIPTION: Exits the current process. Doesn't return to
415 *                              userspace (obviously), but thrNeedSchedule schedules
416 *                              afterwards
417 *
418 * PARAMETERS:  returnCode - the value the current process wants to pass
419 *                                                       to it's parents.
420 *
421 * RETURNS: 0.
422 *
423 ***********************************************************************/
424
425int SysExit(int returnCode)
426{
427        ThrProcessExit(returnCode);
428       
429        /* Shouldn't get here. */
430        return 0;
431}
432
433struct SysCall procSysCallTable[]=
434{
435        SysEntry(SysGetCurrentProcessId, 0),
436        SysEntry(SysExit, 4),
437        SysEntry(SysWaitForProcessFinish, 8),
438        SysEntryEnd()
439};
440
441int ProcessInit()
442{
443        processCache=MemCacheCreate("Processes", sizeof(struct Process), ThrProcessConstructor, NULL, 0);
444
445        SysRegisterRange(SYS_PROCESS_BASE, procSysCallTable);
446
447        /* Create the process set. Exposing the process via the filesystem allows
448         * us to do debugging in quite a nice way. */
449        KeSetCreate(&processSet, NULL, &processType, "Processes");
450
451        return 0;
452}
Note: See TracBrowser for help on using the browser.