]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_sig.c
xnu-344.23.tar.gz
[apple/xnu.git] / bsd / kern / kern_sig.c
index 92f02ba12fef7b2bccf1ab3f933d2952f214b2d5..21c9358d9feaf0464f89b87c8a29caa610f68765 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -62,7 +62,6 @@
 
 #define        SIGPROP         /* include signal properties table */
 #include <sys/param.h>
-#include <sys/signalvar.h>
 #include <sys/resourcevar.h>
 #include <sys/namei.h>
 #include <sys/vnode.h>
 #include <sys/file.h>
 #include <sys/kernel.h>
 #include <sys/wait.h>
+#include <sys/signalvar.h>
+#if KTRACE
 #include <sys/ktrace.h>
+#endif
 #include <sys/syslog.h>
 #include <sys/stat.h>
 #include <sys/lock.h>
+#include <sys/kdebug.h>
 
 #include <sys/mount.h>
 
 #include <sys/user.h>          /* for coredump */
 #include <kern/ast.h>          /* for APC support */
 #include <kern/thread.h>
+#include <kern/sched_prim.h>
 #include <kern/thread_call.h>
+#include <mach/exception.h>
+
+extern void doexception(int exc, int code, int sub);
 
 void stop __P((struct proc *p));
 int cansignal __P((struct proc *, struct pcred *, struct proc *, int));
 int killpg1 __P((struct proc *, int, int, int));
 void sigexit_locked __P((struct proc *, int));
-void setsigvec __P((struct proc *, int, struct sigaction *));
-void exit1 __P((struct proc *, int));
+int setsigvec __P((struct proc *, int, struct __sigaction *));
+void exit1 __P((struct proc *, int, int *));
 int signal_lock __P((struct proc *));
 int signal_unlock __P((struct proc *));
-void signal_setast __P((thread_act_t *));
-void signal_clearast __P((thread_act_t *));
-void psignal_lock __P((struct proc *, int, int, int));
+void signal_setast __P((thread_act_t));
+void psignal_lock __P((struct proc *, int, int));
+void psignal_uthread __P((thread_act_t, int));
+kern_return_t do_bsdexception(int, int, int);
 
 #if SIGNAL_DEBUG
 void ram_printf __P((int));
@@ -112,11 +120,13 @@ ram_printf(int x)
     printf("x is %d",x);
 
 }
-
 #endif /* SIGNAL_DEBUG */
+
 int
 signal_lock(struct proc *p)
 {
+int error = 0;
+#if DIAGNOSTIC
 #if SIGNAL_DEBUG
 #ifdef __ppc__
         {
@@ -134,13 +144,20 @@ signal_lock(struct proc *p)
         }
 #endif /* __ppc__ */       
 #endif /* SIGNAL_DEBUG */
-
-       return(lockmgr(&p->signal_lock, LK_EXCLUSIVE, 0, (struct proc *)0));
+#endif /* DIAGNOSTIC */
+
+siglock_retry:
+       /* TBD:  check p last arg */
+       error = lockmgr(&p->signal_lock, LK_EXCLUSIVE, 0, (struct proc *)p);
+       if (error == EINTR)
+               goto siglock_retry;
+       return(error);
 }
 
 int
 signal_unlock(struct proc *p)
 {
+#if DIAGNOSTIC
 #if SIGNAL_DEBUG
 #ifdef __ppc__
         {
@@ -158,26 +175,17 @@ signal_unlock(struct proc *p)
         }
 #endif /* __ppc__ */       
 #endif /* SIGNAL_DEBUG */
+#endif /* DIAGNOSTIC */
 
-       return(lockmgr(&p->signal_lock, LK_RELEASE, (simple_lock_t)0, (struct proc *)0));
+       /* TBD:  check p last arg */
+       return(lockmgr(&p->signal_lock, LK_RELEASE, (simple_lock_t)0, (struct proc *)p));
 }
 
 void
 signal_setast(sig_actthread)
-thread_act_t *sig_actthread;
-{
-       thread_ast_set(sig_actthread, AST_BSD);
-       if ((thread_act_t *)current_act() == sig_actthread)
-            ast_on(AST_BSD);
-}
-
-void
-signal_clearast(sig_actthread)
-thread_act_t *sig_actthread;
+thread_act_t sig_actthread;
 {
-       thread_ast_clear(sig_actthread, AST_BSD);
-       if ((thread_act_t *)current_act() == sig_actthread)
-            ast_off(AST_BSD);
+       act_set_astbsd(sig_actthread);
 }
 
 /*
@@ -190,6 +198,10 @@ cansignal(p, pc, q, signum)
        struct proc *q;
        int signum;
 {
+       /* you can signal yourself */
+       if (p == q)
+               return(1);
+
        if (pc->pc_ucred->cr_uid == 0)
                return (1);             /* root can always signal */
 
@@ -238,7 +250,7 @@ cansignal(p, pc, q, signum)
 
 struct sigaction_args {
        int     signum;
-       struct sigaction *nsa;
+       struct __sigaction *nsa;
        struct sigaction *osa;
 };
 
@@ -250,10 +262,12 @@ sigaction(p, uap, retval)
        register_t *retval;
 {
        struct sigaction vec;
+       struct __sigaction __vec;
+
        register struct sigaction *sa;
        register struct sigacts *ps = p->p_sigacts;
        register int signum;
-       int bit, error;
+       int bit, error=0;
 
        signum = uap->signum;
        if (signum <= 0 || signum >= NSIG ||
@@ -269,57 +283,153 @@ sigaction(p, uap, retval)
                        sa->sa_flags |= SA_ONSTACK;
                if ((ps->ps_sigintr & bit) == 0)
                        sa->sa_flags |= SA_RESTART;
-               if (p->p_flag & P_NOCLDSTOP)
+               if (ps->ps_siginfo & bit)
+                       sa->sa_flags |= SA_SIGINFO;
+               if (ps->ps_signodefer & bit)
+                       sa->sa_flags |= SA_NODEFER;
+               if ((signum == SIGCHLD) && (p->p_flag & P_NOCLDSTOP))
                        sa->sa_flags |= SA_NOCLDSTOP;
+               if ((signum == SIGCHLD) && (p->p_flag & P_NOCLDWAIT))
+                       sa->sa_flags |= SA_NOCLDWAIT;
                if (error = copyout((caddr_t)sa, (caddr_t)uap->osa,
                    sizeof (vec)))
                        return (error);
        }
        if (uap->nsa) {
-               if (error = copyin((caddr_t)uap->nsa, (caddr_t)sa,
-                   sizeof (vec)))
+               if (error = copyin((caddr_t)uap->nsa, (caddr_t)&__vec,
+                   sizeof (__vec)))
                        return (error);
-               setsigvec(p, signum, sa);
+               error = setsigvec(p, signum, &__vec);
        }
-       return (0);
+       return (error);
 }
 
-static int
-reset_sigbits(thread_act_t th_act, int bit) 
+/* Routines to manipulate bits on all threads */
+int
+clear_procsiglist(struct proc *p,  int bit)
 {
-struct uthread *ut;
-       ut = get_bsdthread_info(th_act);
-       if (ut) {
-               ut->uu_sig &= ~bit;
+       struct uthread * uth;
+       thread_act_t thact;
+
+       signal_lock(p);
+
+       if ((p->p_flag & P_INVFORK) && p->p_vforkact) {
+               thact = p->p_vforkact;  
+               uth = (struct uthread *)get_bsdthread_info(thact);
+               if (uth) {
+                       uth->uu_siglist &= ~bit;
+               }
+               p->p_siglist &= ~bit;
+               signal_unlock(p);
+               return(0);
+       } 
+
+       TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) {
+               uth->uu_siglist &= ~bit;
        }
+       p->p_siglist &= ~bit;
+       signal_unlock(p);
+       return(0);
 }
 
 int
-clear_sigbits (struct proc *p,  int bit)
+unblock_procsigmask(struct proc *p,  int bit)
 {
-task_t task = p->task;
+       struct uthread * uth;
+       thread_act_t thact;
 
-       p->p_siglist &= ~(bit);
-       task_act_iterate_wth_args(task, reset_sigbits, bit);
+       signal_lock(p);
+       if ((p->p_flag & P_INVFORK) && p->p_vforkact) {
+               thact = p->p_vforkact;  
+               uth = (struct uthread *)get_bsdthread_info(thact);
+               if (uth) {
+                       uth->uu_sigmask &= ~bit;
+               }
+               p->p_sigmask &= ~bit;
+               signal_unlock(p);
+               return(0);
+       } 
+       TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) {
+               uth->uu_sigmask &= ~bit;
+       }
+       p->p_sigmask &= ~bit;
+       signal_unlock(p);
        return(0);
 }
 
 
