summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2004-08-08 22:32:20 +0000
committerdavidxu <davidxu@FreeBSD.org>2004-08-08 22:32:20 +0000
commit634d20a05ea861318018f78b9103d3f57baf97f4 (patch)
tree0a9d45cc22c029dc23261ee84436a42a3b90231f
parentf8c21c52ad6e966afbd00b332af6bf2335fff2e6 (diff)
downloadFreeBSD-src-634d20a05ea861318018f78b9103d3f57baf97f4.zip
FreeBSD-src-634d20a05ea861318018f78b9103d3f57baf97f4.tar.gz
1.Add KSE_INTR_DBSUSPEND command for kse_thr_interrupt to suspend a bound
thread, after the bound thread leaves critical region, the thread should check debug flag may suspend itself by using the command. 2.Schedule upcall after thread is suspended by debugger 3.Wakeup upcall thread after process suspension. Reviewed by: deischen
-rw-r--r--sys/kern/kern_kse.c75
-rw-r--r--sys/sys/kse.h9
2 files changed, 51 insertions, 33 deletions
diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c
index 9555687..c85c165 100644
--- a/sys/kern/kern_kse.c
+++ b/sys/kern/kern_kse.c
@@ -185,6 +185,9 @@ kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap)
{
struct proc *p;
struct thread *td2;
+ struct kse_upcall *ku;
+ struct kse_thr_mailbox *tmbx;
+ uint32_t flags;
p = td->td_proc;
@@ -236,6 +239,30 @@ kse_thr_interrupt(struct thread *td, struct kse_thr_interrupt_args *uap)
PROC_LOCK(p);
sigexit(td, (int)uap->data);
break;
+
+ case KSE_INTR_DBSUSPEND:
+ /* this sub-function is only for bound thread */
+ if (td->td_pflags & TDP_SA)
+ return (EINVAL);
+ ku = td->td_upcall;
+ tmbx = (void *)fuword((void *)&ku->ku_mailbox->km_curthread);
+ if (tmbx == NULL || tmbx == (void *)-1)
+ return (EINVAL);
+ flags = 0;
+ while ((p->p_flag & P_TRACED) && !(p->p_flag & P_SINGLE_EXIT)) {
+ flags = fuword32(&tmbx->tm_dflags);
+ if (!(flags & TMDF_SUSPEND))
+ break;
+ PROC_LOCK(p);
+ mtx_lock_spin(&sched_lock);
+ thread_stopped(p);
+ thread_suspend_one(td);
+ PROC_UNLOCK(p);
+ mi_switch(SW_VOL, NULL);
+ mtx_unlock_spin(&sched_lock);
+ }
+ return (0);
+
default:
return (EINVAL);
}
@@ -297,6 +324,9 @@ kse_exit(struct thread *td, struct kse_exit_args *uap)
* XXX need to check it that can be deliverred without a mailbox.
*/
error = suword32(&ku->ku_mailbox->km_flags, ku->ku_mflags|KMF_DONE);
+ if (!(td->td_pflags & TDP_SA))
+ if (suword32(&td->td_mailbox->tm_lwp, 0))
+ error = EFAULT;
PROC_LOCK(p);
if (error)
psignal(p, SIGSEGV);
@@ -361,7 +391,8 @@ kse_release(struct thread *td, struct kse_release_args *uap)
PROC_LOCK(p);
if (ku->ku_mflags & KMF_WAITSIGEVENT) {
/* UTS wants to wait for signal event */
- if (!(p->p_flag & P_SIGEVENT) && !(ku->ku_flags & KUF_DOUPCALL)) {
+ if (!(p->p_flag & P_SIGEVENT) &&
+ !(ku->ku_flags & KUF_DOUPCALL)) {
td->td_kflags |= TDK_KSERELSIG;
error = msleep(&p->p_siglist, &p->p_mtx, PPAUSE|PCATCH,
"ksesigwait", (uap->timeout ? tvtohz(&tv) : 0));
@@ -373,7 +404,9 @@ kse_release(struct thread *td, struct kse_release_args *uap)
error = copyout(&sigset, &ku->ku_mailbox->km_sigscaught,
sizeof(sigset));
} else {
- if (! kg->kg_completed && !(ku->ku_flags & KUF_DOUPCALL)) {
+ if ((ku->ku_flags & KUF_DOUPCALL) == 0 &&
+ ((ku->ku_mflags & KMF_NOCOMPLETED) ||
+ (kg->kg_completed == NULL))) {
kg->kg_upsleeps++;
td->td_kflags |= TDK_KSEREL;
error = msleep(&kg->kg_completed, &p->p_mtx,
@@ -424,7 +457,7 @@ kse_wakeup(struct thread *td, struct kse_wakeup_args *uap)
kg = td->td_ksegrp;
if (kg->kg_upsleeps) {
mtx_unlock_spin(&sched_lock);
- wakeup_one(&kg->kg_completed);
+ wakeup(&kg->kg_completed);
PROC_UNLOCK(p);
return (0);
}
@@ -1078,10 +1111,14 @@ thread_switchout(struct thread *td)
* If it is a short term event, just suspend it in
* a way that takes its KSE with it.
* Select the events for which we want to schedule upcalls.
- * For now it's just sleep.
+ * For now it's just sleep or if thread is suspended but
+ * process wide suspending flag is not set (debugger
+ * suspends thread).
* XXXKSE eventually almost any inhibition could do.
*/
- if (TD_CAN_UNBIND(td) && (td->td_standin) && TD_ON_SLEEPQ(td)) {
+ if (TD_CAN_UNBIND(td) && (td->td_standin) &&
+ (TD_ON_SLEEPQ(td) || (TD_IS_SUSPENDED(td) &&
+ !P_SHOULDSTOP(td->td_proc)))) {
/*
* Release ownership of upcall, and schedule an upcall
* thread, this new upcall thread becomes the owner of
@@ -1134,14 +1171,14 @@ thread_user_enter(struct proc *p, struct thread *td)
KASSERT(ku->ku_owner == td, ("wrong owner"));
KASSERT(!TD_CAN_UNBIND(td), ("can unbind"));
+ if (td->td_standin == NULL)
+ thread_alloc_spare(td);
ku->ku_mflags = fuword32((void *)&ku->ku_mailbox->km_flags);
tmbx = (void *)fuword((void *)&ku->ku_mailbox->km_curthread);
if ((tmbx == NULL) || (tmbx == (void *)-1L) ||
(ku->ku_mflags & KMF_NOUPCALL)) {
td->td_mailbox = NULL;
} else {
- if (td->td_standin == NULL)
- thread_alloc_spare(td);
flags = fuword32(&tmbx->tm_flags);
/*
* On some architectures, TP register points to thread
@@ -1210,16 +1247,6 @@ thread_userret(struct thread *td, struct trapframe *frame)
td->td_pflags &= ~TDP_USTATCLOCK;
}
- /*
- * Check if we should unbind and schedule upcall
- * after returned from interrupt or etcs, this
- * is usually true when process is being debugged.
- */
- if (td->td_mailbox == NULL && ku != NULL &&
- !(td->td_pflags & TDP_UPCALLING) &&
- (kg->kg_completed || ku->ku_flags & KUF_DOUPCALL))
- thread_user_enter(p, td);
-
uts_crit = (td->td_mailbox == NULL);
/*
* Optimisation:
@@ -1257,13 +1284,8 @@ thread_userret(struct thread *td, struct trapframe *frame)
} else if (td->td_mailbox && (ku == NULL)) {
thread_export_context(td, 1);
PROC_LOCK(p);
- /*
- * There are upcall threads waiting for
- * work to do, wake one of them up.
- * XXXKSE Maybe wake all of them up.
- */
if (kg->kg_upsleeps)
- wakeup_one(&kg->kg_completed);
+ wakeup(&kg->kg_completed);
mtx_lock_spin(&sched_lock);
thread_stopped(p);
thread_exit();
@@ -1372,12 +1394,6 @@ out:
}
ku->ku_mflags = 0;
- /*
- * Clear thread mailbox first, then clear system tick count.
- * The order is important because thread_statclock() use
- * mailbox pointer to see if it is an userland thread or
- * an UTS kernel thread.
- */
td->td_mailbox = NULL;
td->td_usticks = 0;
return (error); /* go sync */
@@ -1422,6 +1438,7 @@ thread_continued(struct proc *p)
continue;
FOREACH_UPCALL_IN_GROUP(kg, ku) {
ku->ku_flags |= KUF_DOUPCALL;
+ wakeup(&kg->kg_completed);
if (TD_IS_SUSPENDED(ku->ku_owner)) {
thread_unsuspend_one(ku->ku_owner);
}
diff --git a/sys/sys/kse.h b/sys/sys/kse.h
index bd9f34b..2de3d95 100644
--- a/sys/sys/kse.h
+++ b/sys/sys/kse.h
@@ -107,10 +107,11 @@ struct kse_mailbox {
#define KSE_SWITCHIN_SETTMBX 0x01
/* Commands for kse_thr_interrupt */
-#define KSE_INTR_INTERRUPT 0x01
-#define KSE_INTR_RESTART 0x02
-#define KSE_INTR_SENDSIG 0x03
-#define KSE_INTR_SIGEXIT 0x04
+#define KSE_INTR_INTERRUPT 1
+#define KSE_INTR_RESTART 2
+#define KSE_INTR_SENDSIG 3
+#define KSE_INTR_SIGEXIT 4
+#define KSE_INTR_DBSUSPEND 5
#ifndef _KERNEL
int kse_create(struct kse_mailbox *, int);
OpenPOWER on IntegriCloud