[BACK]Return to sys_sig.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/sys_sig.c between version 1.1 and 1.1.2.9

version 1.1, 2006/10/21 14:26:41 version 1.1.2.9, 2007/01/30 13:51:41
Line 0 
Line 1 
   /*      $NetBSD$        */
   
   /*-
    * Copyright (c) 2006 The NetBSD Foundation, Inc.
    * All rights reserved.
    *
    * This code is derived from software contributed to The NetBSD Foundation
    * by Andrew Doran.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the
    *    documentation and/or other materials provided with the distribution.
    * 3. All advertising materials mentioning features or use of this software
    *    must display the following acknowledgement:
    *      This product includes software developed by the NetBSD
    *      Foundation, Inc. and its contributors.
    * 4. Neither the name of The NetBSD Foundation nor the names of its
    *    contributors may be used to endorse or promote products derived
    *    from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
    * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
    * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
    * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    * POSSIBILITY OF SUCH DAMAGE.
    */
   
   /*
    * Copyright (c) 1982, 1986, 1989, 1991, 1993
    *      The Regents of the University of California.  All rights reserved.
    * (c) UNIX System Laboratories, Inc.
    * All or some portions of this file are derived from material licensed
    * to the University of California by American Telephone and Telegraph
    * Co. or Unix System Laboratories, Inc. and are reproduced herein with
    * the permission of UNIX System Laboratories, Inc.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the
    *    documentation and/or other materials provided with the distribution.
    * 3. Neither the name of the University nor the names of its contributors
    *    may be used to endorse or promote products derived from this software
    *    without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    * SUCH DAMAGE.
    *
    *      @(#)kern_sig.c  8.14 (Berkeley) 5/14/95
    */
   
   #include <sys/cdefs.h>
   __KERNEL_RCSID(0, "$NetBSD$");
   
   #include "opt_ptrace.h"
   #include "opt_compat_netbsd.h"
   #include "opt_compat_netbsd32.h"
   
   #include <sys/param.h>
   #include <sys/kernel.h>
   #include <sys/malloc.h>
   #include <sys/signalvar.h>
   #include <sys/proc.h>
   #include <sys/pool.h>
   #include <sys/syscallargs.h>
   #include <sys/kauth.h>
   #include <sys/wait.h>
   
   #ifdef COMPAT_16
   /* ARGSUSED */
   int
   compat_16_sys___sigaction14(struct lwp *l, void *v, register_t *retval)
   {
           struct compat_16_sys___sigaction14_args /* {
                   syscallarg(int)                         signum;
                   syscallarg(const struct sigaction *)    nsa;
                   syscallarg(struct sigaction *)          osa;
           } */ *uap = v;
           struct sigaction        nsa, osa;
           int                     error;
   
           if (SCARG(uap, nsa)) {
                   error = copyin(SCARG(uap, nsa), &nsa, sizeof(nsa));
                   if (error)
                           return (error);
           }
           error = sigaction1(l, SCARG(uap, signum),
               SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
               NULL, 0);
           if (error)
                   return (error);
           if (SCARG(uap, osa)) {
                   error = copyout(&osa, SCARG(uap, osa), sizeof(osa));
                   if (error)
                           return (error);
           }
           return (0);
   }
   #endif
   
   /* ARGSUSED */
   int
   sys___sigaction_sigtramp(struct lwp *l, void *v, register_t *retval)
   {
           struct sys___sigaction_sigtramp_args /* {
                   syscallarg(int)                         signum;
                   syscallarg(const struct sigaction *)    nsa;
                   syscallarg(struct sigaction *)          osa;
                   syscallarg(void *)                      tramp;
                   syscallarg(int)                         vers;
           } */ *uap = v;
           struct sigaction nsa, osa;
           int error;
   
           if (SCARG(uap, nsa)) {
                   error = copyin(SCARG(uap, nsa), &nsa, sizeof(nsa));
                   if (error)
                           return (error);
           }
           error = sigaction1(l, SCARG(uap, signum),
               SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
               SCARG(uap, tramp), SCARG(uap, vers));
           if (error)
                   return (error);
           if (SCARG(uap, osa)) {
                   error = copyout(&osa, SCARG(uap, osa), sizeof(osa));
                   if (error)
                           return (error);
           }
           return (0);
   }
   
   /*
    * Manipulate signal mask.  Note that we receive new mask, not pointer, and
    * return old mask as return value; the library stub does the rest.
    */
   int
   sys___sigprocmask14(struct lwp *l, void *v, register_t *retval)
   {
           struct sys___sigprocmask14_args /* {
                   syscallarg(int)                 how;
                   syscallarg(const sigset_t *)    set;
                   syscallarg(sigset_t *)          oset;
           } */ *uap = v;
           struct proc     *p = l->l_proc;
           sigset_t        nss, oss;
           int             error;
   
           if (SCARG(uap, set)) {
                   error = copyin(SCARG(uap, set), &nss, sizeof(nss));
                   if (error)
                           return (error);
           }
           mutex_enter(&p->p_smutex);
           error = sigprocmask1(l, SCARG(uap, how),
               SCARG(uap, set) ? &nss : 0, SCARG(uap, oset) ? &oss : 0);
           mutex_exit(&p->p_smutex);
           if (error)
                   return (error);
           if (SCARG(uap, oset)) {
                   error = copyout(&oss, SCARG(uap, oset), sizeof(oss));
                   if (error)
                           return (error);
           }
           return (0);
   }
   
   /* ARGSUSED */
   int
   sys___sigpending14(struct lwp *l, void *v, register_t *retval)
   {
           struct sys___sigpending14_args /* {
                   syscallarg(sigset_t *)  set;
           } */ *uap = v;
           sigset_t ss;
   
           sigpending1(l, &ss);
           return (copyout(&ss, SCARG(uap, set), sizeof(ss)));
   }
   
   /*
    * Suspend process until signal, providing mask to be set in the meantime.
    * Note nonstandard calling convention: libc stub passes mask, not pointer,
    * to save a copyin.
    */
   /* ARGSUSED */
   int
   sys___sigsuspend14(struct lwp *l, void *v, register_t *retval)
   {
           struct sys___sigsuspend14_args /* {
                   syscallarg(const sigset_t *)    set;
           } */ *uap = v;
           sigset_t        ss;
           int             error;
   
           if (SCARG(uap, set)) {
                   error = copyin(SCARG(uap, set), &ss, sizeof(ss));
                   if (error)
                           return (error);
           }
   
           return (sigsuspend1(l, SCARG(uap, set) ? &ss : 0));
   }
   
   /* ARGSUSED */
   int
   sys___sigaltstack14(struct lwp *l, void *v, register_t *retval)
   {
           struct sys___sigaltstack14_args /* {
                   syscallarg(const struct sigaltstack *)  nss;
                   syscallarg(struct sigaltstack *)        oss;
           } */ *uap = v;
           struct sigaltstack      nss, oss;
           int                     error;
   
           if (SCARG(uap, nss)) {
                   error = copyin(SCARG(uap, nss), &nss, sizeof(nss));
                   if (error)
                           return (error);
           }
           error = sigaltstack1(l,
               SCARG(uap, nss) ? &nss : 0, SCARG(uap, oss) ? &oss : 0);
           if (error)
                   return (error);
           if (SCARG(uap, oss)) {
                   error = copyout(&oss, SCARG(uap, oss), sizeof(oss));
                   if (error)
                           return (error);
           }
           return (0);
   }
   
   /* ARGSUSED */
   int
   sys_kill(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_kill_args /* {
                   syscallarg(int) pid;
                   syscallarg(int) signum;
           } */ *uap = v;
           struct proc     *p;
           ksiginfo_t      ksi;
           int signum = SCARG(uap, signum);
           int error;
   
           if ((u_int)signum >= NSIG)
                   return (EINVAL);
           KSI_INIT(&ksi);
           ksi.ksi_signo = signum;
           ksi.ksi_code = SI_USER;
           ksi.ksi_pid = l->l_proc->p_pid;
           ksi.ksi_uid = kauth_cred_geteuid(l->l_cred);
           if (SCARG(uap, pid) > 0) {
                   /* kill single process */
                   if ((p = p_find(SCARG(uap, pid), PFIND_UNLOCK_FAIL)) == NULL)
                           return (ESRCH);
                   mutex_enter(&p->p_mutex);
                   error = kauth_authorize_process(l->l_cred,
                       KAUTH_PROCESS_CANSIGNAL, p, (void *)(uintptr_t)signum,
                       NULL, NULL);
                   if (!error && signum) {
                           mutex_enter(&proclist_mutex);
                           mutex_enter(&p->p_smutex);
                           kpsignal2(p, &ksi);
                           mutex_exit(&p->p_smutex);
                           mutex_exit(&proclist_mutex);
                   }
                   mutex_exit(&p->p_mutex);
                   rw_exit(&proclist_lock);
                   return (error);
           }
           switch (SCARG(uap, pid)) {
           case -1:                /* broadcast signal */
                   return (killpg1(l, &ksi, 0, 1));
           case 0:                 /* signal own process group */
                   return (killpg1(l, &ksi, 0, 0));
           default:                /* negative explicit process group */
                   return (killpg1(l, &ksi, -SCARG(uap, pid), 0));
           }
           /* NOTREACHED */
   }
   
   /*
    * Nonexistent system call-- signal process (may want to handle it).  Flag
    * error in case process won't see signal immediately (blocked or ignored).
    *
    * XXX This should not be here.
    */
   #ifndef PTRACE
   __weak_alias(sys_ptrace, sys_nosys);
   #endif
   
   /* ARGSUSED */
   int
   sys_nosys(struct lwp *l, void *v, register_t *retval)
   {
   
           mutex_enter(&proclist_mutex);
           psignal(l->l_proc, SIGSYS);
           mutex_exit(&proclist_mutex);
           return (ENOSYS);
   }
   
   /* ARGSUSED */
   int
   sys_getcontext(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_getcontext_args /* {
                   syscallarg(struct __ucontext *) ucp;
           } */ *uap = v;
           struct proc *p = l->l_proc;
           ucontext_t uc;
   
           mutex_enter(&p->p_smutex);
           getucontext(l, &uc);
           mutex_exit(&p->p_smutex);
   
           return (copyout(&uc, SCARG(uap, ucp), sizeof (*SCARG(uap, ucp))));
   }
   
   /* ARGSUSED */
   int
   sys_setcontext(struct lwp *l, void *v, register_t *retval)
   {
           struct sys_setcontext_args /* {
                   syscallarg(const ucontext_t *) ucp;
           } */ *uap = v;
           struct proc *p = l->l_proc;
           ucontext_t uc;
           int error;
   
           error = copyin(SCARG(uap, ucp), &uc, sizeof (uc));
           if (error)
                   return (error);
           if (!(uc.uc_flags & _UC_CPU))
                   return (EINVAL);
           mutex_enter(&p->p_smutex);
           error = setucontext(l, &uc);
           mutex_exit(&p->p_smutex);
           if (error)
                   return (error);
   
           return (EJUSTRETURN);
   }
   
   /*
    * sigtimedwait(2) system call, used also for implementation
    * of sigwaitinfo() and sigwait().
    *
    * This only handles single LWP in signal wait. libpthread provides
    * it's own sigtimedwait() wrapper to DTRT WRT individual threads.
    */
   int
   sys___sigtimedwait(struct lwp *l, void *v, register_t *retval)
   {
   
           return __sigtimedwait1(l, v, retval, copyout, copyin, copyout);
   }
   
   int
   sigaction1(struct lwp *l, int signum, const struct sigaction *nsa,
           struct sigaction *osa, const void *tramp, int vers)
   {
           struct proc *p;
           struct sigacts *ps;
           sigset_t tset;
           int prop, error;
   
           if (signum <= 0 || signum >= NSIG)
                   return (EINVAL);
   
           p = l->l_proc;
           error = 0;
   
           /*
            * Trampoline ABI version 0 is reserved for the legacy kernel
            * provided on-stack trampoline.  Conversely, if we are using a
            * non-0 ABI version, we must have a trampoline.  Only validate the
            * vers if a new sigaction was supplied. Emulations use legacy
            * kernel trampolines with version 0, alternatively check for that
            * too.
            */
           if ((vers != 0 && tramp == NULL) ||
   #ifdef SIGTRAMP_VALID
               (nsa != NULL &&
               ((vers == 0) ?
                   (p->p_emul->e_sigcode == NULL) :
                   !SIGTRAMP_VALID(vers))) ||
   #endif
               (vers == 0 && tramp != NULL)) {
                   return (EINVAL);
           }
   
           mutex_enter(&p->p_mutex);       /* p_flag */
           mutex_enter(&p->p_smutex);
   
           ps = p->p_sigacts;
           if (osa)
                   *osa = SIGACTION_PS(ps, signum);
           if (!nsa)
                   goto out;
   
           prop = sigprop[signum];
           if ((nsa->sa_flags & ~SA_ALLBITS) || (prop & SA_CANTMASK)) {
                   error = EINVAL;
                   goto out;
           }
   
           SIGACTION_PS(ps, signum) = *nsa;
           ps->sa_sigdesc[signum].sd_tramp = tramp;
           ps->sa_sigdesc[signum].sd_vers = vers;
           sigminusset(&sigcantmask, &SIGACTION_PS(ps, signum).sa_mask);
   
           if ((prop & SA_NORESET) != 0)
                   SIGACTION_PS(ps, signum).sa_flags &= ~SA_RESETHAND;
   
           if (signum == SIGCHLD) {
                   if (nsa->sa_flags & SA_NOCLDSTOP)
                           p->p_sflag |= PS_NOCLDSTOP;
                   else
                           p->p_sflag &= ~PS_NOCLDSTOP;
                   if (nsa->sa_flags & SA_NOCLDWAIT) {
                           /*
                            * Paranoia: since SA_NOCLDWAIT is implemented by
                            * reparenting the dying child to PID 1 (and trust
                            * it to reap the zombie), PID 1 itself is forbidden
                            * to set SA_NOCLDWAIT.
                            */
                           if (p->p_pid == 1)
                                   p->p_flag &= ~P_NOCLDWAIT;
                           else
                                   p->p_flag |= P_NOCLDWAIT;
                   } else
                           p->p_flag &= ~P_NOCLDWAIT;
   
                   if (nsa->sa_handler == SIG_IGN) {
                           /*
                            * Paranoia: same as above.
                            */
                           if (p->p_pid == 1)
                                   p->p_flag &= ~P_CLDSIGIGN;
                           else
                                   p->p_flag |= P_CLDSIGIGN;
                   } else
                           p->p_flag &= ~P_CLDSIGIGN;
           }
   
           if ((nsa->sa_flags & SA_NODEFER) == 0)
                   sigaddset(&SIGACTION_PS(ps, signum).sa_mask, signum);
           else
                   sigdelset(&SIGACTION_PS(ps, signum).sa_mask, signum);
   
           /*
            * Set bit in p_sigctx.ps_sigignore for signals that are set to
            * SIG_IGN, and for signals set to SIG_DFL where the default is to
            * ignore. However, don't put SIGCONT in p_sigctx.ps_sigignore, as
            * we have to restart the process.
            */
           if (nsa->sa_handler == SIG_IGN ||
               (nsa->sa_handler == SIG_DFL && (prop & SA_IGNORE) != 0)) {
                   /* Never to be seen again. */
                   sigemptyset(&tset);
                   sigaddset(&tset, signum);
                   sigclearall(p, &tset);
                   if (signum != SIGCONT) {
                           /* Easier in psignal */
                           sigaddset(&p->p_sigctx.ps_sigignore, signum);
                   }
                   sigdelset(&p->p_sigctx.ps_sigcatch, signum);
           } else {
                   sigdelset(&p->p_sigctx.ps_sigignore, signum);
                   if (nsa->sa_handler == SIG_DFL)
                           sigdelset(&p->p_sigctx.ps_sigcatch, signum);
                   else
                           sigaddset(&p->p_sigctx.ps_sigcatch, signum);
           }
   
           /*
            * Previously held signals may now have become visible.  Ensure that
            * we check for them before returning to userspace.
            */
           lwp_lock(l);
           l->l_flag |= L_PENDSIG;
           lwp_unlock(l);
    out:
           mutex_exit(&p->p_smutex);
           mutex_exit(&p->p_mutex);
   
           return (error);
   }
   
   int
   sigprocmask1(struct lwp *l, int how, const sigset_t *nss, sigset_t *oss)
   {
           int more;
   
           LOCK_ASSERT(mutex_owned(&l->l_proc->p_smutex));
   
           if (oss)
                   *oss = l->l_sigmask;
           if (nss) {
                   switch (how) {
                   case SIG_BLOCK:
                           sigplusset(nss, &l->l_sigmask);
                           more = 0;
                           break;
                   case SIG_UNBLOCK:
                           sigminusset(nss, &l->l_sigmask);
                           more = 1;
                           break;
                   case SIG_SETMASK:
                           l->l_sigmask = *nss;
                           more = 1;
                           break;
                   default:
                           return (EINVAL);
                   }
                   sigminusset(&sigcantmask, &l->l_sigmask);
                   if (more) {
                           /*
                            * Check for pending signals on return to user.
                            */
                           lwp_lock(l);
                           l->l_flag |= L_PENDSIG;
                           lwp_unlock(l);
                   }
           }
   
           return (0);
   }
   
   void
   sigpending1(struct lwp *l, sigset_t *ss)
   {
           struct proc *p = l->l_proc;
   
           mutex_enter(&p->p_smutex);
           *ss = l->l_sigpend.sp_set;
           sigplusset(&p->p_sigpend.sp_set, ss);
           sigminusset(&l->l_sigmask, ss);
           mutex_exit(&p->p_smutex);
   }
   
   int
   sigsuspend1(struct lwp *l, const sigset_t *ss)
   {
           struct proc *p;
   
           p = l->l_proc;
   
           if (ss) {
                   /*
                    * When returning from sigpause, we want
                    * the old mask to be restored after the
                    * signal handler has finished.  Thus, we
                    * save it here and mark the sigctx structure
                    * to indicate this.
                    */
                   mutex_enter(&p->p_smutex);
                   l->l_sigrestore = 1;
                   l->l_sigoldmask = l->l_sigmask;
                   l->l_sigmask = *ss;
                   sigminusset(&sigcantmask, &l->l_sigmask);
   
                   /* Check for pending signals when sleeping. */
                   lwp_lock(l);
                   l->l_flag |= L_PENDSIG;
                   lwp_unlock(l);
                   mutex_exit(&p->p_smutex);
           }
   
           while (kpause("pause", TRUE, 0, NULL) == 0)
                   ;
   
           /* always return EINTR rather than ERESTART... */
           return (EINTR);
   }
   
   int
   sigaltstack1(struct lwp *l, const struct sigaltstack *nss,
                struct sigaltstack *oss)
   {
           struct proc *p = l->l_proc;
           int error = 0;
   
           mutex_enter(&p->p_smutex);
   
           if (oss)
                   *oss = l->l_sigstk;
   
           if (nss) {
                   if (nss->ss_flags & ~SS_ALLBITS)
                           error = EINVAL;
                   else if (nss->ss_flags & SS_DISABLE) {
                           if (l->l_sigstk.ss_flags & SS_ONSTACK)
                                   error = EINVAL;
                   } else if (nss->ss_size < MINSIGSTKSZ)
                           error = ENOMEM;
   
                   if (!error)
                           l->l_sigstk = *nss;
           }
   
           mutex_exit(&p->p_smutex);
   
           return (error);
   }
   
   int
   __sigtimedwait1(struct lwp *l, void *v, register_t *retval,
       copyout_t put_info, copyin_t fetch_timeout, copyout_t put_timeout)
   {
           struct sys___sigtimedwait_args /* {
                   syscallarg(const sigset_t *) set;
                   syscallarg(siginfo_t *) info;
                   syscallarg(struct timespec *) timeout;
           } */ *uap = v;
           sigset_t *waitset;
           struct proc *p = l->l_proc;
           int error, signum;
           int timo = 0;
           struct timespec ts, tsstart, tsnow;
           ksiginfo_t *ksi;
   
           memset(&tsstart, 0, sizeof tsstart);     /* XXX gcc */
   
           /*
            * Calculate timeout, if it was specified.
            */
           if (SCARG(uap, timeout)) {
                   uint64_t ms;
   
                   if ((error = (*fetch_timeout)(SCARG(uap, timeout), &ts, sizeof(ts))))
                           return (error);
   
                   ms = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
                   timo = mstohz(ms);
                   if (timo == 0 && ts.tv_sec == 0 && ts.tv_nsec > 0)
                           timo = 1;
                   if (timo <= 0)
                           return (EAGAIN);
   
                   /*
                    * Remember current uptime, it would be used in
                    * ECANCELED/ERESTART case.
                    */
                   getnanouptime(&tsstart);
           }
   
           MALLOC(waitset, sigset_t *, sizeof(sigset_t), M_TEMP, M_WAITOK);
           if ((error = copyin(SCARG(uap, set), waitset, sizeof(sigset_t)))) {
                   FREE(waitset, M_TEMP);
                   return (error);
           }
   
           /*
            * Silently ignore SA_CANTMASK signals. psignal1() would ignore
            * SA_CANTMASK signals in waitset, we do this only for the below
            * siglist check.
            */
           sigminusset(&sigcantmask, waitset);
   
           /*
            * Allocate a ksi up front.  We can't sleep with the mutex held.
            */
           if ((ksi = ksiginfo_alloc(p, NULL, PR_WAITOK)) == NULL) {
                   FREE(waitset, M_TEMP);
                   return (ENOMEM);
           }
   
           mutex_enter(&p->p_smutex);
   
           if ((signum = sigget(&p->p_sigpend, ksi, 0, waitset)) == 0)
                   signum = sigget(&l->l_sigpend, ksi, 0, waitset);
   
           if (signum != 0) {
                   /*
                    * We found a pending signal - copy it out to the user.
                    */
                   mutex_exit(&p->p_smutex);
                   goto out;
           }
   
           /*
            * Set up the sigwait list. Pass pointer to malloced memory here;
            * it's not possible to pass pointer to a structure on current
            * process's stack, the current LWP might be swapped out when the
            * when the signal is delivered.
            */
           l->l_sigwaited = ksi;
           l->l_sigwait = waitset;
           LIST_INSERT_HEAD(&p->p_sigwaiters, l, l_sigwaiter);
   
           /*
            * Wait for signal to arrive. We can either be woken up or time out.
            */
           error = cv_timedwait_sig(&l->l_sigcv, &p->p_smutex, timo);
   
           /*
            * Need to find out if we woke as a result of lwp_wakeup() or a
            * signal outside our wait set.
            */
           if (l->l_sigwaited != NULL) {
                   if (error == EINTR) {
                           /* wakeup via _lwp_wakeup() */
                           error = ECANCELED;
                   } else if (!error) {
                           /* spurious wakeup - arrange for syscall restart */
                           error = ERESTART;
                   }
                   l->l_sigwaited = NULL;
                   LIST_REMOVE(l, l_sigwaiter);
           }
   
           l->l_sigwait = NULL;
           mutex_exit(&p->p_smutex);
   
           /*
            * If the sleep was interrupted (either by signal or wakeup), update
            * the timeout and copyout new value back.  It would be used when
            * the syscall would be restarted or called again.
            */
           if (timo && (error == ERESTART || error == ECANCELED)) {
                   getnanouptime(&tsnow);
   
                   /* compute how much time has passed since start */
                   timespecsub(&tsnow, &tsstart, &tsnow);
                   /* substract passed time from timeout */
                   timespecsub(&ts, &tsnow, &ts);
   
                   if (ts.tv_sec < 0)
                           error = EAGAIN;
                   else {
                           /* copy updated timeout to userland */
                           error = (*put_timeout)(&ts, SCARG(uap, timeout),
                               sizeof(ts));
                   }
           }
   
           /*
            * If a signal from the wait set arrived, copy it to userland.
            * Copy only the used part of siginfo, the padding part is
            * left unchanged (userland is not supposed to touch it anyway).
            */
    out:
           FREE(waitset, M_TEMP);
           ksiginfo_free(ksi);
   
           if (error == 0)
                   error = (*put_info)(&ksi->ksi_info, SCARG(uap, info),
                       sizeof(ksi->ksi_info));
   
           return error;
   }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.9

CVSweb <webmaster@jp.NetBSD.org>