summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_kse.c
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 /sys/kern/kern_kse.c
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)
Diffstat (limited to 'sys/kern/kern_kse.c')
-rw-r--r--sys/kern/kern_kse.c177
1 files changed, 121 insertions, 56 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);
OpenPOWER on IntegriCloud