From 788b1fc17a2f0aba5c55ff68bf407ac8e137eafa Mon Sep 17 00:00:00 2001 From: davidxu Date: Sat, 28 Jun 2003 08:29:05 +0000 Subject: o Change kse_thr_interrupt to allow send a signal to a specified thread, or unblock a thread in kernel, and allow UTS to specify whether syscall should be restarted. o Add ability for UTS to monitor signal comes in and removed from process, the flag PS_SIGEVENT is used to indicate the events. o Add a KMF_WAITSIGEVENT for KSE mailbox flag, UTS call kse_release with this flag set to wait for above signal event. o For SA based thread, kernel masks all signal in its signal mask, let UTS to use kse_thr_interrupt interrupt a thread, and install a signal frame in userland for the thread. o Add a tm_syncsig in thread mailbox, when a hardware trap occurs, it is used to deliver synchronous signal to userland, and upcall is schedule, so UTS can process the synchronous signal for the thread. Reviewed by: julian (mentor) --- sys/kern/kern_kse.c | 177 ++++++++++++++++++++++++++++++++--------------- sys/kern/kern_sig.c | 96 ++++++++++++++++++++++--- sys/kern/kern_synch.c | 18 ++--- sys/kern/kern_thread.c | 177 ++++++++++++++++++++++++++++++++--------------- sys/kern/subr_trap.c | 17 +---- sys/kern/syscalls.master | 2 +- sys/sys/kse.h | 5 +- sys/sys/proc.h | 10 +-- sys/sys/sysproto.h | 1 + 9 files changed, 354 insertions(+), 149 deletions(-) diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c index 7695643..2545fe6 100644 --- a/sys/kern/kern_kse.c +++ b/sys/kern/kern_kse.c @@ -384,6 +384,7 @@ proc_linkup(struct proc *p, struct ksegrp *kg, /* struct kse_thr_interrupt_args { struct kse_thr_mailbox * tmbx; + int sig; }; */ int @@ -391,26 +392,48 @@ kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap) { struct proc *p; struct thread *td2; + int sig = uap->sig; p = td->td_proc; - if (!(p->p_flag & P_SA) || (uap->tmbx == NULL)) + if (!(p->p_flag & P_SA) || (uap->tmbx == NULL) || + (sig < -2) || (sig > _SIG_MAXSIG)) return (EINVAL); + + PROC_LOCK(p); mtx_lock_spin(&sched_lock); FOREACH_THREAD_IN_PROC(p, td2) { - if (td2->td_mailbox == uap->tmbx) { - td2->td_flags |= TDF_INTERRUPT; - if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) { - if (td2->td_flags & TDF_CVWAITQ) - cv_abort(td2); - else - abortsleep(td2); - } - mtx_unlock_spin(&sched_lock); - return (0); + if (td2->td_mailbox == uap->tmbx) + break; + } + if (td2 == NULL) { + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + return (ESRCH); + } + if (sig > 0) { + td2->td_flags &= ~TDF_INTERRUPT; + mtx_unlock_spin(&sched_lock); + tdsignal(td2, sig); + } else if (sig == 0) { + mtx_unlock_spin(&sched_lock); + } else { + td2->td_flags |= TDF_INTERRUPT | TDF_ASTPENDING; + if (TD_CAN_UNBIND(td2)) + td->td_upcall->ku_flags |= KUF_DOUPCALL; + if (sig == -1) + td2->td_intrval = EINTR; + else if (sig == -2) + td2->td_intrval = ERESTART; + if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) { + if (td2->td_flags & TDF_CVWAITQ) + cv_abort(td2); + else + abortsleep(td2); } + mtx_unlock_spin(&sched_lock); } - mtx_unlock_spin(&sched_lock); - return (ESRCH); + PROC_UNLOCK(p); + return (0); } /* @@ -488,6 +511,7 @@ kse_release(struct thread *td, struct kse_release_args *uap) struct kse_upcall *ku; struct timespec timeout; struct timeval tv; + sigset_t sigset; int error; p = td->td_proc; @@ -501,19 +525,39 @@ kse_release(struct thread *td, struct kse_release_args *uap) } if (td->td_flags & TDF_SA) td->td_pflags |= TDP_UPCALLING; + else { + ku->ku_mflags = fuword(&ku->ku_mailbox->km_flags); + if (ku->ku_mflags == -1) { + PROC_LOCK(p); + sigexit(td, SIGSEGV); + } + } PROC_LOCK(p); - if ((ku->ku_flags & KUF_DOUPCALL) == 0 && (kg->kg_completed == NULL)) { - kg->kg_upsleeps++; - error = msleep(&kg->kg_completed, &p->p_mtx, PPAUSE|PCATCH, - "kserel", (uap->timeout ? tvtohz(&tv) : 0)); - kg->kg_upsleeps--; + if (ku->ku_mflags & KMF_WAITSIGEVENT) { + /* UTS wants to wait for signal event */ + if (!(p->p_flag & P_SIGEVENT) && !(ku->ku_flags & KUF_DOUPCALL)) + error = msleep(&p->p_siglist, &p->p_mtx, PPAUSE|PCATCH, + "ksesigwait", (uap->timeout ? tvtohz(&tv) : 0)); + p->p_flag &= ~P_SIGEVENT; + sigset = p->p_siglist; + PROC_UNLOCK(p); + error = copyout(&sigset, &ku->ku_mailbox->km_sigscaught, + sizeof(sigset)); + } else { + if (! kg->kg_completed && !(ku->ku_flags & KUF_DOUPCALL)) { + kg->kg_upsleeps++; + error = msleep(&kg->kg_completed, &p->p_mtx, + PPAUSE|PCATCH, "kserel", + (uap->timeout ? tvtohz(&tv) : 0)); + kg->kg_upsleeps--; + } + PROC_UNLOCK(p); } if (ku->ku_flags & KUF_DOUPCALL) { mtx_lock_spin(&sched_lock); ku->ku_flags &= ~KUF_DOUPCALL; mtx_unlock_spin(&sched_lock); } - PROC_UNLOCK(p); return (0); } @@ -559,7 +603,9 @@ kse_wakeup(struct thread *td, struct kse_wakeup_args *uap) if ((td2 = ku->ku_owner) == NULL) { panic("%s: no owner", __func__); } else if (TD_ON_SLEEPQ(td2) && - (td2->td_wchan == &kg->kg_completed)) { + ((td2->td_wchan == &kg->kg_completed) || + (td2->td_wchan == &p->p_siglist && + (ku->ku_mflags & KMF_WAITSIGEVENT)))) { abortsleep(td2); } else { ku->ku_flags |= KUF_DOUPCALL; @@ -698,12 +744,20 @@ kse_create(struct thread *td, struct kse_create_args *uap) if (td->td_standin == NULL) thread_alloc_spare(td, NULL); - mtx_lock_spin(&sched_lock); + PROC_LOCK(p); if (newkg->kg_numupcalls >= ncpus) { - mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); upcall_free(newku); return (EPROCLIM); } + if (first) { + SIGSETOR(p->p_siglist, td->td_siglist); + SIGEMPTYSET(td->td_siglist); + SIGFILLSET(td->td_sigmask); + SIG_CANTMASK(td->td_sigmask); + } + mtx_lock_spin(&sched_lock); + PROC_UNLOCK(p); upcall_link(newku, newkg); if (mbx.km_quantum) newkg->kg_upquantum = max(1, mbx.km_quantum/tick); @@ -943,7 +997,7 @@ thread_export_context(struct thread *td) struct ksegrp *kg; uintptr_t mbx; void *addr; - int error = 0, temp; + int error = 0, temp, sig; mcontext_t mc; p = td->td_proc; @@ -964,6 +1018,23 @@ thread_export_context(struct thread *td) goto bad; } + /* + * Post sync signal, or process SIGKILL and SIGSTOP. + * For sync signal, it is only possible when the signal is not + * caught by userland or process is being debugged. + */ + if (td->td_flags & TDF_NEEDSIGCHK) { + mtx_lock_spin(&sched_lock); + td->td_flags &= ~TDF_NEEDSIGCHK; + mtx_unlock_spin(&sched_lock); + PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); + while ((sig = cursig(td)) != 0) + postsig(sig); + mtx_unlock(&p->p_sigacts->ps_mtx); + PROC_UNLOCK(p); + } + /* Get address in latest mbox of list pointer */ addr = (void *)(&td->td_mailbox->tm_next); /* @@ -1399,52 +1470,39 @@ thread_schedule_upcall(struct thread *td, struct kse_upcall *ku) td2->td_kse = NULL; td2->td_state = TDS_CAN_RUN; td2->td_inhibitors = 0; + SIGFILLSET(td2->td_sigmask); + SIG_CANTMASK(td2->td_sigmask); return (td2); /* bogus.. should be a void function */ } +/* + * It is only used when thread generated a trap and process is being + * debugged. + */ void thread_signal_add(struct thread *td, int sig) { - struct kse_upcall *ku; struct proc *p; - sigset_t ss; + siginfo_t siginfo; + struct sigacts *ps; int error; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); - mtx_assert(&p->p_sigacts->ps_mtx, MA_OWNED); - td = curthread; - ku = td->td_upcall; - mtx_unlock(&p->p_sigacts->ps_mtx); - PROC_UNLOCK(p); - error = copyin(&ku->ku_mailbox->km_sigscaught, &ss, sizeof(sigset_t)); - if (error) - goto error; - - SIGADDSET(ss, sig); - - error = copyout(&ss, &ku->ku_mailbox->km_sigscaught, sizeof(sigset_t)); - if (error) - goto error; + ps = p->p_sigacts; + mtx_assert(&ps->ps_mtx, MA_OWNED); + thread_siginfo(sig, 0, &siginfo); + mtx_unlock(&ps->ps_mtx); + PROC_UNLOCK(p); + error = copyout(&siginfo, &td->td_mailbox->tm_syncsig, sizeof(siginfo)); + if (error) { + PROC_LOCK(p); + sigexit(td, SIGILL); + } PROC_LOCK(p); - mtx_lock(&p->p_sigacts->ps_mtx); - return; -error: - PROC_LOCK(p); - sigexit(td, SIGILL); -} - -/* - * Schedule an upcall to notify a KSE process recieved signals. - * - */ -void -thread_signal_upcall(struct thread *td) -{ - td->td_pflags |= TDP_UPCALLING; - - return; + SIGADDSET(td->td_sigmask, sig); + mtx_lock(&ps->ps_mtx); } void @@ -1623,6 +1681,13 @@ thread_userret(struct thread *td, struct trapframe *frame) */ td->td_pflags |= TDP_UPCALLING; } else if (td->td_mailbox && (ku == NULL)) { + /* + * Because we are exiting, SIGKILL and SIGSTOP shouldn't + * be posted to us anymore, otherwise they will be lost. + */ + mtx_lock_spin(&sched_lock); + td->td_flags |= TDF_NOSIGPOST; + mtx_unlock_spin(&sched_lock); error = thread_export_context(td); /* possibly upcall with error? */ PROC_LOCK(p); diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index b2ce6a8..7f5ef68 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -94,6 +95,7 @@ static int filt_signal(struct knote *kn, long hint); static struct thread *sigtd(struct proc *p, int sig, int prop); static int kern_sigtimedwait(struct thread *td, sigset_t set, siginfo_t *info, struct timespec *timeout); +static void do_tdsignal(struct thread *td, int sig); struct filterops sig_filtops = { 0, filt_sigattach, filt_sigdetach, filt_signal }; @@ -197,7 +199,7 @@ void signotify(struct thread *td) { struct proc *p; - sigset_t set; + sigset_t set, saved; p = td->td_proc; @@ -208,6 +210,8 @@ signotify(struct thread *td) * previously masked by all threads to our siglist. */ set = p->p_siglist; + if (p->p_flag & P_SA) + saved = p->p_siglist; SIGSETNAND(set, td->td_sigmask); SIGSETNAND(p->p_siglist, set); SIGSETOR(td->td_siglist, set); @@ -217,6 +221,15 @@ signotify(struct thread *td) td->td_flags |= TDF_NEEDSIGCHK | TDF_ASTPENDING; mtx_unlock_spin(&sched_lock); } + if ((p->p_flag & P_SA) && !(p->p_flag & P_SIGEVENT)) { + if (SIGSETEQ(saved, p->p_siglist)) + return; + else { + /* pending set changed */ + p->p_flag |= P_SIGEVENT; + wakeup(&p->p_siglist); + } + } } int @@ -375,6 +388,11 @@ kern_sigaction(td, sig, act, oact, flags) if (ps->ps_sigact[_SIG_IDX(sig)] == SIG_IGN || (sigprop(sig) & SA_IGNORE && ps->ps_sigact[_SIG_IDX(sig)] == SIG_DFL)) { + if ((p->p_flag & P_SA) && + SIGISMEMBER(p->p_siglist, sig)) { + p->p_flag |= P_SIGEVENT; + wakeup(&p->p_siglist); + } /* never to be seen again */ SIGDELSET(p->p_siglist, sig); FOREACH_THREAD_IN_PROC(p, td0) @@ -776,6 +794,7 @@ sigtimedwait(struct thread *td, struct sigtimedwait_args *uap) error = kern_sigtimedwait(td, set, &info, timeout); if (error) return (error); + if (uap->info) error = copyout(&info, uap->info, sizeof(info)); /* Repost if we got an error. */ @@ -784,7 +803,7 @@ sigtimedwait(struct thread *td, struct sigtimedwait_args *uap) tdsignal(td, info.si_signo); PROC_UNLOCK(td->td_proc); } else { - td->td_retval[0] = info.si_signo; + td->td_retval[0] = info.si_signo; } return (error); } @@ -860,6 +879,8 @@ kern_sigtimedwait(struct thread *td, sigset_t set, siginfo_t *info, error = EINVAL; goto out; } + if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) + goto nosleep; TIMESPEC_TO_TIMEVAL(&tv, timeout); hz = tvtohz(&tv); } else @@ -872,8 +893,9 @@ kern_sigtimedwait(struct thread *td, sigset_t set, siginfo_t *info, error = 0; else if (error) goto out; - +nosleep: sig = cursig(td); + out: td->td_sigmask = oldmask; if (sig) { @@ -1445,10 +1467,33 @@ trapsignal(struct thread *td, int sig, u_long code) { struct sigacts *ps; struct proc *p; + siginfo_t siginfo; + int error; p = td->td_proc; - - PROC_LOCK(p); + if (td->td_flags & TDF_SA) { + thread_user_enter(p, td); + PROC_LOCK(p); + if (td->td_mailbox) { + SIGDELSET(td->td_sigmask, sig); + mtx_lock_spin(&sched_lock); + /* + * don't psignal to the thread, it only can accept + * its own sync signal. + */ + td->td_flags |= TDF_NOSIGPOST; + /* + * Force scheduling an upcall, so UTS has chance to + * process the signal before thread runs again in + * userland. + */ + if (td->td_upcall) + td->td_upcall->ku_flags |= KUF_DOUPCALL; + mtx_unlock_spin(&sched_lock); + } + } else { + PROC_LOCK(p); + } ps = p->p_sigacts; mtx_lock(&ps->ps_mtx); if ((p->p_flag & P_TRACED) == 0 && SIGISMEMBER(ps->ps_sigcatch, sig) && @@ -1459,8 +1504,22 @@ trapsignal(struct thread *td, int sig, u_long code) ktrpsig(sig, ps->ps_sigact[_SIG_IDX(sig)], &td->td_sigmask, code); #endif - (*p->p_sysent->sv_sendsig)(ps->ps_sigact[_SIG_IDX(sig)], sig, - &td->td_sigmask, code); + if (!(td->td_flags & TDF_SA)) + (*p->p_sysent->sv_sendsig)( + ps->ps_sigact[_SIG_IDX(sig)], sig, + &td->td_sigmask, code); + else { + thread_siginfo(sig, code, &siginfo); + mtx_unlock(&ps->ps_mtx); + PROC_UNLOCK(p); + error = copyout(&siginfo, &td->td_mailbox->tm_syncsig, + sizeof(siginfo)); + PROC_LOCK(p); + if (error) + sigexit(td, SIGILL); + SIGADDSET(td->td_sigmask, sig); + mtx_lock(&ps->ps_mtx); + } SIGSETOR(td->td_sigmask, ps->ps_catchmask[_SIG_IDX(sig)]); if (!SIGISMEMBER(ps->ps_signodefer, sig)) SIGADDSET(td->td_sigmask, sig); @@ -1512,7 +1571,8 @@ sigtd(struct proc *p, int sig, int prop) * masked. */ FOREACH_THREAD_IN_PROC(p, td) - if (!SIGISMEMBER(td->td_sigmask, sig)) + if (!SIGISMEMBER(td->td_sigmask, sig) && + !(td->td_flags & TDF_NOSIGPOST)) return (td); return (FIRST_THREAD_IN_PROC(p)); @@ -1556,6 +1616,26 @@ psignal(struct proc *p, int sig) void tdsignal(struct thread *td, int sig) { + sigset_t saved; + struct proc *p = td->td_proc; + + if (p->p_flag & P_SA) + saved = p->p_siglist; + do_tdsignal(td, sig); + if ((p->p_flag & P_SA) && !(p->p_flag & P_SIGEVENT)) { + if (SIGSETEQ(saved, p->p_siglist)) + return; + else { + /* pending set changed */ + p->p_flag |= P_SIGEVENT; + wakeup(&p->p_siglist); + } + } +} + +static void +do_tdsignal(struct thread *td, int sig) +{ struct proc *p; register sig_t action; sigset_t *siglist; diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 6444b97..7b4784f 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -173,12 +173,15 @@ msleep(ident, mtx, priority, wmesg, timo) * and not the exiting thread or thread was marked as * interrupted. */ - if (catch && - (((p->p_flag & P_WEXIT) && (p->p_singlethread != td)) || - (td->td_flags & TDF_INTERRUPT))) { - td->td_flags &= ~TDF_INTERRUPT; - mtx_unlock_spin(&sched_lock); - return (EINTR); + if (catch) { + if ((p->p_flag & P_WEXIT) && p->p_singlethread != td) { + mtx_unlock_spin(&sched_lock); + return (EINTR); + } + if (td->td_flags & TDF_INTERRUPT) { + mtx_unlock_spin(&sched_lock); + return (td->td_intrval); + } } } if (cold ) { @@ -285,8 +288,7 @@ msleep(ident, mtx, priority, wmesg, timo) } if ((td->td_flags & TDF_INTERRUPT) && (priority & PCATCH) && (rval == 0)) { - td->td_flags &= ~TDF_INTERRUPT; - rval = EINTR; + rval = td->td_intrval; } mtx_unlock_spin(&sched_lock); diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 7695643..2545fe6 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -384,6 +384,7 @@ proc_linkup(struct proc *p, struct ksegrp *kg, /* struct kse_thr_interrupt_args { struct kse_thr_mailbox * tmbx; + int sig; }; */ int @@ -391,26 +392,48 @@ kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap) { struct proc *p; struct thread *td2; + int sig = uap->sig; p = td->td_proc; - if (!(p->p_flag & P_SA) || (uap->tmbx == NULL)) + if (!(p->p_flag & P_SA) || (uap->tmbx == NULL) || + (sig < -2) || (sig > _SIG_MAXSIG)) return (EINVAL); + + PROC_LOCK(p); mtx_lock_spin(&sched_lock); FOREACH_THREAD_IN_PROC(p, td2) { - if (td2->td_mailbox == uap->tmbx) { - td2->td_flags |= TDF_INTERRUPT; - if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) { - if (td2->td_flags & TDF_CVWAITQ) - cv_abort(td2); - else - abortsleep(td2); - } - mtx_unlock_spin(&sched_lock); - return (0); + if (td2->td_mailbox == uap->tmbx) + break; + } + if (td2 == NULL) { + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + return (ESRCH); + } + if (sig > 0) { + td2->td_flags &= ~TDF_INTERRUPT; + mtx_unlock_spin(&sched_lock); + tdsignal(td2, sig); + } else if (sig == 0) { + mtx_unlock_spin(&sched_lock); + } else { + td2->td_flags |= TDF_INTERRUPT | TDF_ASTPENDING; + if (TD_CAN_UNBIND(td2)) + td->td_upcall->ku_flags |= KUF_DOUPCALL; + if (sig == -1) + td2->td_intrval = EINTR; + else if (sig == -2) + td2->td_intrval = ERESTART; + if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR)) { + if (td2->td_flags & TDF_CVWAITQ) + cv_abort(td2); + else + abortsleep(td2); } + mtx_unlock_spin(&sched_lock); } - mtx_unlock_spin(&sched_lock); - return (ESRCH); + PROC_UNLOCK(p); + return (0); } /* @@ -488,6 +511,7 @@ kse_release(struct thread *td, struct kse_release_args *uap) struct kse_upcall *ku; struct timespec timeout; struct timeval tv; + sigset_t sigset; int error; p = td->td_proc; @@ -501,19 +525,39 @@ kse_release(struct thread *td, struct kse_release_args *uap) } if (td->td_flags & TDF_SA) td->td_pflags |= TDP_UPCALLING; + else { + ku->ku_mflags = fuword(&ku->ku_mailbox->km_flags); + if (ku->ku_mflags == -1) { + PROC_LOCK(p); + sigexit(td, SIGSEGV); + } + } PROC_LOCK(p); - if ((ku->ku_flags & KUF_DOUPCALL) == 0 && (kg->kg_completed == NULL)) { - kg->kg_upsleeps++; - error = msleep(&kg->kg_completed, &p->p_mtx, PPAUSE|PCATCH, - "kserel", (uap->timeout ? tvtohz(&tv) : 0)); - kg->kg_upsleeps--; + if (ku->ku_mflags & KMF_WAITSIGEVENT) { + /* UTS wants to wait for signal event */ + if (!(p->p_flag & P_SIGEVENT) && !(ku->ku_flags & KUF_DOUPCALL)) + error = msleep(&p->p_siglist, &p->p_mtx, PPAUSE|PCATCH, + "ksesigwait", (uap->timeout ? tvtohz(&tv) : 0)); + p->p_flag &= ~P_SIGEVENT; + sigset = p->p_siglist; + PROC_UNLOCK(p); + error = copyout(&sigset, &ku->ku_mailbox->km_sigscaught, + sizeof(sigset)); + } else { + if (! kg->kg_completed && !(ku->ku_flags & KUF_DOUPCALL)) { + kg->kg_upsleeps++; + error = msleep(&kg->kg_completed, &p->p_mtx, + PPAUSE|PCATCH, "kserel", + (uap->timeout ? tvtohz(&tv) : 0)); + kg->kg_upsleeps--; + } + PROC_UNLOCK(p); } if (ku->ku_flags & KUF_DOUPCALL) { mtx_lock_spin(&sched_lock); ku->ku_flags &= ~KUF_DOUPCALL; mtx_unlock_spin(&sched_lock); } - PROC_UNLOCK(p); return (0); } @@ -559,7 +603,9 @@ kse_wakeup(struct thread *td, struct kse_wakeup_args *uap) if ((td2 = ku->ku_owner) == NULL) { panic("%s: no owner", __func__); } else if (TD_ON_SLEEPQ(td2) && - (td2->td_wchan == &kg->kg_completed)) { + ((td2->td_wchan == &kg->kg_completed) || + (td2->td_wchan == &p->p_siglist && + (ku->ku_mflags & KMF_WAITSIGEVENT)))) { abortsleep(td2); } else { ku->ku_flags |= KUF_DOUPCALL; @@ -698,12 +744,20 @@ kse_create(struct thread *td, struct kse_create_args *uap) if (td->td_standin == NULL) thread_alloc_spare(td, NULL); - mtx_lock_spin(&sched_lock); + PROC_LOCK(p); if (newkg->kg_numupcalls >= ncpus) { - mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); upcall_free(newku); return (EPROCLIM); } + if (first) { + SIGSETOR(p->p_siglist, td->td_siglist); + SIGEMPTYSET(td->td_siglist); + SIGFILLSET(td->td_sigmask); + SIG_CANTMASK(td->td_sigmask); + } + mtx_lock_spin(&sched_lock); + PROC_UNLOCK(p); upcall_link(newku, newkg); if (mbx.km_quantum) newkg->kg_upquantum = max(1, mbx.km_quantum/tick); @@ -943,7 +997,7 @@ thread_export_context(struct thread *td) struct ksegrp *kg; uintptr_t mbx; void *addr; - int error = 0, temp; + int error = 0, temp, sig; mcontext_t mc; p = td->td_proc; @@ -964,6 +1018,23 @@ thread_export_context(struct thread *td) goto bad; } + /* + * Post sync signal, or process SIGKILL and SIGSTOP. + * For sync signal, it is only possible when the signal is not + * caught by userland or process is being debugged. + */ + if (td->td_flags & TDF_NEEDSIGCHK) { + mtx_lock_spin(&sched_lock); + td->td_flags &= ~TDF_NEEDSIGCHK; + mtx_unlock_spin(&sched_lock); + PROC_LOCK(p); + mtx_lock(&p->p_sigacts->ps_mtx); + while ((sig = cursig(td)) != 0) + postsig(sig); + mtx_unlock(&p->p_sigacts->ps_mtx); + PROC_UNLOCK(p); + } + /* Get address in latest mbox of list pointer */ addr = (void *)(&td->td_mailbox->tm_next); /* @@ -1399,52 +1470,39 @@ thread_schedule_upcall(struct thread *td, struct kse_upcall *ku) td2->td_kse = NULL; td2->td_state = TDS_CAN_RUN; td2->td_inhibitors = 0; + SIGFILLSET(td2->td_sigmask); + SIG_CANTMASK(td2->td_sigmask); return (td2); /* bogus.. should be a void function */ } +/* + * It is only used when thread generated a trap and process is being + * debugged. + */ void thread_signal_add(struct thread *td, int sig) { - struct kse_upcall *ku; struct proc *p; - sigset_t ss; + siginfo_t siginfo; + struct sigacts *ps; int error; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); - mtx_assert(&p->p_sigacts->ps_mtx, MA_OWNED); - td = curthread; - ku = td->td_upcall; - mtx_unlock(&p->p_sigacts->ps_mtx); - PROC_UNLOCK(p); - error = copyin(&ku->ku_mailbox->km_sigscaught, &ss, sizeof(sigset_t)); - if (error) - goto error; - - SIGADDSET(ss, sig); - - error = copyout(&ss, &ku->ku_mailbox->km_sigscaught, sizeof(sigset_t)); - if (error) - goto error; + ps = p->p_sigacts; + mtx_assert(&ps->ps_mtx, MA_OWNED); + thread_siginfo(sig, 0, &siginfo); + mtx_unlock(&ps->ps_mtx); + PROC_UNLOCK(p); + error = copyout(&siginfo, &td->td_mailbox->tm_syncsig, sizeof(siginfo)); + if (error) { + PROC_LOCK(p); + sigexit(td, SIGILL); + } PROC_LOCK(p); - mtx_lock(&p->p_sigacts->ps_mtx); - return; -error: - PROC_LOCK(p); - sigexit(td, SIGILL); -} - -/* - * Schedule an upcall to notify a KSE process recieved signals. - * - */ -void -thread_signal_upcall(struct thread *td) -{ - td->td_pflags |= TDP_UPCALLING; - - return; + SIGADDSET(td->td_sigmask, sig); + mtx_lock(&ps->ps_mtx); } void @@ -1623,6 +1681,13 @@ thread_userret(struct thread *td, struct trapframe *frame) */ td->td_pflags |= TDP_UPCALLING; } else if (td->td_mailbox && (ku == NULL)) { + /* + * Because we are exiting, SIGKILL and SIGSTOP shouldn't + * be posted to us anymore, otherwise they will be lost. + */ + mtx_lock_spin(&sched_lock); + td->td_flags |= TDF_NOSIGPOST; + mtx_unlock_spin(&sched_lock); error = thread_export_context(td); /* possibly upcall with error? */ PROC_LOCK(p); diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index b2262de..3c0a760 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -176,7 +176,7 @@ ast(struct trapframe *framep) p->p_sflag &= ~PS_MACPEND; #endif td->td_flags &= ~(TDF_ASTPENDING | TDF_NEEDSIGCHK | - TDF_NEEDRESCHED | TDF_OWEUPC); + TDF_NEEDRESCHED | TDF_OWEUPC | TDF_INTERRUPT); cnt.v_soft++; prticks = 0; if (flags & TDF_OWEUPC && p->p_flag & P_PROFIL) { @@ -243,25 +243,12 @@ ast(struct trapframe *framep) mtx_unlock_spin(&sched_lock); } if (flags & TDF_NEEDSIGCHK) { - int sigs; - - sigs = 0; PROC_LOCK(p); mtx_lock(&p->p_sigacts->ps_mtx); - while ((sig = cursig(td)) != 0) { + while ((sig = cursig(td)) != 0) postsig(sig); - sigs++; - } mtx_unlock(&p->p_sigacts->ps_mtx); PROC_UNLOCK(p); - if ((td->td_flags & TDF_SA) && sigs) { - struct kse_upcall *ku = td->td_upcall; - if ((void *)TRAPF_PC(framep) != ku->ku_func) { - mtx_lock_spin(&sched_lock); - ku->ku_flags |= KUF_DOUPCALL; - mtx_unlock_spin(&sched_lock); - } - } } userret(td, framep, sticks); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 31fb722..0e171ab 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -556,7 +556,7 @@ 380 MSTD BSD { int kse_wakeup(struct kse_mailbox *mbx); } 381 STD BSD { int kse_create(struct kse_mailbox *mbx, \ int newgroup); } -382 MSTD BSD { int kse_thr_interrupt(struct kse_thr_mailbox *tmbx); } +382 MSTD BSD { int kse_thr_interrupt(struct kse_thr_mailbox *tmbx, int sig); } 383 MSTD BSD { int kse_release(struct timespec *timeout); } 384 MSTD BSD { int __mac_get_proc(struct mac *mac_p); } 385 MSTD BSD { int __mac_set_proc(struct mac *mac_p); } diff --git a/sys/sys/kse.h b/sys/sys/kse.h index 6e7262b..c2a90ab 100644 --- a/sys/sys/kse.h +++ b/sys/sys/kse.h @@ -36,6 +36,7 @@ #include #include #include +#include /* * This file defines the structures needed for communication between @@ -59,6 +60,7 @@ struct kse_thr_mailbox { void *tm_udata; /* For use by the UTS */ unsigned int tm_uticks; unsigned int tm_sticks; + siginfo_t tm_syncsig; int tm_spare[8]; }; @@ -90,12 +92,13 @@ struct kse_mailbox { #define KMF_NOCOMPLETED 0x02 #define KMF_DONE 0x04 #define KMF_BOUND 0x08 +#define KMF_WAITSIGEVENT 0x10 #ifndef _KERNEL int kse_create(struct kse_mailbox *, int); int kse_exit(void); int kse_release(struct timespec *); -int kse_thr_interrupt(struct kse_thr_mailbox *); +int kse_thr_interrupt(struct kse_thr_mailbox *, int); int kse_wakeup(struct kse_mailbox *); #endif /* !_KERNEL */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 4a3e5b7..02c2aac 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -291,8 +291,9 @@ struct thread { u_int td_prticks; /* (*) Profclock hits in sys for user */ struct kse_upcall *td_upcall; /* (*) Upcall structure. */ u_int64_t td_sticks; /* (j) Statclock hits in system mode. */ - u_int td_uuticks; /* (*) Statclock hits in user, for UTS */ - u_int td_usticks; /* (*) Statclock hits in kernel, for UTS */ + u_int td_uuticks; /* (*) Statclock in user, for UTS */ + u_int td_usticks; /* (*) Statclock in kernel, for UTS */ + int td_intrval; /* (*) Return value of TDF_INTERRUPT */ u_int td_critnest; /* (k) Critical section nest level. */ sigset_t td_oldsigmask; /* (k) Saved mask from pre sigpause. */ sigset_t td_sigmask; /* (c) Current signal mask. */ @@ -340,6 +341,7 @@ struct thread { #define TDF_SELECT 0x000040 /* Selecting; wakeup/waiting danger. */ #define TDF_CVWAITQ 0x000080 /* Thread is on a cv_waitq (not slpq). */ #define TDF_ONSLEEPQ 0x000200 /* On the sleep queue. */ +#define TDF_NOSIGPOST 0x000400 /* Thread doesn't want signals */ #define TDF_ASTPENDING 0x000800 /* Thread has some asynchronous events. */ #define TDF_TIMOFAIL 0x001000 /* Timeout from sleep after we were awake. */ #define TDF_INTERRUPT 0x002000 /* Thread is marked as interrupted. */ @@ -637,7 +639,7 @@ struct proc { #define P_STOPPED_SINGLE 0x80000 /* Only one thread can continue */ /* (not to user) */ #define P_PROTECTED 0x100000 /* Do not kill on memory overcommit. */ - +#define P_SIGEVENT 0x200000 /* Process pending signals changed */ /* Should be moved to machine-dependent areas. */ #define P_COWINPROGRESS 0x400000 /* Snapshot copy-on-write in progress. */ @@ -897,7 +899,6 @@ void kse_unlink(struct kse *ke); void ksegrp_link(struct ksegrp *kg, struct proc *p); void ksegrp_unlink(struct ksegrp *kg); void thread_signal_add(struct thread *td, int sig); -void thread_signal_upcall(struct thread *td); struct thread *thread_alloc(void); void thread_exit(void) __dead2; int thread_export_context(struct thread *td); @@ -928,6 +929,7 @@ void upcall_stash(struct kse_upcall *ke); void thread_sanity_check(struct thread *td, char *); void thread_stopped(struct proc *p); void thread_switchout(struct thread *td); +void thread_siginfo(int sig, u_long code, siginfo_t *si); void thr_exit1(void); #endif /* _KERNEL */ diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 0f26245..5c4d5c9 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -1072,6 +1072,7 @@ struct kse_create_args { }; struct kse_thr_interrupt_args { char tmbx_l_[PADL_(struct kse_thr_mailbox *)]; struct kse_thr_mailbox * tmbx; char tmbx_r_[PADR_(struct kse_thr_mailbox *)]; + char sig_l_[PADL_(int)]; int sig; char sig_r_[PADR_(int)]; }; struct kse_release_args { char timeout_l_[PADL_(struct timespec *)]; struct timespec * timeout; char timeout_r_[PADR_(struct timespec *)]; -- cgit v1.1