summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2003-06-28 08:29:05 +0000
committerdavidxu <davidxu@FreeBSD.org>2003-06-28 08:29:05 +0000
commit788b1fc17a2f0aba5c55ff68bf407ac8e137eafa (patch)
treefff12c2b9ef86698c8eec8842a317f437946cfc3
parentdf569db8a679e7bfa0fa1c6792a60f149cc1e235 (diff)
downloadFreeBSD-src-788b1fc17a2f0aba5c55ff68bf407ac8e137eafa.zip
FreeBSD-src-788b1fc17a2f0aba5c55ff68bf407ac8e137eafa.tar.gz
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)
-rw-r--r--sys/kern/kern_kse.c177
-rw-r--r--sys/kern/kern_sig.c96
-rw-r--r--sys/kern/kern_synch.c18
-rw-r--r--sys/kern/kern_thread.c177
-rw-r--r--sys/kern/subr_trap.c17
-rw-r--r--sys/kern/syscalls.master2
-rw-r--r--sys/sys/kse.h5
-rw-r--r--sys/sys/proc.h10
-rw-r--r--sys/sys/sysproto.h1
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 <sys/event.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
+#include <sys/kse.h>
#include <sys/ktr.h>
#include <sys/ktrace.h>
#include <sys/lock.h>
@@ -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 <machine/kse.h>
#include <sys/ucontext.h>
#include <sys/time.h>
+#include <sys/signal.h>
/*
* 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 *)];
OpenPOWER on IntegriCloud