-void
+int
+block_procsigmask(struct proc *p,  int bit)
+{
+       struct uthread * uth;
+       thread_act_t thact;
+
+       signal_lock(p);
+       if ((p->p_flag & P_INVFORK) && p->p_vforkact) {
+               thact = p->p_vforkact;  
+               uth = (struct uthread *)get_bsdthread_info(thact);
+               if (uth) {
+                       uth->uu_sigmask |= bit;
+               }
+               p->p_sigmask |=  bit;
+               signal_unlock(p);
+               return(0);
+       } 
+       TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) {
+               uth->uu_sigmask |= bit;
+       }
+       p->p_sigmask |=  bit;
+       signal_unlock(p);
+       return(0);
+}
+int
+set_procsigmask(struct proc *p,  int bit)
+{
+       struct uthread * uth;
+       thread_act_t thact;
+
+       signal_lock(p);
+       if ((p->p_flag & P_INVFORK) && p->p_vforkact) {
+               thact = p->p_vforkact;  
+               uth = (struct uthread *)get_bsdthread_info(thact);
+               if (uth) {
+                       uth->uu_sigmask = bit;
+               }
+               p->p_sigmask =  bit;
+               signal_unlock(p);
+               return(0);
+       } 
+       TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) {
+               uth->uu_sigmask = bit;
+       }
+       p->p_sigmask =  bit;
+       signal_unlock(p);
+       return(0);
+}
+
+int
 setsigvec(p, signum, sa)
        register struct proc *p;
        int signum;
-       register struct sigaction *sa;
+       register struct __sigaction *sa;
 {
        register struct sigacts *ps = p->p_sigacts;
        register int bit;
 
+       if ((signum == SIGKILL || signum == SIGSTOP) &&
+               sa->sa_handler != SIG_DFL)
+               return(EINVAL);
        bit = sigmask(signum);
        /*
         * Change setting atomically.
         */
        ps->ps_sigact[signum] = sa->sa_handler;
+       ps->ps_trampact[signum] = sa->sa_tramp;
        ps->ps_catchmask[signum] = sa->sa_mask &~ sigcantmask;
+       if (sa->sa_flags & SA_SIGINFO)
+               ps->ps_siginfo |= bit;
+       else
+               ps->ps_siginfo &= ~bit;
        if ((sa->sa_flags & SA_RESTART) == 0)
                ps->ps_sigintr |= bit;
        else
@@ -332,12 +442,33 @@ setsigvec(p, signum, sa)
                ps->ps_usertramp |= bit;
        else
                ps->ps_usertramp &= ~bit;
+       if (sa->sa_flags & SA_RESETHAND)
+               ps->ps_sigreset |= bit;
+       else
+               ps->ps_sigreset &= ~bit;
+       if (sa->sa_flags & SA_NODEFER)
+               ps->ps_signodefer |= bit;
+       else
+               ps->ps_signodefer &= ~bit;
        if (signum == SIGCHLD) {
                if (sa->sa_flags & SA_NOCLDSTOP)
                        p->p_flag |= P_NOCLDSTOP;
                else
                        p->p_flag &= ~P_NOCLDSTOP;
+               if ((sa->sa_flags & SA_NOCLDWAIT) || (sa->sa_handler == SIG_IGN))
+                       p->p_flag |= P_NOCLDWAIT;
+               else
+                       p->p_flag &= ~P_NOCLDWAIT;
        }
+
+#ifdef __ppc__ 
+       if (signum == SIGFPE) {
+               if (sa->sa_handler == SIG_DFL || sa->sa_handler == SIG_IGN) 
+                       thread_enable_fpe(current_act(), 0);
+               else
+                       thread_enable_fpe(current_act(), 1);
+       }
+#endif  /* __ppc__ */
        /*
         * Set bit in p_sigignore for signals that are set to SIG_IGN,
         * and for signals set to SIG_DFL where the default is to ignore.
@@ -346,16 +477,8 @@ setsigvec(p, signum, sa)
         */
        if (sa->sa_handler == SIG_IGN ||
            (sigprop[signum] & SA_IGNORE && sa->sa_handler == SIG_DFL)) {
-               p->p_siglist &= ~bit;           /* never to be seen again */
-               /*
-                *      If this is a thread signal, clean out the
-                *      threads as well.
-                */
-               if (bit & threadmask) {
-                       register        task_t          task = p->task;
 
-                       task_act_iterate_wth_args(task, reset_sigbits, bit);
-               }
+               clear_procsiglist(p, bit);
                if (signum != SIGCONT)
                        p->p_sigignore |= bit;  /* easier in psignal */
                p->p_sigcatch &= ~bit;
@@ -366,6 +489,7 @@ setsigvec(p, signum, sa)
                else
                        p->p_sigcatch |= bit;
        }
+       return(0);
 }
 
 /*
@@ -387,11 +511,13 @@ siginit(p)
  * Reset signals for an exec of the specified process.
  */
 void
-execsigs(p)
+execsigs(p, thr_act)
        register struct proc *p;
+       register thread_act_t thr_act;
 {
        register struct sigacts *ps = p->p_sigacts;
        register int nc, mask;
+       struct uthread *ut;
 
        /*
         * Reset caught signals.  Held signals remain held
@@ -405,7 +531,12 @@ execsigs(p)
                if (sigprop[nc] & SA_IGNORE) {
                        if (nc != SIGCONT)
                                p->p_sigignore |= mask;
-                       p->p_siglist &= ~mask;
+                       if (thr_act){
+                               ut = (struct uthread *)get_bsdthread_info(thr_act);
+                               ut->uu_siglist &= ~mask;
+                               p->p_siglist &= ~mask;
+                       } else
+                               clear_procsiglist(p, mask);
                }
                ps->ps_sigact[nc] = SIG_DFL;
        }
@@ -427,7 +558,8 @@ execsigs(p)
  */
 struct sigprocmask_args {
        int     how;
-       sigset_t mask;
+       sigset_t *mask;
+       sigset_t * omask;
 };
 int
 sigprocmask(p, uap, retval)
@@ -436,21 +568,34 @@ sigprocmask(p, uap, retval)
        register_t *retval;
 {
        int error = 0;
+       sigset_t oldmask, nmask;
+       sigset_t * omask = uap->omask;
+       struct uthread *ut;
 
-       *retval = p->p_sigmask;
+       ut = (struct uthread *)get_bsdthread_info(current_act());
+       oldmask  = ut->uu_sigmask;
+
+       if (uap->mask == (sigset_t *)0) {
+               /* just want old mask */
+               goto out;
+       }
+       error = copyin((caddr_t)uap->mask, &nmask, sizeof(sigset_t));
+       if (error)
+               goto out;
 
        switch (uap->how) {
        case SIG_BLOCK:
-               p->p_sigmask |= uap->mask &~ sigcantmask;
+               block_procsigmask(p, (nmask & ~sigcantmask));
+               signal_setast(current_act());
                break;
 
        case SIG_UNBLOCK:
-               p->p_sigmask &= ~(uap->mask);
+               unblock_procsigmask(p, (nmask & ~sigcantmask));
                signal_setast(current_act());
                break;
 
        case SIG_SETMASK:
-               p->p_sigmask = uap->mask &~ sigcantmask;
+               set_procsigmask(p, (nmask & ~sigcantmask));
                signal_setast(current_act());
                break;
        
@@ -458,19 +603,30 @@ sigprocmask(p, uap, retval)
                error = EINVAL;
                break;
        }
+out:
+       if (!error && omask)
+               copyout(&oldmask, omask, sizeof(sigset_t));
        return (error);
 }
 
-/* ARGSUSED */
+struct sigpending_args {
+       struct sigvec *osv;
+};
 int
 sigpending(p, uap, retval)
        struct proc *p;
-       void *uap;
+       register struct sigpending_args *uap;
        register_t *retval;
 {
+       struct uthread *ut;
+       sigset_t pendlist;
 
-       *retval = p->p_siglist;
-       return (0);
+       ut = (struct uthread *)get_bsdthread_info(current_act());
+       pendlist = ut->uu_siglist;
+
+       if (uap->osv)
+               copyout(&pendlist, uap->osv, sizeof(sigset_t));
+       return(0);
 }
 
 #if COMPAT_43
@@ -489,12 +645,15 @@ osigvec(p, uap, retval)
        register struct osigvec_args *uap;
        register_t *retval;
 {
+       struct sigvec __vec;
        struct sigvec vec;
        register struct sigacts *ps = p->p_sigacts;
        register struct sigvec *sv;
        register int signum;
-       int bit, error;
+       int bit, error=0;
 
+       panic("osigvec: notsupp");
+#if 0
        signum = uap->signum;
        if (signum <= 0 || signum >= NSIG ||
            signum == SIGKILL || signum == SIGSTOP)
@@ -520,9 +679,10 @@ osigvec(p, uap, retval)
                    sizeof (vec)))
                        return (error);
                sv->sv_flags ^= SA_RESTART;     /* opposite of SV_INTERRUPT */
-               setsigvec(p, signum, (struct sigaction *)sv);
+               error = setsigvec(p, signum, (struct sigaction *)sv);
        }
