Much USB code for ARM USB support
[minix3.git] / minix / servers / rs / main.c
blob6b7e032a7457417090a1de73a8e65a0d9d73911f
1 /* Reincarnation Server. This servers starts new system services and detects
2 * they are exiting. In case of errors, system services can be restarted.
3 * The RS server periodically checks the status of all registered services
4 * services to see whether they are still alive. The system services are
5 * expected to periodically send a heartbeat message.
6 *
7 * Changes:
8 * Nov 22, 2009: rewrite of boot process (Cristiano Giuffrida)
9 * Jul 22, 2005: Created (Jorrit N. Herder)
11 #include "inc.h"
12 #include <fcntl.h>
13 #include "kernel/const.h"
14 #include "kernel/type.h"
15 #include "kernel/proc.h"
17 /* Declare some local functions. */
18 static void boot_image_info_lookup( endpoint_t endpoint, struct
19 boot_image *image, struct boot_image **ip, struct boot_image_priv **pp,
20 struct boot_image_sys **sp, struct boot_image_dev **dp);
21 static void catch_boot_init_ready(endpoint_t endpoint);
22 static void get_work(message *m_ptr, int *status_ptr);
24 /* SEF functions and variables. */
25 static void sef_local_startup(void);
26 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
27 static void sef_cb_signal_handler(int signo);
28 static int sef_cb_signal_manager(endpoint_t target, int signo);
31 /*===========================================================================*
32 * main *
33 *===========================================================================*/
34 int main(void)
36 /* This is the main routine of this service. The main loop consists of
37 * three major activities: getting new work, processing the work, and
38 * sending the reply. The loop never terminates, unless a panic occurs.
40 message m; /* request message */
41 int ipc_status; /* status code */
42 int call_nr, who_e,who_p; /* call number and caller */
43 int result; /* result to return */
44 int s;
46 /* SEF local startup. */
47 sef_local_startup();
49 if (OK != (s=sys_getmachine(&machine)))
50 panic("couldn't get machine info: %d", s);
52 if (OK != (s=sys_getkinfo(&kinfo)))
53 panic("couldn't get kernel kinfo: %d", s);
55 /* Main loop - get work and do it, forever. */
56 while (TRUE) {
58 /* Wait for request message. */
59 get_work(&m, &ipc_status);
60 who_e = m.m_source;
61 if(rs_isokendpt(who_e, &who_p) != OK) {
62 panic("message from bogus source: %d", who_e);
65 call_nr = m.m_type;
67 /* Now determine what to do. Four types of requests are expected:
68 * - Heartbeat messages (notifications from registered system services)
69 * - System notifications (synchronous alarm)
70 * - User requests (control messages to manage system services)
71 * - Ready messages (reply messages from registered services)
74 /* Notification messages are control messages and do not need a reply.
75 * These include heartbeat messages and system notifications.
77 if (is_ipc_notify(ipc_status)) {
78 switch (who_p) {
79 case CLOCK:
80 do_period(&m); /* check services status */
81 continue;
82 default: /* heartbeat notification */
83 if (rproc_ptr[who_p] != NULL) { /* mark heartbeat time */
84 rproc_ptr[who_p]->r_alive_tm = m.m_notify.timestamp;
85 } else {
86 printf("RS: warning: got unexpected notify message from %d\n",
87 m.m_source);
92 /* If we get this far, this is a normal request.
93 * Handle the request and send a reply to the caller.
95 else {
96 /* Handler functions are responsible for permission checking. */
97 switch(call_nr) {
98 /* User requests. */
99 case RS_UP: result = do_up(&m); break;
100 case RS_DOWN: result = do_down(&m); break;
101 case RS_REFRESH: result = do_refresh(&m); break;
102 case RS_RESTART: result = do_restart(&m); break;
103 case RS_SHUTDOWN: result = do_shutdown(&m); break;
104 case RS_UPDATE: result = do_update(&m); break;
105 case RS_CLONE: result = do_clone(&m); break;
106 case RS_EDIT: result = do_edit(&m); break;
107 case RS_GETSYSINFO: result = do_getsysinfo(&m); break;
108 case RS_LOOKUP: result = do_lookup(&m); break;
109 /* Ready messages. */
110 case RS_INIT: result = do_init_ready(&m); break;
111 case RS_LU_PREPARE: result = do_upd_ready(&m); break;
112 default:
113 printf("RS: warning: got unexpected request %d from %d\n",
114 m.m_type, m.m_source);
115 result = ENOSYS;
118 /* Finally send reply message, unless disabled. */
119 if (result != EDONTREPLY) {
120 m.m_type = result;
121 reply(who_e, NULL, &m);
127 /*===========================================================================*
128 * sef_local_startup *
129 *===========================================================================*/
130 static void sef_local_startup()
132 /* Register init callbacks. */
133 sef_setcb_init_response(do_init_ready);
134 sef_setcb_init_fresh(sef_cb_init_fresh);
135 sef_setcb_init_restart(sef_cb_init_fail);
137 /* Register live update callbacks. */
138 sef_setcb_lu_response(do_upd_ready);
140 /* Register signal callbacks. */
141 sef_setcb_signal_handler(sef_cb_signal_handler);
142 sef_setcb_signal_manager(sef_cb_signal_manager);
144 /* Let SEF perform startup. */
145 sef_startup();
148 /*===========================================================================*
149 * sef_cb_init_fresh *
150 *===========================================================================*/
151 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
153 /* Initialize the reincarnation server. */
154 struct boot_image *ip;
155 int s,i;
156 int nr_image_srvs, nr_image_priv_srvs, nr_uncaught_init_srvs;
157 struct rproc *rp;
158 struct rprocpub *rpub;
159 struct boot_image image[NR_BOOT_PROCS];
160 struct boot_image_priv *boot_image_priv;
161 struct boot_image_sys *boot_image_sys;
162 struct boot_image_dev *boot_image_dev;
163 int ipc_to;
164 int *calls;
165 int all_c[] = { ALL_C, NULL_C };
166 int no_c[] = { NULL_C };
168 /* See if we run in verbose mode. */
169 env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1);
171 if ((s = sys_getinfo(GET_HZ, &system_hz, sizeof(system_hz), 0, 0)) != OK)
172 panic("Cannot get system timer frequency\n");
174 /* Initialize the global init descriptor. */
175 rinit.rproctab_gid = cpf_grant_direct(ANY, (vir_bytes) rprocpub,
176 sizeof(rprocpub), CPF_READ);
177 if(!GRANT_VALID(rinit.rproctab_gid)) {
178 panic("unable to create rprocpub table grant: %d", rinit.rproctab_gid);
181 /* Initialize some global variables. */
182 rupdate.flags = 0;
183 shutting_down = FALSE;
185 /* Get a copy of the boot image table. */
186 if ((s = sys_getimage(image)) != OK) {
187 panic("unable to get copy of boot image table: %d", s);
190 /* Determine the number of system services in the boot image table. */
191 nr_image_srvs = 0;
192 for(i=0;i<NR_BOOT_PROCS;i++) {
193 ip = &image[i];
195 /* System services only. */
196 if(iskerneln(_ENDPOINT_P(ip->endpoint))) {
197 continue;
199 nr_image_srvs++;
202 /* Determine the number of entries in the boot image priv table and make sure
203 * it matches the number of system services in the boot image table.
205 nr_image_priv_srvs = 0;
206 for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
207 boot_image_priv = &boot_image_priv_table[i];
209 /* System services only. */
210 if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
211 continue;
213 nr_image_priv_srvs++;
215 if(nr_image_srvs != nr_image_priv_srvs) {
216 panic("boot image table and boot image priv table mismatch");
219 /* Reset the system process table. */
220 for (rp=BEG_RPROC_ADDR; rp<END_RPROC_ADDR; rp++) {
221 rp->r_flags = 0;
222 rp->r_pub = &rprocpub[rp - rproc];
223 rp->r_pub->in_use = FALSE;
226 /* Initialize the system process table in 4 steps, each of them following
227 * the appearance of system services in the boot image priv table.
228 * - Step 1: set priviliges, sys properties, and dev properties (if any)
229 * for every system service.
231 for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
232 boot_image_priv = &boot_image_priv_table[i];
234 /* System services only. */
235 if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
236 continue;
239 /* Lookup the corresponding entries in other tables. */
240 boot_image_info_lookup(boot_image_priv->endpoint, image,
241 &ip, NULL, &boot_image_sys, &boot_image_dev);
242 rp = &rproc[boot_image_priv - boot_image_priv_table];
243 rpub = rp->r_pub;
246 * Set privileges.
248 /* Get label. */
249 strcpy(rpub->label, boot_image_priv->label);
251 /* Force a static priv id for system services in the boot image. */
252 rp->r_priv.s_id = static_priv_id(
253 _ENDPOINT_P(boot_image_priv->endpoint));
255 /* Initialize privilege bitmaps and signal manager. */
256 rp->r_priv.s_flags = boot_image_priv->flags; /* priv flags */
257 rp->r_priv.s_trap_mask= SRV_OR_USR(rp, SRV_T, USR_T); /* traps */
258 ipc_to = SRV_OR_USR(rp, SRV_M, USR_M); /* targets */
259 fill_send_mask(&rp->r_priv.s_ipc_to, ipc_to == ALL_M);
260 rp->r_priv.s_sig_mgr= SRV_OR_USR(rp, SRV_SM, USR_SM); /* sig mgr */
261 rp->r_priv.s_bak_sig_mgr = NONE; /* backup sig mgr */
263 /* Initialize kernel call mask bitmap. */
264 calls = SRV_OR_USR(rp, SRV_KC, USR_KC) == ALL_C ? all_c : no_c;
265 fill_call_mask(calls, NR_SYS_CALLS,
266 rp->r_priv.s_k_call_mask, KERNEL_CALL, TRUE);
268 /* Set the privilege structure. RS and VM are exceptions and are already
269 * running.
271 if(boot_image_priv->endpoint != RS_PROC_NR &&
272 boot_image_priv->endpoint != VM_PROC_NR) {
273 if ((s = sys_privctl(ip->endpoint, SYS_PRIV_SET_SYS, &(rp->r_priv)))
274 != OK) {
275 panic("unable to set privilege structure: %d", s);
279 /* Synch the privilege structure with the kernel. */
280 if ((s = sys_getpriv(&(rp->r_priv), ip->endpoint)) != OK) {
281 panic("unable to synch privilege structure: %d", s);
285 * Set sys properties.
287 rpub->sys_flags = boot_image_sys->flags; /* sys flags */
290 * Set dev properties.
292 rpub->dev_nr = boot_image_dev->dev_nr; /* major device number */
294 /* Build command settings. This will also set the process name. */
295 strlcpy(rp->r_cmd, ip->proc_name, sizeof(rp->r_cmd));
296 rp->r_script[0]= '\0';
297 build_cmd_dep(rp);
299 /* Initialize vm call mask bitmap. */
300 calls = SRV_OR_USR(rp, SRV_VC, USR_VC) == ALL_C ? all_c : no_c;
301 fill_call_mask(calls, NR_VM_CALLS, rpub->vm_call_mask, VM_RQ_BASE, TRUE);
303 /* Scheduling parameters. */
304 rp->r_scheduler = SRV_OR_USR(rp, SRV_SCH, USR_SCH);
305 rp->r_priority = SRV_OR_USR(rp, SRV_Q, USR_Q);
306 rp->r_quantum = SRV_OR_USR(rp, SRV_QT, USR_QT);
308 /* Get some settings from the boot image table. */
309 rpub->endpoint = ip->endpoint;
311 /* Set some defaults. */
312 rp->r_old_rp = NULL; /* no old version yet */
313 rp->r_new_rp = NULL; /* no new version yet */
314 rp->r_prev_rp = NULL; /* no prev replica yet */
315 rp->r_next_rp = NULL; /* no next replica yet */
316 rp->r_uid = 0; /* root */
317 rp->r_check_tm = 0; /* not checked yet */
318 getticks(&rp->r_alive_tm); /* currently alive */
319 rp->r_stop_tm = 0; /* not exiting yet */
320 rp->r_restarts = 0; /* no restarts so far */
321 rp->r_period = 0; /* no period yet */
322 rp->r_exec = NULL; /* no in-memory copy yet */
323 rp->r_exec_len = 0;
325 /* Mark as in use and active. */
326 rp->r_flags = RS_IN_USE | RS_ACTIVE;
327 rproc_ptr[_ENDPOINT_P(rpub->endpoint)]= rp;
328 rpub->in_use = TRUE;
331 /* - Step 2: allow every system service in the boot image to run. */
332 nr_uncaught_init_srvs = 0;
333 for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
334 boot_image_priv = &boot_image_priv_table[i];
336 /* System services only. */
337 if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
338 continue;
341 /* Lookup the corresponding slot in the system process table. */
342 rp = &rproc[boot_image_priv - boot_image_priv_table];
343 rpub = rp->r_pub;
345 /* RS/VM are already running as we speak. */
346 if(boot_image_priv->endpoint == RS_PROC_NR ||
347 boot_image_priv->endpoint == VM_PROC_NR) {
348 if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
349 panic("unable to initialize %d: %d", boot_image_priv->endpoint, s);
351 /* VM will still send an RS_INIT message, though. */
352 if (boot_image_priv->endpoint != RS_PROC_NR) {
353 nr_uncaught_init_srvs++;
355 continue;
358 /* Allow the service to run. */
359 if ((s = sched_init_proc(rp)) != OK) {
360 panic("unable to initialize scheduling: %d", s);
362 if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
363 panic("unable to initialize privileges: %d", s);
366 /* Initialize service. We assume every service will always get
367 * back to us here at boot time.
369 if(boot_image_priv->flags & SYS_PROC) {
370 if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
371 panic("unable to initialize service: %d", s);
373 if(rpub->sys_flags & SF_SYNCH_BOOT) {
374 /* Catch init ready message now to synchronize. */
375 catch_boot_init_ready(rpub->endpoint);
377 else {
378 /* Catch init ready message later. */
379 nr_uncaught_init_srvs++;
384 /* - Step 3: let every system service complete initialization by
385 * catching all the init ready messages left.
387 while(nr_uncaught_init_srvs) {
388 catch_boot_init_ready(ANY);
389 nr_uncaught_init_srvs--;
392 /* - Step 4: all the system services in the boot image are now running.
393 * Complete the initialization of the system process table in collaboration
394 * with other system services.
396 for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
397 boot_image_priv = &boot_image_priv_table[i];
399 /* System services only. */
400 if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
401 continue;
404 /* Lookup the corresponding slot in the system process table. */
405 rp = &rproc[boot_image_priv - boot_image_priv_table];
406 rpub = rp->r_pub;
408 /* Get pid from PM. */
409 rp->r_pid = getnpid(rpub->endpoint);
410 if(rp->r_pid < 0) {
411 panic("unable to get pid: %d", rp->r_pid);
415 /* Set alarm to periodically check service status. */
416 if (OK != (s=sys_setalarm(RS_DELTA_T, 0)))
417 panic("couldn't set alarm: %d", s);
419 #if USE_LIVEUPDATE
420 /* Now create a new RS instance and let the current
421 * instance live update into the replica. Clone RS' own slot first.
423 rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
424 if((s = clone_slot(rp, &replica_rp)) != OK) {
425 panic("unable to clone current RS instance: %d", s);
428 /* Fork a new RS instance with root:operator. */
429 pid = srv_fork(0, 0);
430 if(pid < 0) {
431 panic("unable to fork a new RS instance: %d", pid);
433 replica_pid = pid ? pid : getpid();
434 if ((s = getprocnr(replica_pid, &replica_endpoint)) != 0)
435 panic("unable to get replica endpoint: %d", s);
436 replica_rp->r_pid = replica_pid;
437 replica_rp->r_pub->endpoint = replica_endpoint;
439 if(pid == 0) {
440 /* New RS instance running. */
442 /* Live update the old instance into the new one. */
443 s = update_service(&rp, &replica_rp, RS_SWAP);
444 if(s != OK) {
445 panic("unable to live update RS: %d", s);
447 cpf_reload();
449 /* Clean up the old RS instance, the new instance will take over. */
450 cleanup_service(rp);
452 /* Ask VM to pin memory for the new RS instance. */
453 if((s = vm_memctl(RS_PROC_NR, VM_RS_MEM_PIN)) != OK) {
454 panic("unable to pin memory for the new RS instance: %d", s);
457 else {
458 /* Old RS instance running. */
460 /* Set up privileges for the new instance and let it run. */
461 s = sys_privctl(replica_endpoint, SYS_PRIV_SET_SYS, &(replica_rp->r_priv));
462 if(s != OK) {
463 panic("unable to set privileges for the new RS instance: %d", s);
465 if ((s = sched_init_proc(replica_rp)) != OK) {
466 panic("unable to initialize RS replica scheduling: %d", s);
468 s = sys_privctl(replica_endpoint, SYS_PRIV_YIELD, NULL);
469 if(s != OK) {
470 panic("unable to yield control to the new RS instance: %d", s);
472 NOT_REACHABLE;
474 #endif /* USE_LIVEUPDATE */
476 return(OK);
479 /*===========================================================================*
480 * sef_cb_signal_handler *
481 *===========================================================================*/
482 static void sef_cb_signal_handler(int signo)
484 /* Check for known signals, ignore anything else. */
485 switch(signo) {
486 case SIGCHLD:
487 do_sigchld();
488 break;
489 case SIGTERM:
490 do_shutdown(NULL);
491 break;
495 /*===========================================================================*
496 * sef_cb_signal_manager *
497 *===========================================================================*/
498 static int sef_cb_signal_manager(endpoint_t target, int signo)
500 /* Process system signal on behalf of the kernel. */
501 int target_p;
502 struct rproc *rp;
503 struct rprocpub *rpub;
504 message m;
506 /* Lookup slot. */
507 if(rs_isokendpt(target, &target_p) != OK || rproc_ptr[target_p] == NULL) {
508 if(rs_verbose)
509 printf("RS: ignoring spurious signal %d for process %d\n",
510 signo, target);
511 return OK; /* clear the signal */
513 rp = rproc_ptr[target_p];
514 rpub = rp->r_pub;
516 /* Don't bother if a termination signal has already been processed. */
517 if((rp->r_flags & RS_TERMINATED) && !(rp->r_flags & RS_EXITING)) {
518 return EDEADEPT; /* process is gone */
521 /* Ignore external signals for inactive service instances. */
522 if( !(rp->r_flags & RS_ACTIVE) && !(rp->r_flags & RS_EXITING)) {
523 if(rs_verbose)
524 printf("RS: ignoring signal %d for inactive %s\n",
525 signo, srv_to_string(rp));
526 return OK; /* clear the signal */
529 if(rs_verbose)
530 printf("RS: %s got %s signal %d\n", srv_to_string(rp),
531 SIGS_IS_TERMINATION(signo) ? "termination" : "non-termination",signo);
533 /* Print stacktrace if necessary. */
534 if(SIGS_IS_STACKTRACE(signo)) {
535 sys_diagctl_stacktrace(target);
538 /* In case of termination signal handle the event. */
539 if(SIGS_IS_TERMINATION(signo)) {
540 rp->r_flags |= RS_TERMINATED;
541 terminate_service(rp);
543 return EDEADEPT; /* process is now gone */
546 /* Translate every non-termination signal into a message. */
547 m.m_type = SIGS_SIGNAL_RECEIVED;
548 m.m_pm_lsys_sigs_signal.num = signo;
549 asynsend3(rpub->endpoint, &m, AMF_NOREPLY);
551 return OK; /* signal has been delivered */
554 /*===========================================================================*
555 * boot_image_info_lookup *
556 *===========================================================================*/
557 static void boot_image_info_lookup(endpoint, image, ip, pp, sp, dp)
558 endpoint_t endpoint;
559 struct boot_image *image;
560 struct boot_image **ip;
561 struct boot_image_priv **pp;
562 struct boot_image_sys **sp;
563 struct boot_image_dev **dp;
565 /* Lookup entries in boot image tables. */
566 int i;
568 /* When requested, locate the corresponding entry in the boot image table
569 * or panic if not found.
571 if(ip) {
572 for (i=0; i < NR_BOOT_PROCS; i++) {
573 if(image[i].endpoint == endpoint) {
574 *ip = &image[i];
575 break;
578 if(i == NR_BOOT_PROCS) {
579 panic("boot image table lookup failed");
583 /* When requested, locate the corresponding entry in the boot image priv table
584 * or panic if not found.
586 if(pp) {
587 for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
588 if(boot_image_priv_table[i].endpoint == endpoint) {
589 *pp = &boot_image_priv_table[i];
590 break;
593 if(i == NULL_BOOT_NR) {
594 panic("boot image priv table lookup failed");
598 /* When requested, locate the corresponding entry in the boot image sys table
599 * or resort to the default entry if not found.
601 if(sp) {
602 for (i=0; boot_image_sys_table[i].endpoint != DEFAULT_BOOT_NR; i++) {
603 if(boot_image_sys_table[i].endpoint == endpoint) {
604 *sp = &boot_image_sys_table[i];
605 break;
608 if(boot_image_sys_table[i].endpoint == DEFAULT_BOOT_NR) {
609 *sp = &boot_image_sys_table[i]; /* accept the default entry */
613 /* When requested, locate the corresponding entry in the boot image dev table
614 * or resort to the default entry if not found.
616 if(dp) {
617 for (i=0; boot_image_dev_table[i].endpoint != DEFAULT_BOOT_NR; i++) {
618 if(boot_image_dev_table[i].endpoint == endpoint) {
619 *dp = &boot_image_dev_table[i];
620 break;
623 if(boot_image_dev_table[i].endpoint == DEFAULT_BOOT_NR) {
624 *dp = &boot_image_dev_table[i]; /* accept the default entry */
629 /*===========================================================================*
630 * catch_boot_init_ready *
631 *===========================================================================*/
632 static void catch_boot_init_ready(endpoint)
633 endpoint_t endpoint;
635 /* Block and catch an init ready message from the given source. */
636 int r;
637 int ipc_status;
638 message m;
639 struct rproc *rp;
640 int result;
642 /* Receive init ready message. */
643 if ((r = sef_receive_status(endpoint, &m, &ipc_status)) != OK) {
644 panic("unable to receive init reply: %d", r);
646 if(m.m_type != RS_INIT) {
647 panic("unexpected reply from service: %d", m.m_source);
649 result = m.m_rs_init.result;
650 rp = rproc_ptr[_ENDPOINT_P(m.m_source)];
652 /* Check result. */
653 if(result != OK) {
654 panic("unable to complete init for service: %d", m.m_source);
657 /* Send a reply to unblock the service. */
658 m.m_type = OK;
659 reply(m.m_source, rp, &m);
661 /* Mark the slot as no longer initializing. */
662 rp->r_flags &= ~RS_INITIALIZING;
663 rp->r_check_tm = 0;
664 getticks(&rp->r_alive_tm);
667 /*===========================================================================*
668 * get_work *
669 *===========================================================================*/
670 static void get_work(m_ptr, status_ptr)
671 message *m_ptr; /* pointer to message */
672 int *status_ptr; /* pointer to status */
674 int r;
675 if (OK != (r=sef_receive_status(ANY, m_ptr, status_ptr)))
676 panic("sef_receive_status failed: %d", r);