xref: /minix/minix/lib/libsys/sef.c (revision 433d6423)
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 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
28 
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);
32 
33 /* SEF Ping prototypes. */
34 EXTERN int do_sef_ping_request(message *m_ptr);
35 
36 /* SEF Live update prototypes. */
37 EXTERN void do_sef_lu_before_receive(void);
38 EXTERN int do_sef_lu_request(message *m_ptr);
39 
40 /* SEF Signal prototypes. */
41 EXTERN int do_sef_signal_request(message *m_ptr);
42 
43 /* SEF GCOV prototypes. */
44 #ifdef USE_COVERAGE
45 EXTERN int do_sef_gcov_request(message *m_ptr);
46 #endif
47 
48 /* SEF Fault Injection prototypes. */
49 EXTERN int do_sef_fi_request(message *m_ptr);
50 
51 /*===========================================================================*
52  *				sef_startup				     *
53  *===========================================================================*/
54 void sef_startup()
55 {
56 /* SEF startup interface for system services. */
57   int r, status;
58   endpoint_t old_endpoint;
59   int priv_flags;
60 
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));
67   }
68   sef_self_priv_flags = priv_flags;
69   old_endpoint = NONE;
70 
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);
78       }
79       old_endpoint = sef_self_endpoint;
80       sef_self_endpoint = RS_PROC_NR;
81   }
82 #endif /* USE_LIVEUPDATE */
83 
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);
90       }
91   }
92   else if(sef_self_endpoint == VM_PROC_NR) {
93   	/* VM handles initialization by RS later */
94   } else {
95       message m;
96 
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.
102        */
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);
107           }
108       } while(!IS_SEF_INIT_REQUEST(&m));
109 
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);
113       }
114   }
115 #endif
116 
117   /* (Re)initialize SEF variables. */
118   sef_self_first_receive_done = FALSE;
119   sef_self_priv_flags = priv_flags;
120 }
121 
122 /*===========================================================================*
123  *				sef_receive_status			     *
124  *===========================================================================*/
125 int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr)
126 {
127 /* SEF receive() interface for system services. */
128   int r, status;
129 
130   sef_self_receiving = TRUE;
131 
132   while(TRUE) {
133       /* If the caller indicated that it no longer wants to receive a message,
134        * return now.
135        */
136       if (!sef_self_receiving)
137           return EINTR;
138 
139 #if INTERCEPT_SEF_LU_REQUESTS
140       /* Handle SEF Live update before receive events. */
141       do_sef_lu_before_receive();
142 #endif
143 
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;
150       }
151 
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;
157           }
158       }
159 #endif
160 
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;
166           }
167       }
168 #endif
169 
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;
175           }
176       }
177 #endif
178 
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;
185           }
186       }
187 #endif
188 
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;
194           }
195       }
196 #endif
197 
198       /* If we get this far, this is not a valid SEF request, return and
199        * let the caller deal with that.
200        */
201       break;
202   }
203 
204   return r;
205 }
206 
207 /*===========================================================================*
208  *				sef_self				     *
209  *===========================================================================*/
210 endpoint_t sef_self(void)
211 {
212 /* Return the process's own endpoint number. */
213 
214   if (sef_self_endpoint == NONE)
215 	panic("sef_self called before initialization");
216 
217   return sef_self_endpoint;
218 }
219 
220 /*===========================================================================*
221  *				sef_cancel				     *
222  *===========================================================================*/
223 void sef_cancel(void)
224 {
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.
229  */
230 
231   sef_self_receiving = FALSE;
232 }
233 
234 /*===========================================================================*
235  *      	                  sef_exit                                   *
236  *===========================================================================*/
237 void sef_exit(int status)
238 {
239 /* System services use a special version of exit() that generates a
240  * self-termination signal.
241  */
242   message m;
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   int r;
266 
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;
272       }
273   }
274 
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;
281       }
282   }
283 
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;
290       }
291   }
292 
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;
297   }
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;
303   }
304 }
305 
306 /*===========================================================================*
307  *                              sef_debug_header              		     *
308  *===========================================================================*/
309 char* sef_debug_header(void)
310 {
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);
316 
317   return sef_debug_header_buff;
318 }
319 #endif /*SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG*/
320 
321