-       return (0);
+#endif
+       return (error);
 }
 
 struct osigblock_args {
@@ -534,9 +694,10 @@ osigblock(p, uap, retval)
        struct osigblock_args *uap;
        register_t *retval;
 {
+       struct uthread * uth = get_bsdthread_info(current_act());
 
-       *retval = p->p_sigmask;
-       p->p_sigmask |= uap->mask &~ sigcantmask;
+       *retval = uth->uu_sigmask;
+       uth->uu_sigmask |= (uap->mask & ~sigcantmask);
        return (0);
 }
 
@@ -549,9 +710,10 @@ osigsetmask(p, uap, retval)
        struct osigsetmask_args *uap;
        register_t *retval;
 {
+       struct uthread * uth = get_bsdthread_info(current_act());
 
-       *retval = p->p_sigmask;
-       p->p_sigmask = uap->mask &~ sigcantmask;
+       *retval = uth->uu_sigmask;
+       uth->uu_sigmask = (uap->mask & ~sigcantmask);
        return (0);
 }
 #endif /* COMPAT_43 */
@@ -565,11 +727,12 @@ osigsetmask(p, uap, retval)
 int
 sigcontinue(error)
 {
+       struct uthread *ut = get_bsdthread_info(current_act());
   unix_syscall_return(EINTR);
 }
 
 struct sigsuspend_args {
-       int mask;
+       sigset_t mask;
 };
 
 /* ARGSUSED */
@@ -580,6 +743,9 @@ sigsuspend(p, uap, retval)
        register_t *retval;
 {
        register struct sigacts *ps = p->p_sigacts;
+       struct uthread *ut;
+
+       ut = (struct uthread *)get_bsdthread_info(current_act());
 
        /*
         * When returning from sigpause, we want
@@ -588,19 +754,232 @@ sigsuspend(p, uap, retval)
         * save it here and mark the sigacts structure
         * to indicate this.
         */
-       ps->ps_oldmask = p->p_sigmask;
-       ps->ps_flags |= SAS_OLDMASK;
-       p->p_sigmask = uap->mask &~ sigcantmask;
+       ut->uu_oldmask = ut->uu_sigmask;
+       ut->uu_flag |= USAS_OLDMASK;
+       ut->uu_sigmask = (uap->mask & ~sigcantmask);
        (void) tsleep0((caddr_t) p, PPAUSE|PCATCH, "pause", 0, sigcontinue);
        /* always return EINTR rather than ERESTART... */
        return (EINTR);
 }
 
+struct __disable_thsignal_args {
+       int value;
+};
+
+int
+__disable_threadsignal(p, uap, retval)
+       struct proc *p;
+       register struct __disable_thsignal_args *uap;
+       register_t *retval;
+{
+       struct uthread *uth;
+
+       uth = (struct uthread *)get_bsdthread_info(current_act());
+
+       /* No longer valid to have any signal delivered */
+       signal_lock(p);
+       uth->uu_flag |= UNO_SIGMASK;
+       signal_unlock(p);
+
+       return(0);
+
+}
+
+struct pthread_kill_args {
+       void * thread_port;
+       int sig;
+};
+
+int 
+__pthread_kill(p, uap, retval) 
+       struct proc *p;
+       register struct pthread_kill_args *uap;
+       register_t *retval;
+{
+       thread_act_t target_act;
+       int error = 0;
+       int signum = uap->sig;
+       struct uthread *uth;
+
+       target_act = (thread_act_t)port_name_to_act(uap->thread_port);
+
+       if (target_act == THR_ACT_NULL)
+               return (ESRCH);
+       if ((u_int)signum >= NSIG) {
+               error = EINVAL;
+               goto out;
+       }
+
+       uth = (struct uthread *)get_bsdthread_info(target_act);
+       { void *tht = getshuttle_thread(target_act);
+}
+       if (uth->uu_flag & UNO_SIGMASK) {
+               error = ESRCH;
+               goto out;
+       }
+
+       if (signum)
+               psignal_uthread(target_act, signum);
+out:
+       act_deallocate(target_act);
+       return (error);
+}
+
+
+struct pthread_sigmask_args {
+       int how;
+       const sigset_t  *set;
+       sigset_t * oset;
+};
+int 
+pthread_sigmask(p, uap, retval)
+       register struct proc *p;
+       register struct pthread_sigmask_args *uap;
+       register_t *retval;
+{
+       int how = uap->how;
+       const sigset_t  *set = uap->set;
+       sigset_t  * oset = uap->oset;
+       const sigset_t nset;
+       int error = 0;
+       struct uthread *ut;
+       sigset_t  oldset;
+
+       ut = (struct uthread *)get_bsdthread_info(current_act());
+       oldset = ut->uu_sigmask;
+
+       if (set == (sigset_t *) 0) {
+               /* need only old mask */
+               goto out;
+       }
+
+       error = copyin((caddr_t)set, (caddr_t)&nset, sizeof(sigset_t));
+       if (error)
+               goto out;
+
+       switch (uap->how) {
+       case SIG_BLOCK:
+               ut->uu_sigmask |= (nset & ~sigcantmask);
+               break;
+
+       case SIG_UNBLOCK:
+               ut->uu_sigmask &= ~(nset);
+               signal_setast(current_act());
+               break;
+
+       case SIG_SETMASK:
+               ut->uu_sigmask = (nset & ~sigcantmask);
+               signal_setast(current_act());
+               break;
+       
+       default:
+               error = EINVAL;
+
+       }
+out:
+       if (!error && oset)
+               copyout((caddr_t)&oldset, (caddr_t)oset, sizeof(sigset_t));
+
+       return(error);
+}
+
+
+struct sigwait_args {
+       const sigset_t  *set;
+       int *sig;
+};
+
+int 
+sigwait(p, uap, retval)
+       register struct proc *p;
+       register struct sigwait_args *uap;
+       register_t *retval;
+{
+       register struct sigacts *ps = p->p_sigacts;
+       struct uthread *ut;
+       struct uthread *uth;
+       thread_act_t thact;
+       int error = 0;
+       sigset_t mask;
+       sigset_t siglist;
+       sigset_t sigw=0;
+       int signum;
+
+       ut = (struct uthread *)get_bsdthread_info(current_act());
+
+       if (uap->set == (const sigset_t *)0)
+               return(EINVAL);
+
+       error = copyin((caddr_t)uap->set, (caddr_t)&mask, sizeof(sigset_t));
+       if (error)
+               return(error);
+
+       siglist = (mask & ~sigcantmask);
+
+       if (siglist == 0)
+               return(EINVAL);
+
+       signal_lock(p);
+       if ((p->p_flag & P_INVFORK) && p->p_vforkact) {
+               signal_unlock(p);
+               return(EINVAL);
+       } else {
+               TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) {
+                       if (sigw = uth->uu_siglist & siglist) {
+                               break;
+                       }
+               }
+       }
+       signal_unlock(p);
+       if (sigw) {
+               /* The signal was pending on a thread */
+               goto sigwait1;
+       }
+       /*
+        * When returning from sigwait, we want
+        * the old mask to be restored after the
+        * signal handler has finished.  Thus, we
+        * save it here and mark the sigacts structure
+        * to indicate this.
+        */
+       ut->uu_oldmask = ut->uu_sigmask;
+       ut->uu_flag |= USAS_OLDMASK;
+       if (siglist == (sigset_t)0)
+               return(EINVAL);
+       /* SIGKILL and SIGSTOP are not maskable as well */
+       ut->uu_sigmask = ~(siglist|sigcantmask);
+       ut->uu_sigwait = siglist; 
+       /* No Continuations for now */
+       error =  tsleep((caddr_t)&ut->uu_sigwait, PPAUSE|PCATCH, "pause", 0);
+
+       if ((error == EINTR) || (error == ERESTART))
+               error = 0;
+
+       sigw = (ut->uu_sigwait & siglist);
+       ut->uu_sigmask = ut->uu_oldmask;
+       ut->uu_oldmask = 0;
+       ut->uu_flag &= ~USAS_OLDMASK;
+sigwait1:
+       ut->uu_sigwait = 0;
+       if (!error) {
+               signum = ffs((unsigned int)sigw);
+               if (!signum)
+                       panic("sigwait with no signal wakeup");
+               ut->uu_siglist &= ~(sigmask(signum));
+               if (uap->sig)
+                               error = copyout(&signum, uap->sig, sizeof(int));
+       }
+
+       return(error);
+
+}
+
 #if COMPAT_43
 struct osigstack_args {
        struct sigstack *nss;
        struct sigstack *oss;
 };
+
 /* ARGSUSED */
 int
 osigstack(p, uap, retval)
@@ -655,6 +1034,10 @@ sigaltstack(p, uap, retval)
        if (error = copyin((caddr_t)uap->nss, (caddr_t)&ss,
            sizeof (ss)))
                return (error);
+       if ((ss.ss_flags & ~SA_DISABLE) != 0)  {
+               return(EINVAL);
+       }
+
        if (ss.ss_flags & SA_DISABLE) {
                if (psp->ps_sigstk.ss_flags & SA_ONSTACK)
                        return (EINVAL);
@@ -807,12 +1190,33 @@ pgsignal(pgrp, signum, checkctty)
                                psignal(p, signum);
 }
 
