diff options
author | davidxu <davidxu@FreeBSD.org> | 2004-08-08 22:32:20 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2004-08-08 22:32:20 +0000 |
commit | 634d20a05ea861318018f78b9103d3f57baf97f4 (patch) | |
tree | 0a9d45cc22c029dc23261ee84436a42a3b90231f | |
parent | f8c21c52ad6e966afbd00b332af6bf2335fff2e6 (diff) | |
download | FreeBSD-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.c | 75 | ||||
-rw-r--r-- | sys/sys/kse.h | 9 |
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); |