xref: /minix/minix/servers/rs/main.c (revision 83133719)
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)
10  */
11 #include "inc.h"
12 #include <fcntl.h>
13 #include "kernel/const.h"
14 #include "kernel/type.h"
15 #include "kernel/proc.h"
16 
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);
23 
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);
29 
30 
31 /*===========================================================================*
32  *				main                                         *
33  *===========================================================================*/
34 int main(void)
35 {
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.
39  */
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;
45 
46   /* SEF local startup. */
47   sef_local_startup();
48 
49   if (OK != (s=sys_getmachine(&machine)))
50 	  panic("couldn't get machine info: %d", s);
51 
52   if (OK != (s=sys_getkinfo(&kinfo)))
53 	  panic("couldn't get kernel kinfo: %d", s);
54 
55   /* Main loop - get work and do it, forever. */
56   while (TRUE) {
57 
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);
63       }
64 
65       call_nr = m.m_type;
66 
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)
72        */
73 
74       /* Notification messages are control messages and do not need a reply.
75        * These include heartbeat messages and system notifications.
76        */
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);
88 	      }
89 	  }
90       }
91 
92       /* If we get this far, this is a normal request.
93        * Handle the request and send a reply to the caller.
94        */
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;
116           }
117 
118           /* Finally send reply message, unless disabled. */
119           if (result != EDONTREPLY) {
120 	      m.m_type = result;
121               reply(who_e, NULL, &m);
122           }
123       }
124   }
125 }
126 
127 /*===========================================================================*
128  *			       sef_local_startup			     *
129  *===========================================================================*/
130 static void sef_local_startup()
131 {
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);
136 
137   /* Register live update callbacks. */
138   sef_setcb_lu_response(do_upd_ready);
139 
140   /* Register signal callbacks. */
141   sef_setcb_signal_handler(sef_cb_signal_handler);
142   sef_setcb_signal_manager(sef_cb_signal_manager);
143 
144   /* Let SEF perform startup. */
145   sef_startup();
146 }
147 
148 /*===========================================================================*
149  *		            sef_cb_init_fresh                                *
150  *===========================================================================*/
151 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
152 {
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 };
167 
168   /* See if we run in verbose mode. */
169   env_parse("rs_verbose", "d", 0, &rs_verbose, 0, 1);
170 
171   if ((s = sys_getinfo(GET_HZ, &system_hz, sizeof(system_hz), 0, 0)) != OK)
172 	  panic("Cannot get system timer frequency\n");
173 
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);
179   }
180 
181   /* Initialize some global variables. */
182   rupdate.flags = 0;
183   shutting_down = FALSE;
184 
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);
188   }
189 
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];
194 
195       /* System services only. */
196       if(iskerneln(_ENDPOINT_P(ip->endpoint))) {
197           continue;
198       }
199       nr_image_srvs++;
200   }
201 
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.
204    */
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];
208 
209       /* System services only. */
210       if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
211           continue;
212       }
213       nr_image_priv_srvs++;
214   }
215   if(nr_image_srvs != nr_image_priv_srvs) {
216 	panic("boot image table and boot image priv table mismatch");
217   }
218 
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;
224   }
225 
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.
230    */
231   for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
232       boot_image_priv = &boot_image_priv_table[i];
233 
234       /* System services only. */
235       if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
236           continue;
237       }
238 
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;
244 
245       /*
246        * Set privileges.
247        */
248       /* Get label. */
249       strcpy(rpub->label, boot_image_priv->label);
250 
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));
254 
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 */
262 
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);
267 
268       /* Set the privilege structure. RS and VM are exceptions and are already
269        * running.
270        */
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);
276           }
277       }
278 
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);
282       }
283 
284       /*
285        * Set sys properties.
286        */
287       rpub->sys_flags = boot_image_sys->flags;        /* sys flags */
288 
289       /*
290        * Set dev properties.
291        */
292       rpub->dev_nr = boot_image_dev->dev_nr;          /* major device number */
293 
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);
298 
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);
302 
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);
307 
308       /* Get some settings from the boot image table. */
309       rpub->endpoint = ip->endpoint;
310 
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;
324 
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;
329   }
330 
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];
335 
336       /* System services only. */
337       if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
338           continue;
339       }
340 
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;
344 
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);
350           }
351           /* VM will still send an RS_INIT message, though. */
352           if (boot_image_priv->endpoint != RS_PROC_NR) {
353               nr_uncaught_init_srvs++;
354           }
355           continue;
356       }
357 
358       /* Allow the service to run. */
359       if ((s = sched_init_proc(rp)) != OK) {
360           panic("unable to initialize scheduling: %d", s);
361       }
362       if ((s = sys_privctl(rpub->endpoint, SYS_PRIV_ALLOW, NULL)) != OK) {
363           panic("unable to initialize privileges: %d", s);
364       }
365 
366       /* Initialize service. We assume every service will always get
367        * back to us here at boot time.
368        */
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);
372           }
373           if(rpub->sys_flags & SF_SYNCH_BOOT) {
374               /* Catch init ready message now to synchronize. */
375               catch_boot_init_ready(rpub->endpoint);
376           }
377           else {
378               /* Catch init ready message later. */
379               nr_uncaught_init_srvs++;
380           }
381       }
382   }
383 
384   /* - Step 3: let every system service complete initialization by
385    * catching all the init ready messages left.
386    */
387   while(nr_uncaught_init_srvs) {
388       catch_boot_init_ready(ANY);
389       nr_uncaught_init_srvs--;
390   }
391 
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.
395    */
396   for (i=0; boot_image_priv_table[i].endpoint != NULL_BOOT_NR; i++) {
397       boot_image_priv = &boot_image_priv_table[i];
398 
399       /* System services only. */
400       if(iskerneln(_ENDPOINT_P(boot_image_priv->endpoint))) {
401           continue;
402       }
403 
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;
407 
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);
412       }
413   }
414 
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);
418 
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.
422    */
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);
426   }
427 
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);
432   }
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;
438 
439   if(pid == 0) {
440       /* New RS instance running. */
441 
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);
446       }
447       cpf_reload();
448 
449       /* Clean up the old RS instance, the new instance will take over. */
450       cleanup_service(rp);
451 
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);
455       }
456   }
457   else {
458       /* Old RS instance running. */
459 
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);
464       }
465       if ((s = sched_init_proc(replica_rp)) != OK) {
466           panic("unable to initialize RS replica scheduling: %d", s);
467       }
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);
471       }
472       NOT_REACHABLE;
473   }
474 #endif /* USE_LIVEUPDATE */
475 
476   return(OK);
477 }
478 
479 /*===========================================================================*
480  *		            sef_cb_signal_handler                            *
481  *===========================================================================*/
482 static void sef_cb_signal_handler(int signo)
483 {
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;
492   }
493 }
494 
495 /*===========================================================================*
496  *		            sef_cb_signal_manager                            *
497  *===========================================================================*/
498 static int sef_cb_signal_manager(endpoint_t target, int signo)
499 {
500 /* Process system signal on behalf of the kernel. */
501   int target_p;
502   struct rproc *rp;
503   struct rprocpub *rpub;
504   message m;
505 
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 */
512   }
513   rp = rproc_ptr[target_p];
514   rpub = rp->r_pub;
515 
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 */
519   }
520 
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 */
527   }
528 
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);
532 
533   /* Print stacktrace if necessary. */
534   if(SIGS_IS_STACKTRACE(signo)) {
535        sys_diagctl_stacktrace(target);
536   }
537 
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);
542 
543       return EDEADEPT; /* process is now gone */
544   }
545 
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);
550 
551   return OK; /* signal has been delivered */
552 }
553 
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;
564 {
565 /* Lookup entries in boot image tables. */
566   int i;
567 
568   /* When requested, locate the corresponding entry in the boot image table
569    * or panic if not found.
570    */
571   if(ip) {
572       for (i=0; i < NR_BOOT_PROCS; i++) {
573           if(image[i].endpoint == endpoint) {
574               *ip = &image[i];
575               break;
576           }
577       }
578       if(i == NR_BOOT_PROCS) {
579           panic("boot image table lookup failed");
580       }
581   }
582 
583   /* When requested, locate the corresponding entry in the boot image priv table
584    * or panic if not found.
585    */
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;
591           }
592       }
593       if(i == NULL_BOOT_NR) {
594           panic("boot image priv table lookup failed");
595       }
596   }
597 
598   /* When requested, locate the corresponding entry in the boot image sys table
599    * or resort to the default entry if not found.
600    */
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;
606           }
607       }
608       if(boot_image_sys_table[i].endpoint == DEFAULT_BOOT_NR) {
609           *sp = &boot_image_sys_table[i];         /* accept the default entry */
610       }
611   }
612 
613   /* When requested, locate the corresponding entry in the boot image dev table
614    * or resort to the default entry if not found.
615    */
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;
621           }
622       }
623       if(boot_image_dev_table[i].endpoint == DEFAULT_BOOT_NR) {
624           *dp = &boot_image_dev_table[i];         /* accept the default entry */
625       }
626   }
627 }
628 
629 /*===========================================================================*
630  *			      catch_boot_init_ready                          *
631  *===========================================================================*/
632 static void catch_boot_init_ready(endpoint)
633 endpoint_t endpoint;
634 {
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;
641 
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);
645   }
646   if(m.m_type != RS_INIT) {
647       panic("unexpected reply from service: %d", m.m_source);
648   }
649   result = m.m_rs_init.result;
650   rp = rproc_ptr[_ENDPOINT_P(m.m_source)];
651 
652   /* Check result. */
653   if(result != OK) {
654       panic("unable to complete init for service: %d", m.m_source);
655   }
656 
657   /* Send a reply to unblock the service. */
658   m.m_type = OK;
659   reply(m.m_source, rp, &m);
660 
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);
665 }
666 
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 */
673 {
674     int r;
675     if (OK != (r=sef_receive_status(ANY, m_ptr, status_ptr)))
676         panic("sef_receive_status failed: %d", r);
677 }
678 
679