+
+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;
+ 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, 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, 1) == KERN_SUCCESS)
+ return(uth->uu_act);
+ }
+ }
+ if (get_signalact(p->task, &thr_act, 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;
+ register task_t sig_task;
+ 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;
+ }
+
+ s = splhigh();
+ KNOTE(&p->p_klist, NOTE_SIGNAL | signum);
+ splx(s);
+
+ /*
+ * 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;
+
+ /* 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) {
+ if (p->p_flag & P_TTYSLEEP) {
+ p->p_flag &= ~P_TTYSLEEP;
+ wakeup(&p->p_siglist);
+ } else {
+ (void) task_resume(sig_task);
+ }
+ p->p_stat = SRUN;
+ } else if (p->p_stat == SSTOP)
+ goto psigout;
+ 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.
+ */