. service tells you which device it couldn't stat
[minix3.git] / servers / pm / main.c
blobaba8fe67af0e0bfea8efbf8c8f8f682269232d80
1 /* This file contains the main program of the process manager and some related
2 * procedures. When MINIX starts up, the kernel runs for a little while,
3 * initializing itself and its tasks, and then it runs PM and FS. Both PM
4 * and FS initialize themselves as far as they can. PM asks the kernel for
5 * all free memory and starts serving requests.
7 * The entry points into this file are:
8 * main: starts PM running
9 * setreply: set the reply to be sent to process making an PM system call
12 #include "pm.h"
13 #include <minix/keymap.h>
14 #include <minix/callnr.h>
15 #include <minix/com.h>
16 #include <minix/endpoint.h>
17 #include <minix/minlib.h>
18 #include <minix/type.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <sys/resource.h>
23 #include <sys/utsname.h>
24 #include <string.h>
25 #include <archconst.h>
26 #include <archtypes.h>
27 #include <env.h>
28 #include "mproc.h"
29 #include "param.h"
31 #include "../../kernel/const.h"
32 #include "../../kernel/config.h"
33 #include "../../kernel/proc.h"
35 #if ENABLE_SYSCALL_STATS
36 EXTERN unsigned long calls_stats[NCALLS];
37 #endif
39 FORWARD _PROTOTYPE( void get_work, (void) );
40 FORWARD _PROTOTYPE( void pm_init, (void) );
41 FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
42 FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks) );
43 FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks,
44 struct mem_map *map_ptr) );
45 FORWARD _PROTOTYPE( void do_x86_vm, (struct memory mem_chunks[NR_MEMS]) );
46 FORWARD _PROTOTYPE( void send_work, (void) );
47 FORWARD _PROTOTYPE( void handle_fs_reply, (message *m_ptr) );
49 #define click_to_round_k(n) \
50 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
52 /*===========================================================================*
53 * main *
54 *===========================================================================*/
55 PUBLIC int main()
57 /* Main routine of the process manager. */
58 int result, s, proc_nr;
59 struct mproc *rmp;
60 sigset_t sigset;
62 pm_init(); /* initialize process manager tables */
64 /* This is PM's main loop- get work and do it, forever and forever. */
65 while (TRUE) {
66 get_work(); /* wait for an PM system call */
68 /* Check for system notifications first. Special cases. */
69 switch(call_nr)
71 case SYN_ALARM:
72 pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
73 result = SUSPEND; /* don't reply */
74 break;
75 case SYS_SIG: /* signals pending */
76 sigset = m_in.NOTIFY_ARG;
77 if (sigismember(&sigset, SIGKSIG)) {
78 (void) ksig_pending();
80 result = SUSPEND; /* don't reply */
81 break;
82 case PM_GET_WORK:
83 if (who_e == FS_PROC_NR)
85 send_work();
86 result= SUSPEND; /* don't reply */
88 else
89 result= ENOSYS;
90 break;
91 case PM_EXIT_REPLY:
92 case PM_REBOOT_REPLY:
93 case PM_EXEC_REPLY:
94 case PM_CORE_REPLY:
95 case PM_EXIT_REPLY_TR:
96 if (who_e == FS_PROC_NR)
98 handle_fs_reply(&m_in);
99 result= SUSPEND; /* don't reply */
101 else
102 result= ENOSYS;
103 break;
104 case ALLOCMEM:
105 result= do_allocmem();
106 break;
107 case FORK_NB:
108 result= do_fork_nb();
109 break;
110 case EXEC_NEWMEM:
111 result= exec_newmem();
112 break;
113 case EXEC_RESTART:
114 result= do_execrestart();
115 break;
116 case PROCSTAT:
117 result= do_procstat();
118 break;
119 case GETPROCNR:
120 result= do_getprocnr();
121 break;
122 default:
123 /* Else, if the system call number is valid, perform the
124 * call.
126 if ((unsigned) call_nr >= NCALLS) {
127 result = ENOSYS;
128 } else {
129 #if ENABLE_SYSCALL_STATS
130 calls_stats[call_nr]++;
131 #endif
132 result = (*call_vec[call_nr])();
134 break;
137 /* Send the results back to the user to indicate completion. */
138 if (result != SUSPEND) setreply(who_p, result);
140 swap_in(); /* maybe a process can be swapped in? */
142 /* Send out all pending reply messages, including the answer to
143 * the call just made above. The processes must not be swapped out.
145 for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
146 /* In the meantime, the process may have been killed by a
147 * signal (e.g. if a lethal pending signal was unblocked)
148 * without the PM realizing it. If the slot is no longer in
149 * use or just a zombie, don't try to reply.
151 if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
152 (REPLY | IN_USE)) {
153 if ((s=send(rmp->mp_endpoint, &rmp->mp_reply)) != OK) {
154 printf("PM can't reply to %d (%s)\n",
155 rmp->mp_endpoint, rmp->mp_name);
156 panic(__FILE__, "PM can't reply", NO_NUM);
158 rmp->mp_flags &= ~REPLY;
162 return(OK);
165 /*===========================================================================*
166 * get_work *
167 *===========================================================================*/
168 PRIVATE void get_work()
170 /* Wait for the next message and extract useful information from it. */
171 if (receive(ANY, &m_in) != OK)
172 panic(__FILE__,"PM receive error", NO_NUM);
173 who_e = m_in.m_source; /* who sent the message */
174 if(pm_isokendpt(who_e, &who_p) != OK)
175 panic(__FILE__, "PM got message from invalid endpoint", who_e);
176 call_nr = m_in.m_type; /* system call number */
178 /* Process slot of caller. Misuse PM's own process slot if the kernel is
179 * calling. This can happen in case of synchronous alarms (CLOCK) or or
180 * event like pending kernel signals (SYSTEM).
182 mp = &mproc[who_p < 0 ? PM_PROC_NR : who_p];
183 if(who_p >= 0 && mp->mp_endpoint != who_e) {
184 panic(__FILE__, "PM endpoint number out of sync with source",
185 mp->mp_endpoint);
189 /*===========================================================================*
190 * setreply *
191 *===========================================================================*/
192 PUBLIC void setreply(proc_nr, result)
193 int proc_nr; /* process to reply to */
194 int result; /* result of call (usually OK or error #) */
196 /* Fill in a reply message to be sent later to a user process. System calls
197 * may occasionally fill in other fields, this is only for the main return
198 * value, and for setting the "must send reply" flag.
200 register struct mproc *rmp = &mproc[proc_nr];
202 if(proc_nr < 0 || proc_nr >= NR_PROCS)
203 panic(__FILE__,"setreply arg out of range", proc_nr);
205 rmp->mp_reply.reply_res = result;
206 rmp->mp_flags |= REPLY; /* reply pending */
208 if (rmp->mp_flags & ONSWAP)
209 swap_inqueue(rmp); /* must swap this process back in */
212 /*===========================================================================*
213 * pm_init *
214 *===========================================================================*/
215 PRIVATE void pm_init()
217 /* Initialize the process manager.
218 * Memory use info is collected from the boot monitor, the kernel, and
219 * all processes compiled into the system image. Initially this information
220 * is put into an array mem_chunks. Elements of mem_chunks are struct memory,
221 * and hold base, size pairs in units of clicks. This array is small, there
222 * should be no more than 8 chunks. After the array of chunks has been built
223 * the contents are used to initialize the hole list. Space for the hole list
224 * is reserved as an array with twice as many elements as the maximum number
225 * of processes allowed. It is managed as a linked list, and elements of the
226 * array are struct hole, which, in addition to storage for a base and size in
227 * click units also contain space for a link, a pointer to another element.
229 int s;
230 static struct boot_image image[NR_BOOT_PROCS];
231 register struct boot_image *ip;
232 static char core_sigs[] = { SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
233 SIGEMT, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2 };
234 static char ign_sigs[] = { SIGCHLD, SIGWINCH, SIGCONT };
235 static char mess_sigs[] = { SIGTERM, SIGHUP, SIGABRT, SIGQUIT };
236 register struct mproc *rmp;
237 register char *sig_ptr;
238 phys_clicks total_clicks, minix_clicks, free_clicks;
239 message mess;
240 struct mem_map mem_map[NR_LOCAL_SEGS];
241 struct memory mem_chunks[NR_MEMS];
243 /* Initialize process table, including timers. */
244 for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
245 tmr_inittimer(&rmp->mp_timer);
247 rmp->mp_fs_call= PM_IDLE;
248 rmp->mp_fs_call2= PM_IDLE;
251 /* Build the set of signals which cause core dumps, and the set of signals
252 * that are by default ignored.
254 sigemptyset(&core_sset);
255 for (sig_ptr = core_sigs; sig_ptr < core_sigs+sizeof(core_sigs); sig_ptr++)
256 sigaddset(&core_sset, *sig_ptr);
257 sigemptyset(&ign_sset);
258 for (sig_ptr = ign_sigs; sig_ptr < ign_sigs+sizeof(ign_sigs); sig_ptr++)
259 sigaddset(&ign_sset, *sig_ptr);
261 /* Obtain a copy of the boot monitor parameters and the kernel info struct.
262 * Parse the list of free memory chunks. This list is what the boot monitor
263 * reported, but it must be corrected for the kernel and system processes.
265 if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK)
266 panic(__FILE__,"get monitor params failed",s);
267 get_mem_chunks(mem_chunks);
268 if ((s=sys_getkinfo(&kinfo)) != OK)
269 panic(__FILE__,"get kernel info failed",s);
271 /* Get the memory map of the kernel to see how much memory it uses. */
272 if ((s=get_mem_map(SYSTASK, mem_map)) != OK)
273 panic(__FILE__,"couldn't get memory map of SYSTASK",s);
274 minix_clicks = (mem_map[S].mem_phys+mem_map[S].mem_len)-mem_map[T].mem_phys;
275 patch_mem_chunks(mem_chunks, mem_map);
277 /* Initialize PM's process table. Request a copy of the system image table
278 * that is defined at the kernel level to see which slots to fill in.
280 if (OK != (s=sys_getimage(image)))
281 panic(__FILE__,"couldn't get image table: %d\n", s);
282 procs_in_use = 0; /* start populating table */
283 for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {
284 if (ip->proc_nr >= 0) { /* task have negative nrs */
285 procs_in_use += 1; /* found user process */
287 /* Set process details found in the image table. */
288 rmp = &mproc[ip->proc_nr];
289 strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN);
290 rmp->mp_parent = RS_PROC_NR;
291 rmp->mp_nice = get_nice_value(ip->priority);
292 sigemptyset(&rmp->mp_sig2mess);
293 sigemptyset(&rmp->mp_ignore);
294 sigemptyset(&rmp->mp_sigmask);
295 sigemptyset(&rmp->mp_catch);
296 if (ip->proc_nr == INIT_PROC_NR) { /* user process */
297 rmp->mp_procgrp = rmp->mp_pid = INIT_PID;
298 rmp->mp_flags |= IN_USE;
300 else { /* system process */
301 rmp->mp_pid = get_free_pid();
302 rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC;
303 for (sig_ptr = mess_sigs;
304 sig_ptr < mess_sigs+sizeof(mess_sigs);
305 sig_ptr++)
306 sigaddset(&rmp->mp_sig2mess, *sig_ptr);
309 /* Get kernel endpoint identifier. */
310 rmp->mp_endpoint = ip->endpoint;
312 /* Get memory map for this process from the kernel. */
313 if ((s=get_mem_map(ip->proc_nr, rmp->mp_seg)) != OK)
314 panic(__FILE__,"couldn't get process entry",s);
315 if (rmp->mp_seg[T].mem_len != 0) rmp->mp_flags |= SEPARATE;
316 minix_clicks += rmp->mp_seg[S].mem_phys +
317 rmp->mp_seg[S].mem_len - rmp->mp_seg[T].mem_phys;
318 patch_mem_chunks(mem_chunks, rmp->mp_seg);
320 /* Tell FS about this system process. */
321 mess.PR_SLOT = ip->proc_nr;
322 mess.PR_PID = rmp->mp_pid;
323 mess.PR_ENDPT = rmp->mp_endpoint;
324 if (OK != (s=send(FS_PROC_NR, &mess)))
325 panic(__FILE__,"can't sync up with FS", s);
329 /* Override some details. INIT, PM, FS and RS are somewhat special. */
330 mproc[PM_PROC_NR].mp_pid = PM_PID; /* PM has magic pid */
331 mproc[RS_PROC_NR].mp_parent = INIT_PROC_NR; /* INIT is root */
332 sigfillset(&mproc[PM_PROC_NR].mp_ignore); /* guard against signals */
334 /* Tell FS that no more system processes follow and synchronize. */
335 mess.PR_ENDPT = NONE;
336 if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK)
337 panic(__FILE__,"can't sync up with FS", NO_NUM);
339 #if ENABLE_BOOTDEV
340 /* Possibly we must correct the memory chunks for the boot device. */
341 if (kinfo.bootdev_size > 0) {
342 mem_map[T].mem_phys = kinfo.bootdev_base >> CLICK_SHIFT;
343 mem_map[T].mem_len = 0;
344 mem_map[D].mem_len = (kinfo.bootdev_size+CLICK_SIZE-1) >> CLICK_SHIFT;
345 patch_mem_chunks(mem_chunks, mem_map);
347 #endif /* ENABLE_BOOTDEV */
349 /* Withhold some memory from x86 VM */
350 do_x86_vm(mem_chunks);
352 /* Initialize tables to all physical memory and print memory information. */
353 printf("Physical memory:");
354 mem_init(mem_chunks, &free_clicks);
355 total_clicks = minix_clicks + free_clicks;
356 printf(" total %u KB,", click_to_round_k(total_clicks));
357 printf(" system %u KB,", click_to_round_k(minix_clicks));
358 printf(" free %u KB.\n", click_to_round_k(free_clicks));
359 #if (CHIP == INTEL)
360 uts_val.machine[0] = 'i';
361 strcpy(uts_val.machine + 1, itoa(getprocessor()));
362 #endif
365 /*===========================================================================*
366 * get_nice_value *
367 *===========================================================================*/
368 PRIVATE int get_nice_value(queue)
369 int queue; /* store mem chunks here */
371 /* Processes in the boot image have a priority assigned. The PM doesn't know
372 * about priorities, but uses 'nice' values instead. The priority is between
373 * MIN_USER_Q and MAX_USER_Q. We have to scale between PRIO_MIN and PRIO_MAX.
375 int nice_val = (queue - USER_Q) * (PRIO_MAX-PRIO_MIN+1) /
376 (MIN_USER_Q-MAX_USER_Q+1);
377 if (nice_val > PRIO_MAX) nice_val = PRIO_MAX; /* shouldn't happen */
378 if (nice_val < PRIO_MIN) nice_val = PRIO_MIN; /* shouldn't happen */
379 return nice_val;
382 /*===========================================================================*
383 * get_mem_chunks *
384 *===========================================================================*/
385 PRIVATE void get_mem_chunks(mem_chunks)
386 struct memory *mem_chunks; /* store mem chunks here */
388 /* Initialize the free memory list from the 'memory' boot variable. Translate
389 * the byte offsets and sizes in this list to clicks, properly truncated.
391 long base, size, limit;
392 int i;
393 struct memory *memp;
395 /* Obtain and parse memory from system environment. */
396 if(env_memory_parse(mem_chunks, NR_MEMS) != OK)
397 panic(__FILE__,"couldn't obtain memory chunks", NO_NUM);
399 /* Round physical memory to clicks. */
400 for (i = 0; i < NR_MEMS; i++) {
401 memp = &mem_chunks[i]; /* next mem chunk is stored here */
402 base = mem_chunks[i].base;
403 size = mem_chunks[i].size;
404 limit = base + size;
405 base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
406 limit &= ~(long)(CLICK_SIZE-1);
407 if (limit <= base) {
408 memp->base = memp->size = 0;
409 } else {
410 memp->base = base >> CLICK_SHIFT;
411 memp->size = (limit - base) >> CLICK_SHIFT;
416 /*===========================================================================*
417 * patch_mem_chunks *
418 *===========================================================================*/
419 PRIVATE void patch_mem_chunks(mem_chunks, map_ptr)
420 struct memory *mem_chunks; /* store mem chunks here */
421 struct mem_map *map_ptr; /* memory to remove */
423 /* Remove server memory from the free memory list. The boot monitor
424 * promises to put processes at the start of memory chunks. The
425 * tasks all use same base address, so only the first task changes
426 * the memory lists. The servers and init have their own memory
427 * spaces and their memory will be removed from the list.
429 struct memory *memp;
430 for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) {
431 if (memp->base == map_ptr[T].mem_phys) {
432 memp->base += map_ptr[T].mem_len + map_ptr[S].mem_vir;
433 memp->size -= map_ptr[T].mem_len + map_ptr[S].mem_vir;
434 break;
437 if (memp >= &mem_chunks[NR_MEMS])
439 panic(__FILE__,"patch_mem_chunks: can't find map in mem_chunks, start",
440 map_ptr[T].mem_phys);
444 #define PAGE_SIZE 4096
445 #define PAGE_TABLE_COVER (1024*PAGE_SIZE)
446 /*=========================================================================*
447 * do_x86_vm *
448 *=========================================================================*/
449 PRIVATE void do_x86_vm(mem_chunks)
450 struct memory mem_chunks[NR_MEMS];
452 phys_bytes high, bytes;
453 phys_clicks clicks, base_click;
454 unsigned pages;
455 int i, r;
457 /* Compute the highest memory location */
458 high= 0;
459 for (i= 0; i<NR_MEMS; i++)
461 if (mem_chunks[i].size == 0)
462 continue;
463 if (mem_chunks[i].base + mem_chunks[i].size > high)
464 high= mem_chunks[i].base + mem_chunks[i].size;
467 high <<= CLICK_SHIFT;
468 #if VERBOSE_VM
469 printf("do_x86_vm: found high 0x%x\n", high);
470 #endif
472 /* The number of pages we need is one for the page directory, enough
473 * page tables to cover the memory, and one page for alignement.
475 pages= 1 + (high + PAGE_TABLE_COVER-1)/PAGE_TABLE_COVER + 1;
476 bytes= pages*PAGE_SIZE;
477 clicks= (bytes + CLICK_SIZE-1) >> CLICK_SHIFT;
479 #if VERBOSE_VM
480 printf("do_x86_vm: need %d pages\n", pages);
481 printf("do_x86_vm: need %d bytes\n", bytes);
482 printf("do_x86_vm: need %d clicks\n", clicks);
483 #endif
485 for (i= 0; i<NR_MEMS; i++)
487 if (mem_chunks[i].size <= clicks)
488 continue;
489 break;
491 if (i >= NR_MEMS)
492 panic("PM", "not enough memory for VM page tables?", NO_NUM);
493 base_click= mem_chunks[i].base;
494 mem_chunks[i].base += clicks;
495 mem_chunks[i].size -= clicks;
497 #if VERBOSE_VM
498 printf("do_x86_vm: using 0x%x clicks @ 0x%x\n", clicks, base_click);
499 #endif
500 r= sys_vm_setbuf(base_click << CLICK_SHIFT, clicks << CLICK_SHIFT,
501 high);
502 if (r != 0)
503 printf("do_x86_vm: sys_vm_setbuf failed: %d\n", r);
506 /*=========================================================================*
507 * send_work *
508 *=========================================================================*/
509 PRIVATE void send_work()
511 int r, call;
512 struct mproc *rmp;
513 message m;
515 m.m_type= PM_IDLE;
516 for (rmp= mproc; rmp < &mproc[NR_PROCS]; rmp++)
518 call= rmp->mp_fs_call;
519 if (call == PM_IDLE)
520 call= rmp->mp_fs_call2;
521 if (call == PM_IDLE)
522 continue;
523 switch(call)
525 case PM_STIME:
526 m.m_type= call;
527 m.PM_STIME_TIME= boottime;
529 /* FS does not reply */
530 rmp->mp_fs_call= PM_IDLE;
532 /* Wakeup the original caller */
533 setreply(rmp-mproc, OK);
534 break;
536 case PM_SETSID:
537 m.m_type= call;
538 m.PM_SETSID_PROC= rmp->mp_endpoint;
540 /* FS does not reply */
541 rmp->mp_fs_call= PM_IDLE;
543 /* Wakeup the original caller */
544 setreply(rmp-mproc, rmp->mp_procgrp);
545 break;
547 case PM_SETGID:
548 m.m_type= call;
549 m.PM_SETGID_PROC= rmp->mp_endpoint;
550 m.PM_SETGID_EGID= rmp->mp_effgid;
551 m.PM_SETGID_RGID= rmp->mp_realgid;
553 /* FS does not reply */
554 rmp->mp_fs_call= PM_IDLE;
556 /* Wakeup the original caller */
557 setreply(rmp-mproc, OK);
558 break;
560 case PM_SETUID:
561 m.m_type= call;
562 m.PM_SETUID_PROC= rmp->mp_endpoint;
563 m.PM_SETUID_EGID= rmp->mp_effuid;
564 m.PM_SETUID_RGID= rmp->mp_realuid;
566 /* FS does not reply */
567 rmp->mp_fs_call= PM_IDLE;
569 /* Wakeup the original caller */
570 setreply(rmp-mproc, OK);
571 break;
573 case PM_FORK:
575 int parent_p;
576 struct mproc *parent_mp;
578 parent_p = rmp->mp_parent;
579 parent_mp = &mproc[parent_p];
581 m.m_type= call;
582 m.PM_FORK_PPROC= parent_mp->mp_endpoint;
583 m.PM_FORK_CPROC= rmp->mp_endpoint;
584 m.PM_FORK_CPID= rmp->mp_pid;
586 /* FS does not reply */
587 rmp->mp_fs_call= PM_IDLE;
589 /* Wakeup the newly created process */
590 setreply(rmp-mproc, OK);
592 /* Wakeup the parent */
593 setreply(parent_mp-mproc, rmp->mp_pid);
594 break;
597 case PM_EXIT:
598 case PM_EXIT_TR:
599 m.m_type= call;
600 m.PM_EXIT_PROC= rmp->mp_endpoint;
602 /* Mark the process as busy */
603 rmp->mp_fs_call= PM_BUSY;
605 break;
607 case PM_UNPAUSE:
608 m.m_type= call;
609 m.PM_UNPAUSE_PROC= rmp->mp_endpoint;
611 /* FS does not reply */
612 rmp->mp_fs_call2= PM_IDLE;
614 /* Ask the kernel to deliver the signal */
615 r= sys_sigsend(rmp->mp_endpoint,
616 &rmp->mp_sigmsg);
617 if (r != OK)
618 panic(__FILE__,"sys_sigsend failed",r);
620 break;
622 case PM_UNPAUSE_TR:
623 m.m_type= call;
624 m.PM_UNPAUSE_PROC= rmp->mp_endpoint;
626 /* FS does not reply */
627 rmp->mp_fs_call= PM_IDLE;
629 break;
631 case PM_EXEC:
632 m.m_type= call;
633 m.PM_EXEC_PROC= rmp->mp_endpoint;
634 m.PM_EXEC_PATH= rmp->mp_exec_path;
635 m.PM_EXEC_PATH_LEN= rmp->mp_exec_path_len;
636 m.PM_EXEC_FRAME= rmp->mp_exec_frame;
637 m.PM_EXEC_FRAME_LEN= rmp->mp_exec_frame_len;
639 /* Mark the process as busy */
640 rmp->mp_fs_call= PM_BUSY;
642 break;
644 case PM_FORK_NB:
646 int parent_p;
647 struct mproc *parent_mp;
649 parent_p = rmp->mp_parent;
650 parent_mp = &mproc[parent_p];
652 m.m_type= PM_FORK;
653 m.PM_FORK_PPROC= parent_mp->mp_endpoint;
654 m.PM_FORK_CPROC= rmp->mp_endpoint;
655 m.PM_FORK_CPID= rmp->mp_pid;
657 /* FS does not reply */
658 rmp->mp_fs_call= PM_IDLE;
660 break;
663 case PM_DUMPCORE:
664 m.m_type= call;
665 m.PM_CORE_PROC= rmp->mp_endpoint;
666 m.PM_CORE_SEGPTR= (char *)rmp->mp_seg;
668 /* Mark the process as busy */
669 rmp->mp_fs_call= PM_BUSY;
671 break;
673 default:
674 printf("send_work: should report call 0x%x to FS\n",
675 call);
676 break;
678 break;
680 if (m.m_type != PM_IDLE)
682 if (rmp->mp_fs_call == PM_IDLE &&
683 rmp->mp_fs_call2 == PM_IDLE &&
684 (rmp->mp_flags & PM_SIG_PENDING))
686 rmp->mp_flags &= ~PM_SIG_PENDING;
687 check_pending(rmp);
688 if (!(rmp->mp_flags & PM_SIG_PENDING))
690 /* Allow the process to be scheduled */
691 sys_nice(rmp->mp_endpoint, rmp->mp_nice);
695 else if (report_reboot)
697 m.m_type= PM_REBOOT;
698 report_reboot= FALSE;
700 r= send(FS_PROC_NR, &m);
701 if (r != OK) panic("pm", "send_work: send failed", r);
704 PRIVATE void handle_fs_reply(m_ptr)
705 message *m_ptr;
707 int r, proc_e, proc_n;
708 struct mproc *rmp;
710 switch(m_ptr->m_type)
712 case PM_EXIT_REPLY:
713 case PM_EXIT_REPLY_TR:
714 proc_e= m_ptr->PM_EXIT_PROC;
715 if (pm_isokendpt(proc_e, &proc_n) != OK)
717 panic(__FILE__,
718 "PM_EXIT_REPLY: got bad endpoint from FS",
719 proc_e);
721 rmp= &mproc[proc_n];
723 /* Call is finished */
724 rmp->mp_fs_call= PM_IDLE;
726 if (!(rmp->mp_flags & PRIV_PROC))
728 /* destroy the (user) process */
729 if((r=sys_exit(proc_e)) != OK)
731 panic(__FILE__,
732 "PM_EXIT_REPLY: sys_exit failed", r);
736 /* Release the memory occupied by the child. */
737 if (find_share(rmp, rmp->mp_ino, rmp->mp_dev,
738 rmp->mp_ctime) == NULL) {
739 /* No other process shares the text segment,
740 * so free it.
742 free_mem(rmp->mp_seg[T].mem_phys,
743 rmp->mp_seg[T].mem_len);
745 /* Free the data and stack segments. */
746 free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir +
747 rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
749 if (m_ptr->m_type == PM_EXIT_REPLY_TR &&
750 rmp->mp_parent != INIT_PROC_NR)
752 /* Wake up the parent */
753 mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
754 setreply(rmp->mp_parent, OK);
757 /* Clean up if the parent has collected the exit
758 * status
760 if (rmp->mp_flags & TOLD_PARENT)
761 real_cleanup(rmp);
763 break;
765 case PM_REBOOT_REPLY:
767 vir_bytes code_addr;
768 size_t code_size;
770 /* Ask the kernel to abort. All system services, including
771 * the PM, will get a HARD_STOP notification. Await the
772 * notification in the main loop.
774 code_addr = (vir_bytes) monitor_code;
775 code_size = strlen(monitor_code) + 1;
776 sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
777 break;
780 case PM_EXEC_REPLY:
781 proc_e= m_ptr->PM_EXEC_PROC;
782 if (pm_isokendpt(proc_e, &proc_n) != OK)
784 panic(__FILE__,
785 "PM_EXIT_REPLY: got bad endpoint from FS",
786 proc_e);
788 rmp= &mproc[proc_n];
790 /* Call is finished */
791 rmp->mp_fs_call= PM_IDLE;
793 exec_restart(rmp, m_ptr->PM_EXEC_STATUS);
795 if (rmp->mp_flags & PM_SIG_PENDING)
797 printf("handle_fs_reply: restarting signals\n");
798 rmp->mp_flags &= ~PM_SIG_PENDING;
799 check_pending(rmp);
800 if (!(rmp->mp_flags & PM_SIG_PENDING))
802 printf("handle_fs_reply: calling sys_nice\n");
803 /* Allow the process to be scheduled */
804 sys_nice(rmp->mp_endpoint, rmp->mp_nice);
806 else
807 printf("handle_fs_reply: more signals\n");
809 break;
811 case PM_CORE_REPLY:
813 int parent_waiting, right_child;
814 pid_t pidarg;
815 struct mproc *p_mp;
817 proc_e= m_ptr->PM_CORE_PROC;
818 if (pm_isokendpt(proc_e, &proc_n) != OK)
820 panic(__FILE__,
821 "PM_EXIT_REPLY: got bad endpoint from FS",
822 proc_e);
824 rmp= &mproc[proc_n];
826 if (m_ptr->PM_CORE_STATUS == OK)
827 rmp->mp_sigstatus |= DUMPED;
829 /* Call is finished */
830 rmp->mp_fs_call= PM_IDLE;
832 p_mp = &mproc[rmp->mp_parent]; /* process' parent */
833 pidarg = p_mp->mp_wpid; /* who's being waited for? */
834 parent_waiting = p_mp->mp_flags & WAITING;
835 right_child = /* child meets one of the 3 tests? */
836 (pidarg == -1 || pidarg == rmp->mp_pid ||
837 -pidarg == rmp->mp_procgrp);
839 if (parent_waiting && right_child) {
840 tell_parent(rmp); /* tell parent */
841 } else {
842 /* parent not waiting, zombify child */
843 rmp->mp_flags &= (IN_USE|PRIV_PROC);
844 rmp->mp_flags |= ZOMBIE;
845 /* send parent a "child died" signal */
846 sig_proc(p_mp, SIGCHLD);
849 if (!(rmp->mp_flags & PRIV_PROC))
851 /* destroy the (user) process */
852 if((r=sys_exit(proc_e)) != OK)
854 panic(__FILE__,
855 "PM_CORE_REPLY: sys_exit failed", r);
859 /* Release the memory occupied by the child. */
860 if (find_share(rmp, rmp->mp_ino, rmp->mp_dev,
861 rmp->mp_ctime) == NULL) {
862 /* No other process shares the text segment,
863 * so free it.
865 free_mem(rmp->mp_seg[T].mem_phys,
866 rmp->mp_seg[T].mem_len);
868 /* Free the data and stack segments. */
869 free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[S].mem_vir +
870 rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
872 /* Clean up if the parent has collected the exit
873 * status
875 if (rmp->mp_flags & TOLD_PARENT)
876 real_cleanup(rmp);
878 break;
880 default:
881 panic(__FILE__, "handle_fs_reply: unknown reply type",
882 m_ptr->m_type);
883 break;