+/*
+ * Send signal to a backgrounded process blocked due to tty access
+ * In FreeBSD, the backgrounded process wakes up every second and
+ * discovers whether it is foregounded or not. In our case, we block 
+ * the thread in tsleep as we want to avoid storm of processes as well 
+ * as the suspend is only at AST level
+ */
+void
+tty_pgsignal(pgrp, signum)
+       struct pgrp *pgrp;
+       int signum;
+{
+       register struct proc *p;
+
+       if (pgrp)
+               for (p = pgrp->pg_members.lh_first; p != 0;
+                    p = p->p_pglist.le_next)
+                       if ((p->p_flag & P_TTYSLEEP) && (p->p_flag & P_CONTROLT))
+                               psignal(p, signum);
+}
+
 /*
  * Send a signal caused by a trap to a specific thread.
  */
 void
 threadsignal(sig_actthread, signum, code)
-       register thread_act_t *sig_actthread;
+       register thread_act_t sig_actthread;
        register int signum;
        u_long code;
 {
@@ -828,94 +1232,509 @@ threadsignal(sig_actthread, signum, code)
        if ((mask & threadmask) == 0)
                return;
        sig_task = get_threadtask(sig_actthread);
-       /* p = sig_task->proc; */
        p = (struct proc *)(get_bsdtask_info(sig_task));
 
+       uth = get_bsdthread_info(sig_actthread);
+       if (uth && (uth->uu_flag & P_VFORK))
+               p = uth->uu_proc;
+
        if (!(p->p_flag & P_TRACED) && (p->p_sigignore & mask))
                return;
 
-       uth = get_bsdthread_info(sig_actthread);
-       uth->uu_sig |= mask;
+       uth->uu_siglist |= mask;
+       p->p_siglist |= mask;   /* just for lame ones looking here */
        uth->uu_code = code;
        /* mark on process as well */
-       p->p_siglist |= mask;
        signal_setast(sig_actthread);
 }
 
