Revert part of r300109.

The removal of TAILQ_FOREACH_SAFE introduced a small race: when the last
thread on a sleepqueue is awoken, it reclaims the sleepqueue and may begin
executing on a different CPU before sleepq_resume_thread() returns. This
leaves a window during which it may go back to sleep and incorrectly be
awoken again by the caller of sleepq_broadcast().

Reported and tested by:	pho
MFC after:	3 days
Sponsored by:	Dell EMC Isilon
This commit is contained in:
Mark Johnston 2016-12-22 17:51:44 +00:00
parent 57a9273f93
commit aa3c544349
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=310423

View File

@ -880,7 +880,7 @@ int
sleepq_broadcast(void *wchan, int flags, int pri, int queue)
{
struct sleepqueue *sq;
struct thread *td;
struct thread *td, *tdn;
int wakeup_swapper;
CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags);
@ -894,7 +894,7 @@ sleepq_broadcast(void *wchan, int flags, int pri, int queue)
/* Resume all blocked threads on the sleep queue. */
wakeup_swapper = 0;
while ((td = TAILQ_FIRST(&sq->sq_blocked[queue])) != NULL) {
TAILQ_FOREACH_SAFE(td, &sq->sq_blocked[queue], td_slpq, tdn) {
thread_lock(td);
wakeup_swapper |= sleepq_resume_thread(sq, td, pri);
thread_unlock(td);