1 /* This file contains some utility routines for RS.
4 * Nov 22, 2009: Created (Cristiano Giuffrida)
10 #include <minix/sched.h>
11 #include "kernel/proc.h"
13 #define PRINT_SEP() printf("---------------------------------------------------------------------------------\n")
15 /*===========================================================================*
17 *===========================================================================*/
18 int init_service(struct rproc
*rp
, int type
, int flags
)
22 endpoint_t old_endpoint
;
24 rp
->r_flags
|= RS_INITIALIZING
; /* now initializing */
25 rp
->r_alive_tm
= getticks();
26 rp
->r_check_tm
= rp
->r_alive_tm
+ 1; /* expect reply within period */
28 /* In case of RS initialization, we are done. */
29 if(rp
->r_priv
.s_flags
& ROOT_SYS_PROC
) {
33 /* Determine the old endpoint if this is a new instance. */
35 prepare_state
= SEF_LU_STATE_NULL
;
37 old_endpoint
= rp
->r_upd
.state_endpoint
;
38 prepare_state
= rp
->r_upd
.prepare_state
;
40 else if(rp
->r_prev_rp
) {
41 old_endpoint
= rp
->r_prev_rp
->r_pub
->endpoint
;
45 if(rp
->r_pub
->sys_flags
& SF_USE_SCRIPT
) {
46 flags
|= SEF_INIT_SCRIPT_RESTART
;
49 /* Send initialization message. */
51 m
.m_rs_init
.type
= (short) type
;
52 m
.m_rs_init
.flags
= flags
;
53 m
.m_rs_init
.rproctab_gid
= rinit
.rproctab_gid
;
54 m
.m_rs_init
.old_endpoint
= old_endpoint
;
55 m
.m_rs_init
.restarts
= (short) rp
->r_restarts
+1;
56 m
.m_rs_init
.buff_addr
= rp
->r_map_prealloc_addr
;
57 m
.m_rs_init
.buff_len
= rp
->r_map_prealloc_len
;
58 m
.m_rs_init
.prepare_state
= prepare_state
;
59 rp
->r_map_prealloc_addr
= 0;
60 rp
->r_map_prealloc_len
= 0;
61 r
= rs_asynsend(rp
, &m
, 0);
66 /*===========================================================================*
68 *===========================================================================*/
69 int fi_service(struct rproc
*rp
)
73 /* Send fault injection message. */
74 m
.m_type
= COMMON_REQ_FI_CTL
;
75 m
.m_lsys_fi_ctl
.subtype
= RS_FI_CRASH
;
76 return rs_asynsend(rp
, &m
, 0);
79 /*===========================================================================*
81 *===========================================================================*/
82 void fill_send_mask(send_mask
, set_bits
)
83 sys_map_t
*send_mask
; /* the send mask to fill in */
84 int set_bits
; /* TRUE sets all bits, FALSE clears all bits */
86 /* Fill in a send mask. */
89 for (i
= 0; i
< NR_SYS_PROCS
; i
++) {
91 set_sys_bit(*send_mask
, i
);
93 unset_sys_bit(*send_mask
, i
);
97 /*===========================================================================*
99 *===========================================================================*/
100 void fill_call_mask(calls
, tot_nr_calls
, call_mask
, call_base
, is_init
)
101 int *calls
; /* the unordered set of calls */
102 int tot_nr_calls
; /* the total number of calls */
103 bitchunk_t
*call_mask
; /* the call mask to fill in */
104 int call_base
; /* the base offset for the calls */
105 int is_init
; /* set when initializing a call mask */
107 /* Fill a call mask from an unordered set of calls. */
109 int call_mask_size
, nr_calls
;
111 call_mask_size
= BITMAP_CHUNKS(tot_nr_calls
);
113 /* Count the number of calls to fill in. */
115 for(i
=0; calls
[i
] != NULL_C
; i
++) {
119 /* See if all calls are allowed and call mask must be completely filled. */
120 if(nr_calls
== 1 && calls
[0] == ALL_C
) {
121 for(i
=0; i
< call_mask_size
; i
++) {
126 /* When initializing, reset the mask first. */
128 for(i
=0; i
< call_mask_size
; i
++) {
132 /* Enter calls bit by bit. */
133 for(i
=0; i
< nr_calls
; i
++) {
134 SET_BIT(call_mask
, calls
[i
] - call_base
);
139 /*===========================================================================*
140 * srv_to_string_gen *
141 *===========================================================================*/
142 char* srv_to_string_gen(struct rproc
*rp
, int is_verbose
)
144 struct rprocpub
*rpub
;
147 /* LSC: Workaround broken GCC which complains that a const variable is not constant... */
148 #define max_len (RS_MAX_LABEL_LEN + 256)
149 static char srv_string_pool
[3][max_len
];
150 static int srv_string_pool_index
= 0;
153 slot_nr
= rp
- rproc
;
154 srv_string
= srv_string_pool
[srv_string_pool_index
];
155 srv_string_pool_index
= (srv_string_pool_index
+ 1) % 3;
157 #define srv_str(cmd) ((cmd) == NULL || (cmd)[0] == '\0' ? "_" : (cmd))
158 #define srv_active_str(rp) ((rp)->r_flags & RS_ACTIVE ? "*" : " ")
159 #define srv_version_str(rp) ((rp)->r_new_rp || (rp)->r_next_rp ? "-" : \
160 ((rp)->r_old_rp || (rp)->r_prev_rp ? "+" : " "))
163 snprintf(srv_string
, max_len
, "service '%s'%s%s"
164 "(slot %d, ep %d, pid %d, cmd %s,"
165 " script %s, proc %s, major %d,"
166 " flags 0x%03x, sys_flags 0x%02x)",
167 rpub
->label
, srv_active_str(rp
), srv_version_str(rp
),
168 slot_nr
, rpub
->endpoint
, rp
->r_pid
, srv_str(rp
->r_cmd
),
169 srv_str(rp
->r_script
), srv_str(rpub
->proc_name
), rpub
->dev_nr
,
170 rp
->r_flags
, rpub
->sys_flags
);
173 snprintf(srv_string
, max_len
, "service '%s'%s%s(slot %d, ep %d, pid %d)",
174 rpub
->label
, srv_active_str(rp
), srv_version_str(rp
),
175 slot_nr
, rpub
->endpoint
, rp
->r_pid
);
179 #undef srv_active_str
180 #undef srv_version_str
186 /*===========================================================================*
187 * srv_upd_to_string *
188 *===========================================================================*/
189 char* srv_upd_to_string(struct rprocupd
*rpupd
)
191 static char srv_upd_string
[256];
192 struct rprocpub
*rpub
, *next_rpub
, *prev_rpub
;
193 rpub
= rpupd
->rp
? rpupd
->rp
->r_pub
: NULL
;
194 next_rpub
= rpupd
->next_rpupd
&& rpupd
->next_rpupd
->rp
? rpupd
->next_rpupd
->rp
->r_pub
: NULL
;
195 prev_rpub
= rpupd
->prev_rpupd
&& rpupd
->prev_rpupd
->rp
? rpupd
->prev_rpupd
->rp
->r_pub
: NULL
;
197 #define srv_ep(RPUB) (RPUB ? (RPUB)->endpoint : -1)
198 #define srv_upd_luflag_c(F) (rpupd->lu_flags & F ? '1' : '0')
199 #define srv_upd_iflag_c(F) (rpupd->init_flags & F ? '1' : '0')
201 snprintf(srv_upd_string
, sizeof(srv_upd_string
), "update (lu_flags(SAMPNDRV)="
203 " init_flags=(FCTD)=%c%c%c%c, state %d (%s),"
204 " tm %u, maxtime %u, endpoint %d,"
205 " state_data_gid %d, prev_ep %d, next_ep %d)",
206 srv_upd_luflag_c(SEF_LU_SELF
), srv_upd_luflag_c(SEF_LU_ASR
),
207 srv_upd_luflag_c(SEF_LU_MULTI
), srv_upd_luflag_c(SEF_LU_PREPARE_ONLY
),
208 srv_upd_luflag_c(SEF_LU_NOMMAP
), srv_upd_luflag_c(SEF_LU_DETACHED
),
209 srv_upd_luflag_c(SEF_LU_INCLUDES_RS
),
210 srv_upd_luflag_c(SEF_LU_INCLUDES_VM
), srv_upd_iflag_c(SEF_INIT_FAIL
),
211 srv_upd_iflag_c(SEF_INIT_CRASH
), srv_upd_iflag_c(SEF_INIT_TIMEOUT
),
212 srv_upd_iflag_c(SEF_INIT_DEFCB
), rpupd
->prepare_state
,
213 rpupd
->prepare_state_data
.eval_addr
? rpupd
->prepare_state_data
.eval_addr
: "",
214 rpupd
->prepare_tm
, rpupd
->prepare_maxtime
, srv_ep(rpub
),
215 rpupd
->prepare_state_data_gid
, srv_ep(prev_rpub
), srv_ep(next_rpub
));
217 return srv_upd_string
;
220 /*===========================================================================*
222 *===========================================================================*/
223 int rs_asynsend(struct rproc
*rp
, message
*m_ptr
, int no_reply
)
225 struct rprocpub
*rpub
;
231 r
= asynsend3(rpub
->endpoint
, m_ptr
, AMF_NOREPLY
);
234 r
= asynsend(rpub
->endpoint
, m_ptr
);
238 printf("RS: %s being asynsent to with message type %d, noreply=%d, result=%d\n",
239 srv_to_string(rp
), m_ptr
->m_type
, no_reply
, r
);
244 /*===========================================================================*
246 *===========================================================================*/
247 int rs_receive_ticks(endpoint_t src
, message
*m_ptr
,
248 int *status_ptr
, clock_t ticks
)
250 /* IPC receive with timeout. Implemented with IPC filters. The timer
251 * management logic comes from the tickdelay(3) implementation.
253 ipc_filter_el_t ipc_filter
[2];
254 clock_t time_left
, uptime
;
257 /* Use IPC filters to receive from the provided source and CLOCK only.
258 * We make the hard assumption that RS did not already have IPC filters set.
260 memset(ipc_filter
, 0, sizeof(ipc_filter
));
261 ipc_filter
[0].flags
= IPCF_MATCH_M_SOURCE
;
262 ipc_filter
[0].m_source
= CLOCK
;
263 ipc_filter
[1].flags
= IPCF_MATCH_M_SOURCE
;
264 ipc_filter
[1].m_source
= src
;
266 if ((s
= sys_statectl(SYS_STATE_ADD_IPC_WL_FILTER
, ipc_filter
,
267 sizeof(ipc_filter
))) != OK
)
268 panic("RS: rs_receive_ticks: setting IPC filter failed: %d", s
);
270 /* Set a new alarm, and get information about the previous alarm. */
271 if ((s
= sys_setalarm2(ticks
, FALSE
, &time_left
, &uptime
)) != OK
)
272 panic("RS: rs_receive_ticks: setting alarm failed: %d", s
);
274 /* Receive a message from either the provided source or CLOCK. */
275 while ((r
= ipc_receive(ANY
, m_ptr
, &status
)) == OK
&&
276 m_ptr
->m_source
== CLOCK
) {
277 /* Ignore early clock notifications. */
278 if (m_ptr
->m_type
== NOTIFY_MESSAGE
&&
279 m_ptr
->m_notify
.timestamp
>= uptime
+ ticks
)
283 /* Reinstate the previous alarm, if any. Do this in any case. */
284 if (time_left
!= TMR_NEVER
) {
285 if (time_left
> ticks
)
288 time_left
= 1; /* force an alarm */
290 (void)sys_setalarm(time_left
, FALSE
);
293 /* Clear the IPC filters. */
294 if ((s
= sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS
, NULL
, 0)) != OK
)
295 panic("RS: rs_receive_ticks: setting IPC filter failed: %d", s
);
297 /* If the last received message was from CLOCK, we timed out. */
298 if (r
== OK
&& m_ptr
->m_source
== CLOCK
)
301 if (status_ptr
!= NULL
)
302 *status_ptr
= status
;
306 /*===========================================================================*
308 *===========================================================================*/
309 void reply(who
, rp
, m_ptr
)
310 endpoint_t who
; /* replyee */
311 struct rproc
*rp
; /* replyee slot (if any) */
312 message
*m_ptr
; /* reply message */
314 int r
; /* send status */
316 /* No need to actually reply to RS */
317 if(who
== RS_PROC_NR
) {
322 printf("RS: %s being replied to with message type %d\n", srv_to_string(rp
), m_ptr
->m_type
);
324 r
= ipc_sendnb(who
, m_ptr
); /* send the message */
326 printf("RS: unable to send reply to %d: %d\n", who
, r
);
329 /*===========================================================================*
331 *===========================================================================*/
332 void late_reply(rp
, code
)
333 struct rproc
*rp
; /* pointer to process slot */
334 int code
; /* status code */
336 /* If a caller is waiting for a reply, unblock it. */
337 if(rp
->r_flags
& RS_LATEREPLY
) {
341 printf("RS: %s late reply %d to %d for request %d\n",
342 srv_to_string(rp
), code
, rp
->r_caller
, rp
->r_caller_request
);
344 reply(rp
->r_caller
, NULL
, &m
);
345 rp
->r_flags
&= ~RS_LATEREPLY
;
349 /*===========================================================================*
351 *===========================================================================*/
352 int rs_isokendpt(endpoint_t endpoint
, int *proc
)
354 *proc
= _ENDPOINT_P(endpoint
);
355 if(*proc
< -NR_TASKS
|| *proc
>= NR_PROCS
)
361 /*===========================================================================*
363 *===========================================================================*/
364 int sched_init_proc(struct rproc
*rp
)
369 /* Make sure user processes have no scheduler. PM deals with them. */
370 is_usr_proc
= !(rp
->r_priv
.s_flags
& SYS_PROC
);
371 if(is_usr_proc
) assert(rp
->r_scheduler
== NONE
);
372 if(!is_usr_proc
) assert(rp
->r_scheduler
!= NONE
);
374 /* Start scheduling for the given process. */
375 if ((s
= sched_start(rp
->r_scheduler
, rp
->r_pub
->endpoint
,
376 RS_PROC_NR
, rp
->r_priority
, rp
->r_quantum
, rp
->r_cpu
,
377 &rp
->r_scheduler
)) != OK
) {
384 /*===========================================================================*
386 *===========================================================================*/
387 int update_sig_mgrs(struct rproc
*rp
, endpoint_t sig_mgr
,
388 endpoint_t bak_sig_mgr
)
391 struct rprocpub
*rpub
;
396 printf("RS: %s updates signal managers: %d%s / %d\n", srv_to_string(rp
),
397 sig_mgr
== SELF
? rpub
->endpoint
: sig_mgr
,
398 sig_mgr
== SELF
? "(SELF)" : "",
399 bak_sig_mgr
== NONE
? -1 : bak_sig_mgr
);
401 /* Synch privilege structure with the kernel. */
402 if ((r
= sys_getpriv(&rp
->r_priv
, rpub
->endpoint
)) != OK
) {
403 printf("unable to synch privilege structure: %d", r
);
407 /* Set signal managers. */
408 rp
->r_priv
.s_sig_mgr
= sig_mgr
;
409 rp
->r_priv
.s_bak_sig_mgr
= bak_sig_mgr
;
411 /* Update privilege structure. */
412 r
= sys_privctl(rpub
->endpoint
, SYS_PRIV_UPDATE_SYS
, &rp
->r_priv
);
414 printf("unable to update privilege structure: %d", r
);
421 /*===========================================================================*
423 *===========================================================================*/
428 for (slot_nr
= 0; slot_nr
< NR_SYS_PROCS
; slot_nr
++) {
429 rp
= &rproc
[slot_nr
];
430 if (!(rp
->r_flags
& RS_IN_USE
)) {
433 if(!RS_SRV_IS_IDLE(rp
)) {
440 /*===========================================================================*
442 *===========================================================================*/
443 void rs_idle_period()
446 struct rprocpub
*rpub
;
449 /* Not much to do when RS is not idle. */
450 /* However, to avoid deadlocks it is absolutely necessary that during system
451 * shutdown, dead services are actually cleaned up. Override the idle check.
453 if(!shutting_down
&& !rs_is_idle()) {
457 /* Cleanup dead services. */
458 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
459 if((rp
->r_flags
& (RS_IN_USE
|RS_DEAD
)) == (RS_IN_USE
|RS_DEAD
)) {
464 if (shutting_down
) return;
466 /* Create missing replicas when necessary. */
467 for (rp
=BEG_RPROC_ADDR
; rp
<END_RPROC_ADDR
; rp
++) {
469 if((rp
->r_flags
& RS_ACTIVE
) && (rpub
->sys_flags
& SF_USE_REPL
) && rp
->r_next_rp
== NULL
) {
470 if(rpub
->endpoint
== VM_PROC_NR
&& (rp
->r_old_rp
|| rp
->r_new_rp
)) {
471 /* Only one replica at the time for VM. */
474 if ((r
= clone_service(rp
, RST_SYS_PROC
, 0)) != OK
) {
475 printf("RS: warning: unable to clone %s (error %d)\n",
476 srv_to_string(rp
), r
);
482 /*===========================================================================*
483 * print_services_status *
484 *===========================================================================*/
485 void print_services_status()
489 int num_services
= 0;
490 int num_service_instances
= 0;
494 printf("Printing information about all the system service instances:\n");
496 for (slot_nr
= 0; slot_nr
< NR_SYS_PROCS
; slot_nr
++) {
497 rp
= &rproc
[slot_nr
];
498 if (!(rp
->r_flags
& RS_IN_USE
)) {
501 if (rp
->r_flags
& RS_ACTIVE
) {
504 num_service_instances
++;
505 printf("%s\n", srv_to_string_gen(rp
, is_verbose
));
508 printf("Found %d service instances, of which %d are active services\n",
509 num_service_instances
, num_services
);
513 /*===========================================================================*
514 * print_update_status *
515 *===========================================================================*/
516 void print_update_status()
518 struct rprocupd
*prev_rpupd
, *rpupd
;
519 int is_updating
= RUPDATE_IS_UPDATING();
522 #define rupdate_flag_c(F) (rupdate.flags & F ? '1' : '0')
524 if(!is_updating
&& !RUPDATE_IS_UPD_SCHEDULED()) {
526 printf("No update is in progress or scheduled\n");
533 printf("A %s-component update is %s, flags(UIRV)=%c%c%c%c:\n", RUPDATE_IS_UPD_MULTI() ? "multi" : "single",
534 is_updating
? "in progress" : "scheduled",
535 rupdate_flag_c(RS_UPDATING
), rupdate_flag_c(RS_INITIALIZING
),
536 rupdate
.rs_rpupd
? '1' : '0', rupdate
.vm_rpupd
? '1' : '0');
538 RUPDATE_ITER(rupdate
.first_rpupd
, prev_rpupd
, rpupd
,
539 printf("%d. %s %s %s\n", i
++, srv_to_string(rpupd
->rp
),
540 is_updating
? "updating with" : "scheduled for",
541 srv_upd_to_string(rpupd
));
545 #undef rupdate_flag_c