custom message type for VM_INFO
[minix3.git] / lib / libsys / sef.c
blob389118719a7924b48aa9ddf15e7f3fd805cca4fa
1 #include "syslib.h"
2 #include <assert.h>
3 #include <minix/sysutil.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <string.h>
9 /* Self variables. */
10 #define SEF_SELF_NAME_MAXLEN 20
11 char sef_self_name[SEF_SELF_NAME_MAXLEN];
12 endpoint_t sef_self_endpoint = NONE;
13 int sef_self_priv_flags;
14 int sef_self_first_receive_done;
15 int sef_self_receiving;
17 /* Debug. */
18 #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG
19 #define SEF_DEBUG_HEADER_MAXLEN 32
20 static time_t sef_debug_boottime = 0;
21 static u32_t sef_debug_system_hz = 0;
22 static time_t sef_debug_time_sec = 0;
23 static time_t sef_debug_time_us = 0;
24 static char sef_debug_header_buff[SEF_DEBUG_HEADER_MAXLEN];
25 static void sef_debug_refresh_params(void);
26 char* sef_debug_header(void);
27 #endif
29 /* SEF Init prototypes. */
30 EXTERN int do_sef_rs_init(endpoint_t old_endpoint);
31 EXTERN int do_sef_init_request(message *m_ptr);
33 /* SEF Ping prototypes. */
34 EXTERN int do_sef_ping_request(message *m_ptr);
36 /* SEF Live update prototypes. */
37 EXTERN void do_sef_lu_before_receive(void);
38 EXTERN int do_sef_lu_request(message *m_ptr);
40 /* SEF Signal prototypes. */
41 EXTERN int do_sef_signal_request(message *m_ptr);
43 /* SEF GCOV prototypes. */
44 #ifdef USE_COVERAGE
45 EXTERN int do_sef_gcov_request(message *m_ptr);
46 #endif
48 /* SEF Fault Injection prototypes. */
49 EXTERN int do_sef_fi_request(message *m_ptr);
51 /*===========================================================================*
52 * sef_startup *
53 *===========================================================================*/
54 void sef_startup()
56 /* SEF startup interface for system services. */
57 int r, status;
58 endpoint_t old_endpoint;
59 int priv_flags;
61 /* Get information about self. */
62 r = sys_whoami(&sef_self_endpoint, sef_self_name, SEF_SELF_NAME_MAXLEN,
63 &priv_flags);
64 if ( r != OK) {
65 sef_self_endpoint = SELF;
66 strlcpy(sef_self_name, "Unknown", sizeof(sef_self_name));
68 sef_self_priv_flags = priv_flags;
69 old_endpoint = NONE;
71 #if USE_LIVEUPDATE
72 /* RS may wake up with the wrong endpoint, perfom the update in that case. */
73 if((sef_self_priv_flags & ROOT_SYS_PROC) && sef_self_endpoint != RS_PROC_NR) {
74 r = vm_update(RS_PROC_NR, sef_self_endpoint);
75 if(r != OK) {
76 panic("unable to update RS from instance %d to %d: %d",
77 RS_PROC_NR, sef_self_endpoint, r);
79 old_endpoint = sef_self_endpoint;
80 sef_self_endpoint = RS_PROC_NR;
82 #endif /* USE_LIVEUPDATE */
84 #if INTERCEPT_SEF_INIT_REQUESTS
85 /* Intercept SEF Init requests. */
86 if(sef_self_priv_flags & ROOT_SYS_PROC) {
87 /* RS initialization is special. */
88 if((r = do_sef_rs_init(old_endpoint)) != OK) {
89 panic("RS unable to complete init: %d", r);
92 else if(sef_self_endpoint == VM_PROC_NR) {
93 /* VM handles initialization by RS later */
94 } else {
95 message m;
97 /* Wait for an initialization message from RS. We need this to learn the
98 * initialization type and parameters. When restarting after a crash, we
99 * may get some spurious IPC messages from RS (e.g. update request) that
100 * were originally meant to be delivered to the old instance. We discard
101 * these messages and block till a proper initialization request arrives.
103 do {
104 r = ipc_receive(RS_PROC_NR, &m, &status);
105 if(r != OK) {
106 panic("unable to ipc_receive from RS: %d", r);
108 } while(!IS_SEF_INIT_REQUEST(&m));
110 /* Process initialization request for this system service. */
111 if((r = do_sef_init_request(&m)) != OK) {
112 panic("unable to process init request: %d", r);
115 #endif
117 /* (Re)initialize SEF variables. */
118 sef_self_first_receive_done = FALSE;
119 sef_self_priv_flags = priv_flags;
122 /*===========================================================================*
123 * sef_receive_status *
124 *===========================================================================*/
125 int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr)
127 /* SEF receive() interface for system services. */
128 int r, status;
130 sef_self_receiving = TRUE;
132 while(TRUE) {
133 /* If the caller indicated that it no longer wants to receive a message,
134 * return now.
136 if (!sef_self_receiving)
137 return EINTR;
139 #if INTERCEPT_SEF_LU_REQUESTS
140 /* Handle SEF Live update before receive events. */
141 do_sef_lu_before_receive();
142 #endif
144 /* Receive and return in case of error. */
145 r = ipc_receive(src, m_ptr, &status);
146 if(status_ptr) *status_ptr = status;
147 if(!sef_self_first_receive_done) sef_self_first_receive_done = TRUE;
148 if(r != OK) {
149 return r;
152 #if INTERCEPT_SEF_PING_REQUESTS
153 /* Intercept SEF Ping requests. */
154 if(IS_SEF_PING_REQUEST(m_ptr, status)) {
155 if(do_sef_ping_request(m_ptr) == OK) {
156 continue;
159 #endif
161 #if INTERCEPT_SEF_LU_REQUESTS
162 /* Intercept SEF Live update requests. */
163 if(IS_SEF_LU_REQUEST(m_ptr, status)) {
164 if(do_sef_lu_request(m_ptr) == OK) {
165 continue;
168 #endif
170 #if INTERCEPT_SEF_SIGNAL_REQUESTS
171 /* Intercept SEF Signal requests. */
172 if(IS_SEF_SIGNAL_REQUEST(m_ptr, status)) {
173 if(do_sef_signal_request(m_ptr) == OK) {
174 continue;
177 #endif
179 #ifdef USE_COVERAGE
180 /* Intercept GCOV data requests (sent by VFS in vfs/gcov.c). */
181 if(m_ptr->m_type == COMMON_REQ_GCOV_DATA &&
182 m_ptr->m_source == VFS_PROC_NR) {
183 if(do_sef_gcov_request(m_ptr) == OK) {
184 continue;
187 #endif
189 #ifdef INTERCEPT_SEF_FI_REQUESTS
190 /* Intercept Fault injection requests. */
191 if(IS_SEF_FI_REQUEST(m_ptr, status)) {
192 if(do_sef_fi_request(m_ptr) == OK) {
193 continue;
196 #endif
198 /* If we get this far, this is not a valid SEF request, return and
199 * let the caller deal with that.
201 break;
204 return r;
207 /*===========================================================================*
208 * sef_self *
209 *===========================================================================*/
210 endpoint_t sef_self(void)
212 /* Return the process's own endpoint number. */
214 if (sef_self_endpoint == NONE)
215 panic("sef_self called before initialization");
217 return sef_self_endpoint;
220 /*===========================================================================*
221 * sef_cancel *
222 *===========================================================================*/
223 void sef_cancel(void)
225 /* Cancel receiving a message. This function be called from a callback invoked
226 * from within sef_receive_status(), which will then return an EINTR error
227 * code. In particular, this function can be used to exit from the main receive
228 * loop when a signal handler causes the process to want to shut down.
231 sef_self_receiving = FALSE;
234 /*===========================================================================*
235 * sef_exit *
236 *===========================================================================*/
237 void sef_exit(int status)
239 /* System services use a special version of exit() that generates a
240 * self-termination signal.
242 message m;
244 /* Ask the kernel to exit. */
245 sys_exit();
247 /* If everything else fails, hang. */
248 printf("Warning: system service %d couldn't exit\n", sef_self_endpoint);
249 for(;;) { }
252 #ifdef __weak_alias
253 __weak_alias(_exit, sef_exit);
254 __weak_alias(__exit, sef_exit);
255 #endif
257 #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG
258 /*===========================================================================*
259 * sef_debug_refresh_params *
260 *===========================================================================*/
261 static void sef_debug_refresh_params(void)
263 /* Refresh SEF debug params. */
264 clock_t uptime;
265 int r;
267 /* Get boottime the first time. */
268 if(!sef_debug_boottime) {
269 r = sys_times(NONE, NULL, NULL, NULL, &sef_debug_boottime);
270 if ( r != OK) {
271 sef_debug_boottime = -1;
275 /* Get system hz the first time. */
276 if(!sef_debug_system_hz) {
277 r = sys_getinfo(GET_HZ, &sef_debug_system_hz,
278 sizeof(sef_debug_system_hz), 0, 0);
279 if ( r != OK) {
280 sef_debug_system_hz = -1;
284 /* Get uptime. */
285 uptime = -1;
286 if(sef_debug_boottime!=-1 && sef_debug_system_hz!=-1) {
287 r = sys_times(NONE, NULL, NULL, &uptime, NULL);
288 if ( r != OK) {
289 uptime = -1;
293 /* Compute current time. */
294 if(sef_debug_boottime==-1 || sef_debug_system_hz==-1 || uptime==-1) {
295 sef_debug_time_sec = 0;
296 sef_debug_time_us = 0;
298 else {
299 sef_debug_time_sec = (time_t) (sef_debug_boottime
300 + (uptime/sef_debug_system_hz));
301 sef_debug_time_us = (uptime%sef_debug_system_hz)
302 * 1000000/sef_debug_system_hz;
306 /*===========================================================================*
307 * sef_debug_header *
308 *===========================================================================*/
309 char* sef_debug_header(void)
311 /* Build and return a SEF debug header. */
312 sef_debug_refresh_params();
313 snprintf(sef_debug_header_buff, sizeof(sef_debug_header_buff),
314 "%s: time = %ds %06dus", sef_self_name, (int) sef_debug_time_sec,
315 (int) sef_debug_time_us);
317 return sef_debug_header_buff;
319 #endif /*SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG*/