-void
-psignal_pend(p) 
-       register struct proc *p;
-{
-       boolean_t funnel_state;
-       register int sigbits, mask, signum;
+void
+psignal(p, signum)
+       register struct proc *p;
+       register int signum;
+{
+       psignal_lock(p, signum, 1);
+}
+
+void
+psignal_vfork(p, new_task, thr_act, signum)
+       register struct proc *p;
+       task_t new_task;
+       thread_act_t thr_act;
+       register int signum;
+{
+       int withlock = 1;
+       int pend = 0;
+       register int s, prop;
+       register sig_t action;
+       int mask;
+       kern_return_t kret;
+       struct uthread *uth;
+
+       if ((u_int)signum >= NSIG || signum == 0)
+               panic("psignal signal number");
+       mask = sigmask(signum);
+       prop = sigprop[signum];
+
+#if SIGNAL_DEBUG
+        if(rdebug_proc && (p == rdebug_proc)) {
+                ram_printf(3);
+        }
+#endif /* SIGNAL_DEBUG */
+
+       if ((new_task == TASK_NULL) || (thr_act == (thread_act_t)NULL)  || is_kerneltask(new_task))
+               return;
+
+
+       uth = get_bsdthread_info(thr_act);
+       signal_lock(p);
+
+       /*
+        * proc is traced, always give parent a chance.
+        */
+       action = SIG_DFL;
+
+       if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) &&
+               (p->p_flag & P_TRACED) == 0)
+               p->p_nice = NZERO;
+
+       if (prop & SA_CONT) {
+               p->p_siglist &= ~stopsigmask;
+               uth->uu_siglist &= ~stopsigmask;
+       }
+
+       if (prop & SA_STOP) {
+               /*
+                * If sending a tty stop signal to a member of an orphaned
+                * process group, discard the signal here if the action
+                * is default; don't stop the process below if sleeping,
+                * and don't clear any pending SIGCONT.
+                */
+               if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 &&
+                       action == SIG_DFL)
+                       goto psigout;
+               uth->uu_siglist &= ~contsigmask;
+               p->p_siglist &= ~contsigmask;
+       }
+       uth->uu_siglist |= mask;
+       p->p_siglist |= mask;   /* just for lame ones looking here */
+       
+       /* Deliver signal to the activation passed in */
+       act_set_astbsd(thr_act);
+
+       /*
+        *      SIGKILL priority twiddling moved here from above because
+        *      it needs sig_thread.  Could merge it into large switch
+        *      below if we didn't care about priority for tracing
+        *      as SIGKILL's action is always SIG_DFL.
+        */
+       if ((signum == SIGKILL) && (p->p_nice > NZERO)) {
+               p->p_nice = NZERO;
+       }
+
+       /*
+        *      This Process is traced - wake it up (if not already
+        *      stopped) so that it can discover the signal in
+        *      issig() and stop for the parent.
+        */
+         if (p->p_flag & P_TRACED) {
+               if (p->p_stat != SSTOP)
+                       goto run;
+               else
+                       goto psigout;
+       }
+run:
+       /*
+        * If we're being traced (possibly because someone attached us
+        * while we were stopped), check for a signal from the debugger.
+        */
+       if (p->p_stat == SSTOP) {
+               if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) {
+                       uth->uu_siglist |= sigmask(p->p_xstat); 
+                       p->p_siglist |= mask;   /* just for lame ones looking here */
+               }
+       }
+
+       /*
+        * setrunnable(p) in BSD
+        */
+       p->p_stat = SRUN;
+
+psigout:
+       signal_unlock(p);
+}
+
+thread_act_t
+get_signalthread(struct proc *p, int signum)
+{
+       struct uthread *uth;
+       thread_act_t thr_act;
+       sigset_t mask = sigmask(signum);
+       thread_act_t sig_thread_act;
+       struct task * sig_task = p->task;
+       thread_t sig_thread;
+       kern_return_t kret;
+       
+       if ((p->p_flag & P_INVFORK) && p->p_vforkact) {
+               sig_thread_act = p->p_vforkact; 
+               kret = check_actforsig(sig_task, sig_thread_act, &sig_thread, 1);
+               if (kret == KERN_SUCCESS) 
+                       return(sig_thread_act);
+               else
+                       return(THR_ACT_NULL);
+       } 
+
+       TAILQ_FOREACH(uth, &p->p_uthlist, uu_list) {
+               if(((uth->uu_flag & UNO_SIGMASK)== 0) && 
+                       (((uth->uu_sigmask & mask) == 0) || (uth->uu_sigwait & mask))) {
+                       if (check_actforsig(p->task, uth->uu_act, NULL, 1) == KERN_SUCCESS)
+                               return(uth->uu_act);
+               }
+       }
+       if (get_signalact(p->task, &thr_act, NULL, 1) == KERN_SUCCESS) {
+               return(thr_act);
+       }
+
+       return(THR_ACT_NULL);
+}
+
+/*
+ * Send the signal to the process.  If the signal has an action, the action
+ * is usually performed by the target process rather than the caller; we add
+ * the signal to the set of pending signals for the process.
+ *
+ * Exceptions:
+ *   o When a stop signal is sent to a sleeping process that takes the
+ *     default action, the process is stopped without awakening it.
+ *   o SIGCONT restarts stopped processes (or puts them back to sleep)
+ *     regardless of the signal action (eg, blocked or ignored).
+ *
+ * Other ignored signals are discarded immediately.
+ */
+void
+psignal_lock(p, signum, withlock)
+       register struct proc *p;
+       register int signum;
+       register int withlock;
+{
+       register int s, prop;
+       register sig_t action;
+       thread_act_t    sig_thread_act;
+       thread_t        sig_thread;
+       register task_t         sig_task;
+       register thread_t       cur_thread;
+       thread_act_t    cur_act;
+       int mask;
+       struct uthread *uth;
+       kern_return_t kret;
+       int sw_funnel = 0;
+
+       if ((u_int)signum >= NSIG || signum == 0)
+               panic("psignal signal number");
+       mask = sigmask(signum);
+       prop = sigprop[signum];
+
+#if SIGNAL_DEBUG
+        if(rdebug_proc && (p == rdebug_proc)) {
+                ram_printf(3);
+        }
+#endif /* SIGNAL_DEBUG */
+
+       if (thread_funnel_get() == (funnel_t *)network_flock) {
+               sw_funnel = 1;
+               thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
+       }
+       /*
+        *      We will need the task pointer later.  Grab it now to
+        *      check for a zombie process.  Also don't send signals
+        *      to kernel internal tasks.
+        */
+       if (((sig_task = p->task) == TASK_NULL)  || is_kerneltask(sig_task)) {
+               if (sw_funnel)
+                       thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+               return;
+       }
+
+       /*
+        * do not send signals to the process that has the thread
+        * doing a reboot(). Not doing so will mark that thread aborted
+        * and can cause IO failures wich will cause data loss.
+        */
+       if (ISSET(p->p_flag, P_REBOOT)) {
+               if (sw_funnel)
+                       thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
+               return;
+       }
+
+       if (withlock)
+               signal_lock(p);
+
+       /*
+        *      Deliver the signal to the first thread in the task. This
+        *      allows single threaded applications which use signals to
+        *      be able to be linked with multithreaded libraries.  We have
+        *      an implicit reference to the current_thread, but need
+        *      an explicit one otherwise.  The thread reference keeps
+        *      the corresponding task data structures around too.  This
+        *      reference is released by thread_deallocate.
+        */
+       
+       if (((p->p_flag & P_TRACED) == 0) && (p->p_sigignore & mask))
+               goto psigout;
+
+       cur_thread = current_thread();   /* this is a shuttle */
+       cur_act = current_act();
+        
+       /* If successful return with ast set */
+       sig_thread_act = get_signalthread(p, signum);
+
+       if (sig_thread_act == THR_ACT_NULL) {
+               /* XXXX FIXME
+               /* if it is sigkill, may be we should
+               * inject a thread to terminate
+               */
+#if SIGNAL_DEBUG
+                       ram_printf(1);
+#endif /* SIGNAL_DEBUG */
+               goto psigout;
+       }
+
+       uth = get_bsdthread_info(sig_thread_act);
+
+       /*
+        * If proc is traced, always give parent a chance.
+        */
+       if (p->p_flag & P_TRACED)
+               action = SIG_DFL;
+       else {
+               /*
+                * If the signal is being ignored,
+                * then we forget about it immediately.
+                * (Note: we don't set SIGCONT in p_sigignore,
+                * and if it is set to SIG_IGN,
+                * action will be SIG_DFL here.)
+                */
+               if (p->p_sigignore & mask)
+                       goto psigout;
+               if (uth->uu_sigwait & mask)
+                       action = SIG_WAIT;
+               if (uth->uu_sigmask & mask)
+                       action = SIG_HOLD;
+               else if (p->p_sigcatch & mask)
+                       action = SIG_CATCH;
+               else
+                       action = SIG_DFL;
+       }
+
+       if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) &&
+               (p->p_flag & P_TRACED) == 0)
+               p->p_nice = NZERO;
+
+       if (prop & SA_CONT) {
+               uth->uu_siglist &= ~stopsigmask;
+               p->p_siglist &= ~stopsigmask;
+       }
+
+       if (prop & SA_STOP) {
+               /*
+                * If sending a tty stop signal to a member of an orphaned
+                * process group, discard the signal here if the action
+                * is default; don't stop the process below if sleeping,
+                * and don't clear any pending SIGCONT.
+                */
+               if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 &&
+                       action == SIG_DFL)
+                       goto psigout;
+               uth->uu_siglist &= ~contsigmask;
+               p->p_siglist &= ~contsigmask;
+       }
+       uth->uu_siglist |= mask;
+       p->p_siglist |= mask;   /* just for lame ones looking here */
+
+       
+       /*
+        * Defer further processing for signals which are held,
+        * except that stopped processes must be continued by SIGCONT.
+        */
+       if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP)) {
+               goto psigout;
+       }
+       /*
+        *      SIGKILL priority twiddling moved here from above because
+        *      it needs sig_thread.  Could merge it into large switch
+        *      below if we didn't care about priority for tracing
+        *      as SIGKILL's action is always SIG_DFL.
+        */
+       if ((signum == SIGKILL) && (p->p_nice > NZERO)) {
+               p->p_nice = NZERO;
+       }
+
+       /*
+        *      Process is traced - wake it up (if not already
+        *      stopped) so that it can discover the signal in
+        *      issig() and stop for the parent.
+        */
+       if (p->p_flag & P_TRACED) {
+               if (p->p_stat != SSTOP)
+                       goto run;
+               else
+                       goto psigout;
+       }
+
+       if (action == SIG_WAIT) {
+               uth->uu_sigwait = mask;
+               uth->uu_siglist &= ~mask;
+               p->p_siglist &= ~mask;
+               wakeup(&uth->uu_sigwait);
+               /* if it is SIGCONT resume whole process */
+               if (prop & SA_CONT)
+                       (void) task_resume(sig_task);
+               goto psigout;
+       }
+
+       if (action != SIG_DFL) {
+               /*
+                *      User wants to catch the signal.
+                *      Wake up the thread, but don't un-suspend it
+                *      (except for SIGCONT).
+                */
+               if (prop & SA_CONT)
+                       (void) task_resume(sig_task);
+               goto run;
+       } else {
+               /*      Default action - varies */
+               if (mask & stopsigmask) {
+                       /*
+                        * These are the signals which by default
+                        * stop a process.
+                        *
+                        * Don't clog system with children of init
+                        * stopped from the keyboard.
+                        */
+                       if (!(prop & SA_STOP) && p->p_pptr == initproc) {
+                               psignal_lock(p, SIGKILL, 0);
+                               uth->uu_siglist &= ~mask;
+                               p->p_siglist &= ~mask;
+                               goto psigout;
+                       }
+                        
+                       /*
+                        *      Stop the task
+                        *      if task hasn't already been stopped by
+                        *      a signal.
+                        */
+                       uth->uu_siglist &= ~mask;
+                       p->p_siglist &= ~mask;
+                       if (p->p_stat != SSTOP) {
+                               p->p_xstat = signum;
+                               stop(p);
+                               if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) {
+                                       struct proc *pp = p->p_pptr;
+
+                                       pp->si_pid = p->p_pid;
+                                       pp->si_status = p->p_xstat;
+                                       pp->si_code = CLD_STOPPED;
+                                       pp->si_uid = p->p_cred->p_ruid;
+                                       psignal(pp, SIGCHLD);
+                               }
+                       }
+                       goto psigout;
+               }
+
+               switch (signum) {
+                       /*
+                        * Signals ignored by default have been dealt
+                        * with already, since their bits are on in
+                        * p_sigignore.
+                        */
 
-       thread_funnel_set(kernel_flock, TRUE);
+               case SIGKILL:
+                       /*
+                        * Kill signal always sets process running and
+                        * unsuspends it.
+                        */
+                       /*
+                        *      Process will be running after 'run'
+                        */
+                       p->p_stat = SRUN;
 
-       if (p->p_sigpending == 0)
-                       return;
-       
+                       thread_abort(sig_thread_act);
 
-       signal_lock(p);
+                       goto psigout;
 
-       for (;;) {
-               sigbits = p->p_sigpending;
-               if (sigbits == 0)
-                       goto out;
-               signum = ffs((long)sigbits);
-               mask = sigmask(signum);
-               p->p_sigpending &= ~mask;
+               case SIGCONT:
+                       /*
+                        * Let the process run.  If it's sleeping on an
+                        * event, it remains so.
+                        */
+                       if (p->p_flag & P_TTYSLEEP) {
+                               p->p_flag &= ~P_TTYSLEEP;
+                               wakeup(&p->p_siglist);
+                       } else {
+                               (void) task_resume(sig_task);
+                       }
+                       uth->uu_siglist &= ~mask;
+                       p->p_siglist &= ~mask;
+                       p->p_stat = SRUN;
 
-               psignal_lock(p, signum, 0, 0);
+                       goto psigout;
 
+               default:
+                       /*
+                        * All other signals wake up the process, but don't
+                        * resume it.
+                        */
+                       goto run;
+               }
        }
-out:
-       p->p_flag &= ~P_SIGTHR;
-       signal_unlock(p);
-       thread_funnel_set(kernel_flock, FALSE);
-}
-
-void
-psignal(p, signum)
-       register struct proc *p;
-       register int signum;
-{
-       psignal_lock(p, signum, 1, 1);
+       /*NOTREACHED*/
+run:
+       /*
+        * If we're being traced (possibly because someone attached us
+        * while we were stopped), check for a signal from the debugger.
+        */
+       if (p->p_stat == SSTOP) {
+               if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0)
+                       uth->uu_siglist |= sigmask(p->p_xstat); 
+       } else {
+               /*
+                * setrunnable(p) in BSD and
+                * Wake up the thread if it is interruptible.
+                */
+               p->p_stat = SRUN;
+               thread_abort_safely(sig_thread_act);
+       }
+psigout:
+       if (withlock) 
+               signal_unlock(p);
+       if (sw_funnel)
+               thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
 }
 
 
-/*
- * Send the signal to the process.  If the signal has an action, the action
- * is usually performed by the target process rather than the caller; we add
- * the signal to the set of pending signals for the process.
- *
- * Exceptions:
- *   o When a stop signal is sent to a sleeping process that takes the
- *     default action, the process is stopped without awakening it.
- *   o SIGCONT restarts stopped processes (or puts them back to sleep)
- *     regardless of the signal action (eg, blocked or ignored).
- *
- * Other ignored signals are discarded immediately.
- */
+/* psignal_lock(p, signum, withlock ) */
 void
