Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_thread.c
Show First 20 Lines • Show All 559 Lines • ▼ Show 20 Lines | if (p->p_numthreads > 1) { | ||||
* sole exiting thread. P_STOPPED_SINGLE is unset | * sole exiting thread. P_STOPPED_SINGLE is unset | ||||
* in exit1() after it is the only survivor. | * in exit1() after it is the only survivor. | ||||
*/ | */ | ||||
if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { | if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { | ||||
if (p->p_numthreads == p->p_suspcount) { | if (p->p_numthreads == p->p_suspcount) { | ||||
thread_lock(p->p_singlethread); | thread_lock(p->p_singlethread); | ||||
wakeup_swapper = thread_unsuspend_one( | wakeup_swapper = thread_unsuspend_one( | ||||
p->p_singlethread, p, false); | p->p_singlethread, p, false); | ||||
thread_unlock(p->p_singlethread); | |||||
if (wakeup_swapper) | if (wakeup_swapper) | ||||
kick_proc0(); | kick_proc0(); | ||||
} | } | ||||
} | } | ||||
PCPU_SET(deadthread, td); | PCPU_SET(deadthread, td); | ||||
} else { | } else { | ||||
/* | /* | ||||
Show All 24 Lines | #endif | ||||
td->td_runtime += runtime; | td->td_runtime += runtime; | ||||
td->td_incruntime += runtime; | td->td_incruntime += runtime; | ||||
PCPU_SET(switchtime, new_switchtime); | PCPU_SET(switchtime, new_switchtime); | ||||
PCPU_SET(switchticks, ticks); | PCPU_SET(switchticks, ticks); | ||||
VM_CNT_INC(v_swtch); | VM_CNT_INC(v_swtch); | ||||
/* Save our resource usage in our process. */ | /* Save our resource usage in our process. */ | ||||
td->td_ru.ru_nvcsw++; | td->td_ru.ru_nvcsw++; | ||||
ruxagg(p, td); | ruxagg_locked(p, td); | ||||
rucollect(&p->p_ru, &td->td_ru); | rucollect(&p->p_ru, &td->td_ru); | ||||
PROC_STATUNLOCK(p); | PROC_STATUNLOCK(p); | ||||
td->td_state = TDS_INACTIVE; | td->td_state = TDS_INACTIVE; | ||||
#ifdef WITNESS | #ifdef WITNESS | ||||
witness_thread_exit(td); | witness_thread_exit(td); | ||||
#endif | #endif | ||||
CTR1(KTR_PROC, "thread_exit: cpu_throw() thread %p", td); | CTR1(KTR_PROC, "thread_exit: cpu_throw() thread %p", td); | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int wakeup_swapper; | int wakeup_swapper; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
PROC_SLOCK_ASSERT(p, MA_OWNED); | PROC_SLOCK_ASSERT(p, MA_OWNED); | ||||
THREAD_LOCK_ASSERT(td2, MA_OWNED); | THREAD_LOCK_ASSERT(td2, MA_OWNED); | ||||
wakeup_swapper = 0; | wakeup_swapper = 0; | ||||
/* | |||||
* Since the thread lock is dropped by the scheduler we have | |||||
* to retry to check for races. | |||||
*/ | |||||
restart: | |||||
switch (mode) { | switch (mode) { | ||||
case SINGLE_EXIT: | case SINGLE_EXIT: | ||||
if (TD_IS_SUSPENDED(td2)) | if (TD_IS_SUSPENDED(td2)) { | ||||
wakeup_swapper |= thread_unsuspend_one(td2, p, true); | wakeup_swapper |= thread_unsuspend_one(td2, p, true); | ||||
if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) | thread_lock(td2); | ||||
goto restart; | |||||
} | |||||
if (TD_CAN_ABORT(td2)) { | |||||
wakeup_swapper |= sleepq_abort(td2, EINTR); | wakeup_swapper |= sleepq_abort(td2, EINTR); | ||||
return (wakeup_swapper); | |||||
} | |||||
break; | break; | ||||
case SINGLE_BOUNDARY: | case SINGLE_BOUNDARY: | ||||
case SINGLE_NO_EXIT: | case SINGLE_NO_EXIT: | ||||
if (TD_IS_SUSPENDED(td2) && (td2->td_flags & TDF_BOUNDARY) == 0) | if (TD_IS_SUSPENDED(td2) && | ||||
(td2->td_flags & TDF_BOUNDARY) == 0) { | |||||
wakeup_swapper |= thread_unsuspend_one(td2, p, false); | wakeup_swapper |= thread_unsuspend_one(td2, p, false); | ||||
if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) | thread_lock(td2); | ||||
goto restart; | |||||
} | |||||
if (TD_CAN_ABORT(td2)) { | |||||
wakeup_swapper |= sleepq_abort(td2, ERESTART); | wakeup_swapper |= sleepq_abort(td2, ERESTART); | ||||
return (wakeup_swapper); | |||||
} | |||||
break; | break; | ||||
case SINGLE_ALLPROC: | case SINGLE_ALLPROC: | ||||
/* | /* | ||||
* ALLPROC suspend tries to avoid spurious EINTR for | * ALLPROC suspend tries to avoid spurious EINTR for | ||||
* threads sleeping interruptable, by suspending the | * threads sleeping interruptable, by suspending the | ||||
* thread directly, similarly to sig_suspend_threads(). | * thread directly, similarly to sig_suspend_threads(). | ||||
* Since such sleep is not performed at the user | * Since such sleep is not performed at the user | ||||
* boundary, TDF_BOUNDARY flag is not set, and TDF_ALLPROCSUSP | * boundary, TDF_BOUNDARY flag is not set, and TDF_ALLPROCSUSP | ||||
* is used to avoid immediate un-suspend. | * is used to avoid immediate un-suspend. | ||||
*/ | */ | ||||
if (TD_IS_SUSPENDED(td2) && (td2->td_flags & (TDF_BOUNDARY | | if (TD_IS_SUSPENDED(td2) && (td2->td_flags & (TDF_BOUNDARY | | ||||
TDF_ALLPROCSUSP)) == 0) | TDF_ALLPROCSUSP)) == 0) { | ||||
wakeup_swapper |= thread_unsuspend_one(td2, p, false); | wakeup_swapper |= thread_unsuspend_one(td2, p, false); | ||||
if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) { | thread_lock(td2); | ||||
goto restart; | |||||
} | |||||
if (TD_CAN_ABORT(td2)) { | |||||
if ((td2->td_flags & TDF_SBDRY) == 0) { | if ((td2->td_flags & TDF_SBDRY) == 0) { | ||||
thread_suspend_one(td2); | thread_suspend_one(td2); | ||||
td2->td_flags |= TDF_ALLPROCSUSP; | td2->td_flags |= TDF_ALLPROCSUSP; | ||||
} else { | } else { | ||||
wakeup_swapper |= sleepq_abort(td2, ERESTART); | wakeup_swapper |= sleepq_abort(td2, ERESTART); | ||||
return (wakeup_swapper); | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
default: | |||||
break; | |||||
} | } | ||||
thread_unlock(td2); | |||||
return (wakeup_swapper); | return (wakeup_swapper); | ||||
} | } | ||||
/* | /* | ||||
* Enforce single-threading. | * Enforce single-threading. | ||||
* | * | ||||
* Returns 1 if the caller must abort (another thread is waiting to | * Returns 1 if the caller must abort (another thread is waiting to | ||||
* exit the process or similar). Process is locked! | * exit the process or similar). Process is locked! | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | FOREACH_THREAD_IN_PROC(p, td2) { | ||||
continue; | continue; | ||||
thread_lock(td2); | thread_lock(td2); | ||||
td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; | td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; | ||||
if (TD_IS_INHIBITED(td2)) { | if (TD_IS_INHIBITED(td2)) { | ||||
wakeup_swapper |= weed_inhib(mode, td2, p); | wakeup_swapper |= weed_inhib(mode, td2, p); | ||||
#ifdef SMP | #ifdef SMP | ||||
} else if (TD_IS_RUNNING(td2) && td != td2) { | } else if (TD_IS_RUNNING(td2) && td != td2) { | ||||
forward_signal(td2); | forward_signal(td2); | ||||
thread_unlock(td2); | |||||
#endif | #endif | ||||
} | } else | ||||
thread_unlock(td2); | thread_unlock(td2); | ||||
} | } | ||||
if (wakeup_swapper) | if (wakeup_swapper) | ||||
kick_proc0(); | kick_proc0(); | ||||
remaining = calc_remaining(p, mode); | remaining = calc_remaining(p, mode); | ||||
/* | /* | ||||
* Maybe we suspended some threads.. was it enough? | * Maybe we suspended some threads.. was it enough? | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | while (thread_suspend_check_needed()) { | ||||
PROC_SLOCK(p); | PROC_SLOCK(p); | ||||
thread_stopped(p); | thread_stopped(p); | ||||
if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { | if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { | ||||
if (p->p_numthreads == p->p_suspcount + 1) { | if (p->p_numthreads == p->p_suspcount + 1) { | ||||
thread_lock(p->p_singlethread); | thread_lock(p->p_singlethread); | ||||
wakeup_swapper = thread_unsuspend_one( | wakeup_swapper = thread_unsuspend_one( | ||||
p->p_singlethread, p, false); | p->p_singlethread, p, false); | ||||
thread_unlock(p->p_singlethread); | |||||
if (wakeup_swapper) | if (wakeup_swapper) | ||||
kick_proc0(); | kick_proc0(); | ||||
} | } | ||||
} | } | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
thread_lock(td); | thread_lock(td); | ||||
/* | /* | ||||
* When a thread suspends, it just | * When a thread suspends, it just | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | thread_unsuspend_one(struct thread *td, struct proc *p, bool boundary) | ||||
if (td->td_proc == p) { | if (td->td_proc == p) { | ||||
PROC_SLOCK_ASSERT(p, MA_OWNED); | PROC_SLOCK_ASSERT(p, MA_OWNED); | ||||
p->p_suspcount--; | p->p_suspcount--; | ||||
if (boundary && (td->td_flags & TDF_BOUNDARY) != 0) { | if (boundary && (td->td_flags & TDF_BOUNDARY) != 0) { | ||||
td->td_flags &= ~TDF_BOUNDARY; | td->td_flags &= ~TDF_BOUNDARY; | ||||
p->p_boundary_count--; | p->p_boundary_count--; | ||||
} | } | ||||
} | } | ||||
return (setrunnable(td)); | return (setrunnable(td, 0)); | ||||
} | } | ||||
/* | /* | ||||
* Allow all threads blocked by single threading to continue running. | * Allow all threads blocked by single threading to continue running. | ||||
*/ | */ | ||||
void | void | ||||
thread_unsuspend(struct proc *p) | thread_unsuspend(struct proc *p) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
int wakeup_swapper; | int wakeup_swapper; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
PROC_SLOCK_ASSERT(p, MA_OWNED); | PROC_SLOCK_ASSERT(p, MA_OWNED); | ||||
wakeup_swapper = 0; | wakeup_swapper = 0; | ||||
if (!P_SHOULDSTOP(p)) { | if (!P_SHOULDSTOP(p)) { | ||||
FOREACH_THREAD_IN_PROC(p, td) { | FOREACH_THREAD_IN_PROC(p, td) { | ||||
thread_lock(td); | thread_lock(td); | ||||
if (TD_IS_SUSPENDED(td)) { | if (TD_IS_SUSPENDED(td)) { | ||||
wakeup_swapper |= thread_unsuspend_one(td, p, | wakeup_swapper |= thread_unsuspend_one(td, p, | ||||
true); | true); | ||||
} | } else | ||||
thread_unlock(td); | thread_unlock(td); | ||||
} | } | ||||
} else if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE && | } else if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE && | ||||
p->p_numthreads == p->p_suspcount) { | p->p_numthreads == p->p_suspcount) { | ||||
/* | /* | ||||
* Stopping everything also did the job for the single | * Stopping everything also did the job for the single | ||||
* threading request. Now we've downgraded to single-threaded, | * threading request. Now we've downgraded to single-threaded, | ||||
* let it continue. | * let it continue. | ||||
*/ | */ | ||||
if (p->p_singlethread->td_proc == p) { | if (p->p_singlethread->td_proc == p) { | ||||
thread_lock(p->p_singlethread); | thread_lock(p->p_singlethread); | ||||
wakeup_swapper = thread_unsuspend_one( | wakeup_swapper = thread_unsuspend_one( | ||||
p->p_singlethread, p, false); | p->p_singlethread, p, false); | ||||
thread_unlock(p->p_singlethread); | |||||
} | } | ||||
} | } | ||||
if (wakeup_swapper) | if (wakeup_swapper) | ||||
kick_proc0(); | kick_proc0(); | ||||
} | } | ||||
/* | /* | ||||
* End the single threading mode.. | * End the single threading mode.. | ||||
Show All 29 Lines | thread_single_end(struct proc *p, int mode) | ||||
* to continue however as this is a bad place to stop. | * to continue however as this is a bad place to stop. | ||||
*/ | */ | ||||
if (p->p_numthreads != remain_for_mode(mode) && !P_SHOULDSTOP(p)) { | if (p->p_numthreads != remain_for_mode(mode) && !P_SHOULDSTOP(p)) { | ||||
FOREACH_THREAD_IN_PROC(p, td) { | FOREACH_THREAD_IN_PROC(p, td) { | ||||
thread_lock(td); | thread_lock(td); | ||||
if (TD_IS_SUSPENDED(td)) { | if (TD_IS_SUSPENDED(td)) { | ||||
wakeup_swapper |= thread_unsuspend_one(td, p, | wakeup_swapper |= thread_unsuspend_one(td, p, | ||||
mode == SINGLE_BOUNDARY); | mode == SINGLE_BOUNDARY); | ||||
} | } else | ||||
thread_unlock(td); | thread_unlock(td); | ||||
} | } | ||||
} | } | ||||
KASSERT(mode != SINGLE_BOUNDARY || p->p_boundary_count == 0, | KASSERT(mode != SINGLE_BOUNDARY || p->p_boundary_count == 0, | ||||
("inconsistent boundary count %d", p->p_boundary_count)); | ("inconsistent boundary count %d", p->p_boundary_count)); | ||||
PROC_SUNLOCK(p); | PROC_SUNLOCK(p); | ||||
if (wakeup_swapper) | if (wakeup_swapper) | ||||
kick_proc0(); | kick_proc0(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 67 Lines • Show Last 20 Lines |