Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_thread.c
Show First 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x6b0, | _Static_assert(offsetof(struct thread, td_emuldata) == 0x6b0, | ||||
"struct thread KBI td_emuldata"); | "struct thread KBI td_emuldata"); | ||||
_Static_assert(offsetof(struct proc, p_flag) == 0xb8, | _Static_assert(offsetof(struct proc, p_flag) == 0xb8, | ||||
"struct proc KBI p_flag"); | "struct proc KBI p_flag"); | ||||
_Static_assert(offsetof(struct proc, p_pid) == 0xc4, | _Static_assert(offsetof(struct proc, p_pid) == 0xc4, | ||||
"struct proc KBI p_pid"); | "struct proc KBI p_pid"); | ||||
_Static_assert(offsetof(struct proc, p_filemon) == 0x3c8, | _Static_assert(offsetof(struct proc, p_filemon) == 0x3c8, | ||||
"struct proc KBI p_filemon"); | "struct proc KBI p_filemon"); | ||||
_Static_assert(offsetof(struct proc, p_comm) == 0x3e0, | _Static_assert(offsetof(struct proc, p_comm) == 0x3e4, | ||||
"struct proc KBI p_comm"); | "struct proc KBI p_comm"); | ||||
_Static_assert(offsetof(struct proc, p_emuldata) == 0x4c8, | _Static_assert(offsetof(struct proc, p_emuldata) == 0x4c8, | ||||
"struct proc KBI p_emuldata"); | "struct proc KBI p_emuldata"); | ||||
#endif | #endif | ||||
#ifdef __i386__ | #ifdef __i386__ | ||||
_Static_assert(offsetof(struct thread, td_flags) == 0x9c, | _Static_assert(offsetof(struct thread, td_flags) == 0x9c, | ||||
"struct thread KBI td_flags"); | "struct thread KBI td_flags"); | ||||
_Static_assert(offsetof(struct thread, td_pflags) == 0xa4, | _Static_assert(offsetof(struct thread, td_pflags) == 0xa4, | ||||
▲ Show 20 Lines • Show All 1,028 Lines • ▼ Show 20 Lines | if (TD_CAN_ABORT(td2)) { | ||||
return (wakeup_swapper); | 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 neccessary performed at the user | ||||
* boundary, TDF_BOUNDARY flag is not set, and TDF_ALLPROCSUSP | * boundary, TDF_ALLPROCSUSP is used to avoid immediate | ||||
* is used to avoid immediate un-suspend. | * un-suspend. | ||||
markj: The comment still references TDF_BOUNDARY. | |||||
*/ | */ | ||||
if (TD_IS_SUSPENDED(td2) && (td2->td_flags & (TDF_BOUNDARY | | if (TD_IS_SUSPENDED(td2) && (td2->td_flags & | ||||
TDF_ALLPROCSUSP)) == 0) { | TDF_ALLPROCSUSP) == 0) { | ||||
wakeup_swapper |= thread_unsuspend_one(td2, p, false); | wakeup_swapper |= thread_unsuspend_one(td2, p, false); | ||||
thread_lock(td2); | thread_lock(td2); | ||||
goto restart; | goto restart; | ||||
} | } | ||||
if (TD_CAN_ABORT(td2)) { | if (TD_CAN_ABORT(td2)) { | ||||
if ((td2->td_flags & TDF_SBDRY) == 0) { | |||||
thread_suspend_one(td2); | |||||
td2->td_flags |= TDF_ALLPROCSUSP; | td2->td_flags |= TDF_ALLPROCSUSP; | ||||
} else { | |||||
wakeup_swapper |= sleepq_abort(td2, ERESTART); | wakeup_swapper |= sleepq_abort(td2, ERESTART); | ||||
return (wakeup_swapper); | return (wakeup_swapper); | ||||
} | } | ||||
} | |||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
thread_unlock(td2); | thread_unlock(td2); | ||||
return (wakeup_swapper); | return (wakeup_swapper); | ||||
} | } | ||||
Show All 28 Lines | thread_single(struct proc *p, int mode) | ||||
* this is not implemented because it is not used. | * this is not implemented because it is not used. | ||||
*/ | */ | ||||
KASSERT((mode == SINGLE_ALLPROC && td->td_proc != p) || | KASSERT((mode == SINGLE_ALLPROC && td->td_proc != p) || | ||||
(mode != SINGLE_ALLPROC && td->td_proc == p), | (mode != SINGLE_ALLPROC && td->td_proc == p), | ||||
("mode %d proc %p curproc %p", mode, p, td->td_proc)); | ("mode %d proc %p curproc %p", mode, p, td->td_proc)); | ||||
mtx_assert(&Giant, MA_NOTOWNED); | mtx_assert(&Giant, MA_NOTOWNED); | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
if ((p->p_flag & P_HADTHREADS) == 0 && mode != SINGLE_ALLPROC) | /* | ||||
* Is someone already single threading? | |||||
* Or may be singlethreading is not needed at all. | |||||
*/ | |||||
if (mode == SINGLE_ALLPROC) { | |||||
while ((p->p_flag & P_STOPPED_SINGLE) != 0) { | |||||
if ((p->p_flag2 & P2_WEXIT) != 0) | |||||
return (1); | |||||
msleep(&p->p_flag, &p->p_mtx, PCATCH, "thrsgl", 0); | |||||
Done Inline ActionsIt's not obvious to me that you intend to catch signals here either. markj: It's not obvious to me that you intend to catch signals here either. | |||||
Done Inline ActionsSee above. kib: See above. | |||||
} | |||||
} else if ((p->p_flag & P_HADTHREADS) == 0) | |||||
return (0); | return (0); | ||||
/* Is someone already single threading? */ | |||||
if (p->p_singlethread != NULL && p->p_singlethread != td) | if (p->p_singlethread != NULL && p->p_singlethread != td) | ||||
return (1); | return (1); | ||||
if (mode == SINGLE_EXIT) { | if (mode == SINGLE_EXIT) { | ||||
p->p_flag |= P_SINGLE_EXIT; | p->p_flag |= P_SINGLE_EXIT; | ||||
p->p_flag &= ~P_SINGLE_BOUNDARY; | p->p_flag &= ~P_SINGLE_BOUNDARY; | ||||
} else { | } else { | ||||
p->p_flag &= ~P_SINGLE_EXIT; | p->p_flag &= ~P_SINGLE_EXIT; | ||||
if (mode == SINGLE_BOUNDARY) | if (mode == SINGLE_BOUNDARY) | ||||
p->p_flag |= P_SINGLE_BOUNDARY; | p->p_flag |= P_SINGLE_BOUNDARY; | ||||
else | else | ||||
p->p_flag &= ~P_SINGLE_BOUNDARY; | p->p_flag &= ~P_SINGLE_BOUNDARY; | ||||
} | } | ||||
if (mode == SINGLE_ALLPROC) | if (mode == SINGLE_ALLPROC) { | ||||
p->p_flag |= P_TOTAL_STOP; | p->p_flag |= P_TOTAL_STOP; | ||||
thread_lock(td); | |||||
td->td_flags |= TDF_DOING_SA; | |||||
thread_unlock(td); | |||||
} | |||||
p->p_flag |= P_STOPPED_SINGLE; | p->p_flag |= P_STOPPED_SINGLE; | ||||
PROC_SLOCK(p); | PROC_SLOCK(p); | ||||
p->p_singlethread = td; | p->p_singlethread = td; | ||||
remaining = calc_remaining(p, mode); | remaining = calc_remaining(p, mode); | ||||
while (remaining != remain_for_mode(mode)) { | while (remaining != remain_for_mode(mode)) { | ||||
if (P_SHOULDSTOP(p) != P_STOPPED_SINGLE) | if (P_SHOULDSTOP(p) != P_STOPPED_SINGLE) | ||||
goto stopme; | goto stopme; | ||||
wakeup_swapper = 0; | wakeup_swapper = 0; | ||||
FOREACH_THREAD_IN_PROC(p, td2) { | FOREACH_THREAD_IN_PROC(p, td2) { | ||||
if (td2 == td) | if (td2 == td) | ||||
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)) { | ||||
forward_signal(td2); | forward_signal(td2); | ||||
thread_unlock(td2); | thread_unlock(td2); | ||||
#endif | #endif | ||||
} else | } else | ||||
thread_unlock(td2); | thread_unlock(td2); | ||||
} | } | ||||
if (wakeup_swapper) | if (wakeup_swapper) | ||||
kick_proc0(); | kick_proc0(); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | FOREACH_THREAD_IN_PROC(p, td2) { | ||||
KASSERT((td2->td_flags & TDF_BOUNDARY) != 0, | KASSERT((td2->td_flags & TDF_BOUNDARY) != 0, | ||||
("td %p not on boundary", td2)); | ("td %p not on boundary", td2)); | ||||
KASSERT(TD_IS_SUSPENDED(td2), | KASSERT(TD_IS_SUSPENDED(td2), | ||||
("td %p is not suspended", td2)); | ("td %p is not suspended", td2)); | ||||
thread_unlock(td2); | thread_unlock(td2); | ||||
} | } | ||||
} | } | ||||
PROC_SUNLOCK(p); | PROC_SUNLOCK(p); | ||||
if (mode == SINGLE_ALLPROC) { | |||||
thread_lock(td); | |||||
td->td_flags &= ~TDF_DOING_SA; | |||||
thread_unlock(td); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
bool | bool | ||||
thread_suspend_check_needed(void) | thread_suspend_check_needed(void) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct thread *td; | struct thread *td; | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | thread_unsuspend(struct proc *p) | ||||
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) && (td->td_flags & | ||||
TDF_DOING_SA) == 0) { | |||||
wakeup_swapper |= thread_unsuspend_one(td, p, | wakeup_swapper |= thread_unsuspend_one(td, p, | ||||
true); | true); | ||||
} else | } 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) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | thread_single_end(struct proc *p, int mode) | ||||
* on the process. The single threader must be allowed | * on the process. The single threader must be allowed | ||||
* 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); | true); | ||||
} else | } 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(); | ||||
wakeup(&p->p_flag); | |||||
} | } | ||||
/* | /* | ||||
* Locate a thread by number and return with proc lock held. | * Locate a thread by number and return with proc lock held. | ||||
* | * | ||||
* thread exit establishes proc -> tidhash lock ordering, but lookup | * thread exit establishes proc -> tidhash lock ordering, but lookup | ||||
* takes tidhash first and needs to return locked proc. | * takes tidhash first and needs to return locked proc. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 98 Lines • Show Last 20 Lines |
The comment still references TDF_BOUNDARY.