1 | /* signal.c -- Manage signals and exceptions
|
---|
2 | Copyright (c) 1994-1998 by Eberhard Mattes
|
---|
3 |
|
---|
4 | This file is part of emx.
|
---|
5 |
|
---|
6 | emx is free software; you can redistribute it and/or modify it
|
---|
7 | under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2, or (at your option)
|
---|
9 | any later version.
|
---|
10 |
|
---|
11 | emx is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with emx; see the file COPYING. If not, write to
|
---|
18 | the Free Software Foundation, 59 Temple Place - Suite 330,
|
---|
19 | Boston, MA 02111-1307, USA.
|
---|
20 |
|
---|
21 | As special exception, emx.dll can be distributed without source code
|
---|
22 | unless it has been changed. If you modify emx.dll, this exception
|
---|
23 | no longer applies and you must remove this paragraph from all source
|
---|
24 | files for emx.dll. */
|
---|
25 |
|
---|
26 |
|
---|
27 | #define INCL_DOSEXCEPTIONS
|
---|
28 | #define INCL_DOSPROCESS
|
---|
29 | #define INCL_DOSSEMAPHORES
|
---|
30 | #define INCL_DOSDATETIME
|
---|
31 | #define INCL_DOSMISC
|
---|
32 | #define INCL_DOSERRORS
|
---|
33 | #include <os2emx.h>
|
---|
34 | #include "wrapper.h"
|
---|
35 | #include <sys/signal.h>
|
---|
36 | #include <sys/uflags.h>
|
---|
37 | #include <sys/errno.h>
|
---|
38 | #include <emx/syscalls.h>
|
---|
39 | #include "emxdll.h"
|
---|
40 |
|
---|
41 | #define SIGF_CORE 0x01
|
---|
42 |
|
---|
43 | /* TODO: SIGSTOP */
|
---|
44 | #define SET_BLOCKED(td,set) ((td)->sig_blocked = (set) & ~_SIGMASK (SIGKILL))
|
---|
45 |
|
---|
46 |
|
---|
47 | /* This structure describes a signal. */
|
---|
48 |
|
---|
49 | struct signal_descr
|
---|
50 | {
|
---|
51 | const char *name; /* Name of the signal */
|
---|
52 | BYTE dfl_action; /* Action for SIG_DFL */
|
---|
53 | BYTE fun_action; /* Action taken after function */
|
---|
54 | BYTE flags; /* Flags (SIGF_CORE) */
|
---|
55 | };
|
---|
56 |
|
---|
57 |
|
---|
58 | /* Inhibit core dumps. */
|
---|
59 |
|
---|
60 | BYTE nocore_flag;
|
---|
61 |
|
---|
62 | /* Don't display harderror popups. This is done by terminating the
|
---|
63 | process instead of returning XCPT_CONTINUE_SEARCH from the
|
---|
64 | exception handler. */
|
---|
65 |
|
---|
66 | BYTE no_popup;
|
---|
67 |
|
---|
68 | /* Event semaphore for temporarily blocked signal. */
|
---|
69 |
|
---|
70 | HEV signal_sem;
|
---|
71 |
|
---|
72 | /* This flag is set when a temporarily blocked signal is generated. */
|
---|
73 |
|
---|
74 | char sig_flag;
|
---|
75 |
|
---|
76 | /* When exec() is called in a forked process, we pass on signals to
|
---|
77 | the child process until it terminates. This variable holds the
|
---|
78 | process ID of the child process. If the value is zero, there is no
|
---|
79 | such child process. */
|
---|
80 |
|
---|
81 | ULONG fork_exec_pid;
|
---|
82 |
|
---|
83 | /* Critical sections for signal processing are protected by this Mutex
|
---|
84 | semaphore. */
|
---|
85 |
|
---|
86 | static HMTX sig_access;
|
---|
87 |
|
---|
88 |
|
---|
89 | /* 16-bit signal handler. */
|
---|
90 |
|
---|
91 | extern _far16ptr old_sig16_handler;
|
---|
92 | extern void (*sig16_handler)(void);
|
---|
93 |
|
---|
94 | #define ST_TERM 0 /* Terminate process (SIGINT for instance) */
|
---|
95 | #define ST_NEXT 1 /* Pass on to next exception handler */
|
---|
96 | #define ST_IGNORE 2 /* Ignore exception and continue thread */
|
---|
97 |
|
---|
98 |
|
---|
99 | /* This array contains TRUE for all valid signal numbers. */
|
---|
100 |
|
---|
101 | char const signal_valid[NSIG] =
|
---|
102 | {
|
---|
103 | FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, /* 0..9 */
|
---|
104 | TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, /* 10..19 */
|
---|
105 | FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE /* 20..28 */
|
---|
106 | };
|
---|
107 |
|
---|
108 | /* This array contains constant information about the signals: The
|
---|
109 | name of the signal, what to do for SIG_DFL and after calling the
|
---|
110 | signal handler, respectively, and whether to dump core or not. */
|
---|
111 |
|
---|
112 | static struct signal_descr const signal_info[NSIG] =
|
---|
113 | {
|
---|
114 | {"SIG0", ST_TERM, ST_TERM, 0},
|
---|
115 | {"SIGHUP", ST_TERM, ST_IGNORE, 0},
|
---|
116 | {"SIGINT", ST_TERM, ST_IGNORE, 0},
|
---|
117 | {"SIGQUIT", ST_TERM, ST_IGNORE, SIGF_CORE},
|
---|
118 | {"SIGILL", ST_NEXT, ST_NEXT, SIGF_CORE},
|
---|
119 | {"SIGTRAP", ST_NEXT, ST_NEXT, SIGF_CORE},
|
---|
120 | {"SIGABRT", ST_TERM, ST_TERM, SIGF_CORE},
|
---|
121 | {"SIGEMT", ST_TERM, ST_TERM, SIGF_CORE},
|
---|
122 | {"SIGFPE", ST_NEXT, ST_NEXT, SIGF_CORE},
|
---|
123 | {"SIGKILL", ST_TERM, ST_TERM, 0},
|
---|
124 | {"SIGBUS", ST_TERM, ST_TERM, SIGF_CORE},
|
---|
125 | {"SIGSEGV", ST_NEXT, ST_NEXT, SIGF_CORE},
|
---|
126 | {"SIGSYS", ST_TERM, ST_TERM, SIGF_CORE},
|
---|
127 | {"SIGPIPE", ST_TERM, ST_IGNORE, 0},
|
---|
128 | {"SIGALRM", ST_TERM, ST_IGNORE, 0},
|
---|
129 | {"SIGTERM", ST_NEXT, ST_IGNORE, 0},
|
---|
130 | {"SIGUSR1", ST_IGNORE, ST_IGNORE, 0},
|
---|
131 | {"SIGUSR2", ST_IGNORE, ST_IGNORE, 0},
|
---|
132 | {"SIGCLD", ST_IGNORE, ST_IGNORE, 0},
|
---|
133 | {"SIG19", ST_TERM, ST_TERM, 0},
|
---|
134 | {"SIG20", ST_TERM, ST_TERM, 0},
|
---|
135 | {"SIGBREAK", ST_TERM, ST_IGNORE, 0},
|
---|
136 | {"SIG22", ST_TERM, ST_TERM, 0},
|
---|
137 | {"SIG23", ST_TERM, ST_TERM, 0},
|
---|
138 | {"SIG24", ST_TERM, ST_TERM, 0},
|
---|
139 | {"SIG25", ST_TERM, ST_TERM, 0},
|
---|
140 | {"SIG26", ST_TERM, ST_TERM, 0},
|
---|
141 | {"SIG27", ST_TERM, ST_TERM, 0},
|
---|
142 | {"SIGWINCH", ST_IGNORE, ST_IGNORE, 0}
|
---|
143 | };
|
---|
144 |
|
---|
145 |
|
---|
146 | /* Prototypes. */
|
---|
147 |
|
---|
148 | static ULONG kill_emx (int pid, int signo, int tree);
|
---|
149 |
|
---|
150 |
|
---|
151 | /* Display a message when terminating a process due to signal
|
---|
152 | SIGNO. */
|
---|
153 |
|
---|
154 | static void signal_message (int signo)
|
---|
155 | {
|
---|
156 | if (signo == SIGABRT)
|
---|
157 | otext ("\r\nAbnormal program termination\r\n");
|
---|
158 | else
|
---|
159 | oprintf ("\r\nProcess terminated by %s\r\n", signal_info[signo].name);
|
---|
160 | }
|
---|
161 |
|
---|
162 |
|
---|
163 | static void sig_lock (void)
|
---|
164 | {
|
---|
165 | ULONG count;
|
---|
166 |
|
---|
167 | DosEnterMustComplete (&count);
|
---|
168 | request_mutex (sig_access);
|
---|
169 | }
|
---|
170 |
|
---|
171 |
|
---|
172 | static void sig_unlock (void)
|
---|
173 | {
|
---|
174 | ULONG count;
|
---|
175 |
|
---|
176 | DosReleaseMutexSem (sig_access);
|
---|
177 | DosExitMustComplete (&count);
|
---|
178 | }
|
---|
179 |
|
---|
180 |
|
---|
181 | /* Acknowledge the signal to OS/2. */
|
---|
182 |
|
---|
183 | static void acknowledge (int signo)
|
---|
184 | {
|
---|
185 | switch (signo)
|
---|
186 | {
|
---|
187 | case SIGINT:
|
---|
188 | DosAcknowledgeSignalException (XCPT_SIGNAL_INTR);
|
---|
189 | break;
|
---|
190 | case SIGTERM:
|
---|
191 | DosAcknowledgeSignalException (XCPT_SIGNAL_KILLPROC);
|
---|
192 | break;
|
---|
193 | case SIGBREAK:
|
---|
194 | DosAcknowledgeSignalException (XCPT_SIGNAL_BREAK);
|
---|
195 | break;
|
---|
196 | }
|
---|
197 | }
|
---|
198 |
|
---|
199 |
|
---|
200 | static void acknowledge_mult (ULONG set)
|
---|
201 | {
|
---|
202 | if (set & _SIGMASK (SIGINT))
|
---|
203 | acknowledge (SIGINT);
|
---|
204 | if (set & _SIGMASK (SIGBREAK))
|
---|
205 | acknowledge (SIGBREAK);
|
---|
206 | if (set & _SIGMASK (SIGKILL))
|
---|
207 | acknowledge (SIGKILL);
|
---|
208 | }
|
---|
209 |
|
---|
210 |
|
---|
211 | /* Generate a signal. */
|
---|
212 |
|
---|
213 | void generate_signal (thread_data *td, int signo)
|
---|
214 | {
|
---|
215 | struct signal_entry *p;
|
---|
216 |
|
---|
217 | sig_lock ();
|
---|
218 | p = td->sig_table + signo;
|
---|
219 | if (p->handler != SIG_IGN)
|
---|
220 | {
|
---|
221 | td->sig_pending |= _SIGMASK (signo);
|
---|
222 | if ((td->sig_blocked & ~td->sig_prev_blocked & _SIGMASK (signo))
|
---|
223 | && p->handler != SIG_DFL)
|
---|
224 | {
|
---|
225 | /* Wake up __select() */
|
---|
226 |
|
---|
227 | sig_flag = TRUE;
|
---|
228 | DosPostEventSem (signal_sem);
|
---|
229 | }
|
---|
230 | if (td == threads[1] && get_tid () != 1)
|
---|
231 | {
|
---|
232 | /* Interrupt thread 1 and let it examine its set of pending
|
---|
233 | signals. */
|
---|
234 |
|
---|
235 | DosFlagProcess (my_pid, FLGP_PID, PFLG_A, 0);
|
---|
236 | }
|
---|
237 | }
|
---|
238 | sig_unlock ();
|
---|
239 | }
|
---|
240 |
|
---|
241 |
|
---|
242 | static void regen_sigcld (int lock)
|
---|
243 | {
|
---|
244 | if (lock) sig_lock ();
|
---|
245 | if (zombie_count > 0)
|
---|
246 | threads[1]->sig_pending |= _SIGMASK (SIGCLD);
|
---|
247 | if (lock) sig_unlock ();
|
---|
248 | }
|
---|
249 |
|
---|
250 |
|
---|
251 | /* Terminate the process. Optionally do a core dump, taking the
|
---|
252 | registers from the syscall stack frame or the exception context
|
---|
253 | record. Actually, the process is not terminated by this function
|
---|
254 | if CONTEXT_RECORD is non-NULL and no_popup is false. */
|
---|
255 |
|
---|
256 | static void sig_terminate (int signo, syscall_frame *frame,
|
---|
257 | CONTEXTRECORD *context_record)
|
---|
258 | {
|
---|
259 | signal_message (signo);
|
---|
260 |
|
---|
261 | if (signo == SIGKILL
|
---|
262 | || (!nocore_flag && (signal_info[signo].flags & SIGF_CORE)))
|
---|
263 | {
|
---|
264 | if (frame != NULL)
|
---|
265 | {
|
---|
266 | core_regs_i (frame);
|
---|
267 | core_dump ();
|
---|
268 | }
|
---|
269 | else if (context_record != NULL)
|
---|
270 | {
|
---|
271 | core_regs_e (context_record);
|
---|
272 | core_dump ();
|
---|
273 | }
|
---|
274 | }
|
---|
275 | if (context_record == NULL || no_popup)
|
---|
276 | quit (3);
|
---|
277 | }
|
---|
278 |
|
---|
279 |
|
---|
280 | /* Call a signal handler. This function's stack frame contains four
|
---|
281 | magic words, a pointer to the syscall frame, and a pointer to the
|
---|
282 | context record. This allows backtracing over invocations of signal
|
---|
283 | handlers. */
|
---|
284 |
|
---|
285 | static void call_handler2 (ULONG magic1, ULONG magic2, ULONG magic3,
|
---|
286 | ULONG magic4, syscall_frame *frame,
|
---|
287 | CONTEXTRECORD *context_record,
|
---|
288 | void (*handler)(int), int signo)
|
---|
289 | {
|
---|
290 | handler (signo);
|
---|
291 | }
|
---|
292 |
|
---|
293 |
|
---|
294 | /* Call a signal handler. This function puts magic words into the
|
---|
295 | stack, see call_handler2(). */
|
---|
296 |
|
---|
297 | static void call_handler1 (void (*handler)(int), int signo,
|
---|
298 | syscall_frame *frame, CONTEXTRECORD *context_record)
|
---|
299 | {
|
---|
300 | call_handler2 (_SIG_MAGIC1, _SIG_MAGIC2, _SIG_MAGIC3, _SIG_MAGIC4,
|
---|
301 | frame, context_record, handler, signo);
|
---|
302 | }
|
---|
303 |
|
---|
304 |
|
---|
305 |
|
---|
306 | /* Deliver a signal. FRAME points to the system call stack frame,
|
---|
307 | CONTEXT_RECORD points to the exception context record. This
|
---|
308 | function must be called with sig_lock() in effect; sig_unlock() is
|
---|
309 | called by this function.
|
---|
310 |
|
---|
311 | Return ST_TERM, ST_IGNORE, or ST_NEXT. */
|
---|
312 |
|
---|
313 | static int deliver_signal (thread_data *td, int signo,
|
---|
314 | syscall_frame *frame,
|
---|
315 | CONTEXTRECORD *context_record)
|
---|
316 | {
|
---|
317 | struct signal_entry *p;
|
---|
318 | void (*handler)(int signo);
|
---|
319 | ULONG mask, old_blocked;
|
---|
320 |
|
---|
321 | mask = _SIGMASK (signo);
|
---|
322 | p = td->sig_table + signo;
|
---|
323 |
|
---|
324 | td->sig_pending &= ~mask;
|
---|
325 | handler = p->handler;
|
---|
326 |
|
---|
327 | if (handler == SIG_IGN)
|
---|
328 | {
|
---|
329 | /* Ignore the signal. */
|
---|
330 |
|
---|
331 | sig_unlock ();
|
---|
332 | }
|
---|
333 | else if (handler == SIG_DFL)
|
---|
334 | {
|
---|
335 | /* If the default handler SIG_DFL is installed, check the signal
|
---|
336 | information table to learn whether to ignore the signal or to
|
---|
337 | terminate the process. */
|
---|
338 |
|
---|
339 | sig_unlock ();
|
---|
340 | if (signal_info[signo].dfl_action != ST_IGNORE)
|
---|
341 | {
|
---|
342 | sig_terminate (signo, frame, context_record);
|
---|
343 | return signal_info[signo].dfl_action;
|
---|
344 | }
|
---|
345 | }
|
---|
346 | else
|
---|
347 | {
|
---|
348 | /* Call the user-defined signal handler. */
|
---|
349 |
|
---|
350 | if (p->sa_flags & SA_SYSV)
|
---|
351 | {
|
---|
352 | p->handler = SIG_DFL;
|
---|
353 | sig_unlock ();
|
---|
354 | call_handler1 (handler, signo, frame, context_record);
|
---|
355 | }
|
---|
356 | else if (p->sa_flags & SA_ACK)
|
---|
357 | {
|
---|
358 | td->sig_blocked |= mask;
|
---|
359 | sig_unlock ();
|
---|
360 | call_handler1 (handler, signo, frame, context_record);
|
---|
361 | }
|
---|
362 | else
|
---|
363 | {
|
---|
364 | old_blocked = td->sig_blocked;
|
---|
365 | SET_BLOCKED (td, td->sig_blocked | mask | p->sa_mask);
|
---|
366 | sig_unlock ();
|
---|
367 | call_handler1 (handler, signo, frame, context_record);
|
---|
368 | td->sig_blocked = old_blocked;
|
---|
369 | }
|
---|
370 | if (signo == SIGCLD && td == threads[1])
|
---|
371 | regen_sigcld (TRUE);
|
---|
372 |
|
---|
373 | /* Check the signal information table to learn whether to
|
---|
374 | continue the program or to terminate the process. This is
|
---|
375 | only done when called from an exception handler. */
|
---|
376 |
|
---|
377 | if (context_record != NULL && signal_info[signo].fun_action != ST_IGNORE)
|
---|
378 | {
|
---|
379 | sig_terminate (signo, frame, context_record);
|
---|
380 | return signal_info[signo].fun_action;
|
---|
381 | }
|
---|
382 | }
|
---|
383 | return ST_IGNORE;
|
---|
384 | }
|
---|
385 |
|
---|
386 |
|
---|
387 | /* Deliver all pending signals. */
|
---|
388 |
|
---|
389 | int deliver_pending_signals (thread_data *td, syscall_frame *frame,
|
---|
390 | CONTEXTRECORD *context_record)
|
---|
391 | {
|
---|
392 | int signo, action;
|
---|
393 |
|
---|
394 | sig_lock ();
|
---|
395 | while ((td->sig_pending & ~td->sig_blocked) != 0)
|
---|
396 | {
|
---|
397 | for (signo = 1; signo < NSIG; ++signo)
|
---|
398 | if (td->sig_pending & ~td->sig_blocked & _SIGMASK (signo))
|
---|
399 | {
|
---|
400 | action = deliver_signal (td, signo, frame, context_record);
|
---|
401 | if (action != ST_IGNORE)
|
---|
402 | return action;
|
---|
403 | sig_lock ();
|
---|
404 | }
|
---|
405 | }
|
---|
406 | sig_unlock ();
|
---|
407 | return ST_IGNORE;
|
---|
408 | }
|
---|
409 |
|
---|
410 |
|
---|
411 | /* This function is called from the 16-bit signal handler to generate
|
---|
412 | signal SIGNO (if SIGNO is non-zero) and to deliver pending
|
---|
413 | signals. */
|
---|
414 |
|
---|
415 | void raise_from_16 (int signo)
|
---|
416 | {
|
---|
417 | if (fork_exec_pid != 0)
|
---|
418 | kill_emx (fork_exec_pid, signo, FALSE);
|
---|
419 | else
|
---|
420 | {
|
---|
421 | if (signo != 0)
|
---|
422 | generate_signal (threads[1], signo);
|
---|
423 | deliver_pending_signals (threads[1], NULL, NULL);
|
---|
424 | }
|
---|
425 | }
|
---|
426 |
|
---|
427 |
|
---|
428 | /* Unblock temporarily blocked signals, raise pending signals. */
|
---|
429 |
|
---|
430 | void sig_block_end (void)
|
---|
431 | {
|
---|
432 | thread_data *td;
|
---|
433 |
|
---|
434 | td = get_thread ();
|
---|
435 | sig_lock ();
|
---|
436 | td->sig_blocked = td->sig_prev_blocked;
|
---|
437 | td->sig_prev_blocked = 0;
|
---|
438 | sig_unlock ();
|
---|
439 | deliver_pending_signals (td, NULL, NULL);
|
---|
440 | }
|
---|
441 |
|
---|
442 |
|
---|
443 | /* Temporarily block signals (for the duration of a system call).
|
---|
444 | From now on, no signals will be raised. Instead, generated signals
|
---|
445 | will be made pending. */
|
---|
446 |
|
---|
447 | void sig_block_start (void)
|
---|
448 | {
|
---|
449 | thread_data *td;
|
---|
450 |
|
---|
451 | td = get_thread ();
|
---|
452 | sig_lock ();
|
---|
453 | sig_flag = FALSE;
|
---|
454 | reset_event_sem (signal_sem); /* select() waits for this semaphore */
|
---|
455 | td->sig_prev_blocked = td->sig_blocked;
|
---|
456 | SET_BLOCKED (td, ~0);
|
---|
457 | sig_unlock ();
|
---|
458 | }
|
---|
459 |
|
---|
460 |
|
---|
461 | /* Send a signal to another process (or process tree). PID is the
|
---|
462 | process ID of the target process and SIGNO is the signal number.
|
---|
463 | Send signal to the process tree starting at PID if tree is true. */
|
---|
464 |
|
---|
465 | static ULONG kill_emx (int pid, int signo, int tree)
|
---|
466 | {
|
---|
467 | return DosFlagProcess (pid, (tree ? FLGP_SUBTREE : FLGP_PID), PFLG_A, signo);
|
---|
468 | }
|
---|
469 |
|
---|
470 |
|
---|
471 | void do_raise (int signo, syscall_frame *frame)
|
---|
472 | {
|
---|
473 | thread_data *td;
|
---|
474 |
|
---|
475 | td = get_thread ();
|
---|
476 | generate_signal (td, signo);
|
---|
477 | deliver_pending_signals (td, frame, NULL);
|
---|
478 | }
|
---|
479 |
|
---|
480 |
|
---|
481 | /* This function implements the __kill() system call. SIGNO is the
|
---|
482 | signal number (or 0 to check whether the target process is alive).
|
---|
483 | PID is the process ID of the target process. Store the error
|
---|
484 | number (errno) to *ERRNOP. Return 0 on success, -1 on failure. */
|
---|
485 |
|
---|
486 | int do_kill (int signo, int pid, syscall_frame *frame, int *errnop)
|
---|
487 | {
|
---|
488 | ULONG rc;
|
---|
489 | int org_pid;
|
---|
490 |
|
---|
491 | /* Check whether process PID is alive if SIGNO is 0. */
|
---|
492 |
|
---|
493 | if (signo == 0)
|
---|
494 | {
|
---|
495 | if (proc_check (pid))
|
---|
496 | {
|
---|
497 | /* The process is alive. */
|
---|
498 |
|
---|
499 | *errnop = 0;
|
---|
500 | return 0;
|
---|
501 | }
|
---|
502 |
|
---|
503 | /* The process does not exist. */
|
---|
504 |
|
---|
505 | *errnop = ESRCH;
|
---|
506 | return -1;
|
---|
507 | }
|
---|
508 |
|
---|
509 | /* Fail if SIGNO is not a valid signal number. */
|
---|
510 |
|
---|
511 | if (signo < 0 || signo >= NSIG || !signal_valid[signo])
|
---|
512 | {
|
---|
513 | *errnop = EINVAL;
|
---|
514 | return -1;
|
---|
515 | }
|
---|
516 |
|
---|
517 | /* Map `kill(getpid(),signo)' to `raise(signo)' to enable core
|
---|
518 | dumps. Do this only for the main thread as kill() is defined
|
---|
519 | (for emx) to send the signal to the main thread. */
|
---|
520 |
|
---|
521 | if (pid == my_pid && get_tid () == 1)
|
---|
522 | {
|
---|
523 | do_raise (signo, frame);
|
---|
524 | *errnop = 0;
|
---|
525 | return 0;
|
---|
526 | }
|
---|
527 |
|
---|
528 | /* Save the original process or group ID and turn a group ID (PID is
|
---|
529 | negative) into a process ID. */
|
---|
530 |
|
---|
531 | org_pid = pid;
|
---|
532 | if (pid < -1) /* Process group? */
|
---|
533 | pid = -pid; /* Yes: compute PID from group ID */
|
---|
534 |
|
---|
535 | /* SIGKILL is treated specially: Call DosKillProcess. */
|
---|
536 |
|
---|
537 | if (signo == SIGKILL)
|
---|
538 | {
|
---|
539 | /* When sending SIGKILL to a process group, first try to kill
|
---|
540 | the process tree. If this fails, kill only one process.
|
---|
541 | When sending SIGKILL to a single process, kill only that
|
---|
542 | process. */
|
---|
543 |
|
---|
544 | if (org_pid < -1)
|
---|
545 | {
|
---|
546 | rc = DosKillProcess (DKP_PROCESSTREE, pid);
|
---|
547 | if (rc != 0)
|
---|
548 | rc = DosKillProcess (DKP_PROCESS, pid);
|
---|
549 | }
|
---|
550 | else
|
---|
551 | rc = DosKillProcess (DKP_PROCESS, pid);
|
---|
552 |
|
---|
553 | /* If the process has already been killed but has not yet
|
---|
554 | reacted to the signal, the return code will be
|
---|
555 | ERROR_SIGNAL_PENDING. Ignore this error. */
|
---|
556 |
|
---|
557 | if (rc == 0 || rc == ERROR_SIGNAL_PENDING)
|
---|
558 | {
|
---|
559 | *errnop = 0;
|
---|
560 | return 0;
|
---|
561 | }
|
---|
562 | *errnop = set_error (rc);
|
---|
563 | return -1;
|
---|
564 | }
|
---|
565 |
|
---|
566 | /* We can send SIGINT and SIGBREAK to child processes. */
|
---|
567 |
|
---|
568 | if ((signo == SIGINT || signo == SIGBREAK) && pid != my_pid)
|
---|
569 | {
|
---|
570 | rc = DosSendSignalException (pid, ((signo == SIGINT)
|
---|
571 | ? XCPT_SIGNAL_INTR
|
---|
572 | : XCPT_SIGNAL_BREAK));
|
---|
573 | if (rc == 0)
|
---|
574 | {
|
---|
575 | *errnop = 0;
|
---|
576 | return 0;
|
---|
577 | }
|
---|
578 | /* Seems not to be a child process. Use DosFlagProcess. */
|
---|
579 | }
|
---|
580 |
|
---|
581 | /* Send the signal via a 16-bit signal (DosFlagProcess). This works
|
---|
582 | only for emx programs. */
|
---|
583 |
|
---|
584 | if (org_pid < -1)
|
---|
585 | {
|
---|
586 | rc = kill_emx (pid, signo, TRUE);
|
---|
587 | if (rc != 0)
|
---|
588 | rc = kill_emx (pid, signo, FALSE);
|
---|
589 | }
|
---|
590 | else
|
---|
591 | rc = kill_emx (pid, signo, FALSE);
|
---|
592 | if (rc == 0)
|
---|
593 | {
|
---|
594 | *errnop = 0;
|
---|
595 | return 0;
|
---|
596 | }
|
---|
597 | *errnop = set_error (rc);
|
---|
598 | return -1;
|
---|
599 | }
|
---|
600 |
|
---|
601 |
|
---|
602 | /* Set a signal handler or acknowledge a signal. This is the main
|
---|
603 | code for the __signal() system call. SIGNO is the signal number.
|
---|
604 | HANDLER is SIG_DFL, SIG_IGN, SIG_ACK or the address of the signal
|
---|
605 | handler to be used. FRAME points to the syscall stack frame in
|
---|
606 | case we have to dump core. Return the previous (or current for
|
---|
607 | SIG_ACK) signal handler or SIG_ERR on error. */
|
---|
608 |
|
---|
609 | sigfun *do_signal (ULONG signo, sigfun *handler, syscall_frame *frame)
|
---|
610 | {
|
---|
611 | if (handler == SIG_ACK)
|
---|
612 | {
|
---|
613 | thread_data *td;
|
---|
614 | struct signal_entry *p;
|
---|
615 | void (*result)(int signo);
|
---|
616 |
|
---|
617 | /* Acknowledge (unblock) the signal. */
|
---|
618 |
|
---|
619 | if (signo < 1 || signo >= NSIG || !signal_valid[signo])
|
---|
620 | return SIG_ERR;
|
---|
621 |
|
---|
622 | td = get_thread ();
|
---|
623 | p = td->sig_table + signo;
|
---|
624 |
|
---|
625 | sig_lock ();
|
---|
626 | if (!(p->sa_flags & SA_ACK))
|
---|
627 | {
|
---|
628 | sig_unlock ();
|
---|
629 | return SIG_ERR;
|
---|
630 | }
|
---|
631 | acknowledge (signo);
|
---|
632 | td->sig_blocked &= ~_SIGMASK (signo);
|
---|
633 | result = p->handler;
|
---|
634 | sig_unlock ();
|
---|
635 | deliver_pending_signals (td, frame, NULL);
|
---|
636 | return handler;
|
---|
637 | }
|
---|
638 | else
|
---|
639 | {
|
---|
640 | struct sigaction isa, osa;
|
---|
641 |
|
---|
642 | isa.sa_handler = handler;
|
---|
643 | isa.sa_mask = 0;
|
---|
644 | switch (uflags & _UF_SIG_MODEL)
|
---|
645 | {
|
---|
646 | case _UF_SIG_SYSV:
|
---|
647 | isa.sa_flags = SA_SYSV;
|
---|
648 | break;
|
---|
649 | case _UF_SIG_EMX:
|
---|
650 | isa.sa_flags = SA_ACK;
|
---|
651 | break;
|
---|
652 | default:
|
---|
653 | isa.sa_flags = 0;
|
---|
654 | break;
|
---|
655 | }
|
---|
656 | if (do_sigaction (signo, &isa, &osa) != 0)
|
---|
657 | return SIG_ERR;
|
---|
658 | else
|
---|
659 | return osa.sa_handler;
|
---|
660 | }
|
---|
661 | }
|
---|
662 |
|
---|
663 |
|
---|
664 | /* This function implements the __sigaction() system call. */
|
---|
665 |
|
---|
666 | int do_sigaction (int signo, const struct sigaction *iact,
|
---|
667 | struct sigaction *oact)
|
---|
668 | {
|
---|
669 | thread_data *td;
|
---|
670 | struct signal_entry *p;
|
---|
671 | struct sigaction output;
|
---|
672 |
|
---|
673 | /* Check the signal number. */
|
---|
674 |
|
---|
675 | if (signo < 1 || signo >= NSIG || !signal_valid[signo])
|
---|
676 | return EINVAL;
|
---|
677 |
|
---|
678 | /* Fail if the process tries to set the action for SIGKILL.
|
---|
679 |
|
---|
680 | POSIX.1, 3.3.1.3: "The system shall not allow the action for the
|
---|
681 | signals SIGKILL or SIGSTOP to be set to SIG_IGN."
|
---|
682 |
|
---|
683 | POSIX.1, 3.3.1.3: "The system shall not allow a process to catch
|
---|
684 | the signals SIGKILL and SIGSTOP."
|
---|
685 |
|
---|
686 | POSIX.1, 3.3.4.2: "It is unspecified whether an attempt to set
|
---|
687 | the action for a signal that cannot be caught or ignored to
|
---|
688 | SIG_DFL is ignored or causes an error to be returned with errno
|
---|
689 | set to [EINVAL]." */
|
---|
690 |
|
---|
691 | if (signo == SIGKILL && iact != NULL)
|
---|
692 | return EINVAL;
|
---|
693 |
|
---|
694 | /* Get a pointer to the thread data block and a pointer to the
|
---|
695 | signal table entry for SIGNO of the current thread. */
|
---|
696 |
|
---|
697 | td = get_thread ();
|
---|
698 | p = td->sig_table + signo;
|
---|
699 |
|
---|
700 | /* Save the previous action. */
|
---|
701 |
|
---|
702 | sig_lock ();
|
---|
703 | output.sa_handler = p->handler;
|
---|
704 | output.sa_mask = p->sa_mask;
|
---|
705 | output.sa_flags = p->sa_flags;
|
---|
706 |
|
---|
707 | /* Install new action if IACT is not NULL. */
|
---|
708 |
|
---|
709 | if (iact != NULL)
|
---|
710 | {
|
---|
711 | p->handler = iact->sa_handler;
|
---|
712 | p->sa_mask = iact->sa_mask;
|
---|
713 | p->sa_flags = iact->sa_flags;
|
---|
714 |
|
---|
715 | if ((p->handler == SIG_DFL && signal_info[signo].dfl_action != ST_IGNORE)
|
---|
716 | || p->handler == SIG_IGN)
|
---|
717 | {
|
---|
718 | /* POSIX.1, 3.3.1.3: "Setting a signal action to SIG_DFL for
|
---|
719 | a signal that is pending, and whose default action is to
|
---|
720 | ignore the signal (for example, SIGCHLD), shall cause the
|
---|
721 | pending signal to be discarded, whether or not it is
|
---|
722 | blocked."
|
---|
723 |
|
---|
724 | POSIX.1, 3.3.1.3: "Setting a signal action to SIG_IGN for
|
---|
725 | a signal that is pending shall cause the pending signal
|
---|
726 | to be discarded, whether or not it is blocked." */
|
---|
727 |
|
---|
728 | td->sig_pending &= ~_SIGMASK (signo);
|
---|
729 | }
|
---|
730 |
|
---|
731 | if ((p->sa_flags & SA_SYSV) && signo == SIGCLD)
|
---|
732 | regen_sigcld (FALSE);
|
---|
733 | }
|
---|
734 |
|
---|
735 | /* Store previous action to *OACT if OACT is not NULL. Do this
|
---|
736 | after reading *IACT because IACT may point to the same set as
|
---|
737 | OACT. */
|
---|
738 |
|
---|
739 | if (oact != NULL)
|
---|
740 | *oact = output;
|
---|
741 |
|
---|
742 | sig_unlock ();
|
---|
743 | return 0;
|
---|
744 | }
|
---|
745 |
|
---|
746 |
|
---|
747 | int do_sigpending (sigset_t *set)
|
---|
748 | {
|
---|
749 | thread_data *td;
|
---|
750 |
|
---|
751 | td = get_thread ();
|
---|
752 | sig_lock ();
|
---|
753 | *set = td->sig_blocked & td->sig_pending;
|
---|
754 | sig_unlock ();
|
---|
755 | return 0;
|
---|
756 | }
|
---|
757 |
|
---|
758 |
|
---|
759 | int do_sigprocmask (int how, const sigset_t *iset, sigset_t *oset,
|
---|
760 | syscall_frame *frame)
|
---|
761 | {
|
---|
762 | thread_data *td;
|
---|
763 | ULONG temp, output;
|
---|
764 |
|
---|
765 | td = get_thread ();
|
---|
766 | sig_lock ();
|
---|
767 | output = td->sig_blocked;
|
---|
768 | if (iset != NULL)
|
---|
769 | {
|
---|
770 | switch (how)
|
---|
771 | {
|
---|
772 | case SIG_BLOCK:
|
---|
773 | temp = td->sig_blocked | *iset;
|
---|
774 | break;
|
---|
775 | case SIG_UNBLOCK:
|
---|
776 | temp = td->sig_blocked & ~*iset;
|
---|
777 | break;
|
---|
778 | case SIG_SETMASK:
|
---|
779 | temp = *iset;
|
---|
780 | break;
|
---|
781 | default:
|
---|
782 | sig_unlock ();
|
---|
783 | return EINVAL;
|
---|
784 | }
|
---|
785 | acknowledge_mult (td->sig_blocked & ~temp);
|
---|
786 | SET_BLOCKED (td, temp);
|
---|
787 |
|
---|
788 | }
|
---|
789 |
|
---|
790 | /* Set *OSET after reading *ISET, because ISET may point to the same
|
---|
791 | set as OSET. */
|
---|
792 |
|
---|
793 | if (oset != NULL)
|
---|
794 | *oset = output;
|
---|
795 |
|
---|
796 | /* POSIX.1, 3.3.5.2: "If there are any pending unblocked signals
|
---|
797 | after the call to the sigprocmask() function, at least one of
|
---|
798 | those signals shall be delivered before the sigprocmask()
|
---|
799 | function returns." */
|
---|
800 |
|
---|
801 | sig_unlock ();
|
---|
802 | deliver_pending_signals (td, frame, NULL);
|
---|
803 | return 0;
|
---|
804 | }
|
---|
805 |
|
---|
806 |
|
---|
807 | /* This function implements the __pause() system call. Wait for the
|
---|
808 | occurance of a signal. Signals set to SIG_IGN should not make this
|
---|
809 | function return, but they do (for now). */
|
---|
810 |
|
---|
811 | void do_pause (void)
|
---|
812 | {
|
---|
813 | ULONG rc;
|
---|
814 |
|
---|
815 | do
|
---|
816 | {
|
---|
817 | rc = DosSleep ((ULONG)(-1));
|
---|
818 | } while (rc == 0);
|
---|
819 | }
|
---|
820 |
|
---|
821 |
|
---|
822 | int do_sigsuspend (const sigset_t *mask)
|
---|
823 | {
|
---|
824 | ULONG old_blocked;
|
---|
825 | thread_data *td;
|
---|
826 |
|
---|
827 | td = get_thread ();
|
---|
828 | sig_lock ();
|
---|
829 | old_blocked = td->sig_blocked;
|
---|
830 | acknowledge_mult (~*mask & td->sig_blocked);
|
---|
831 | SET_BLOCKED (td, *mask);
|
---|
832 | sig_unlock ();
|
---|
833 | do_pause ();
|
---|
834 | td->sig_blocked = old_blocked;
|
---|
835 | return EINTR;
|
---|
836 | }
|
---|
837 |
|
---|
838 |
|
---|
839 | /* Raise signal SIGNO from the exception handler. */
|
---|
840 |
|
---|
841 | ULONG signal_exception (int signo, CONTEXTRECORD *context)
|
---|
842 | {
|
---|
843 | thread_data *td;
|
---|
844 | struct signal_entry *p;
|
---|
845 | int action;
|
---|
846 |
|
---|
847 | if (fork_exec_pid != 0)
|
---|
848 | {
|
---|
849 | kill_emx (fork_exec_pid, signo, FALSE);
|
---|
850 | acknowledge (signo);
|
---|
851 | return XCPT_CONTINUE_EXECUTION;
|
---|
852 | }
|
---|
853 |
|
---|
854 | /* Get a pointer to the thread data block and a pointer to the
|
---|
855 | signal table entry for SIGNO of the current thread. */
|
---|
856 |
|
---|
857 | td = get_thread ();
|
---|
858 | p = td->sig_table + signo;
|
---|
859 |
|
---|
860 | if (p->handler != SIG_IGN)
|
---|
861 | {
|
---|
862 | generate_signal (td, signo);
|
---|
863 | action = deliver_pending_signals (td, NULL, context);
|
---|
864 | switch (action)
|
---|
865 | {
|
---|
866 | case ST_TERM:
|
---|
867 | quit (3);
|
---|
868 | case ST_NEXT:
|
---|
869 | acknowledge (signo);
|
---|
870 | return XCPT_CONTINUE_SEARCH;
|
---|
871 | default:
|
---|
872 | break;
|
---|
873 | }
|
---|
874 | }
|
---|
875 | acknowledge (signo);
|
---|
876 | return XCPT_CONTINUE_EXECUTION;
|
---|
877 | }
|
---|
878 |
|
---|
879 |
|
---|
880 | static ULONG trap (EXCEPTIONREPORTRECORD *report,
|
---|
881 | CONTEXTRECORD *context,
|
---|
882 | int signo)
|
---|
883 | {
|
---|
884 | struct signal_entry *p;
|
---|
885 | thread_data *td;
|
---|
886 |
|
---|
887 | /* Don't try to do anything if the stack is invalid or in a nested
|
---|
888 | exception. */
|
---|
889 |
|
---|
890 | if (report->fHandlerFlags & (EH_STACK_INVALID|EH_NESTED_CALL))
|
---|
891 | return XCPT_CONTINUE_SEARCH;
|
---|
892 |
|
---|
893 | /* Get a pointer to the thread data block and a pointer to the
|
---|
894 | signal table entry for SIGNO of the current thread. */
|
---|
895 |
|
---|
896 | td = get_thread ();
|
---|
897 | p = get_thread ()->sig_table + signo;
|
---|
898 |
|
---|
899 | if (p->handler != SIG_IGN)
|
---|
900 | {
|
---|
901 | generate_signal (td, signo);
|
---|
902 |
|
---|
903 | /* Deliver the signal even if its blocked. */
|
---|
904 |
|
---|
905 | sig_lock ();
|
---|
906 | deliver_signal (td, signo, NULL, context);
|
---|
907 |
|
---|
908 | /* Deliver any other pending signals. */
|
---|
909 |
|
---|
910 | deliver_pending_signals (td, NULL, context);
|
---|
911 | }
|
---|
912 |
|
---|
913 | /* Invoke the next exception handler. */
|
---|
914 |
|
---|
915 | return XCPT_CONTINUE_SEARCH;
|
---|
916 | }
|
---|
917 |
|
---|
918 |
|
---|
919 | /* Load a heap page from a dumped executable. */
|
---|
920 |
|
---|
921 | static void load_heap (ULONG addr)
|
---|
922 | {
|
---|
923 | ULONG rc, cbread, newpos;
|
---|
924 |
|
---|
925 | addr &= ~0xfff;
|
---|
926 | rc = DosSetFilePtr (exe_fhandle, addr - heap_objs[0].base + heap_off,
|
---|
927 | FILE_BEGIN, &newpos);
|
---|
928 | if (rc == 0)
|
---|
929 | rc = DosRead (exe_fhandle, (void *)addr, 0x1000, &cbread);
|
---|
930 | if (rc != 0)
|
---|
931 | {
|
---|
932 | otext ("\r\nCannot read EXE file\r\n");
|
---|
933 | quit (255);
|
---|
934 | }
|
---|
935 | }
|
---|
936 |
|
---|
937 |
|
---|
938 | /* This is the exception handler. */
|
---|
939 |
|
---|
940 | ULONG exception (EXCEPTIONREPORTRECORD *report,
|
---|
941 | EXCEPTIONREGISTRATIONRECORD *registration,
|
---|
942 | CONTEXTRECORD *context, void *dummy)
|
---|
943 | {
|
---|
944 | ULONG addr;
|
---|
945 |
|
---|
946 | /* Don't trust -- clear the decrement flag. */
|
---|
947 |
|
---|
948 | __asm__ ("cld");
|
---|
949 |
|
---|
950 | /* Don't do anything when unwinding exception handlers. */
|
---|
951 |
|
---|
952 | if (report->fHandlerFlags & (EH_EXIT_UNWIND|EH_UNWINDING))
|
---|
953 | return XCPT_CONTINUE_SEARCH;
|
---|
954 |
|
---|
955 | /* The rest of this function depends on the exception number. */
|
---|
956 |
|
---|
957 | switch (report->ExceptionNum)
|
---|
958 | {
|
---|
959 | case XCPT_GUARD_PAGE_VIOLATION:
|
---|
960 |
|
---|
961 | /* Guard page violation. This exception is used for loading
|
---|
962 | heap pages from a dumped executable. Moreover, this is used
|
---|
963 | by old emx programs for expanding the stack. First, get the
|
---|
964 | address of the page. */
|
---|
965 |
|
---|
966 | addr = report->ExceptionInfo[1];
|
---|
967 |
|
---|
968 | /* Load a page from the executable if the page is in the heap
|
---|
969 | and we have a dumped executable. */
|
---|
970 |
|
---|
971 | if (exe_heap && heap_obj_count >= 1
|
---|
972 | && addr >= heap_objs[0].base && addr < heap_objs[0].brk)
|
---|
973 | {
|
---|
974 | load_heap (addr);
|
---|
975 | return XCPT_CONTINUE_EXECUTION;
|
---|
976 | }
|
---|
977 |
|
---|
978 | /* Looks like a guard page created by the application program.
|
---|
979 | Pass the exception to the next exception handler. */
|
---|
980 |
|
---|
981 | return XCPT_CONTINUE_SEARCH;
|
---|
982 |
|
---|
983 | case XCPT_ACCESS_VIOLATION:
|
---|
984 | case XCPT_DATATYPE_MISALIGNMENT:
|
---|
985 |
|
---|
986 | /* Map access violations to SIGSEGV. */
|
---|
987 |
|
---|
988 | return trap (report, context, SIGSEGV);
|
---|
989 |
|
---|
990 | case XCPT_INTEGER_DIVIDE_BY_ZERO:
|
---|
991 | case XCPT_INTEGER_OVERFLOW:
|
---|
992 | case XCPT_ARRAY_BOUNDS_EXCEEDED:
|
---|
993 | case XCPT_FLOAT_DENORMAL_OPERAND:
|
---|
994 | case XCPT_FLOAT_DIVIDE_BY_ZERO:
|
---|
995 | case XCPT_FLOAT_INEXACT_RESULT:
|
---|
996 | case XCPT_FLOAT_INVALID_OPERATION:
|
---|
997 | case XCPT_FLOAT_OVERFLOW:
|
---|
998 | case XCPT_FLOAT_STACK_CHECK:
|
---|
999 | case XCPT_FLOAT_UNDERFLOW:
|
---|
1000 |
|
---|
1001 | /* Map integer division by zero and floating point exceptions to
|
---|
1002 | SIGFPE. */
|
---|
1003 |
|
---|
1004 | return trap (report, context, SIGFPE);
|
---|
1005 |
|
---|
1006 | case XCPT_ILLEGAL_INSTRUCTION:
|
---|
1007 | case XCPT_INVALID_LOCK_SEQUENCE:
|
---|
1008 | case XCPT_PRIVILEGED_INSTRUCTION:
|
---|
1009 |
|
---|
1010 | /* Map the various exceptions for illegal instructions to
|
---|
1011 | SIGILL. */
|
---|
1012 |
|
---|
1013 | return trap (report, context, SIGILL);
|
---|
1014 |
|
---|
1015 | case XCPT_SIGNAL:
|
---|
1016 |
|
---|
1017 | /* Map signal exceptions to SIGINT, SIGTERM or SIGBREAK. */
|
---|
1018 |
|
---|
1019 | if (report->cParameters >= 1)
|
---|
1020 | switch (report->ExceptionInfo[0])
|
---|
1021 | {
|
---|
1022 | case XCPT_SIGNAL_INTR:
|
---|
1023 | return signal_exception (SIGINT, context);
|
---|
1024 | case XCPT_SIGNAL_KILLPROC:
|
---|
1025 | return signal_exception (SIGTERM, context);
|
---|
1026 | case XCPT_SIGNAL_BREAK:
|
---|
1027 | return signal_exception (SIGBREAK, context);
|
---|
1028 | }
|
---|
1029 | return XCPT_CONTINUE_SEARCH;
|
---|
1030 | }
|
---|
1031 |
|
---|
1032 | /* The exception is not handled by emx. Pass it to the next
|
---|
1033 | exception handler. */
|
---|
1034 |
|
---|
1035 | return XCPT_CONTINUE_SEARCH;
|
---|
1036 | }
|
---|
1037 |
|
---|
1038 |
|
---|
1039 | /* Install the exception handler for the main thread. REGISTRATION
|
---|
1040 | points to the exception registration record, which must be in the
|
---|
1041 | stack (at the `bottom' of the stack). */
|
---|
1042 |
|
---|
1043 | void install_except (EXCEPTIONREGISTRATIONRECORD *registration)
|
---|
1044 | {
|
---|
1045 | ULONG rc;
|
---|
1046 |
|
---|
1047 | registration->prev_structure = NULL;
|
---|
1048 | registration->ExceptionHandler = exception;
|
---|
1049 | rc = DosSetExceptionHandler (registration);
|
---|
1050 | if (rc != 0)
|
---|
1051 | error (rc, "DosSetExceptionHandler");
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 |
|
---|
1055 | /* Install the exception handler for another thread. REGISTRATION
|
---|
1056 | points to the exception registration record, which must be in the
|
---|
1057 | stack (at the `bottom' of the stack). */
|
---|
1058 |
|
---|
1059 | int initthread (EXCEPTIONREGISTRATIONRECORD *registration)
|
---|
1060 | {
|
---|
1061 | ULONG rc;
|
---|
1062 |
|
---|
1063 | registration->prev_structure = NULL;
|
---|
1064 | registration->ExceptionHandler = exception;
|
---|
1065 | rc = DosSetExceptionHandler (registration);
|
---|
1066 | return 0;
|
---|
1067 | }
|
---|
1068 |
|
---|
1069 |
|
---|
1070 | /* We want to receive signals. */
|
---|
1071 |
|
---|
1072 | void receive_signals (void)
|
---|
1073 | {
|
---|
1074 | ULONG times;
|
---|
1075 |
|
---|
1076 | DosSetSignalExceptionFocus (SIG_SETFOCUS, ×);
|
---|
1077 | }
|
---|
1078 |
|
---|
1079 |
|
---|
1080 | void init_exceptions (void)
|
---|
1081 | {
|
---|
1082 | USHORT old_sig16_action; /* Dummy (output) */
|
---|
1083 |
|
---|
1084 | sig_flag = FALSE;
|
---|
1085 | create_event_sem (&signal_sem, DC_SEM_SHARED);
|
---|
1086 | create_mutex_sem (&sig_access);
|
---|
1087 | install_except (exc_reg_ptr);
|
---|
1088 | init_signal16 ();
|
---|
1089 | DosSetSigHandler (_emx_32to16 (&sig16_handler), &old_sig16_handler,
|
---|
1090 | &old_sig16_action, SIGA_ACCEPT, SIG_PFLG_A);
|
---|
1091 | }
|
---|
1092 |
|
---|
1093 |
|
---|
1094 | /* alarm() */
|
---|
1095 |
|
---|
1096 | static BYTE alarm_started;
|
---|
1097 | static BYTE alarm_set;
|
---|
1098 | static ULONG alarm_interval;
|
---|
1099 | static ULONG alarm_time;
|
---|
1100 | static HTIMER alarm_timer;
|
---|
1101 | static HEV alarm_sem_timer;
|
---|
1102 | static TID alarm_tid;
|
---|
1103 |
|
---|
1104 |
|
---|
1105 | /* Exception handler for alarm_thread(). On termination of the
|
---|
1106 | thread, alarm_tid will be set to zero. */
|
---|
1107 |
|
---|
1108 | static ULONG alarm_exception (EXCEPTIONREPORTRECORD *report,
|
---|
1109 | EXCEPTIONREGISTRATIONRECORD *registration,
|
---|
1110 | CONTEXTRECORD *context,
|
---|
1111 | void *dummy)
|
---|
1112 | {
|
---|
1113 | if (report->fHandlerFlags & (EH_EXIT_UNWIND|EH_UNWINDING))
|
---|
1114 | return XCPT_CONTINUE_SEARCH;
|
---|
1115 | switch (report->ExceptionNum)
|
---|
1116 | {
|
---|
1117 | case XCPT_ASYNC_PROCESS_TERMINATE: /* This is the correct one */
|
---|
1118 | case XCPT_PROCESS_TERMINATE: /* OS/2 bug */
|
---|
1119 | alarm_tid = 0;
|
---|
1120 | break;
|
---|
1121 | }
|
---|
1122 | return XCPT_CONTINUE_SEARCH;
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 |
|
---|
1126 | static void alarm_thread (ULONG arg)
|
---|
1127 | {
|
---|
1128 | ULONG rc;
|
---|
1129 | EXCEPTIONREGISTRATIONRECORD registration;
|
---|
1130 |
|
---|
1131 | registration.prev_structure = NULL;
|
---|
1132 | registration.ExceptionHandler = alarm_exception;
|
---|
1133 | DosSetExceptionHandler (®istration);
|
---|
1134 |
|
---|
1135 | for (;;)
|
---|
1136 | {
|
---|
1137 | rc = DosWaitEventSem (alarm_sem_timer, -1);
|
---|
1138 | if (rc == 0)
|
---|
1139 | {
|
---|
1140 | reset_event_sem (alarm_sem_timer);
|
---|
1141 | generate_signal (threads[1], SIGALRM);
|
---|
1142 | }
|
---|
1143 | else if (rc != ERROR_INTERRUPT)
|
---|
1144 | error (rc, "DosWaitEventSem");
|
---|
1145 | }
|
---|
1146 | }
|
---|
1147 |
|
---|
1148 |
|
---|
1149 | void start_alarm (void)
|
---|
1150 | {
|
---|
1151 | ULONG rc;
|
---|
1152 |
|
---|
1153 | if (create_event_sem (&alarm_sem_timer, DC_SEM_SHARED) == 0)
|
---|
1154 | {
|
---|
1155 | rc = DosCreateThread (&alarm_tid, alarm_thread, 0,
|
---|
1156 | CREATE_READY | STACK_COMMITTED, 0x4000);
|
---|
1157 | if (rc != 0)
|
---|
1158 | error (rc, "DosCreateThread");
|
---|
1159 | else
|
---|
1160 | alarm_started = TRUE;
|
---|
1161 | }
|
---|
1162 | }
|
---|
1163 |
|
---|
1164 |
|
---|
1165 | ULONG set_alarm (ULONG value)
|
---|
1166 | {
|
---|
1167 | ULONG rc, rest, result;
|
---|
1168 |
|
---|
1169 | if (!alarm_started)
|
---|
1170 | {
|
---|
1171 | start_alarm ();
|
---|
1172 | if (!alarm_started)
|
---|
1173 | return -1;
|
---|
1174 | }
|
---|
1175 | result = 0;
|
---|
1176 | if (alarm_set)
|
---|
1177 | {
|
---|
1178 | rest = querysysinfo (QSV_TIME_LOW) - alarm_time;
|
---|
1179 | if (alarm_interval >= rest)
|
---|
1180 | result = alarm_interval - rest;
|
---|
1181 | DosStopTimer (alarm_timer);
|
---|
1182 | alarm_set = FALSE;
|
---|
1183 | reset_event_sem (alarm_sem_timer);
|
---|
1184 | }
|
---|
1185 | if (value == 0)
|
---|
1186 | alarm_interval = 0;
|
---|
1187 | else
|
---|
1188 | {
|
---|
1189 | alarm_set = TRUE;
|
---|
1190 | alarm_interval = value;
|
---|
1191 | rc = DosAsyncTimer (1000 * value, (HSEM)alarm_sem_timer, &alarm_timer);
|
---|
1192 | if (rc != 0)
|
---|
1193 | error (rc, "DosAsyncTimer");
|
---|
1194 | alarm_time = querysysinfo (QSV_TIME_LOW);
|
---|
1195 | }
|
---|
1196 | return result;
|
---|
1197 | }
|
---|
1198 |
|
---|
1199 |
|
---|
1200 | void stop_alarm (void)
|
---|
1201 | {
|
---|
1202 | if (!alarm_started)
|
---|
1203 | set_alarm (0);
|
---|
1204 | }
|
---|
1205 |
|
---|
1206 |
|
---|
1207 | /* Called from DLL termination routine. */
|
---|
1208 |
|
---|
1209 | void term_signal (void)
|
---|
1210 | {
|
---|
1211 | if (alarm_tid != 0)
|
---|
1212 | DosKillThread (alarm_tid);
|
---|
1213 | }
|
---|
1214 |
|
---|
1215 |
|
---|
1216 | /* Inherit signal settings from parent process. These are passed in
|
---|
1217 | the `_emx_sig' environment variable, which consists of the PID of
|
---|
1218 | the parent process (to ensure that we get the signal settings of
|
---|
1219 | our parent process), a colon, and a 32-bit number. Bit n is set in
|
---|
1220 | that number if signal n is to be ignored. Each number is passed as
|
---|
1221 | 8 hexadecimal digits. */
|
---|
1222 |
|
---|
1223 | void init2_signal (void)
|
---|
1224 | {
|
---|
1225 | PSZ val;
|
---|
1226 | ULONG ppid, sigset;
|
---|
1227 | int sig;
|
---|
1228 |
|
---|
1229 | if (!(debug_flags & DEBUG_NOINHSIG)
|
---|
1230 | && DosScanEnv ("_emx_sig", &val) == 0 && conv_hex8 (val, &ppid)
|
---|
1231 | && ppid == init_pib_ptr->pib_ulppid && val[8] == ':'
|
---|
1232 | && conv_hex8 (val + 9, &sigset) && val[17] == 0)
|
---|
1233 | {
|
---|
1234 | for (sig = 1; sig < NSIG; ++sig)
|
---|
1235 | if (sigset & (1 << sig))
|
---|
1236 | threads[1]->sig_table[sig].handler = SIG_IGN;
|
---|
1237 | }
|
---|
1238 | }
|
---|