panic() cleanup.
[minix.git] / servers / pm / main.c
bloba4fb748e6b86392f0b96cd5762040d6661cd5dfe
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/ds.h>
17 #include <minix/type.h>
18 #include <minix/endpoint.h>
19 #include <minix/minlib.h>
20 #include <minix/type.h>
21 #include <minix/vm.h>
22 #include <minix/crtso.h>
23 #include <signal.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <sys/resource.h>
27 #include <sys/utsname.h>
28 #include <string.h>
29 #include <archconst.h>
30 #include <archtypes.h>
31 #include <env.h>
32 #include "mproc.h"
33 #include "param.h"
35 #include "../../kernel/const.h"
36 #include "../../kernel/config.h"
37 #include "../../kernel/proc.h"
39 #if ENABLE_SYSCALL_STATS
40 EXTERN unsigned long calls_stats[NCALLS];
41 #endif
43 FORWARD _PROTOTYPE( void get_work, (void) );
44 FORWARD _PROTOTYPE( int get_nice_value, (int queue) );
45 FORWARD _PROTOTYPE( void handle_fs_reply, (void) );
47 #define click_to_round_k(n) \
48 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
50 extern int unmap_ok;
52 /* SEF functions and variables. */
53 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
54 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
56 /*===========================================================================*
57 * main *
58 *===========================================================================*/
59 PUBLIC int main()
61 /* Main routine of the process manager. */
62 int result, s, proc_nr;
63 struct mproc *rmp;
64 sigset_t sigset;
66 /* SEF local startup. */
67 sef_local_startup();
69 /* This is PM's main loop- get work and do it, forever and forever. */
70 while (TRUE) {
71 get_work(); /* wait for an PM system call */
73 /* Drop delayed calls from exiting processes. */
74 if (mp->mp_flags & EXITING)
75 continue;
77 /* Check for system notifications first. Special cases. */
78 if (is_notify(call_nr)) {
79 switch(who_p) {
80 case CLOCK:
81 pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
82 result = SUSPEND; /* don't reply */
83 break;
84 case SYSTEM: /* signals pending */
85 sigset = m_in.NOTIFY_ARG;
86 if (sigismember(&sigset, SIGKSIG)) {
87 (void) ksig_pending();
89 result = SUSPEND; /* don't reply */
90 break;
91 default :
92 result = ENOSYS;
95 /* done, send reply and continue */
96 goto send_reply;
99 switch(call_nr)
101 case PM_SETUID_REPLY:
102 case PM_SETGID_REPLY:
103 case PM_SETSID_REPLY:
104 case PM_EXEC_REPLY:
105 case PM_EXIT_REPLY:
106 case PM_CORE_REPLY:
107 case PM_FORK_REPLY:
108 case PM_FORK_NB_REPLY:
109 case PM_UNPAUSE_REPLY:
110 case PM_REBOOT_REPLY:
111 case PM_SETGROUPS_REPLY:
112 if (who_e == FS_PROC_NR)
114 handle_fs_reply();
115 result= SUSPEND; /* don't reply */
117 else
118 result= ENOSYS;
119 break;
120 default:
121 /* Else, if the system call number is valid, perform the
122 * call.
124 if ((unsigned) call_nr >= NCALLS) {
125 result = ENOSYS;
126 } else {
127 #if ENABLE_SYSCALL_STATS
128 calls_stats[call_nr]++;
129 #endif
131 result = (*call_vec[call_nr])();
134 break;
137 send_reply:
138 /* Send the results back to the user to indicate completion. */
139 if (result != SUSPEND) setreply(who_p, result);
141 /* Send out all pending reply messages, including the answer to
142 * the call just made above.
144 for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
145 /* In the meantime, the process may have been killed by a
146 * signal (e.g. if a lethal pending signal was unblocked)
147 * without the PM realizing it. If the slot is no longer in
148 * use or the process is exiting, don't try to reply.
150 if ((rmp->mp_flags & (REPLY | IN_USE | EXITING)) ==
151 (REPLY | IN_USE)) {
152 s=sendnb(rmp->mp_endpoint, &rmp->mp_reply);
153 if (s != OK) {
154 printf("PM can't reply to %d (%s): %d\n",
155 rmp->mp_endpoint, rmp->mp_name, s);
157 rmp->mp_flags &= ~REPLY;
161 return(OK);
164 /*===========================================================================*
165 * sef_local_startup *
166 *===========================================================================*/
167 PRIVATE void sef_local_startup()
169 /* Register init callbacks. */
170 sef_setcb_init_fresh(sef_cb_init_fresh);
171 sef_setcb_init_restart(sef_cb_init_restart_fail);
173 /* No live update support for now. */
175 /* Let SEF perform startup. */
176 sef_startup();
179 /*===========================================================================*
180 * sef_cb_init_fresh *
181 *===========================================================================*/
182 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
184 /* Initialize the process manager.
185 * Memory use info is collected from the boot monitor, the kernel, and
186 * all processes compiled into the system image. Initially this information
187 * is put into an array mem_chunks. Elements of mem_chunks are struct memory,
188 * and hold base, size pairs in units of clicks. This array is small, there
189 * should be no more than 8 chunks. After the array of chunks has been built
190 * the contents are used to initialize the hole list. Space for the hole list
191 * is reserved as an array with twice as many elements as the maximum number
192 * of processes allowed. It is managed as a linked list, and elements of the
193 * array are struct hole, which, in addition to storage for a base and size in
194 * click units also contain space for a link, a pointer to another element.
196 int s;
197 static struct boot_image image[NR_BOOT_PROCS];
198 register struct boot_image *ip;
199 static char core_sigs[] = { SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
200 SIGEMT, SIGFPE, SIGBUS, SIGSEGV };
201 static char ign_sigs[] = { SIGCHLD, SIGWINCH, SIGCONT };
202 static char mess_sigs[] = { SIGTERM, SIGHUP, SIGABRT, SIGQUIT };
203 static char noign_sigs[] = { SIGILL, SIGTRAP, SIGEMT, SIGFPE,
204 SIGBUS, SIGSEGV };
205 register struct mproc *rmp;
206 register char *sig_ptr;
207 message mess;
209 /* Initialize process table, including timers. */
210 for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
211 tmr_inittimer(&rmp->mp_timer);
214 /* Build the set of signals which cause core dumps, and the set of signals
215 * that are by default ignored.
217 sigemptyset(&core_sset);
218 for (sig_ptr = core_sigs; sig_ptr < core_sigs+sizeof(core_sigs); sig_ptr++)
219 sigaddset(&core_sset, *sig_ptr);
220 sigemptyset(&ign_sset);
221 for (sig_ptr = ign_sigs; sig_ptr < ign_sigs+sizeof(ign_sigs); sig_ptr++)
222 sigaddset(&ign_sset, *sig_ptr);
223 sigemptyset(&noign_sset);
224 for (sig_ptr = noign_sigs; sig_ptr < noign_sigs+sizeof(noign_sigs); sig_ptr++)
225 sigaddset(&noign_sset, *sig_ptr);
227 /* Obtain a copy of the boot monitor parameters and the kernel info struct.
228 * Parse the list of free memory chunks. This list is what the boot monitor
229 * reported, but it must be corrected for the kernel and system processes.
231 if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK)
232 panic("get monitor params failed: %d", s);
233 if ((s=sys_getkinfo(&kinfo)) != OK)
234 panic("get kernel info failed: %d", s);
236 /* Initialize PM's process table. Request a copy of the system image table
237 * that is defined at the kernel level to see which slots to fill in.
239 if (OK != (s=sys_getimage(image)))
240 panic("couldn't get image table: %d", s);
241 procs_in_use = 0; /* start populating table */
242 for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {
243 if (ip->proc_nr >= 0) { /* task have negative nrs */
244 procs_in_use += 1; /* found user process */
246 /* Set process details found in the image table. */
247 rmp = &mproc[ip->proc_nr];
248 strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN);
249 rmp->mp_nice = get_nice_value(ip->priority);
250 sigemptyset(&rmp->mp_sig2mess);
251 sigemptyset(&rmp->mp_ignore);
252 sigemptyset(&rmp->mp_sigmask);
253 sigemptyset(&rmp->mp_catch);
254 if (ip->proc_nr == INIT_PROC_NR) { /* user process */
255 /* INIT is root, we make it father of itself. This is
256 * not really OK, INIT should have no father, i.e.
257 * a father with pid NO_PID. But PM currently assumes
258 * that mp_parent always points to a valid slot number.
260 rmp->mp_parent = INIT_PROC_NR;
261 rmp->mp_procgrp = rmp->mp_pid = INIT_PID;
262 rmp->mp_flags |= IN_USE;
264 else { /* system process */
265 if(ip->proc_nr == RS_PROC_NR) {
266 rmp->mp_parent = INIT_PROC_NR;
268 else {
269 rmp->mp_parent = RS_PROC_NR;
271 rmp->mp_pid = get_free_pid();
272 rmp->mp_flags |= IN_USE | PRIV_PROC;
273 for (sig_ptr = mess_sigs;
274 sig_ptr < mess_sigs+sizeof(mess_sigs);
275 sig_ptr++)
276 sigaddset(&rmp->mp_sig2mess, *sig_ptr);
279 /* Get kernel endpoint identifier. */
280 rmp->mp_endpoint = ip->endpoint;
282 /* Tell FS about this system process. */
283 mess.m_type = PM_INIT;
284 mess.PM_SLOT = ip->proc_nr;
285 mess.PM_PID = rmp->mp_pid;
286 mess.PM_PROC = rmp->mp_endpoint;
287 if (OK != (s=send(FS_PROC_NR, &mess)))
288 panic("can't sync up with FS: %d", s);
292 /* Override some details for PM. */
293 sigfillset(&mproc[PM_PROC_NR].mp_ignore); /* guard against signals */
295 /* Tell FS that no more system processes follow and synchronize. */
296 mess.PR_ENDPT = NONE;
297 if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK)
298 panic("can't sync up with FS");
300 #if (CHIP == INTEL)
301 uts_val.machine[0] = 'i';
302 strcpy(uts_val.machine + 1, itoa(getprocessor()));
303 #endif
305 system_hz = sys_hz();
307 /* Map out our own text and data. This is normally done in crtso.o
308 * but PM is an exception - we don't get to talk to VM so early on.
309 * That's why we override munmap() and munmap_text() in utility.c.
311 * _minix_unmapzero() is the same code in crtso.o that normally does
312 * it on startup. It's best that it's there as crtso.o knows exactly
313 * what the ranges are of the filler data.
315 unmap_ok = 1;
316 _minix_unmapzero();
318 return(OK);
321 /*===========================================================================*
322 * get_work *
323 *===========================================================================*/
324 PRIVATE void get_work()
326 /* Wait for the next message and extract useful information from it. */
327 if (sef_receive(ANY, &m_in) != OK)
328 panic("PM sef_receive error");
329 who_e = m_in.m_source; /* who sent the message */
330 if(pm_isokendpt(who_e, &who_p) != OK)
331 panic("PM got message from invalid endpoint: %d", who_e);
332 call_nr = m_in.m_type; /* system call number */
334 /* Process slot of caller. Misuse PM's own process slot if the kernel is
335 * calling. This can happen in case of synchronous alarms (CLOCK) or or
336 * event like pending kernel signals (SYSTEM).
338 mp = &mproc[who_p < 0 ? PM_PROC_NR : who_p];
339 if(who_p >= 0 && mp->mp_endpoint != who_e) {
340 panic("PM endpoint number out of sync with source: %d", mp->mp_endpoint);
344 /*===========================================================================*
345 * setreply *
346 *===========================================================================*/
347 PUBLIC void setreply(proc_nr, result)
348 int proc_nr; /* process to reply to */
349 int result; /* result of call (usually OK or error #) */
351 /* Fill in a reply message to be sent later to a user process. System calls
352 * may occasionally fill in other fields, this is only for the main return
353 * value, and for setting the "must send reply" flag.
355 register struct mproc *rmp = &mproc[proc_nr];
357 if(proc_nr < 0 || proc_nr >= NR_PROCS)
358 panic("setreply arg out of range: %d", proc_nr);
360 rmp->mp_reply.reply_res = result;
361 rmp->mp_flags |= REPLY; /* reply pending */
364 /*===========================================================================*
365 * get_nice_value *
366 *===========================================================================*/
367 PRIVATE int get_nice_value(queue)
368 int queue; /* store mem chunks here */
370 /* Processes in the boot image have a priority assigned. The PM doesn't know
371 * about priorities, but uses 'nice' values instead. The priority is between
372 * MIN_USER_Q and MAX_USER_Q. We have to scale between PRIO_MIN and PRIO_MAX.
374 int nice_val = (queue - USER_Q) * (PRIO_MAX-PRIO_MIN+1) /
375 (MIN_USER_Q-MAX_USER_Q+1);
376 if (nice_val > PRIO_MAX) nice_val = PRIO_MAX; /* shouldn't happen */
377 if (nice_val < PRIO_MIN) nice_val = PRIO_MIN; /* shouldn't happen */
378 return nice_val;
381 void checkme(char *str, int line)
383 struct mproc *trmp;
384 int boned = 0;
385 int proc_nr;
386 for (proc_nr=0, trmp=mproc; proc_nr < NR_PROCS; proc_nr++, trmp++) {
387 if ((trmp->mp_flags & (REPLY | IN_USE | EXITING)) ==
388 (REPLY | IN_USE)) {
389 int tp;
390 if(pm_isokendpt(trmp->mp_endpoint, &tp) != OK) {
391 printf("PM: %s:%d: reply %d to %s is bogus endpoint %d after call %d by %d\n",
392 str, line, trmp->mp_reply.m_type,
393 trmp->mp_name, trmp->mp_endpoint, call_nr, who_e);
394 boned=1;
397 if(boned) panic("corrupt mp_endpoint?");
401 /*===========================================================================*
402 * handle_fs_reply *
403 *===========================================================================*/
404 PRIVATE void handle_fs_reply()
406 struct mproc *rmp;
407 endpoint_t proc_e;
408 int r, proc_n;
410 /* PM_REBOOT is the only request not associated with a process.
411 * Handle its reply first.
413 if (call_nr == PM_REBOOT_REPLY) {
414 vir_bytes code_addr;
415 size_t code_size;
417 /* Ask the kernel to abort. All system services, including
418 * the PM, will get a HARD_STOP notification. Await the
419 * notification in the main loop.
421 code_addr = (vir_bytes) monitor_code;
422 code_size = strlen(monitor_code) + 1;
423 sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
425 return;
428 /* Get the process associated with this call */
429 proc_e = m_in.PM_PROC;
431 if (pm_isokendpt(proc_e, &proc_n) != OK) {
432 panic("handle_fs_reply: got bad endpoint from FS: %d", proc_e);
435 rmp = &mproc[proc_n];
437 /* Now that FS replied, mark the process as FS-idle again */
438 if (!(rmp->mp_flags & FS_CALL))
439 panic("handle_fs_reply: reply without request: %d", call_nr);
441 rmp->mp_flags &= ~FS_CALL;
443 if (rmp->mp_flags & UNPAUSED)
444 panic("handle_fs_reply: UNPAUSED set on entry: %d", call_nr);
446 /* Call-specific handler code */
447 switch (call_nr) {
448 case PM_SETUID_REPLY:
449 case PM_SETGID_REPLY:
450 case PM_SETGROUPS_REPLY:
451 /* Wake up the original caller */
452 setreply(rmp-mproc, OK);
454 break;
456 case PM_SETSID_REPLY:
457 /* Wake up the original caller */
458 setreply(rmp-mproc, rmp->mp_procgrp);
460 break;
462 case PM_EXEC_REPLY:
463 exec_restart(rmp, m_in.PM_STATUS);
465 break;
467 case PM_EXIT_REPLY:
468 exit_restart(rmp, FALSE /*dump_core*/);
470 break;
472 case PM_CORE_REPLY:
473 if (m_in.PM_STATUS == OK)
474 rmp->mp_sigstatus |= DUMPED;
476 exit_restart(rmp, TRUE /*dump_core*/);
478 break;
480 case PM_FORK_REPLY:
481 /* Wake up the newly created process */
482 setreply(proc_n, OK);
484 /* Wake up the parent */
485 setreply(rmp->mp_parent, rmp->mp_pid);
487 break;
489 case PM_FORK_NB_REPLY:
490 /* Nothing to do */
492 break;
494 case PM_UNPAUSE_REPLY:
495 /* Process is now unpaused */
496 rmp->mp_flags |= UNPAUSED;
498 break;
500 default:
501 panic("handle_fs_reply: unknown reply code: %d", call_nr);
504 /* Now that the process is idle again, look at pending signals */
505 if ((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE)
506 restart_sigs(rmp);