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.
8 * Nov 22, 2009: rewrite of boot process (Cristiano Giuffrida)
9 * Jul 22, 2005: Created (Jorrit N. Herder)
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 /*===========================================================================*
33 *===========================================================================*/
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 */
46 /* 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. */
58 /* Wait for request message. */
59 get_work(&m
, &ipc_status
);
61 if(rs_isokendpt(who_e
, &who_p
) != OK
) {
62 panic("message from bogus source: %d", who_e
);
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
)) {
80 do_period(&m
); /* check services status */
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
;
86 printf("RS: warning: got unexpected notify message from %d\n",
92 /* If we get this far, this is a normal request.
93 * Handle the request and send a reply to the caller.
96 /* Handler functions are responsible for permission checking. */
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;
113 printf("RS: warning: got unexpected request %d from %d\n",
114 m
.m_type
, m
.m_source
);
118 /* Finally send reply message, unless disabled. */
119 if (result
!= EDONTREPLY
) {
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. */
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
;
156 int nr_image_srvs
, nr_image_priv_srvs
, nr_uncaught_init_srvs
;
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
;
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. */
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. */
192 for(i
=0;i
<NR_BOOT_PROCS
;i
++) {
195 /* System services only. */
196 if(iskerneln(_ENDPOINT_P(ip
->endpoint
))) {
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
))) {
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
++) {
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
))) {
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
];
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
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
)))
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';
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 */
325 /* Mark as in use and active. */
326 rp
->r_flags
= RS_IN_USE
| RS_ACTIVE
;
327 rproc_ptr
[_ENDPOINT_P(rpub
->endpoint
)]= rp
;
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
))) {
341 /* Lookup the corresponding slot in the system process table. */
342 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
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
++;
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
);
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
))) {
404 /* Lookup the corresponding slot in the system process table. */
405 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
408 /* Get pid from PM. */
409 rp
->r_pid
= getnpid(rpub
->endpoint
);
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
);
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);
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
;
440 /* New RS instance running. */
442 /* Live update the old instance into the new one. */
443 s
= update_service(&rp
, &replica_rp
, RS_SWAP
);
445 panic("unable to live update RS: %d", s
);
449 /* Clean up the old RS instance, the new instance will take over. */
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
);
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
));
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
);
470 panic("unable to yield control to the new RS instance: %d", s
);
474 #endif /* USE_LIVEUPDATE */
479 /*===========================================================================*
480 * sef_cb_signal_handler *
481 *===========================================================================*/
482 static void sef_cb_signal_handler(int signo
)
484 /* Check for known signals, ignore anything else. */
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. */
503 struct rprocpub
*rpub
;
507 if(rs_isokendpt(target
, &target_p
) != OK
|| rproc_ptr
[target_p
] == NULL
) {
509 printf("RS: ignoring spurious signal %d for process %d\n",
511 return OK
; /* clear the signal */
513 rp
= rproc_ptr
[target_p
];
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
)) {
524 printf("RS: ignoring signal %d for inactive %s\n",
525 signo
, srv_to_string(rp
));
526 return OK
; /* clear the signal */
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
.SIGS_SIG_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
)
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. */
568 /* When requested, locate the corresponding entry in the boot image table
569 * or panic if not found.
572 for (i
=0; i
< NR_BOOT_PROCS
; i
++) {
573 if(image
[i
].endpoint
== endpoint
) {
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.
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
];
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.
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
];
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.
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
];
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
)
635 /* Block and catch an init ready message from the given source. */
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
.RS_INIT_RESULT
;
650 rp
= rproc_ptr
[_ENDPOINT_P(m
.m_source
)];
654 panic("unable to complete init for service: %d", m
.m_source
);
657 /* Send a reply to unblock the service. */
659 reply(m
.m_source
, rp
, &m
);
661 /* Mark the slot as no longer initializing. */
662 rp
->r_flags
&= ~RS_INITIALIZING
;
664 getticks(&rp
->r_alive_tm
);
667 /*===========================================================================*
669 *===========================================================================*/
670 static void get_work(m_ptr
, status_ptr
)
671 message
*m_ptr
; /* pointer to message */
672 int *status_ptr
; /* pointer to status */
675 if (OK
!= (r
=sef_receive_status(ANY
, m_ptr
, status_ptr
)))
676 panic("sef_receive_status failed: %d", r
);