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)
14 #include <minix/crtso.h>
15 #include "kernel/const.h"
16 #include "kernel/type.h"
17 #include "kernel/proc.h"
18 #include "../pm/mproc.h"
20 /* Declare some local functions. */
21 FORWARD
_PROTOTYPE(void exec_image_copy
, ( int boot_proc_idx
,
22 struct boot_image
*ip
, struct rproc
*rp
) );
23 FORWARD
_PROTOTYPE(void boot_image_info_lookup
, ( endpoint_t endpoint
,
24 struct boot_image
*image
,
25 struct boot_image
**ip
, struct boot_image_priv
**pp
,
26 struct boot_image_sys
**sp
, struct boot_image_dev
**dp
) );
27 FORWARD
_PROTOTYPE(void catch_boot_init_ready
, (endpoint_t endpoint
) );
28 FORWARD
_PROTOTYPE(void get_work
, (message
*m_ptr
, int *status_ptr
) );
30 /* Flag set when memory unmapping can be done. */
33 /* SEF functions and variables. */
34 FORWARD
_PROTOTYPE( void sef_local_startup
, (void) );
35 FORWARD
_PROTOTYPE( int sef_cb_init_fresh
, (int type
, sef_init_info_t
*info
) );
36 FORWARD
_PROTOTYPE( void sef_cb_signal_handler
, (int signo
) );
37 FORWARD
_PROTOTYPE( int sef_cb_signal_manager
, (endpoint_t target
, int signo
) );
39 /*===========================================================================*
41 *===========================================================================*/
44 /* This is the main routine of this service. The main loop consists of
45 * three major activities: getting new work, processing the work, and
46 * sending the reply. The loop never terminates, unless a panic occurs.
48 message m
; /* request message */
49 int ipc_status
; /* status code */
50 int call_nr
, who_e
,who_p
; /* call number and caller */
51 int result
; /* result to return */
53 /* SEF local startup. */
56 /* Main loop - get work and do it, forever. */
59 /* Wait for request message. */
60 get_work(&m
, &ipc_status
);
62 if(rs_isokendpt(who_e
, &who_p
) != OK
) {
63 panic("message from bogus source: %d", who_e
);
68 /* Now determine what to do. Four types of requests are expected:
69 * - Heartbeat messages (notifications from registered system services)
70 * - System notifications (synchronous alarm)
71 * - User requests (control messages to manage system services)
72 * - Ready messages (reply messages from registered services)
75 /* Notification messages are control messages and do not need a reply.
76 * These include heartbeat messages and system notifications.
78 if (is_ipc_notify(ipc_status
)) {
81 do_period(&m
); /* check services status */
83 default: /* heartbeat notification */
84 if (rproc_ptr
[who_p
] != NULL
) { /* mark heartbeat time */
85 rproc_ptr
[who_p
]->r_alive_tm
= m
.NOTIFY_TIMESTAMP
;
87 printf("RS: warning: got unexpected notify message from %d\n",
93 /* If we get this far, this is a normal request.
94 * Handle the request and send a reply to the caller.
97 if (call_nr
!= GETSYSINFO
&&
98 (call_nr
< RS_RQ_BASE
|| call_nr
>= RS_RQ_BASE
+0x100))
100 /* Ignore invalid requests. Do not try to reply. */
101 printf("RS: warning: got invalid request %d from endpoint %d\n",
102 call_nr
, m
.m_source
);
106 /* Handler functions are responsible for permission checking. */
109 case RS_UP
: result
= do_up(&m
); break;
110 case RS_DOWN
: result
= do_down(&m
); break;
111 case RS_REFRESH
: result
= do_refresh(&m
); break;
112 case RS_RESTART
: result
= do_restart(&m
); break;
113 case RS_SHUTDOWN
: result
= do_shutdown(&m
); break;
114 case RS_UPDATE
: result
= do_update(&m
); break;
115 case GETSYSINFO
: result
= do_getsysinfo(&m
); break;
116 case RS_LOOKUP
: result
= do_lookup(&m
); break;
117 /* Ready messages. */
118 case RS_INIT
: result
= do_init_ready(&m
); break;
119 case RS_LU_PREPARE
: result
= do_upd_ready(&m
); break;
121 printf("RS: warning: got unexpected request %d from %d\n",
122 m
.m_type
, m
.m_source
);
126 /* Finally send reply message, unless disabled. */
127 if (result
!= EDONTREPLY
) {
135 /*===========================================================================*
136 * sef_local_startup *
137 *===========================================================================*/
138 PRIVATE
void sef_local_startup()
140 /* Register init callbacks. */
141 sef_setcb_init_fresh(sef_cb_init_fresh
); /* RS can only start fresh. */
143 /* Register signal callbacks. */
144 sef_setcb_signal_handler(sef_cb_signal_handler
);
145 sef_setcb_signal_manager(sef_cb_signal_manager
);
147 /* Let SEF perform startup. */
151 /*===========================================================================*
152 * sef_cb_init_fresh *
153 *===========================================================================*/
154 PRIVATE
int sef_cb_init_fresh(int type
, sef_init_info_t
*info
)
156 /* Initialize the reincarnation server. */
157 struct boot_image
*ip
;
159 int nr_image_srvs
, nr_image_priv_srvs
, nr_uncaught_init_srvs
;
161 struct rprocpub
*rpub
;
162 struct boot_image image
[NR_BOOT_PROCS
];
163 struct mproc mproc
[NR_PROCS
];
165 struct boot_image_priv
*boot_image_priv
;
166 struct boot_image_sys
*boot_image_sys
;
167 struct boot_image_dev
*boot_image_dev
;
169 /* See if we run in verbose mode. */
170 env_parse("rs_verbose", "d", 0, &rs_verbose
, 0, 1);
172 /* Initialize the global init descriptor. */
173 rinit
.rproctab_gid
= cpf_grant_direct(ANY
, (vir_bytes
) rprocpub
,
174 sizeof(rprocpub
), CPF_READ
);
175 if(!GRANT_VALID(rinit
.rproctab_gid
)) {
176 panic("unable to create rprocpub table grant: %d", rinit
.rproctab_gid
);
179 /* Initialize some global variables. */
181 shutting_down
= FALSE
;
183 /* Get a copy of the boot image table. */
184 if ((s
= sys_getimage(image
)) != OK
) {
185 panic("unable to get copy of boot image table: %d", s
);
188 /* Determine the number of system services in the boot image table and
189 * compute the size required for the boot image buffer.
192 boot_image_buffer_size
= 0;
193 for(i
=0;i
<NR_BOOT_PROCS
;i
++) {
196 /* System services only. */
197 if(iskerneln(_ENDPOINT_P(ip
->endpoint
))) {
202 /* Lookup the corresponding entry in the boot image sys table. */
203 boot_image_info_lookup(ip
->endpoint
, image
,
204 NULL
, NULL
, &boot_image_sys
, NULL
);
206 /* If we must keep a copy of this system service, read the header
207 * and increase the size of the boot image buffer.
209 if(boot_image_sys
->flags
& SF_USE_REPL
) {
210 boot_image_sys
->flags
|= SF_USE_COPY
;
212 if(boot_image_sys
->flags
& SF_USE_COPY
) {
213 if((s
= sys_getaoutheader(&header
, i
)) != OK
) {
214 panic("unable to get copy of a.out header: %d", s
);
216 boot_image_buffer_size
+= header
.a_hdrlen
217 + header
.a_text
+ header
.a_data
;
221 /* Determine the number of entries in the boot image priv table and make sure
222 * it matches the number of system services in the boot image table.
224 nr_image_priv_srvs
= 0;
225 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
226 boot_image_priv
= &boot_image_priv_table
[i
];
228 /* System services only. */
229 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
232 nr_image_priv_srvs
++;
234 if(nr_image_srvs
!= nr_image_priv_srvs
) {
235 panic("boot image table and boot image priv table mismatch");
238 /* Allocate boot image buffer. */
239 if(boot_image_buffer_size
> 0) {
240 boot_image_buffer
= rs_startup_sbrk(boot_image_buffer_size
);
241 if(boot_image_buffer
== (char *) -1) {
242 panic("unable to allocate boot image buffer");
246 /* Reset the system process table. */
247 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
249 rp
->r_pub
= &rprocpub
[rp
- rproc
];
250 rp
->r_pub
->in_use
= FALSE
;
253 /* Initialize the system process table in 4 steps, each of them following
254 * the appearance of system services in the boot image priv table.
255 * - Step 1: get a copy of the executable image of every system service that
256 * requires it while it is not yet running.
257 * In addition, set priviliges, sys properties, and dev properties (if any)
258 * for every system service.
260 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
261 boot_image_priv
= &boot_image_priv_table
[i
];
263 /* System services only. */
264 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
268 /* Lookup the corresponding entries in other tables. */
269 boot_image_info_lookup(boot_image_priv
->endpoint
, image
,
270 &ip
, NULL
, &boot_image_sys
, &boot_image_dev
);
271 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
275 * Get a copy of the executable image if required.
279 if(boot_image_sys
->flags
& SF_USE_COPY
) {
280 exec_image_copy(ip
- image
, ip
, rp
);
287 strcpy(rpub
->label
, boot_image_priv
->label
);
289 /* Get heartbeat period. */
290 rpub
->period
= boot_image_priv
->period
;
292 if(boot_image_priv
->endpoint
!= RS_PROC_NR
) {
293 /* Force a static priv id for system services in the boot image. */
294 rp
->r_priv
.s_id
= static_priv_id(
295 _ENDPOINT_P(boot_image_priv
->endpoint
));
297 /* Initialize privilege bitmaps and signal manager. */
298 rp
->r_priv
.s_flags
= boot_image_priv
->flags
; /* priv flags */
299 rp
->r_priv
.s_trap_mask
= boot_image_priv
->trap_mask
; /* traps */
300 memcpy(&rp
->r_priv
.s_ipc_to
, &boot_image_priv
->ipc_to
,
301 sizeof(rp
->r_priv
.s_ipc_to
)); /* targets */
302 rp
->r_priv
.s_sig_mgr
= boot_image_priv
->sig_mgr
; /* sig mgr */
304 /* Initialize kernel call mask bitmap from unordered set. */
305 fill_call_mask(boot_image_priv
->k_calls
, NR_SYS_CALLS
,
306 rp
->r_priv
.s_k_call_mask
, KERNEL_CALL
, TRUE
);
308 /* Set the privilege structure. */
309 if ((s
= sys_privctl(ip
->endpoint
, SYS_PRIV_SET_SYS
, &(rp
->r_priv
)))
311 panic("unable to set privilege structure: %d", s
);
315 /* Synch the privilege structure with the kernel. */
316 if ((s
= sys_getpriv(&(rp
->r_priv
), ip
->endpoint
)) != OK
) {
317 panic("unable to synch privilege structure: %d", s
);
321 * Set sys properties.
323 rpub
->sys_flags
= boot_image_sys
->flags
; /* sys flags */
326 * Set dev properties.
328 rpub
->dev_flags
= boot_image_dev
->flags
; /* device flags */
329 rpub
->dev_nr
= boot_image_dev
->dev_nr
; /* major device number */
330 rpub
->dev_style
= boot_image_dev
->dev_style
; /* device style */
331 rpub
->dev_style2
= boot_image_dev
->dev_style2
; /* device style 2 */
333 /* Get process name. */
334 strcpy(rpub
->proc_name
, ip
->proc_name
);
336 /* Get command settings. */
337 strcpy(rp
->r_cmd
, ip
->proc_name
);
338 rp
->r_script
[0]= '\0';
341 /* Initialize vm call mask bitmap from unordered set. */
342 fill_call_mask(boot_image_priv
->vm_calls
, NR_VM_CALLS
,
343 rpub
->vm_call_mask
, VM_RQ_BASE
, TRUE
);
345 /* Get some settings from the boot image table. */
346 rp
->r_nice
= ip
->priority
;
347 rpub
->endpoint
= ip
->endpoint
;
349 /* Set some defaults. */
350 rp
->r_old_rp
= NULL
; /* no old version yet */
351 rp
->r_new_rp
= NULL
; /* no new version yet */
352 rp
->r_prev_rp
= NULL
; /* no prev replica yet */
353 rp
->r_next_rp
= NULL
; /* no next replica yet */
354 rp
->r_uid
= 0; /* root */
355 rp
->r_check_tm
= 0; /* not checked yet */
356 getuptime(&rp
->r_alive_tm
); /* currently alive */
357 rp
->r_stop_tm
= 0; /* not exiting yet */
358 rp
->r_restarts
= 0; /* no restarts so far */
359 rp
->r_set_resources
= 0; /* don't set resources */
361 /* Mark as in use and active. */
362 rp
->r_flags
= RS_IN_USE
| RS_ACTIVE
;
363 rproc_ptr
[_ENDPOINT_P(rpub
->endpoint
)]= rp
;
367 /* - Step 2: allow every system service in the boot image to run.
369 nr_uncaught_init_srvs
= 0;
370 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
371 boot_image_priv
= &boot_image_priv_table
[i
];
373 /* System services only. */
374 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
379 if(boot_image_priv
->endpoint
== RS_PROC_NR
) {
383 /* Lookup the corresponding slot in the system process table. */
384 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
387 /* Allow the service to run. */
388 if ((s
= sys_privctl(rpub
->endpoint
, SYS_PRIV_ALLOW
, NULL
)) != OK
) {
389 panic("unable to initialize privileges: %d", s
);
392 /* Initialize service. We assume every service will always get
393 * back to us here at boot time.
395 if(boot_image_priv
->flags
& SYS_PROC
) {
396 if ((s
= init_service(rp
, SEF_INIT_FRESH
)) != OK
) {
397 panic("unable to initialize service: %d", s
);
399 if(rpub
->sys_flags
& SF_SYNCH_BOOT
) {
400 /* Catch init ready message now to synchronize. */
401 catch_boot_init_ready(rpub
->endpoint
);
404 /* Catch init ready message later. */
405 nr_uncaught_init_srvs
++;
410 /* - Step 3: let every system service complete initialization by
411 * catching all the init ready messages left.
413 while(nr_uncaught_init_srvs
) {
414 catch_boot_init_ready(ANY
);
415 nr_uncaught_init_srvs
--;
418 /* - Step 4: all the system services in the boot image are now running.
419 * Complete the initialization of the system process table in collaboration
420 * with other system services.
422 if ((s
= getsysinfo(PM_PROC_NR
, SI_PROC_TAB
, mproc
)) != OK
) {
423 panic("unable to get copy of PM process table: %d", s
);
425 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
426 boot_image_priv
= &boot_image_priv_table
[i
];
428 /* System services only. */
429 if(iskerneln(_ENDPOINT_P(boot_image_priv
->endpoint
))) {
433 /* Lookup the corresponding slot in the system process table. */
434 rp
= &rproc
[boot_image_priv
- boot_image_priv_table
];
437 /* Get pid from PM process table. */
439 for (j
= 0; j
< NR_PROCS
; j
++) {
440 if (mproc
[j
].mp_endpoint
== rpub
->endpoint
) {
441 rp
->r_pid
= mproc
[j
].mp_pid
;
446 panic("unable to get pid");
449 /* If we must keep a replica of this system service, create it now. */
450 if(rpub
->sys_flags
& SF_USE_REPL
) {
451 if ((s
= clone_service(rp
)) != OK
) {
452 panic("unable to clone service: %d", s
);
458 * Now complete RS initialization process in collaboration with other
461 /* Let the rest of the system know about our dynamically allocated buffer. */
462 if(boot_image_buffer_size
> 0) {
463 boot_image_buffer
= rs_startup_sbrk_synch(boot_image_buffer_size
);
464 if(boot_image_buffer
== (char *) -1) {
465 panic("unable to synch boot image buffer");
469 /* Set alarm to periodically check service status. */
470 if (OK
!= (s
=sys_setalarm(RS_DELTA_T
, 0)))
471 panic("couldn't set alarm: %d", s
);
473 /* Map out our own text and data. This is normally done in crtso.o
474 * but RS is an exception - we don't get to talk to VM so early on.
475 * That's why we override munmap() and munmap_text() in utility.c.
477 * _minix_unmapzero() is the same code in crtso.o that normally does
478 * it on startup. It's best that it's there as crtso.o knows exactly
479 * what the ranges are of the filler data.
487 /*===========================================================================*
488 * sef_cb_signal_handler *
489 *===========================================================================*/
490 PRIVATE
void sef_cb_signal_handler(int signo
)
492 /* Check for known signals, ignore anything else. */
503 /*===========================================================================*
504 * sef_cb_signal_manager *
505 *===========================================================================*/
506 PRIVATE
int sef_cb_signal_manager(endpoint_t target
, int signo
)
508 /* Process system signal on behalf of the kernel. */
511 struct rprocpub
*rpub
;
515 if(rs_isokendpt(target
, &target_p
) != OK
|| rproc_ptr
[target_p
] == NULL
) {
517 printf("RS: ignoring spurious signal %d for process %d\n",
519 return OK
; /* clear the signal */
521 rp
= rproc_ptr
[target_p
];
524 /* Don't bother if a termination signal has already been processed. */
525 if((rp
->r_flags
& RS_TERMINATED
) && !(rp
->r_flags
& RS_EXITING
)) {
526 return EDEADSRCDST
; /* process is gone */
529 /* Ignore external signals for inactive service instances. */
530 if( !(rp
->r_flags
& RS_ACTIVE
) && !(rp
->r_flags
& RS_EXITING
)) {
532 printf("RS: ignoring signal %d for inactive %s\n",
533 signo
, srv_to_string(rp
));
534 return OK
; /* clear the signal */
538 printf("RS: %s got %s signal %d\n", srv_to_string(rp
),
539 SIGS_IS_TERMINATION(signo
) ? "termination" : "non-termination",signo
);
541 /* Print stacktrace if necessary. */
542 if(SIGS_IS_STACKTRACE(signo
)) {
543 sys_sysctl_stacktrace(target
);
546 /* In case of termination signal handle the event. */
547 if(SIGS_IS_TERMINATION(signo
)) {
548 rp
->r_flags
|= RS_TERMINATED
;
549 terminate_service(rp
);
551 return EDEADSRCDST
; /* process is now gone */
554 /* Translate every non-termination signal into a message. */
555 m
.m_type
= SIGS_SIGNAL_RECEIVED
;
556 m
.SIGS_SIG_NUM
= signo
;
557 asynsend3(rpub
->endpoint
, &m
, AMF_NOREPLY
);
559 return OK
; /* signal has been delivered */
562 /*===========================================================================*
564 *===========================================================================*/
565 PRIVATE
void exec_image_copy(boot_proc_idx
, ip
, rp
)
567 struct boot_image
*ip
;
570 /* Copy the executable image of the given boot process. */
573 static char *boot_image_ptr
= NULL
;
575 if(boot_image_ptr
== NULL
) {
576 boot_image_ptr
= boot_image_buffer
;
579 /* Get a.out header. */
581 if(boot_image_buffer
+boot_image_buffer_size
- boot_image_ptr
< sizeof(header
)
582 || (s
= sys_getaoutheader(&header
, boot_proc_idx
)) != OK
) {
583 panic("unable to get copy of a.out header: %d", s
);
585 memcpy(boot_image_ptr
, &header
, header
.a_hdrlen
);
586 boot_image_ptr
+= header
.a_hdrlen
;
588 /* Get text segment. */
590 if(boot_image_buffer
+boot_image_buffer_size
- boot_image_ptr
< header
.a_text
591 || (s
= rs_startup_segcopy(ip
->endpoint
, T
, D
, (vir_bytes
) boot_image_ptr
,
592 header
.a_text
)) != OK
) {
593 panic("unable to get copy of text segment: %d", s
);
595 boot_image_ptr
+= header
.a_text
;
597 /* Get data segment. */
599 if(boot_image_buffer
+boot_image_buffer_size
- boot_image_ptr
< header
.a_data
600 || (s
= rs_startup_segcopy(ip
->endpoint
, D
, D
, (vir_bytes
) boot_image_ptr
,
601 header
.a_data
)) != OK
) {
602 panic("unable to get copy of data segment: %d", s
);
604 boot_image_ptr
+= header
.a_data
;
606 /* Set the executable image for the given boot process. */
607 rp
->r_exec_len
= header
.a_hdrlen
+ header
.a_text
+ header
.a_data
;
608 rp
->r_exec
= boot_image_ptr
- rp
->r_exec_len
;
611 /*===========================================================================*
612 * boot_image_info_lookup *
613 *===========================================================================*/
614 PRIVATE
void boot_image_info_lookup(endpoint
, image
, ip
, pp
, sp
, dp
)
616 struct boot_image
*image
;
617 struct boot_image
**ip
;
618 struct boot_image_priv
**pp
;
619 struct boot_image_sys
**sp
;
620 struct boot_image_dev
**dp
;
622 /* Lookup entries in boot image tables. */
625 /* When requested, locate the corresponding entry in the boot image table
626 * or panic if not found.
629 for (i
=0; i
< NR_BOOT_PROCS
; i
++) {
630 if(image
[i
].endpoint
== endpoint
) {
635 if(i
== NR_BOOT_PROCS
) {
636 panic("boot image table lookup failed");
640 /* When requested, locate the corresponding entry in the boot image priv table
641 * or panic if not found.
644 for (i
=0; boot_image_priv_table
[i
].endpoint
!= NULL_BOOT_NR
; i
++) {
645 if(boot_image_priv_table
[i
].endpoint
== endpoint
) {
646 *pp
= &boot_image_priv_table
[i
];
650 if(i
== NULL_BOOT_NR
) {
651 panic("boot image priv table lookup failed");
655 /* When requested, locate the corresponding entry in the boot image sys table
656 * or resort to the default entry if not found.
659 for (i
=0; boot_image_sys_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
660 if(boot_image_sys_table
[i
].endpoint
== endpoint
) {
661 *sp
= &boot_image_sys_table
[i
];
665 if(boot_image_sys_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
666 *sp
= &boot_image_sys_table
[i
]; /* accept the default entry */
670 /* When requested, locate the corresponding entry in the boot image dev table
671 * or resort to the default entry if not found.
674 for (i
=0; boot_image_dev_table
[i
].endpoint
!= DEFAULT_BOOT_NR
; i
++) {
675 if(boot_image_dev_table
[i
].endpoint
== endpoint
) {
676 *dp
= &boot_image_dev_table
[i
];
680 if(boot_image_dev_table
[i
].endpoint
== DEFAULT_BOOT_NR
) {
681 *dp
= &boot_image_dev_table
[i
]; /* accept the default entry */
686 /*===========================================================================*
687 * catch_boot_init_ready *
688 *===========================================================================*/
689 PRIVATE
void catch_boot_init_ready(endpoint
)
692 /* Block and catch an init ready message from the given source. */
699 /* Receive init ready message. */
700 if ((r
= sef_receive_status(endpoint
, &m
, &ipc_status
)) != OK
) {
701 panic("unable to receive init reply: %d", r
);
703 if(m
.m_type
!= RS_INIT
) {
704 panic("unexpected reply from service: %d", m
.m_source
);
706 result
= m
.RS_INIT_RESULT
;
707 rp
= rproc_ptr
[_ENDPOINT_P(m
.m_source
)];
711 panic("unable to complete init for service: %d", m
.m_source
);
714 /* Send a reply to unblock the service. */
716 reply(m
.m_source
, &m
);
718 /* Mark the slot as no longer initializing. */
719 rp
->r_flags
&= ~RS_INITIALIZING
;
721 getuptime(&rp
->r_alive_tm
);
724 /*===========================================================================*
726 *===========================================================================*/
727 PRIVATE
void get_work(m_ptr
, status_ptr
)
728 message
*m_ptr
; /* pointer to message */
729 int *status_ptr
; /* pointer to status */
732 if (OK
!= (r
=sef_receive_status(ANY
, m_ptr
, status_ptr
)))
733 panic("sef_receive_status failed: %d", r
);