-psignal_lock(p, signum, withlock, pend)
-       register struct proc *p;
-       register int signum;
-       register int withlock;
-       register int pend;
+psignal_uthread(thr_act, signum)
+       thread_act_t thr_act;
+       int signum;
 {
+       struct proc *p;
        register int s, prop;
        register sig_t action;
        thread_act_t    sig_thread_act;
        thread_t        sig_thread;
        register task_t         sig_task;
        register thread_t       cur_thread;
-       thread_act_t    *cur_act;
+       thread_act_t    cur_act;
        int mask;
+       struct uthread *uth;
        kern_return_t kret;
+       int error = 0;
 
+       p = (struct proc *)get_bsdtask_info(get_threadtask(thr_act));
        if ((u_int)signum >= NSIG || signum == 0)
-               panic("psignal signal number");
+               panic("Invalid signal number in psignal_uthread"); 
        mask = sigmask(signum);
        prop = sigprop[signum];
 
@@ -924,40 +1743,53 @@ psignal_lock(p, signum, withlock, pend)
                 ram_printf(3);
         }
 #endif /* SIGNAL_DEBUG */
+
        /*
         *      We will need the task pointer later.  Grab it now to
         *      check for a zombie process.  Also don't send signals
         *      to kernel internal tasks.
         */
-       if (((sig_task = p->task) == TASK_NULL)  || is_kerneltask(sig_task))
+       if (((sig_task = p->task) == TASK_NULL)  || is_kerneltask(sig_task)) {
                return;
+       }
 
+       sig_thread_act = thr_act;
        /*
         * do not send signals to the process that has the thread
         * doing a reboot(). Not doing so will mark that thread aborted
         * and can cause IO failures wich will cause data loss.
         */
-       if (ISSET(p->p_flag, P_REBOOT))
+       if (ISSET(p->p_flag, P_REBOOT)) {
                return;
+       }
 
-       /* 
-        * if the traced process is blocked waiting for
-        * gdb then do not block the caller just pend 
-        * the signal. Setup a callout  to process the
-        * pended signal if not alreadu set
+       signal_lock(p);
+
+       /*
+        *      Deliver the signal to the first thread in the task. This
+        *      allows single threaded applications which use signals to
+        *      be able to be linked with multithreaded libraries.  We have
+        *      an implicit reference to the current_thread, but need
+        *      an explicit one otherwise.  The thread reference keeps
+        *      the corresponding task data structures around too.  This
+        *      reference is released by thread_deallocate.
         */
-       if (pend && (p->p_flag & P_TRACED) && p->sigwait) {
-               p->p_sigpending |= mask;
-               if (!(p->p_flag & P_SIGTHR)) {
-                       p->p_flag |= P_SIGTHR;
-                       thread_call_func((thread_call_func_t)psignal_pend, p,
-                        FALSE);
-               }
-               return;
+       
+       if (((p->p_flag & P_TRACED) == 0) && (p->p_sigignore & mask))
+               goto puthout;
+
+       cur_thread = current_thread();   /* this is a shuttle */
+       cur_act = current_act();
+        
+       kret = check_actforsig(sig_task, sig_thread_act, &sig_thread, 1);
+
+       if (kret != KERN_SUCCESS) {
+               error = EINVAL;
+               goto puthout;
        }
 
-       if (withlock)
-               signal_lock(p);
+
+       uth = get_bsdthread_info(sig_thread_act);
 
        /*
         * If proc is traced, always give parent a chance.
@@ -973,8 +1805,10 @@ psignal_lock(p, signum, withlock, pend)
                 * action will be SIG_DFL here.)
                 */
                if (p->p_sigignore & mask)
-                       goto psigout;
-               if (p->p_sigmask & mask)
+                       goto puthout;
+               if (uth->uu_sigwait & mask)
+                       action = SIG_WAIT;
+               if (uth->uu_sigmask & mask)
                        action = SIG_HOLD;
                else if (p->p_sigcatch & mask)
                        action = SIG_CATCH;
@@ -986,8 +1820,10 @@ psignal_lock(p, signum, withlock, pend)
                (p->p_flag & P_TRACED) == 0)
                p->p_nice = NZERO;
 
-       if (prop & SA_CONT)
+       if (prop & SA_CONT) {
+               uth->uu_siglist &= ~stopsigmask;
                p->p_siglist &= ~stopsigmask;
+       }
 
        if (prop & SA_STOP) {
                /*
@@ -998,55 +1834,20 @@ psignal_lock(p, signum, withlock, pend)
                 */
                if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 &&
                        action == SIG_DFL)
-                       goto psigout;
+                       goto puthout;
+               uth->uu_siglist &= ~contsigmask;
                p->p_siglist &= ~contsigmask;
        }
-       p->p_siglist |= mask;
+       uth->uu_siglist |= mask;
+       p->p_siglist |= mask;   /* just for lame ones looking here */
 
        /*
         * Defer further processing for signals which are held,
         * except that stopped processes must be continued by SIGCONT.
         */
        if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP))
-               goto psigout;
+               goto puthout;
                
-       /*
-        *      Deliver the signal to the first thread in the task. This
-        *      allows single threaded applications which use signals to
-        *      be able to be linked with multithreaded libraries.  We have
-        *      an implicit reference to the current_thread, but need
-        *      an explicit one otherwise.  The thread reference keeps
-        *      the corresponding task data structures around too.  This
-        *      reference is released by thread_deallocate.
-        */
-       
-       cur_thread = current_thread();   /* this is a shuttle */
-       cur_act = current_act();
-        
-       /* If successful return with ast set */
-       kret = (kern_return_t)get_signalact(sig_task, 
-                               &sig_thread_act, &sig_thread, 1);
-
-       if ((kret != KERN_SUCCESS) || (sig_thread_act == THREAD_NULL)) {
-               /* XXXX FIXME
-               /* if it is sigkill, may be we should
-                * inject a thread to terminate
-                */
-               printf("WARNING: no activation in psignal\n");
-#if SIGNAL_DEBUG
-                ram_printf(1);
-#endif /* SIGNAL_DEBUG */
-               goto psigout;
-       }
-
-       if (sig_thread == THREAD_NULL) {
-               printf("WARNING: valid act; but no shutte in psignal\n");
-#if 0
-               /* FIXME : NO VALID SHUTTLE */
-               goto psigout;
-#endif
-       }
-
        /*
         *      SIGKILL priority twiddling moved here from above because
         *      it needs sig_thread.  Could merge it into large switch
@@ -1055,12 +1856,6 @@ psignal_lock(p, signum, withlock, pend)
         */
        if ((signum == SIGKILL) && (p->p_nice > NZERO)) {
                p->p_nice = NZERO;
-#if XXX
-               /*
-                * we need to make changes here to get nice to work 
-                * reset priority to BASEPRI_USER
-                */
-#endif
        }
 
        /*
@@ -1070,9 +1865,20 @@ psignal_lock(p, signum, withlock, pend)
         */
        if (p->p_flag & P_TRACED) {
                if (p->p_stat != SSTOP)
-                       goto run;
+                       goto psurun;
                else
-                       goto psigout;
+                       goto puthout;
+       }
+
+       if (action == SIG_WAIT) {
+               uth->uu_sigwait = mask;
+               uth->uu_siglist &= ~mask;
+               p->p_siglist &= ~mask;
+               wakeup(&uth->uu_sigwait);
+               /* if it is SIGCONT resume whole process */
+               if (prop & SA_CONT)
+                       (void) task_resume(sig_task);
+               goto puthout;
        }
 
        if (action != SIG_DFL) {
@@ -1083,7 +1889,7 @@ psignal_lock(p, signum, withlock, pend)
                 */
                if (prop & SA_CONT)
                        (void) task_resume(sig_task);
-               goto run;
+               goto psurun;
        } else {
                /*      Default action - varies */
                if (mask & stopsigmask) {
@@ -1095,44 +1901,33 @@ psignal_lock(p, signum, withlock, pend)
                         * stopped from the keyboard.
                         */
                        if (!(prop & SA_STOP) && p->p_pptr == initproc) {
-                               psignal_lock(p, SIGKILL, 0, 1);
+                               psignal_lock(p, SIGKILL, 0);
+                               uth->uu_siglist &= ~mask;
                                p->p_siglist &= ~mask;
-                               goto psigout;
+                               goto puthout;
                        }
                         
                        /*
-                        *      Stop the task.
+                        *      Stop the task
+                        *      if task hasn't already been stopped by
+                        *      a signal.
                         */
-                       if (!is_thread_running(sig_thread)) {
-                               /*  Thread is not running 
-                                *      If task hasn't already been stopped by
-                                *      a signal, stop it.
-                                */
-                               p->p_siglist &= ~mask;
-                               if (get_task_userstop(sig_task) == 0) {
-                                       /*
-                                        * p_cursig must not be set, because
-                                        * it will be psig()'d if it is not
-                                        * zero, and the signal is being
-                                        * handled here.  But save the signal
-                                        * in p_stopsig so WUNTRACED
-                                        * option to wait can find it.
-                                        */
-                                       p->p_xstat = signum;
-                                       if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
-                                               psignal(p->p_pptr, SIGCHLD);
-                                       stop(p);
+                       uth->uu_siglist &= ~mask;
+                       p->p_siglist &= ~mask;
+                       if (p->p_stat != SSTOP) {
+                               p->p_xstat = signum;
+                               if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) {
+                                       struct proc *pp = p->p_pptr;
+
+                                       pp->si_pid = p->p_pid;
+                                       pp->si_status = p->p_xstat;
+                                       pp->si_code = CLD_STOPPED;
+                                       pp->si_uid = p->p_cred->p_ruid;
+                                       psignal(pp, SIGCHLD);
                                }
-#if 0
-                               /* unconditional check is bad */
-                               signal_clearast(sig_thread_act);
-#endif
-                               goto psigout;
-                       } else {
-                               if (p->p_stat != SZOMB) 
-                                       signal_setast(cur_act);
-                               goto psigout;
+                               stop(p);
                        }
+                       goto puthout;
                }
 
                switch (signum) {
@@ -1154,7 +1949,7 @@ psignal_lock(p, signum, withlock, pend)
 
                        thread_abort(sig_thread_act);
 
-                       goto psigout;
+                       goto puthout;
 
                case SIGCONT:
                        /*
@@ -1167,50 +1962,44 @@ psignal_lock(p, signum, withlock, pend)
                        } else {
                                (void) task_resume(sig_task);
                        }
+                       uth->uu_siglist &= ~mask;
                        p->p_siglist &= ~mask;
                        p->p_stat = SRUN;
-#if 0
-                       /* do not clear AST as tcsh is sendig SIGTERM followed by 
-                        * SIGCONT and the ast was getting cleared unconditinally
-                        * This is not right.
-                        */
-                       signal_clearast(sig_thread_act);
-#endif
-                       goto psigout;
+                       goto puthout;
 
                default:
                        /*
                         * All other signals wake up the process, but don't
                         * resume it.
                         */
-                       goto run;
+                       goto psurun;
                }
        }
        /*NOTREACHED*/
-run:
+psurun:
        /*
         * If we're being traced (possibly because someone attached us
         * while we were stopped), check for a signal from the debugger.
         */
        if (p->p_stat == SSTOP) {
-               if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0)
+               if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) {
+                       uth->uu_siglist |= sigmask(p->p_xstat); 
                        p->p_siglist |= sigmask(p->p_xstat); 
+               }
+       } else {
+               /*
+                * setrunnable(p) in BSD and
+                * Wake up the thread if it is interruptible.
+                */
+               p->p_stat = SRUN;
+               thread_abort_safely(sig_thread_act);
        }
 
