xref: /minix3/minix/lib/libsys/sef.c (revision eda6f5931d42c77e1480347b1fc3eef2f8d33806)
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>
8 
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;
16 
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 int sef_debug_init = 0;
21 static time_t sef_debug_boottime = 0;
22 static u32_t sef_debug_system_hz = 0;
23 static time_t sef_debug_time_sec = 0;
24 static time_t sef_debug_time_us = 0;
25 static char sef_debug_header_buff[SEF_DEBUG_HEADER_MAXLEN];
26 static void sef_debug_refresh_params(void);
27 char* sef_debug_header(void);
28 #endif
29 
30 /* SEF Init prototypes. */
31 EXTERN int do_sef_rs_init(endpoint_t old_endpoint);
32 EXTERN int do_sef_init_request(message *m_ptr);
33 
34 /* SEF Ping prototypes. */
35 EXTERN int do_sef_ping_request(message *m_ptr);
36 
37 /* SEF Live update prototypes. */
38 EXTERN void do_sef_lu_before_receive(void);
39 EXTERN int do_sef_lu_request(message *m_ptr);
40 
41 /* SEF Signal prototypes. */
42 EXTERN int do_sef_signal_request(message *m_ptr);
43 
44 /* SEF GCOV prototypes. */
45 #ifdef USE_COVERAGE
46 EXTERN int do_sef_gcov_request(message *m_ptr);
47 #endif
48 
49 /* SEF Fault Injection prototypes. */
50 EXTERN int do_sef_fi_request(message *m_ptr);
51 
52 /*===========================================================================*
53  *				sef_startup				     *
54  *===========================================================================*/
55 void sef_startup()
56 {
57 /* SEF startup interface for system services. */
58   int r, status;
59   endpoint_t old_endpoint;
60   int priv_flags;
61 
62   /* Get information about self. */
63   r = sys_whoami(&sef_self_endpoint, sef_self_name, SEF_SELF_NAME_MAXLEN,
64       &priv_flags);
65   if ( r != OK) {
66       sef_self_endpoint = SELF;
67       strlcpy(sef_self_name, "Unknown", sizeof(sef_self_name));
68   }
69   sef_self_priv_flags = priv_flags;
70   old_endpoint = NONE;
71 
72 #if USE_LIVEUPDATE
73   /* RS may wake up with the wrong endpoint, perfom the update in that case. */
74   if((sef_self_priv_flags & ROOT_SYS_PROC) && sef_self_endpoint != RS_PROC_NR) {
75       r = vm_update(RS_PROC_NR, sef_self_endpoint);
76       if(r != OK) {
77           panic("unable to update RS from instance %d to %d: %d",
78               RS_PROC_NR, sef_self_endpoint, r);
79       }
80       old_endpoint = sef_self_endpoint;
81       sef_self_endpoint = RS_PROC_NR;
82   }
83 #endif /* USE_LIVEUPDATE */
84 
85 #if INTERCEPT_SEF_INIT_REQUESTS
86   /* Intercept SEF Init requests. */
87   if(sef_self_priv_flags & ROOT_SYS_PROC) {
88       /* RS initialization is special. */
89       if((r = do_sef_rs_init(old_endpoint)) != OK) {
90           panic("RS unable to complete init: %d", r);
91       }
92   }
93   else if(sef_self_endpoint == VM_PROC_NR) {
94   	/* VM handles initialization by RS later */
95   } else {
96       message m;
97 
98       /* Wait for an initialization message from RS. We need this to learn the
99        * initialization type and parameters. When restarting after a crash, we
100        * may get some spurious IPC messages from RS (e.g. update request) that
101        * were originally meant to be delivered to the old instance. We discard
102        * these messages and block till a proper initialization request arrives.
103        */
104       do {
105           r = ipc_receive(RS_PROC_NR, &m, &status);
106           if(r != OK) {
107               panic("unable to ipc_receive from RS: %d", r);
108           }
109       } while(!IS_SEF_INIT_REQUEST(&m));
110 
111       /* Process initialization request for this system service. */
112       if((r = do_sef_init_request(&m)) != OK) {
113           panic("unable to process init request: %d", r);
114       }
115   }
116 #endif
117 
118   /* (Re)initialize SEF variables. */
119   sef_self_first_receive_done = FALSE;
120   sef_self_priv_flags = priv_flags;
121 }
122 
123 /*===========================================================================*
124  *				sef_receive_status			     *
125  *===========================================================================*/
126 int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr)
127 {
128 /* SEF receive() interface for system services. */
129   int r, status;
130 
131   sef_self_receiving = TRUE;
132 
133   while(TRUE) {
134       /* If the caller indicated that it no longer wants to receive a message,
135        * return now.
136        */
137       if (!sef_self_receiving)
138           return EINTR;
139 
140 #if INTERCEPT_SEF_LU_REQUESTS
141       /* Handle SEF Live update before receive events. */
142       do_sef_lu_before_receive();
143 #endif
144 
145       /* Receive and return in case of error. */
146       r = ipc_receive(src, m_ptr, &status);
147       if(status_ptr) *status_ptr = status;
148       if(!sef_self_first_receive_done) sef_self_first_receive_done = TRUE;
149       if(r != OK) {
150           return r;
151       }
152 
153 #if INTERCEPT_SEF_PING_REQUESTS
154       /* Intercept SEF Ping requests. */
155       if(IS_SEF_PING_REQUEST(m_ptr, status)) {
156           if(do_sef_ping_request(m_ptr) == OK) {
157               continue;
158           }
159       }
160 #endif
161 
162 #if INTERCEPT_SEF_LU_REQUESTS
163       /* Intercept SEF Live update requests. */
164       if(IS_SEF_LU_REQUEST(m_ptr, status)) {
165           if(do_sef_lu_request(m_ptr) == OK) {
166               continue;
167           }
168       }
169 #endif
170 
171 #if INTERCEPT_SEF_SIGNAL_REQUESTS
172       /* Intercept SEF Signal requests. */
173       if(IS_SEF_SIGNAL_REQUEST(m_ptr, status)) {
174           if(do_sef_signal_request(m_ptr) == OK) {
175               continue;
176           }
177       }
178 #endif
179 
180 #ifdef USE_COVERAGE
181       /* Intercept GCOV data requests (sent by VFS in vfs/gcov.c). */
182       if(m_ptr->m_type == COMMON_REQ_GCOV_DATA &&
183 	 m_ptr->m_source == VFS_PROC_NR) {
184           if(do_sef_gcov_request(m_ptr) == OK) {
185               continue;
186           }
187       }
188 #endif
189 
190 #ifdef INTERCEPT_SEF_FI_REQUESTS
191       /* Intercept Fault injection requests. */
192       if(IS_SEF_FI_REQUEST(m_ptr, status)) {
193           if(do_sef_fi_request(m_ptr) == OK) {
194               continue;
195           }
196       }
197 #endif
198 
199       /* If we get this far, this is not a valid SEF request, return and
200        * let the caller deal with that.
201        */
202       break;
203   }
204 
205   return r;
206 }
207 
208 /*===========================================================================*
209  *				sef_self				     *
210  *===========================================================================*/
211 endpoint_t sef_self(void)
212 {
213 /* Return the process's own endpoint number. */
214 
215   if (sef_self_endpoint == NONE)
216 	panic("sef_self called before initialization");
217 
218   return sef_self_endpoint;
219 }
220 
221 /*===========================================================================*
222  *				sef_cancel				     *
223  *===========================================================================*/
224 void sef_cancel(void)
225 {
226 /* Cancel receiving a message. This function be called from a callback invoked
227  * from within sef_receive_status(), which will then return an EINTR error
228  * code. In particular, this function can be used to exit from the main receive
229  * loop when a signal handler causes the process to want to shut down.
230  */
231 
232   sef_self_receiving = FALSE;
233 }
234 
235 /*===========================================================================*
236  *      	                  sef_exit                                   *
237  *===========================================================================*/
238 void sef_exit(int status)
239 {
240 /* System services use a special version of exit() that generates a
241  * self-termination signal.
242  */
243 
244   /* Ask the kernel to exit. */
245   sys_exit();
246 
247   /* If everything else fails, hang. */
248   printf("Warning: system service %d couldn't exit\n", sef_self_endpoint);
249   for(;;) { }
250 }
251 
252 #ifdef __weak_alias
253 __weak_alias(_exit, sef_exit);
254 __weak_alias(__exit, sef_exit);
255 #endif
256 
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)
262 {
263 /* Refresh SEF debug params. */
264   clock_t uptime;
265 
266   /* Get boottime and system hz the first time. */
267   if(!sef_debug_init) {
268       if (sys_times(NONE, NULL, NULL, NULL, &sef_debug_boottime) != OK)
269 	  sef_debug_init = -1;
270       else if (sys_getinfo(GET_HZ, &sef_debug_system_hz,
271         sizeof(sef_debug_system_hz), 0, 0) != OK)
272 	  sef_debug_init = -1;
273       else
274 	  sef_debug_init = 1;
275   }
276 
277   /* Get uptime. */
278   uptime = -1;
279   if (sef_debug_init < 1 || sys_times(NONE, NULL, NULL, &uptime, NULL) != OK) {
280       sef_debug_time_sec = 0;
281       sef_debug_time_us = 0;
282   }
283   else {
284       /* Compute current time. */
285       sef_debug_time_sec = (time_t) (sef_debug_boottime
286           + (uptime/sef_debug_system_hz));
287       sef_debug_time_us = (uptime%sef_debug_system_hz)
288           * 1000000/sef_debug_system_hz;
289   }
290 }
291 
292 /*===========================================================================*
293  *                              sef_debug_header              		     *
294  *===========================================================================*/
295 char* sef_debug_header(void)
296 {
297 /* Build and return a SEF debug header. */
298   sef_debug_refresh_params();
299   snprintf(sef_debug_header_buff, sizeof(sef_debug_header_buff),
300       "%s: time = %ds %06dus", sef_self_name, (int) sef_debug_time_sec,
301       (int) sef_debug_time_us);
302 
303   return sef_debug_header_buff;
304 }
305 #endif /*SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG*/
306 
307