* Copyright (c) 1980 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
static char sccsid
[] = "@(#)sigretro.c 5.3 (Berkeley) %G%";
* Retrofit new signal interface to old signal primitives.
* to set all held signals to ignored signals in the
* child process after fork(2)
typedef int (*sigtype
)();
sigtype
sigdisp(), sighold(), sigignore();
* The following helps us keep the extended signal semantics together.
* We remember for each signal the address of the function we're
* supposed to call. s_func is SIG_DFL / SIG_IGN if appropriate.
sigtype s_func
; /* What to call */
int s_flag
; /* Signal flags; see below */
#define SHELD 1 /* Signal is being held */
#define SDEFER 2 /* Signal occured while held */
#define SSET 4 /* s_func is believable */
#define SPAUSE 8 /* are pausing, waiting for sig */
jmp_buf _pause
; /* For doing sigpause() */
* Approximate sigsys() system call
* This is almost useless since one only calls sigsys()
* in the child of a vfork(). If you have vfork(), you have new signals
* anyway. The real sigsys() does all the stuff needed to support
* the real sigset() library. We don't bother here, assuming that
* you are either ignoring or defaulting a signal in the child.
* Set the (permanent) disposition of a signal.
* If the signal is subsequently (or even now) held,
* the action you set here can be enabled using sigrelse().
if (sig
< 1 || sig
> NSIG
) {
* Does anyone actually call sigset with SIG_HOLD!?
sigtable
[sig
].s_flag
|= SSET
;
sigtable
[sig
].s_func
= func
;
* If signal has been held, must retain
* the catch so that we can note occurrance
if ((sigtable
[sig
].s_flag
& SHELD
) == 0)
sigtable
[sig
].s_flag
&= ~SDEFER
;
* This CAN be tricky if the signal's disposition is SIG_DFL.
* In that case, we still catch the signal so we can note it
* happened and do something crazy later.
if (sig
< 1 || sig
> NSIG
) {
if (sigtable
[sig
].s_flag
& SHELD
)
* When the default action is required, we have to
* set up to catch the signal to note signal's occurrance.
sigtable
[sig
].s_flag
|= SSET
;
sigtable
[sig
].s_flag
|= SHELD
;
* If the signal occurred while we had it held, cause the signal.
if (sig
< 1 || sig
> NSIG
) {
if ((sigtable
[sig
].s_flag
& SHELD
) == 0)
sigtable
[sig
].s_flag
&= ~SHELD
;
if (sigtable
[sig
].s_flag
& SDEFER
)
* If disposition was the default, then we can unset the
* catch to _sigtramp() and let the system do the work.
if (sigtable
[sig
].s_func
== SIG_DFL
)
return(sigset(sig
, SIG_IGN
));
* Pause, waiting for sig to occur.
* We assume LUSER called us with the signal held.
* When we got the signal, mark the signal as having
* occurred. It will actually cause something when
* the signal is released.
* This is probably useless without job control anyway.
if (sig
< 1 || sig
> NSIG
) {
sigtable
[sig
].s_flag
|= SHELD
|SPAUSE
;
sigtable
[sig
].s_flag
&= ~SPAUSE
;
sigtable
[sig
].s_flag
|= SDEFER
;
* In the child process after fork(2), set the disposition of all held
* signals to SIG_IGN. This is a new procedure not in the real sigset()
* package, provided for retrofitting purposes.
for (i
= 1; i
<= NSIG
; i
++)
if (sigtable
[i
].s_flag
& SHELD
)
* Return the current disposition of a signal
* If we have not set this signal before, we have to
if (sig
< 1 || sig
> NSIG
) {
* If we have no knowledge of this signal,
* ask the system, then save the result for later.
if ((sigtable
[sig
].s_flag
& SSET
) == 0) {
old
= signal(sig
, SIG_IGN
);
sigtable
[sig
].s_func
= old
;
sigtable
[sig
].s_flag
|= SSET
;
* If we have set this signal before, then sigset()
* will have been careful to leave something meaningful
return(sigtable
[sig
].s_func
);
* The following routine gets called for any signal
* that is to be trapped to a user function.
if (sig
< 1 || sig
> NSIG
) {
old
= signal(sig
, SIG_IGN
);
* If signal being paused on, wakeup sigpause()
if (sigtable
[sig
].s_flag
& SPAUSE
)
* If signal being held, mark its table entry
* so we can trigger it when signal released.
if (sigtable
[sig
].s_flag
& SHELD
) {
sigtable
[sig
].s_flag
|= SDEFER
;
* If the signal is being ignored, just return.
* This would make SIGCONT more normal, but of course
* any system with SIGCONT also has the new signal pkg, so...
if (sigtable
[sig
].s_func
== SIG_IGN
)
* If the signal is SIG_DFL, then we probably got here
* by holding the signal, having it happen, then releasing
* the signal. I wonder if a process is allowed to send
if (sigtable
[sig
].s_func
== SIG_DFL
) {
/* Will we get back here? */
* Looks like we should just cause the signal...
* We hold the signal for the duration of the user's
* code with the signal re-enabled. If the signal
* happens again while in user code, we will recursively
* trap here and mark that we had another occurance
* and return to the user's trap code. When we return
* from there, we can cause the signal again.
sigtable
[sig
].s_flag
&= ~SDEFER
;
sigtable
[sig
].s_flag
|= SHELD
;
(*sigtable
[sig
].s_func
)(sig
);
* If the signal re-occurred while in the user's routine,
* just go try it again...
sigtable
[sig
].s_flag
&= ~SHELD
;
if (sigtable
[sig
].s_flag
& SDEFER
)