-       /*
-        * setrunnable(p) in BSD
-        */
-       p->p_stat = SRUN;
-
-       /*
-        *      Wake up the thread if it is interruptible.
-        */
-       thread_abort_safely(sig_thread_act);
-psigout:
-       if (withlock) 
+puthout:
                signal_unlock(p);
 }
 
+
 __inline__ void
 sig_lock_to_exit(
        struct proc     *p)
@@ -1242,7 +2031,7 @@ sig_try_locked(
                                        (THREAD_INTERRUPTIBLE));
                }
                signal_unlock(p);
-               thread_block(0);
+               thread_block(THREAD_CONTINUE_NULL);
                signal_lock(p);
                if (thread_should_abort(self)) {
                        /*
@@ -1277,13 +2066,18 @@ issignal(p)
        int     s;
        struct uthread * ut;
        kern_return_t kret;
+       struct proc *pp;
 
        cur_thread = current_thread();
        cur_act = current_act();
 
+#if SIGNAL_DEBUG
+        if(rdebug_proc && (p == rdebug_proc)) {
+                ram_printf(3);
+        }
+#endif /* SIGNAL_DEBUG */
        signal_lock(p);
 
-
        /*
         * Try to grab the signal lock.
         */
@@ -1294,7 +2088,7 @@ issignal(p)
 
        ut = get_bsdthread_info(cur_act);
        for(;;) {
-               sigbits = (ut->uu_sig |p->p_siglist) & ~p->p_sigmask;
+               sigbits = ut->uu_siglist  & ~ut->uu_sigmask;
 
                if (p->p_flag & P_PPWAIT)
                        sigbits &= ~stopsigmask;
@@ -1306,20 +2100,16 @@ issignal(p)
                mask = sigmask(signum);
                prop = sigprop[signum];
 
-               if (mask & threadmask) {
-                       /* we can take this signal */
-                       ut->uu_sig &= ~mask;
-               } 
-
                /*
                 * We should see pending but ignored signals
                 * only if P_TRACED was on when they were posted.
                 */
                if (mask & p->p_sigignore && (p->p_flag & P_TRACED) == 0) {
+                       ut->uu_siglist &= ~mask;                /* take the signal! */
                        p->p_siglist &= ~mask;          /* take the signal! */
                        continue;
                }
-               if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) {
+               if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0)  {
                        register int    hold;
                        register task_t task;
                        /*
@@ -1328,25 +2118,46 @@ issignal(p)
                         */
                        /* ptrace debugging */
                        p->p_xstat = signum;
-                       psignal(p->p_pptr, SIGCHLD);
-                       /*
-                        *      XXX Have to really stop for debuggers;
-                        *      XXX stop() doesn't do the right thing.
-                        *      XXX Inline the task_suspend because we
-                        *      XXX have to diddle Unix state in the
-                        *      XXX middle of it.
-                        */
-                       task = p->task;
-                        task_hold(task);
-                       p->sigwait = TRUE;
-                       p->sigwait_thread = cur_act;
-                       p->p_stat = SSTOP;
-                       p->p_flag &= ~P_WAITED;
-                       p->p_siglist &= ~mask;  /* clear the old signal */
-
-                       wakeup((caddr_t)p->p_pptr);
-                       assert_wait((caddr_t)&p->sigwait, (THREAD_INTERRUPTIBLE));
-                       thread_block(0);
+                       pp = p->p_pptr;
+                       if (p->p_flag & P_SIGEXC) {
+                               p->sigwait = TRUE;
+                               p->sigwait_thread = cur_act;
+                               p->p_stat = SSTOP;
+                               p->p_flag &= ~P_WAITED;
+                               ut->uu_siglist &= ~mask;        /* clear the old signal */
+                               p->p_siglist &= ~mask;  /* clear the old signal */
+                               signal_unlock(p);
+                               do_bsdexception(EXC_SOFTWARE, EXC_SOFT_SIGNAL, signum);
+                               signal_lock(p);
+                       } else {
+                               pp->si_pid = p->p_pid;
+                               pp->si_status = p->p_xstat;
+                               pp->si_code = CLD_TRAPPED;
+                               pp->si_uid = p->p_cred->p_ruid;
+                               psignal(pp, SIGCHLD);
+                               /*
+                               *       XXX Have to really stop for debuggers;
+                               *       XXX stop() doesn't do the right thing.
+                               *       XXX Inline the task_suspend because we
+                               *       XXX have to diddle Unix state in the
+                               *       XXX middle of it.
+                               */
+                               task = p->task;
+                               task_hold(task);
+                               p->sigwait = TRUE;
+                               p->sigwait_thread = cur_act;
+                               p->p_stat = SSTOP;
+                               p->p_flag &= ~P_WAITED;
+                               ut->uu_siglist &= ~mask;        /* clear the old signal */
+                               p->p_siglist &= ~mask;  /* clear the old signal */
+
+                               wakeup((caddr_t)p->p_pptr);
+                               signal_unlock(p);
+                               assert_wait((caddr_t)&p->sigwait, (THREAD_INTERRUPTIBLE));
+                               thread_block(THREAD_CONTINUE_NULL);
+                               signal_lock(p);
+                       }
+
                        p->sigwait = FALSE;
                        p->sigwait_thread = NULL;
                        wakeup((caddr_t)&p->sigwait_thread);
@@ -1357,7 +2168,7 @@ issignal(p)
                         * pgsignal would get the SIGKILL to traced program
                         * That's what we are trying to see (I hope)
                         */
-                       if (p->p_siglist & sigmask(SIGKILL)) {
+                       if (ut->uu_siglist & sigmask(SIGKILL)) {
                                /*
                                 * Wait event may still be outstanding;
                                 * clear it, since sig_lock_to_exit will
@@ -1373,7 +2184,7 @@ issignal(p)
                                * calls closef() which can trash u_qsave.)
                                */
                                signal_unlock(p);
-                               exit1(p,signum);
+                               exit1(p,signum, (int *)NULL);
                                return(0);
                        }
 
@@ -1397,11 +2208,9 @@ issignal(p)
                         * signal is being masked, look for other signals.
                         */
                        mask = sigmask(signum);
-                       if (mask & threadmask)
-                               ut->uu_sig |= mask;
-                       else
-                               p->p_siglist |= mask;
-                       if (p->p_sigmask & mask)
+                       ut->uu_siglist |= mask;
+                       p->p_siglist |= mask;   /* just for lame ones looking here */
+                       if (ut->uu_sigmask & mask)
                                continue;
                }
 
@@ -1441,17 +2250,17 @@ issignal(p)
                                        (p->p_pgrp->pg_jobc == 0 &&
                                        prop & SA_TTYSTOP))
                                        break;  /* == ignore */
-                               p->p_xstat = signum;
-                               stop(p);
-                               if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
-                                       psignal(p->p_pptr, SIGCHLD);
-                               thread_block(0);
-                               /*
-                                *      We may have to quit
-                                */
-                               if (thread_should_abort(current_thread())) {
-                                       signal_unlock(p);
-                                       return(0);
+                               if (p->p_stat != SSTOP) {
+                                       p->p_xstat = signum;
+                                       stop(p);
+                                       if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) {
+                                               pp = p->p_pptr;
+                                               pp->si_pid = p->p_pid;
+                                               pp->si_status = p->p_xstat;
+                                               pp->si_code = CLD_STOPPED;
+                                               pp->si_uid = p->p_cred->p_ruid;
+                                               psignal(pp, SIGCHLD);
+                                       }
                                }
                                break;
                        } else if (prop & SA_IGNORE) {
@@ -1461,6 +2270,8 @@ issignal(p)
                                 */
                                break;          /* == ignore */
                        } else {
+                               ut->uu_siglist &= ~mask;        /* take the signal! */
+                               p->p_siglist &= ~mask;  /* take the signal! */
                                signal_unlock(p);
                                return (signum);
                        }
