638 lines
17 KiB
C
638 lines
17 KiB
C
/*
|
|
* This file is part of Jehanne.
|
|
*
|
|
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
|
*
|
|
* This is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, version 3 of the License.
|
|
*
|
|
* Jehanne is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* POSIX signals have weird semantics that are hard to emulate in a
|
|
* sane system without giving up on its sanity.
|
|
*
|
|
* We distinguish control signals (SIGKILL, SIGSTOP, SIGTSTP, SIGCONT,
|
|
* SIGABRT, SIGTTIN, SIGTTOU, SIGIOT), SIGCHLD/SIGCLD, timers' wakeups
|
|
* (SIGALRM, SIGPROF, SIGVTALRM) and all the others.
|
|
*
|
|
* TRASMISSION
|
|
* -----------
|
|
* Signal transmission is done though a file server mounted /dev/posix/,
|
|
* provided by sys/posixly. On startup and at each fork, processes
|
|
* create a file named /dev/posix/signal with ORDWR mode and perm
|
|
* equals to their pid. Writing and Reading such file they can
|
|
* control signal dispatching, process groups and so on.
|
|
*
|
|
* When a signal is written to /dev/posix/signal, it is translated for
|
|
* each receiver to a note, and written to the specific note file.
|
|
*
|
|
* If the receiver is a known process, the note is in the format
|
|
* posix: si_signo si_pid si_uid si_value si_code
|
|
* otherwise, if possible, it is translated to an idiomatic note
|
|
* (eg "interrupt" or "alarm").
|
|
*
|
|
* Since notes in Jehanne are not reentrant, signals translated to
|
|
* notes will be enqueued in kernel. A special machinery is implemented
|
|
* for timers, so that they can be used in signal handlers to wakeup
|
|
* the calling process.
|
|
*
|
|
* For all the signals except SIGCONT, the burden of interpreting the
|
|
* signal is on the receiver: the sender just send the signal.
|
|
*
|
|
* The receiver will translate the note back to the appropriate signal
|
|
* number and invoke the trampoline: if trampoline returns 0 no function
|
|
* registered with signal() handled the signal and the library will
|
|
* invoke the default disposition associated to the signal.
|
|
*
|
|
* CONTROL MESSAGES
|
|
* ----------------
|
|
* Control messages are translated by the receiver to equivalent actions:
|
|
* - SIGKILL => write "kill" to the control file of the current process
|
|
* - SIGSTOP, SIGTSTP, SIGTTOU, SIGTTIN
|
|
* => write "stop" to the control file of the current process
|
|
* (when the signal is not handled nor ignored)
|
|
* - SIGABRT/SIGIOT => invoke the registered signal handlers and abort
|
|
* the current process
|
|
* - SIGCONT => invoke the registered signal handlers via the signal
|
|
* trampoline and continue; note that (since a stopped
|
|
* process cannot resume itself) sys/posixly will write
|
|
* "start" to the control file of the receiver.
|
|
*
|
|
* SIGCHLD/SIGCLD
|
|
* --------------
|
|
* Jehanne (like Plan 9) does not support a SIGCHLD equivalent.
|
|
* The user space emulation provided here is quite expensive, so it's
|
|
* disabled by default.
|
|
* Calling libposix_emulate_SIGCHLD() during libposix initialization
|
|
* will enable this machinery for the whole life of the process.
|
|
*
|
|
* Such emulation changes the way POSIX_fork and POSIX_kill works.
|
|
*
|
|
* Each fork() will spawn an additional process that share the memory
|
|
* of the parent, and waits for the child, so that it can send SIGCHLD:
|
|
*
|
|
* parent
|
|
* +- nanny
|
|
* +- child
|
|
*
|
|
* Such "nannies" connect to sys/posixly by creating /dev/posix/nanny
|
|
* so that the filesystem will handle them differently:
|
|
* - any signal for the nanny sent from the parent is delivered to the child
|
|
* - any signal for the nanny sent from the child is delivered to the parent
|
|
* - any signal for the nanny sent from anybody else is delivered to the child
|
|
*
|
|
* Finally fork in child will return 0.
|
|
*
|
|
* When the child exits, the proxy will send a SIGCHLD sigchld to parent
|
|
* and then exit with the same status.
|
|
*
|
|
* As the parent process will see the proxy as its child, it will send
|
|
* any signal to it via kill or sigqueue and will wait it on SIGCHLD.
|
|
*
|
|
* TIMERS
|
|
* ------
|
|
* The functions alarm() and setitimer() generate SIGALRM, SIGPROF
|
|
* or SIGVTALRM for the current process. We want timers to be able to
|
|
* expire in a signal handler (interrupting a blocking syscall) but
|
|
* without giving up the simplicity of notes.
|
|
*
|
|
* (TO BE IMPLEMENTED: )
|
|
* We allocate these timers on libposix initialization. When normal
|
|
* code is running timers will be implemented via Jehanne's alarms,
|
|
* producing a note on expiration that will be mapped to the proper
|
|
* signal for the trampoline by the receiving process.
|
|
*
|
|
* However, when a signal handler is being executed, the timers will
|
|
* be implemented using the awake syscall that will be able
|
|
* to interrupt blocking syscalls in the signal handler.
|
|
* When a signal handler returns, if the timer has not be cleared and
|
|
* did not expired, the wakeup is cleared and replaced with an alarm
|
|
* note.
|
|
*/
|
|
|
|
#include <u.h>
|
|
#include <lib9.h>
|
|
#include <posix.h>
|
|
#include "internal.h"
|
|
|
|
int *__handling_external_signal;
|
|
int *__restart_syscall;
|
|
extern PosixSignalMask *__libposix_signal_mask;
|
|
extern int *__libposix_devsignal;
|
|
|
|
typedef union {
|
|
PosixSignalInfo signal;
|
|
char raw[sizeof(PosixSignalInfo)];
|
|
} SignalBuf;
|
|
typedef union {
|
|
PosixSignalMask signals;
|
|
char raw[sizeof(PosixSignalMask)];
|
|
} SigSetBuf;
|
|
|
|
static SignalConf signal_configurations[PosixNumberOfSignals];
|
|
SignalConf *__libposix_signals = signal_configurations;
|
|
|
|
typedef enum PosixSignalDisposition
|
|
{
|
|
IgnoreWithNoEffect = 0,
|
|
TerminateTheProcess,
|
|
TerminateTheProcessAndCoreDump,
|
|
StopTheProcess,
|
|
ResumeTheProcess
|
|
} PosixSignalDisposition;
|
|
|
|
static PosixError
|
|
note_all_writable_processes(PosixSignalInfo* siginfo)
|
|
{
|
|
// TODO: loop over writable note files and post note.
|
|
return PosixEPERM;
|
|
}
|
|
|
|
static void
|
|
terminated_by_signal(int signo)
|
|
{
|
|
char buf[64];
|
|
|
|
__libposix_free_wait_list();
|
|
|
|
snprint(buf, sizeof(buf), __POSIX_EXIT_SIGNAL_PREFIX "%d", signo);
|
|
exits(buf);
|
|
}
|
|
|
|
void
|
|
__libposix_init_signal_handlers(void)
|
|
{
|
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGCHLD));
|
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGURG));
|
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(PosixSIGWINCH));
|
|
__libposix_signals[PosixSIGCHLD-1].handler = (void*)1;
|
|
__libposix_signals[PosixSIGCHLD-1].sa_restart = 1;
|
|
__libposix_signals[PosixSIGURG-1].handler = (void*)1;
|
|
__libposix_signals[PosixSIGURG-1].sa_restart = 1;
|
|
__libposix_signals[PosixSIGWINCH-1].handler = (void*)1;
|
|
__libposix_signals[PosixSIGWINCH-1].sa_restart = 1;
|
|
}
|
|
|
|
int
|
|
__libposix_send_control_msg(int pid, char *msg)
|
|
{
|
|
int fd, n;
|
|
char buf[256];
|
|
|
|
n = snprint(buf, sizeof(buf), "/proc/%d/ctl", pid);
|
|
if(n < 0)
|
|
goto ErrorBeforeOpen;
|
|
fd = open(buf, OWRITE);
|
|
if(fd < 0)
|
|
goto ErrorBeforeOpen;
|
|
n = snprint(buf, sizeof(buf), "%s", msg);
|
|
if(n < 0)
|
|
goto ErrorAfterOpen;
|
|
if(write(fd, buf, n) < n)
|
|
goto ErrorAfterOpen;
|
|
close(fd);
|
|
return 1;
|
|
|
|
ErrorAfterOpen:
|
|
close(fd);
|
|
ErrorBeforeOpen:
|
|
return 0;
|
|
}
|
|
|
|
/* Executes a PosixSignalDisposition.
|
|
*/
|
|
static int
|
|
execute_disposition(int signo, PosixSignalDisposition action)
|
|
{
|
|
int aborted_by_signal;
|
|
|
|
switch(action){
|
|
case ResumeTheProcess: // the sender resumed us already
|
|
case IgnoreWithNoEffect:
|
|
*__restart_syscall = 1;
|
|
return 1;
|
|
case TerminateTheProcess:
|
|
terminated_by_signal(signo);
|
|
break;
|
|
case TerminateTheProcessAndCoreDump:
|
|
aborted_by_signal = 0;
|
|
assert(aborted_by_signal);
|
|
break;
|
|
case StopTheProcess:
|
|
return __libposix_send_control_msg(*__libposix_pid, "stop");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PosixSignalDisposition
|
|
default_signal_disposition(PosixSignals signal)
|
|
{
|
|
if(signal >= PosixSIGRTMIN && signal <= PosixSIGRTMAX)
|
|
return TerminateTheProcess;
|
|
|
|
switch(signal){
|
|
default:
|
|
sysfatal("libposix: undefined signal %d", signal);
|
|
|
|
case PosixSIGALRM:
|
|
case PosixSIGHUP:
|
|
case PosixSIGINT:
|
|
case PosixSIGKILL:
|
|
case PosixSIGPIPE:
|
|
case PosixSIGTERM:
|
|
case PosixSIGUSR1:
|
|
case PosixSIGUSR2:
|
|
case PosixSIGPOLL:
|
|
case PosixSIGPROF:
|
|
case PosixSIGVTALRM:
|
|
return TerminateTheProcess;
|
|
case PosixSIGSTOP:
|
|
case PosixSIGTSTP:
|
|
case PosixSIGTTIN:
|
|
case PosixSIGTTOU:
|
|
return StopTheProcess;
|
|
case PosixSIGABRT:
|
|
case PosixSIGILL:
|
|
case PosixSIGFPE:
|
|
case PosixSIGBUS:
|
|
case PosixSIGQUIT:
|
|
case PosixSIGSEGV:
|
|
case PosixSIGSYS:
|
|
case PosixSIGTRAP:
|
|
case PosixSIGXCPU:
|
|
case PosixSIGXFSZ:
|
|
return TerminateTheProcessAndCoreDump;
|
|
case PosixSIGCHLD:
|
|
case PosixSIGURG:
|
|
return IgnoreWithNoEffect;
|
|
case PosixSIGCONT:
|
|
return ResumeTheProcess;
|
|
}
|
|
}
|
|
|
|
/* returns 1 if the signal handling has been completed, 0 otherwise */
|
|
int
|
|
__libposix_run_signal_handler(SignalConf *c, PosixSignalInfo *siginfo)
|
|
{
|
|
PosixSigHandler h;
|
|
PosixSigAction a;
|
|
PosixSignalMask m;
|
|
|
|
switch((uintptr_t)c->handler){
|
|
case 0:
|
|
/* SIG_DFL */
|
|
if(c->sa_restart)
|
|
*__restart_syscall = 1;
|
|
break;
|
|
case 1:
|
|
/* SIG_IGN */
|
|
if(siginfo->si_signo == PosixSIGABRT)
|
|
break;
|
|
*__restart_syscall = 1;
|
|
return 1;
|
|
default:
|
|
m = *__libposix_signal_mask;
|
|
*__libposix_signal_mask |= c->mask;
|
|
__libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
|
|
a = c->handler;
|
|
h = c->handler;
|
|
|
|
if(c->sa_resethand)
|
|
c->handler = 0;
|
|
|
|
if(c->sa_siginfo){
|
|
a(siginfo->si_signo, siginfo, nil);
|
|
} else {
|
|
h(siginfo->si_signo);
|
|
}
|
|
if(c->sa_restart)
|
|
*__restart_syscall = 1;
|
|
*__libposix_signal_mask = m;
|
|
__libposix_sighelper_set(PHBlockSignals, *__libposix_signal_mask);
|
|
if(siginfo->si_signo == PosixSIGABRT)
|
|
break;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PosixError
|
|
__libposix_receive_signal(PosixSignalInfo *siginfo)
|
|
{
|
|
SignalConf *c;
|
|
PosixSignalDisposition disposition;
|
|
PosixSignals signo = siginfo->si_signo;
|
|
|
|
if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
|
|
goto ExecuteDefaultDisposition;
|
|
|
|
if(__libposix_signal_blocked(siginfo))
|
|
return 0;
|
|
|
|
c = __libposix_signals + (signo-1);
|
|
if(__libposix_run_signal_handler(c, siginfo))
|
|
return 0;
|
|
|
|
ExecuteDefaultDisposition:
|
|
disposition = default_signal_disposition(signo);
|
|
if(!execute_disposition(signo, disposition))
|
|
return PosixEPERM;
|
|
return 0;
|
|
}
|
|
|
|
long
|
|
__libposix_sighelper_signal(PosixHelperCommand command, int posix_process_pid, PosixSignalInfo *siginfo)
|
|
{
|
|
union {
|
|
PosixHelperRequest request;
|
|
long raw;
|
|
} offset;
|
|
char buf[sizeof(PosixSignalInfo)];
|
|
|
|
offset.request.command = command;
|
|
offset.request.target = posix_process_pid;
|
|
|
|
memcpy(buf, siginfo, sizeof(buf));
|
|
|
|
return pwrite(*__libposix_devsignal, buf, sizeof(buf), offset.raw);
|
|
}
|
|
|
|
long
|
|
__libposix_sighelper_set(PosixHelperCommand command, PosixSignalMask signal_set)
|
|
{
|
|
union {
|
|
PosixHelperRequest request;
|
|
long raw;
|
|
} offset;
|
|
union {
|
|
PosixSignalMask mask;
|
|
char raw[sizeof(PosixSignalMask)];
|
|
} buffer;
|
|
|
|
offset.request.command = command;
|
|
offset.request.target = 0;
|
|
|
|
buffer.mask = signal_set;
|
|
|
|
return pwrite(*__libposix_devsignal, buffer.raw, sizeof(buffer.raw), offset.raw);
|
|
}
|
|
|
|
PosixError
|
|
__libposix_notify_signal_to_process(int pid, PosixSignalInfo *siginfo)
|
|
{
|
|
long e = __libposix_sighelper_signal(PHSignalProcess, pid, siginfo);
|
|
return (PosixError)e;
|
|
}
|
|
|
|
static PosixError
|
|
notify_signal_to_group(int pid, PosixSignalInfo* siginfo)
|
|
{
|
|
long e = __libposix_sighelper_signal(PHSignalGroup, pid, siginfo);
|
|
return (PosixError)e;
|
|
}
|
|
|
|
PosixError
|
|
__libposix_dispatch_signal(int pid, PosixSignalInfo* siginfo)
|
|
{
|
|
PosixError error;
|
|
switch(pid){
|
|
case 0:
|
|
return notify_signal_to_group(*__libposix_pid, siginfo);
|
|
case -1:
|
|
return note_all_writable_processes(siginfo);
|
|
default:
|
|
if(pid < 0)
|
|
return notify_signal_to_group(-pid, siginfo);
|
|
break;
|
|
}
|
|
error = __libposix_notify_signal_to_process(pid, siginfo);
|
|
if(siginfo->si_signo == PosixSIGCONT && !__libposix_is_child(pid))
|
|
__libposix_send_control_msg(pid, "start");
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
translate_jehanne_kernel_note(const char *note, PosixSignalInfo *siginfo)
|
|
{
|
|
char *trap[3];
|
|
char *tmp;
|
|
|
|
assert(siginfo->si_signo == 0);
|
|
|
|
if(strncmp("trap: fault ", note, 12) == 0){
|
|
// trap: fault read addr=0x0 pc=0x400269
|
|
note += 12;
|
|
siginfo->si_signo = PosixSIGTRAP;
|
|
tmp = strdup(note);
|
|
if(getfields(tmp, trap, 3, 1, " ") == 3){
|
|
if(trap[0][0] == 'r')
|
|
siginfo->si_code = PosixSIFaultMapError;
|
|
else
|
|
siginfo->si_code = PosixSIFaultAccessError;
|
|
siginfo->si_value._sival_raw = atoll(trap[1]+5);
|
|
}
|
|
free(tmp);
|
|
} else if(strncmp("write on closed pipe", note, 20) == 0){
|
|
// write on closed pipe pc=0x400269
|
|
siginfo->si_signo = PosixSIGPIPE;
|
|
note += 24;
|
|
siginfo->si_value._sival_raw = atoll(note);
|
|
} else if(strncmp("bad address in syscall", note, 22) == 0){
|
|
// bad address in syscall pc=0x41cc54
|
|
siginfo->si_signo = PosixSIGSEGV;
|
|
note += 26;
|
|
siginfo->si_value._sival_raw = atoll(note);
|
|
}
|
|
// TODO: implement
|
|
|
|
return siginfo->si_signo == 0 ? 0 : 1;
|
|
}
|
|
|
|
static int
|
|
translate_jehanne_note(const char *note, PosixSignalInfo *siginfo)
|
|
{
|
|
if(note == nil || note[0] == 0)
|
|
return 0;
|
|
|
|
if(strncmp("alarm", note, 5) == 0){
|
|
siginfo->si_signo = PosixSIGALRM;
|
|
return 1;
|
|
}
|
|
if(strncmp("sys: ", note, 5) == 0)
|
|
return translate_jehanne_kernel_note(note + 5, siginfo);
|
|
if(strncmp("interrupt", note, 9) == 0){
|
|
siginfo->si_signo = PosixSIGINT;
|
|
return 1;
|
|
}
|
|
if(strncmp("hangup", note, 6) == 0){
|
|
siginfo->si_signo = PosixSIGHUP;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
__libposix_signal_to_note(const PosixSignalInfo *si, char *buf, int size)
|
|
{
|
|
return
|
|
snprint(buf, size, __POSIX_SIGNAL_PREFIX "%d %d %d %#p %d",
|
|
si->si_signo, si->si_pid, si->si_uid,
|
|
si->si_value._sival_raw, si->si_code);
|
|
}
|
|
|
|
/* The format of a note sent by libposix as a signal is
|
|
*
|
|
* "posix: %d %d %d %#p %d", signo, pid, uid, value, code
|
|
*/
|
|
int
|
|
__libposix_note_to_signal(const char *note, PosixSignalInfo *siginfo)
|
|
{
|
|
assert(siginfo->si_signo == 0); /* siginfo must be zeroed */
|
|
if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0)
|
|
return translate_jehanne_note(note, siginfo);
|
|
char *rest = (char*)note + __POSIX_SIGNAL_PREFIX_LEN;
|
|
if(*rest == 0)
|
|
return 0;
|
|
siginfo->si_signo = strtol(rest, &rest, 0);
|
|
if(*rest == 0)
|
|
return 1;
|
|
siginfo->si_pid = strtol(rest, &rest, 0);
|
|
if(*rest == 0)
|
|
return 1;
|
|
siginfo->si_uid = strtoul(rest, &rest, 0);
|
|
if(*rest == 0)
|
|
return 1;
|
|
siginfo->si_value._sival_raw = strtoull(rest, &rest, 0);
|
|
if(*rest == 0)
|
|
return 1;
|
|
siginfo->si_code = strtoul(rest, &rest, 0);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
__libposix_note_handler(void *ureg, char *note)
|
|
{
|
|
PosixSignalInfo siginfo;
|
|
PosixError error;
|
|
|
|
memset(&siginfo, 0, sizeof(PosixSignalInfo));
|
|
|
|
if(!__libposix_note_to_signal(note, &siginfo)
|
|
&& (siginfo.si_signo < 1 || siginfo.si_signo > PosixNumberOfSignals))
|
|
sysfatal("libposix: '%s' does not carry a signal", note);
|
|
*__handling_external_signal = 1;
|
|
error = __libposix_receive_signal(&siginfo);
|
|
*__handling_external_signal = 0;
|
|
werrstr("interrupted");
|
|
return error == 0;
|
|
}
|
|
|
|
int
|
|
__libposix_restart_syscall(void)
|
|
{
|
|
int r;
|
|
|
|
if(*__handling_external_signal)
|
|
return 0;
|
|
|
|
r = *__restart_syscall;
|
|
*__restart_syscall = 0;
|
|
return r;
|
|
}
|
|
|
|
int
|
|
POSIX_sigaction(int *errnop, int signo, const struct sigaction *act, struct sigaction *old)
|
|
{
|
|
SignalConf *c, oconf;
|
|
|
|
if(signo < 1 || signo > PosixNumberOfSignals)
|
|
goto FailWithEINVAL;
|
|
|
|
c = __libposix_signals + (signo-1);
|
|
|
|
if(old)
|
|
memcpy(&oconf, c, sizeof(SignalConf));
|
|
|
|
if(act){
|
|
memset(c, 0, sizeof(SignalConf));
|
|
if(signo == PosixSIGKILL || signo == PosixSIGSTOP)
|
|
goto FailWithEINVAL;
|
|
if(act->sa_flags & PosixSAFSigInfo){
|
|
c->sa_siginfo = 1;
|
|
c->handler = act->sa_sigaction;
|
|
} else {
|
|
c->handler = act->sa_handler;
|
|
}
|
|
c->mask = act->sa_mask & ~((255UL<<56) | SIGNAL_MASK(PosixSIGKILL) | SIGNAL_MASK(PosixSIGSTOP));
|
|
if(act->sa_flags & PosixSAFResetHandler)
|
|
c->sa_resethand = 1;
|
|
else
|
|
c->sa_resethand = 0;
|
|
if(act->sa_flags & PosixSAFRestart)
|
|
c->sa_restart = 1;
|
|
else
|
|
c->sa_restart = 0;
|
|
if(signo == PosixSIGCHLD){
|
|
if(act->sa_flags & PosixSAFNoChildrenWait)
|
|
c->sa_nochildwait = 1;
|
|
else
|
|
c->sa_nochildwait = 0;
|
|
if(c->handler == (void*)1) /* SIGCHLD && SIG_IGN => SA_NOCLDWAIT */
|
|
c->sa_nochildwait = 1;
|
|
}
|
|
if(c->handler == (void*)1){
|
|
/* ignore signal */
|
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(signo));
|
|
} else if(c->handler == (void*)0){
|
|
/* default behavior */
|
|
switch(signo){
|
|
case PosixSIGCHLD:
|
|
case PosixSIGURG:
|
|
case PosixSIGWINCH:
|
|
__libposix_sighelper_set(PHIgnoreSignal, SIGNAL_MASK(signo));
|
|
break;
|
|
default:
|
|
__libposix_sighelper_set(PHEnableSignal, SIGNAL_MASK(signo));
|
|
break;
|
|
}
|
|
} else {
|
|
/* do not ignore signal */
|
|
__libposix_sighelper_set(PHEnableSignal, SIGNAL_MASK(signo));
|
|
}
|
|
}
|
|
|
|
if(old){
|
|
if(oconf.sa_siginfo){
|
|
old->sa_sigaction = oconf.handler;
|
|
old->sa_mask = oconf.mask;
|
|
old->sa_flags = 0;
|
|
if(oconf.sa_siginfo)
|
|
old->sa_flags |= PosixSAFSigInfo;
|
|
if(oconf.sa_resethand)
|
|
old->sa_flags |= PosixSAFResetHandler;
|
|
if(oconf.sa_restart)
|
|
old->sa_flags |= PosixSAFRestart;
|
|
if(oconf.sa_nochildwait)
|
|
old->sa_flags |= PosixSAFNoChildrenWait;
|
|
} else {
|
|
old->sa_handler = oconf.handler;
|
|
old->sa_flags = 0;
|
|
old->sa_mask = 0;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
FailWithEINVAL:
|
|
*errnop = __libposix_get_errno(PosixEINVAL);
|
|
return -1;
|
|
}
|