diff options
author | deischen <deischen@FreeBSD.org> | 2004-04-28 20:36:53 +0000 |
---|---|---|
committer | deischen <deischen@FreeBSD.org> | 2004-04-28 20:36:53 +0000 |
commit | 122d328ccb51e6b9f7f19a2850a336f658546a9b (patch) | |
tree | eb057d17b0ef06b7f741ec8ed3a383eba8487c94 | |
parent | 83ecd7781ef9028a17cdb24709202983677ba2d3 (diff) | |
download | FreeBSD-src-122d328ccb51e6b9f7f19a2850a336f658546a9b.zip FreeBSD-src-122d328ccb51e6b9f7f19a2850a336f658546a9b.tar.gz |
Keep track of threads waiting in kse_release() to avoid a race
condition where kse_wakeup() doesn't yet see them in (interruptible)
sleep queues. Also add an upcall check to sleepqueue_catch_signals()
suggested by jhb.
This commit should fix recent mysql hangs.
Reviewed by: jhb, davidxu
Mysql'd by: Robin P. Blanchard <robin.blanchard at gactr uga edu>
-rw-r--r-- | sys/kern/kern_kse.c | 53 | ||||
-rw-r--r-- | sys/kern/kern_thread.c | 53 | ||||
-rw-r--r-- | sys/kern/subr_sleepqueue.c | 6 | ||||
-rw-r--r-- | sys/sys/proc.h | 6 |
4 files changed, 85 insertions, 33 deletions
diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c index cf2557e..43b0f74 100644 --- a/sys/kern/kern_kse.c +++ b/sys/kern/kern_kse.c @@ -621,9 +621,12 @@ 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)); + td->td_kflags &= ~(TDK_KSERELSIG | TDK_WAKEUP); + } p->p_flag &= ~P_SIGEVENT; sigset = p->p_siglist; PROC_UNLOCK(p); @@ -632,9 +635,11 @@ kse_release(struct thread *td, struct kse_release_args *uap) } else { if (! kg->kg_completed && !(ku->ku_flags & KUF_DOUPCALL)) { kg->kg_upsleeps++; + td->td_kflags |= TDK_KSEREL; error = msleep(&kg->kg_completed, &p->p_mtx, PPAUSE|PCATCH, "kserel", (uap->timeout ? tvtohz(&tv) : 0)); + td->td_kflags &= ~(TDK_KSEREL | TDK_WAKEUP); kg->kg_upsleeps--; } PROC_UNLOCK(p); @@ -678,31 +683,36 @@ kse_wakeup(struct thread *td, struct kse_wakeup_args *uap) } else { kg = td->td_ksegrp; if (kg->kg_upsleeps) { - wakeup_one(&kg->kg_completed); mtx_unlock_spin(&sched_lock); + wakeup_one(&kg->kg_completed); PROC_UNLOCK(p); return (0); } ku = TAILQ_FIRST(&kg->kg_upcalls); } - if (ku) { - if ((td2 = ku->ku_owner) == NULL) { - panic("%s: no owner", __func__); - } else if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) && - ((td2->td_wchan == &kg->kg_completed) || - (td2->td_wchan == &p->p_siglist && - (ku->ku_mflags & KMF_WAITSIGEVENT)))) { - sleepq_abort(td2); - } else { - ku->ku_flags |= KUF_DOUPCALL; - } + if (ku == NULL) { mtx_unlock_spin(&sched_lock); PROC_UNLOCK(p); - return (0); + return (ESRCH); + } + if ((td2 = ku->ku_owner) == NULL) { + mtx_unlock_spin(&sched_lock); + panic("%s: no owner", __func__); + } else if (td2->td_kflags & (TDK_KSEREL | TDK_KSERELSIG)) { + mtx_unlock_spin(&sched_lock); + if (!(td2->td_kflags & TDK_WAKEUP)) { + td2->td_kflags |= TDK_WAKEUP; + if (td2->td_kflags & TDK_KSEREL) + sleepq_remove(td2, &kg->kg_completed); + else + sleepq_remove(td2, &p->p_siglist); + } + } else { + ku->ku_flags |= KUF_DOUPCALL; + mtx_unlock_spin(&sched_lock); } - mtx_unlock_spin(&sched_lock); PROC_UNLOCK(p); - return (ESRCH); + return (0); } /* @@ -1464,6 +1474,7 @@ thread_link(struct thread *td, struct ksegrp *kg) td->td_ksegrp = kg; td->td_last_kse = NULL; td->td_flags = 0; + td->td_kflags = 0; td->td_kse = NULL; LIST_INIT(&td->td_contested); @@ -2222,3 +2233,13 @@ thread_single_end(void) } mtx_unlock_spin(&sched_lock); } + +int +thread_upcall_check(struct thread *td) +{ + PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); + if (td->td_kflags & TDK_WAKEUP) + return (1); + else + return (0); +} diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index cf2557e..43b0f74 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -621,9 +621,12 @@ 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)); + td->td_kflags &= ~(TDK_KSERELSIG | TDK_WAKEUP); + } p->p_flag &= ~P_SIGEVENT; sigset = p->p_siglist; PROC_UNLOCK(p); @@ -632,9 +635,11 @@ kse_release(struct thread *td, struct kse_release_args *uap) } else { if (! kg->kg_completed && !(ku->ku_flags & KUF_DOUPCALL)) { kg->kg_upsleeps++; + td->td_kflags |= TDK_KSEREL; error = msleep(&kg->kg_completed, &p->p_mtx, PPAUSE|PCATCH, "kserel", (uap->timeout ? tvtohz(&tv) : 0)); + td->td_kflags &= ~(TDK_KSEREL | TDK_WAKEUP); kg->kg_upsleeps--; } PROC_UNLOCK(p); @@ -678,31 +683,36 @@ kse_wakeup(struct thread *td, struct kse_wakeup_args *uap) } else { kg = td->td_ksegrp; if (kg->kg_upsleeps) { - wakeup_one(&kg->kg_completed); mtx_unlock_spin(&sched_lock); + wakeup_one(&kg->kg_completed); PROC_UNLOCK(p); return (0); } ku = TAILQ_FIRST(&kg->kg_upcalls); } - if (ku) { - if ((td2 = ku->ku_owner) == NULL) { - panic("%s: no owner", __func__); - } else if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) && - ((td2->td_wchan == &kg->kg_completed) || - (td2->td_wchan == &p->p_siglist && - (ku->ku_mflags & KMF_WAITSIGEVENT)))) { - sleepq_abort(td2); - } else { - ku->ku_flags |= KUF_DOUPCALL; - } + if (ku == NULL) { mtx_unlock_spin(&sched_lock); PROC_UNLOCK(p); - return (0); + return (ESRCH); + } + if ((td2 = ku->ku_owner) == NULL) { + mtx_unlock_spin(&sched_lock); + panic("%s: no owner", __func__); + } else if (td2->td_kflags & (TDK_KSEREL | TDK_KSERELSIG)) { + mtx_unlock_spin(&sched_lock); + if (!(td2->td_kflags & TDK_WAKEUP)) { + td2->td_kflags |= TDK_WAKEUP; + if (td2->td_kflags & TDK_KSEREL) + sleepq_remove(td2, &kg->kg_completed); + else + sleepq_remove(td2, &p->p_siglist); + } + } else { + ku->ku_flags |= KUF_DOUPCALL; + mtx_unlock_spin(&sched_lock); } - mtx_unlock_spin(&sched_lock); PROC_UNLOCK(p); - return (ESRCH); + return (0); } /* @@ -1464,6 +1474,7 @@ thread_link(struct thread *td, struct ksegrp *kg) td->td_ksegrp = kg; td->td_last_kse = NULL; td->td_flags = 0; + td->td_kflags = 0; td->td_kse = NULL; LIST_INIT(&td->td_contested); @@ -2222,3 +2233,13 @@ thread_single_end(void) } mtx_unlock_spin(&sched_lock); } + +int +thread_upcall_check(struct thread *td) +{ + PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); + if (td->td_kflags & TDK_WAKEUP) + return (1); + else + return (0); +} diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 36f6850..1e50cc1 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -293,8 +293,10 @@ sleepq_catch_signals(void *wchan) struct sleepqueue *sq; struct thread *td; struct proc *p; + int do_upcall; int sig; + do_upcall = 0; td = curthread; p = td->td_proc; sc = SC_LOOKUP(wchan); @@ -318,6 +320,8 @@ sleepq_catch_signals(void *wchan) mtx_unlock(&p->p_sigacts->ps_mtx); if (sig == 0 && thread_suspend_check(1)) sig = SIGSTOP; + else + do_upcall = thread_upcall_check(td); PROC_UNLOCK(p); /* @@ -326,7 +330,7 @@ sleepq_catch_signals(void *wchan) */ sq = sleepq_lookup(wchan); mtx_lock_spin(&sched_lock); - if (TD_ON_SLEEPQ(td) && sig != 0) { + if (TD_ON_SLEEPQ(td) && (sig != 0 || do_upcall != 0)) { mtx_unlock_spin(&sched_lock); sleepq_wakeup_thread(sq, td, -1); } else diff --git a/sys/sys/proc.h b/sys/sys/proc.h index d73f59d..7e534b8 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -302,6 +302,7 @@ struct thread { TAILQ_ENTRY(thread) td_umtx; /* (c?) Link for when we're blocked. */ volatile u_int td_generation; /* (k) Enable detection of preemption */ stack_t td_sigstk; /* (k) Stack ptr and on-stack flag. */ + int td_kflags; /* (c) Flags for KSE threading. */ #define td_endzero td_base_pri @@ -371,6 +372,10 @@ struct thread { #define TDI_LOCK 0x0008 /* Stopped on a lock. */ #define TDI_IWAIT 0x0010 /* Awaiting interrupt. */ +#define TDK_KSEREL 0x0001 /* Blocked in msleep on kg->kg_completed. */ +#define TDK_KSERELSIG 0x0002 /* Blocked in msleep on p->p_siglist. */ +#define TDK_WAKEUP 0x0004 /* Thread has been woken by kse_wakeup. */ + #define TD_CAN_UNBIND(td) \ (((td)->td_flags & TDF_CAN_UNBIND) == TDF_CAN_UNBIND && \ ((td)->td_upcall != NULL)) @@ -913,6 +918,7 @@ void thread_unlink(struct thread *td); void thread_unsuspend(struct proc *p); void thread_unsuspend_one(struct thread *td); int thread_userret(struct thread *td, struct trapframe *frame); +int thread_upcall_check(struct thread *td); void thread_user_enter(struct proc *p, struct thread *td); void thread_wait(struct proc *p); int thread_statclock(int user); |