Index: share/man/man9/kthread.9 =================================================================== --- share/man/man9/kthread.9 (revision 201968) +++ share/man/man9/kthread.9 (working copy) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 26, 2009 +.Dd January 9, 2010 .Dt KTHREAD 9 .Os .Sh NAME @@ -50,7 +50,7 @@ .Ft int .Fn kthread_suspend "struct thread *td" "int timo" .Ft void -.Fn kthread_suspend_check "struct thread *td" +.Fn kthread_suspend_check "void" .In sys/unistd.h .Ft int .Fo kthread_add @@ -208,12 +208,9 @@ During the main loop of its execution, a kernel thread that wishes to allow itself to be suspended should call .Fn kthread_suspend_check -passing in -.Va curthread -as the only argument. -This function checks to see if the kernel thread has been asked to suspend. +in order to check if the it has been asked to suspend. If it has, it will -.Xr tsleep 9 +.Xr msleep 9 until it is told to resume. Once it has been told to resume it will return allowing execution of the kernel thread to continue. Index: sys/kern/kern_kthread.c =================================================================== --- sys/kern/kern_kthread.c (revision 201968) +++ sys/kern/kern_kthread.c (working copy) @@ -335,30 +335,42 @@ int kthread_suspend(struct thread *td, int timo) { - if ((td->td_pflags & TDP_KTHREAD) == 0) { + int error; + + /* + * td_pflags should not be read by any other thread different by + * curthread, but as long as that flag is invariant during the + * thread life it is ok to check for it now. + */ + if ((td->td_pflags & TDP_KTHREAD) == 0) return (EINVAL); - } + + /* + * The caller of the primitive should have already checked that + * the thread is up and running, thus not being treatned by + * thirdy-part conditions. + */ thread_lock(td); td->td_flags |= TDF_KTH_SUSP; + error = msleep_spin(&td->td_flags, td->td_lock, "suspkt", timo); thread_unlock(td); - /* - * If it's stopped for some other reason, - * kick it to notice our request - * or we'll end up timing out - */ - wakeup(td); /* traditional place for kernel threads to sleep on */ /* XXX ?? */ - return (tsleep(&td->td_flags, PPAUSE | PDROP, "suspkt", timo)); + return (error); } /* - * let the kthread it can keep going again. + * Resume a thread previously put asleep with kthread_suspend(). */ int kthread_resume(struct thread *td) { - if ((td->td_pflags & TDP_KTHREAD) == 0) { + + /* + * td_pflags should not be read by any other thread different by + * curthread, but as long as that flag is invariant during the + * thread life it is ok to check for it now. + */ + if ((td->td_pflags & TDP_KTHREAD) == 0) return (EINVAL); - } thread_lock(td); td->td_flags &= ~TDF_KTH_SUSP; thread_unlock(td); @@ -367,19 +379,33 @@ } /* - * Used by the thread to poll as to whether it should yield/sleep + * Used by curthread to poll as to whether it should yield/sleep * and notify the caller that is has happened. */ void -kthread_suspend_check(struct thread *td) +kthread_suspend_check() { + struct thread *td; + + td = curthread; + thread_lock(td); while (td->td_flags & TDF_KTH_SUSP) { + thread_unlock(td); + /* - * let the caller know we got the message then sleep + * Let the caller know the message is received and then sleep. + * The thread spinlock must be unlocked in order to prevent + * LOR with the sleepqueue spinlock when awaking the suspender, + * thus check about the condition again when reacquiring the + * spinlock. */ wakeup(&td->td_flags); - tsleep(&td->td_name, PPAUSE, "ktsusp", 0); + thread_lock(td); + if ((td->td_flags & TDF_KTH_SUSP) == 0) + break; + msleep_spin(&td->td_name, td->td_lock, "ktsusp", 0); } + thread_unlock(td); } int Index: sys/sys/kthread.h =================================================================== --- sys/sys/kthread.h (revision 201968) +++ sys/sys/kthread.h (working copy) @@ -73,7 +73,7 @@ void kthread_shutdown(void *, int); void kthread_start(const void *); int kthread_suspend(struct thread *, int); -void kthread_suspend_check(struct thread *); +void kthread_suspend_check(void); #endif /* !_SYS_KTHREAD_H_ */