@@ -1482,11 +2293,13 @@ issignal(p)
                         * This signal has an action, let
                         * postsig() process it.
                         */
+                       ut->uu_siglist &= ~mask;                /* take the signal! */
+                       p->p_siglist &= ~mask;          /* take the signal! */
                        signal_unlock(p);
                        return (signum);
                }
+               ut->uu_siglist &= ~mask;                /* take the signal! */
                p->p_siglist &= ~mask;          /* take the signal! */
-               p->p_sigpending &= ~mask;       /* take the pending signal */
                }
        /* NOTREACHED */
 }
@@ -1504,18 +2317,19 @@ CURSIG(p)
        struct uthread * ut;
        int retnum = 0;
            
-       if (p->p_siglist == 0)
-               return (0);
-
-       if (((p->p_siglist & ~p->p_sigmask) == 0) && ((p->p_flag & P_TRACED) == 0))
-               return (0);
 
        cur_thread = current_thread();
        cur_act = current_act();
 
        ut = get_bsdthread_info(cur_act);
 
-       sigbits = (ut->uu_sig | p->p_siglist) & ~p->p_sigmask;
+       if (ut->uu_siglist == 0)
+               return (0);
+
+       if (((ut->uu_siglist & ~ut->uu_sigmask) == 0) && ((p->p_flag & P_TRACED) == 0))
+               return (0);
+
+       sigbits = ut->uu_siglist & ~ut->uu_sigmask;
 
        for(;;) {
                if (p->p_flag & P_PPWAIT)
@@ -1541,7 +2355,7 @@ CURSIG(p)
                         * signal is being masked, look for other signals.
                         */
                        mask = sigmask(signum);
-                       if (p->p_sigmask & mask)
+                       if (ut->uu_sigmask & mask)
                                continue;
                        return(signum);
                }
@@ -1646,6 +2460,7 @@ postsig(signum)
        register sig_t action;
        u_long code;
        int mask, returnmask;
+       struct uthread * ut;
 
 #if DIAGNOSTIC
        if (signum == 0)
@@ -1662,18 +2477,20 @@ postsig(signum)
         * Try to grab the signal lock.
         */
        if (sig_try_locked(p) <= 0) {
-                signal_unlock(p);
+               signal_unlock(p);
                return;
        }
 
+       ut = (struct uthread *)get_bsdthread_info(current_act());
        mask = sigmask(signum);
+       ut->uu_siglist &= ~mask;
        p->p_siglist &= ~mask;
        action = ps->ps_sigact[signum];
 #if KTRACE
        if (KTRPOINT(p, KTR_PSIG))
                ktrpsig(p->p_tracep,
-                   signum, action, ps->ps_flags & SAS_OLDMASK ?
-                   ps->ps_oldmask : p->p_sigmask, 0);
+                   signum, action, ut->uu_flag & USAS_OLDMASK ?
+                   &ut->uu_oldmask : &ut->uu_sigmask, 0, -1);
 #endif
        if (action == SIG_DFL) {
                /*
@@ -1689,7 +2506,7 @@ postsig(signum)
                 * If we get here, the signal must be caught.
                 */
 #if DIAGNOSTIC
-               if (action == SIG_IGN || (p->p_sigmask & mask))
+               if (action == SIG_IGN || (ut->uu_sigmask & mask))
                        log(LOG_WARNING,
                                "postsig: processing masked or ignored signal\n");
 #endif
@@ -1702,12 +2519,29 @@ postsig(signum)
                 * mask from before the sigpause is what we want
                 * restored after the signal processing is completed.
                 */
-               if (ps->ps_flags & SAS_OLDMASK) {
-                       returnmask = ps->ps_oldmask;
-                       ps->ps_flags &= ~SAS_OLDMASK;
+               if (ut->uu_flag & USAS_OLDMASK) {
+                       returnmask = ut->uu_oldmask;
+                       ut->uu_flag &= ~USAS_OLDMASK;
+                       ut->uu_oldmask = 0;
                } else
-                       returnmask = p->p_sigmask;
-               p->p_sigmask |= ps->ps_catchmask[signum] | mask;
+                       returnmask = ut->uu_sigmask;
+               ut->uu_sigmask |= ps->ps_catchmask[signum];
+               if ((ps->ps_signodefer & mask) == 0)
+                       ut->uu_sigmask |= mask;
+               if ((signum != SIGILL) && (signum != SIGTRAP) && (ps->ps_sigreset & mask)) {
+                       if ((signum != SIGCONT) && (sigprop[signum] & SA_IGNORE))
+                               p->p_sigignore |= mask;
+                       ps->ps_sigact[signum] = SIG_DFL;
+                       ps->ps_siginfo &= ~mask;
+                       ps->ps_signodefer &= ~mask;
+               }
+#ifdef __ppc__
+               /* Needs to disable to run in user mode */
+               if (signum == SIGFPE) {
+                       thread_enable_fpe(current_act(), 0);
+               }
+#endif  /* __ppc__ */
+
                if (ps->ps_sig != signum) {
                        code = 0;
                } else {
@@ -1743,7 +2577,7 @@ sigexit_locked(p, signum)
                        signum |= WCOREFLAG;
        }
        signal_unlock(p);
-       exit1(p, W_EXITCODE(0, signum));
+       exit1(p, W_EXITCODE(0, signum), (int *)NULL);
        /* NOTREACHED */
 }
 
@@ -1755,6 +2589,7 @@ bsd_ast(thread_act_t thr_act)
        int     signum;
        unsigned int pc;
        boolean_t funnel_state;
+       static bsd_init_done = 0;
 
        if (p == NULL)
                return;
@@ -1771,7 +2606,12 @@ bsd_ast(thread_act_t thr_act)
                while (signum = issignal(p))
                        postsig(signum);
        }
-       ast_off(AST_BSD);
+       if (!bsd_init_done) {
+               extern void     bsdinit_task(void);
+
+               bsd_init_done = 1;
+               bsdinit_task();
+       }
 
        (void) thread_funnel_set(kernel_flock, FALSE);
 }
@@ -1788,7 +2628,7 @@ psignal_vtalarm(struct proc *p)
        if (p == NULL)
                return;
        funnel_state = thread_funnel_set(kernel_flock, TRUE);
-       psignal_lock(p, SIGVTALRM, 1, 1);
+       psignal_lock(p, SIGVTALRM, 1);
        (void) thread_funnel_set(kernel_flock, FALSE);
 }
 
@@ -1800,7 +2640,7 @@ psignal_xcpu(struct proc *p)
        if (p == NULL)
                return;
        funnel_state = thread_funnel_set(kernel_flock, TRUE);
-       psignal_lock(p, SIGXCPU, 1, 1);
+       psignal_lock(p, SIGXCPU, 1);
        (void) thread_funnel_set(kernel_flock, FALSE);
 }
 
@@ -1812,7 +2652,7 @@ psignal_sigprof(struct proc *p)
        if (p == NULL)
                return;
        funnel_state = thread_funnel_set(kernel_flock, TRUE);
-       psignal_lock(p, SIGPROF, 1, 1);
+       psignal_lock(p, SIGPROF, 1);
        (void) thread_funnel_set(kernel_flock, FALSE);
 }
 
@@ -1832,3 +2672,18 @@ task_t task;
                }
        }
 }
+
+kern_return_t
+do_bsdexception(
+           int exc,
+           int code,
+           int sub)
+{
+       exception_data_type_t   codes[EXCEPTION_CODE_MAX];
+       extern kern_return_t bsd_exception(int, exception_data_type_t codes[], int);
+
+       codes[0] = code;        
+       codes[1] = sub;
+       return(bsd_exception(exc, codes, 2));
+}
+