source: vendor/emx/current/src/os2/signal.c

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 31.3 KB
Line 
1/* signal.c -- Manage signals and exceptions
2 Copyright (c) 1994-1998 by Eberhard Mattes
3
4This file is part of emx.
5
6emx is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emx is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emx; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
20
21As special exception, emx.dll can be distributed without source code
22unless it has been changed. If you modify emx.dll, this exception
23no longer applies and you must remove this paragraph from all source
24files 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
49struct 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
60BYTE 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
66BYTE no_popup;
67
68/* Event semaphore for temporarily blocked signal. */
69
70HEV signal_sem;
71
72/* This flag is set when a temporarily blocked signal is generated. */
73
74char 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
81ULONG fork_exec_pid;
82
83/* Critical sections for signal processing are protected by this Mutex
84 semaphore. */
85
86static HMTX sig_access;
87
88
89/* 16-bit signal handler. */
90
91extern _far16ptr old_sig16_handler;
92extern 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
101char 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
112static 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
148static 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
154static 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
163static void sig_lock (void)
164{
165 ULONG count;
166
167 DosEnterMustComplete (&count);
168 request_mutex (sig_access);
169}
170
171
172static 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
183static 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
200static 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
213void 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
242static 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
256static 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
285static 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
297static 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
313static 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
389int 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
415void 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
430void 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
447void 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
465static 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
471void 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
486int 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
609sigfun *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
666int 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
747int 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
759int 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
811void do_pause (void)
812{
813 ULONG rc;
814
815 do
816 {
817 rc = DosSleep ((ULONG)(-1));
818 } while (rc == 0);
819}
820
821
822int 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
841ULONG 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
880static 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
921static 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
940ULONG 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
1043void 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
1059int 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
1072void receive_signals (void)
1073{
1074 ULONG times;
1075
1076 DosSetSignalExceptionFocus (SIG_SETFOCUS, &times);
1077}
1078
1079
1080void 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
1096static BYTE alarm_started;
1097static BYTE alarm_set;
1098static ULONG alarm_interval;
1099static ULONG alarm_time;
1100static HTIMER alarm_timer;
1101static HEV alarm_sem_timer;
1102static 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
1108static 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
1126static 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 (&registration);
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
1149void 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
1165ULONG 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
1200void stop_alarm (void)
1201{
1202 if (!alarm_started)
1203 set_alarm (0);
1204}
1205
1206
1207/* Called from DLL termination routine. */
1208
1209void 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
1223void 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}
Note: See TracBrowser for help on using the repository browser.