summaryrefslogtreecommitdiff
path: root/ext/POSIX/POSIX.xs
diff options
context:
space:
mode:
authoranders@broadcom.com <anders@broadcom.com>2001-03-07 06:35:24 -0800
committerJarkko Hietaniemi <jhi@iki.fi>2001-03-09 01:47:16 +0000
commit1dfe7606714789cb685cd524877388fe1e9008b4 (patch)
treeed3519776a3dfc75e7f504e2f5ac10d21a5c1d2b /ext/POSIX/POSIX.xs
parent3a57e0bb0403a797d32021f5aeec1a7881541f1e (diff)
downloadperl-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.xs127
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: