TDF_EXITING|TDF_RUNQ)) != TDF_EXITING) {
return (0);
}
+ KASSERT((td->td_flags & TDF_TSLEEPQ) == 0,
+ ("lwp_wait: td %p (%s) still on sleep queue", td, td->td_comm));
return (1);
}
static void loadav (void *arg);
static void schedcpu (void *arg);
#ifdef SMP
-static void tsleep_wakeup(struct thread *td);
+static void tsleep_wakeup_remote(struct thread *td);
#endif
/*
* This function mus be called while in a critical section but if the
* target thread is sleeping on a different cpu we cannot safely probe
* td_flags.
+ *
+ * This function is only called from a different cpu via setrunnable()
+ * when the thread is in a known sleep. However, multiple wakeups are
+ * possible and we must hold the td to prevent a race against the thread
+ * exiting.
*/
static __inline
void
globaldata_t gd = mycpu;
if (td->td_gd != gd) {
- lwkt_send_ipiq(td->td_gd, (ipifunc1_t)tsleep_wakeup, td);
+ lwkt_hold(td);
+ lwkt_send_ipiq(td->td_gd, (ipifunc1_t)tsleep_wakeup_remote, td);
return;
}
#endif
#ifdef SMP
static
void
-tsleep_wakeup(struct thread *td)
+tsleep_wakeup_remote(struct thread *td)
{
_tsleep_wakeup(td);
+ lwkt_rele(td);
}
#endif
* has an effect if we are in SSLEEP. We only break out of the
* tsleep if LWP_BREAKTSLEEP is set, otherwise we just fix-up the state.
*
- * NOTE: With the MP lock held we can only safely manipulate the process
- * structure. We cannot safely manipulate the thread structure.
+ * NOTE: With proc_token held we can only safely manipulate the process
+ * structure and the lp's lwp_stat.
*/
void
setrunnable(struct lwp *lp)
void
lwkt_hold(thread_t td)
{
- ++td->td_refs;
+ atomic_add_int(&td->td_refs, 1);
}
void
lwkt_rele(thread_t td)
{
KKASSERT(td->td_refs > 0);
- --td->td_refs;
+ atomic_add_int(&td->td_refs, -1);
}
void
void
lwkt_free_thread(thread_t td)
{
+ KKASSERT(td->td_refs == 0);
KKASSERT((td->td_flags & (TDF_RUNNING|TDF_PREEMPT_LOCK|TDF_RUNQ)) == 0);
if (td->td_flags & TDF_ALLOCATED_THREAD) {
objcache_put(thread_cache, td);
tsleep_remove(td);
lwkt_deschedule_self(td);
lwkt_remove_tdallq(td);
+ KKASSERT(td->td_refs == 0);
/*
* Final cleanup