diff options
author | anders@broadcom.com <anders@broadcom.com> | 2001-03-07 06:35:24 -0800 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 2001-03-09 01:47:16 +0000 |
commit | 1dfe7606714789cb685cd524877388fe1e9008b4 (patch) | |
tree | ed3519776a3dfc75e7f504e2f5ac10d21a5c1d2b /ext/POSIX/POSIX.xs | |
parent | 3a57e0bb0403a797d32021f5aeec1a7881541f1e (diff) | |
download | perl-1dfe7606714789cb685cd524877388fe1e9008b4.tar.gz |
A modified version of
Subject: [ID 20010307.005] POSIX::sigaction has various problems
Message-Id: <200103072235.OAA25368@dt-sj1-130.sj.broadcom.com>
Currently the sigaction.t test #6 fails (and is fudged to look
like an "ok") in Linux (at least in Debian 2.2 Linux 2.4.2 x86).
This may well be a genuine bug in Linux sigaction() (since at
least Tru64, Solaris, and HP-UX disagree with Linux).
Anyone with POSIX / SUSv2 tome handy? The problem is that
the flags of the oldaction don't match with the flags in
the previously installed disposition.
p4raw-id: //depot/perl@9086
Diffstat (limited to 'ext/POSIX/POSIX.xs')
-rw-r--r-- | ext/POSIX/POSIX.xs | 127 |
1 files changed, 93 insertions, 34 deletions
diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs index 861900a5c7..83498ed1bc 100644 --- a/ext/POSIX/POSIX.xs +++ b/ext/POSIX/POSIX.xs @@ -2777,6 +2777,17 @@ not_there: return 0; } +static void +restore_sigmask(sigset_t *ossetp) +{ + /* Fortunately, restoring the signal mask can't fail, because + * there's nothing we can do about it if it does -- we're not + * supposed to return -1 from sigaction unless the disposition + * was unaffected. + */ + (void)sigprocmask(SIG_SETMASK, ossetp, (sigset_t *)0); +} + MODULE = SigSet PACKAGE = POSIX::SigSet PREFIX = sig POSIX::SigSet @@ -3374,9 +3385,9 @@ tanh(x) NV x SysRet -sigaction(sig, action, oldaction = 0) +sigaction(sig, optaction, oldaction = 0) int sig - POSIX::SigAction action + SV * optaction POSIX::SigAction oldaction CODE: #ifdef WIN32 @@ -3386,9 +3397,12 @@ sigaction(sig, action, oldaction = 0) # interface look beautiful, which is hard. { + POSIX__SigAction action; GV *siggv = gv_fetchpv("SIG", TRUE, SVt_PVHV); struct sigaction act; struct sigaction oact; + sigset_t sset; + sigset_t osset; POSIX__SigSet sigset; SV** svp; SV** sigsvp = hv_fetch(GvHVn(siggv), @@ -3397,11 +3411,61 @@ sigaction(sig, action, oldaction = 0) TRUE); STRLEN n_a; - /* Remember old handler name if desired. */ + /* Check optaction and set action */ + if(SvTRUE(optaction)) { + if(sv_isa(optaction, "POSIX::SigAction")) + action = (HV*)SvRV(optaction); + else + croak("action is not of type POSIX::SigAction"); + } + else { + action=0; + } + + /* sigaction() is supposed to look atomic. In particular, any + * signal handler invoked during a sigaction() call should + * see either the old or the new disposition, and not something + * in between. We use sigprocmask() to make it so. + */ + sigfillset(&sset); + RETVAL=sigprocmask(SIG_BLOCK, &sset, &osset); + if(RETVAL == -1) + XSRETURN(1); + ENTER; + /* Restore signal mask no matter how we exit this block. */ + SAVEDESTRUCTOR(restore_sigmask, &osset); + + RETVAL=-1; /* In case both oldaction and action are 0. */ + + /* Remember old disposition if desired. */ if (oldaction) { - char *hand = SvPVx(*sigsvp, n_a); svp = hv_fetch(oldaction, "HANDLER", 7, TRUE); - sv_setpv(*svp, *hand ? hand : "DEFAULT"); + if(!svp) + croak("Can't supply an oldaction without a HANDLER"); + if(SvTRUE(*sigsvp)) { /* TBD: what if "0"? */ + sv_setsv(*svp, *sigsvp); + } + else { + sv_setpv(*svp, "DEFAULT"); + } + RETVAL = sigaction(sig, (struct sigaction *)0, & oact); + if(RETVAL == -1) + XSRETURN(1); + /* Get back the mask. */ + svp = hv_fetch(oldaction, "MASK", 4, TRUE); + if (sv_isa(*svp, "POSIX::SigSet")) { + IV tmp = SvIV((SV*)SvRV(*svp)); + sigset = INT2PTR(sigset_t*, tmp); + } + else { + New(0, sigset, 1, sigset_t); + sv_setptrobj(*svp, sigset, "POSIX::SigSet"); + } + *sigset = oact.sa_mask; + + /* Get back the flags. */ + svp = hv_fetch(oldaction, "FLAGS", 5, TRUE); + sv_setiv(*svp, oact.sa_flags); } if (action) { @@ -3410,15 +3474,29 @@ sigaction(sig, action, oldaction = 0) svp = hv_fetch(action, "HANDLER", 7, FALSE); if (!svp) croak("Can't supply an action without a HANDLER"); - sv_setpv(*sigsvp, SvPV(*svp, n_a)); + sv_setsv(*sigsvp, *svp); mg_set(*sigsvp); /* handles DEFAULT and IGNORE */ - act.sa_handler = PL_sighandlerp; + if(SvPOK(*svp)) { + char *s=SvPVX(*svp); + if(strEQ(s,"IGNORE")) { + act.sa_handler = SIG_IGN; + } + else if(strEQ(s,"DEFAULT")) { + act.sa_handler = SIG_DFL; + } + else { + act.sa_handler = PL_sighandlerp; + } + } + else { + act.sa_handler = PL_sighandlerp; + } /* Set up any desired mask. */ svp = hv_fetch(action, "MASK", 4, FALSE); if (svp && sv_isa(*svp, "POSIX::SigSet")) { IV tmp = SvIV((SV*)SvRV(*svp)); - sigset = INT2PTR(sigset_t*, tmp); + sigset = INT2PTR(sigset_t*, tmp); act.sa_mask = *sigset; } else @@ -3427,35 +3505,16 @@ sigaction(sig, action, oldaction = 0) /* Set up any desired flags. */ svp = hv_fetch(action, "FLAGS", 5, FALSE); act.sa_flags = svp ? SvIV(*svp) : 0; - } - /* Now work around sigaction oddities */ - if (action && oldaction) - RETVAL = sigaction(sig, & act, & oact); - else if (action) + /* Don't worry about cleaning up *sigsvp if this fails, + * because that means we tried to disposition a + * nonblockable signal, in which case *sigsvp is + * essentially meaningless anyway. + */ RETVAL = sigaction(sig, & act, (struct sigaction *)0); - else if (oldaction) - RETVAL = sigaction(sig, (struct sigaction *)0, & oact); - else - RETVAL = -1; - - if (oldaction) { - /* Get back the mask. */ - svp = hv_fetch(oldaction, "MASK", 4, TRUE); - if (sv_isa(*svp, "POSIX::SigSet")) { - IV tmp = SvIV((SV*)SvRV(*svp)); - sigset = INT2PTR(sigset_t*, tmp); - } - else { - New(0, sigset, 1, sigset_t); - sv_setptrobj(*svp, sigset, "POSIX::SigSet"); - } - *sigset = oact.sa_mask; - - /* Get back the flags. */ - svp = hv_fetch(oldaction, "FLAGS", 5, TRUE); - sv_setiv(*svp, oact.sa_flags); } + + LEAVE; } #endif OUTPUT: |