Implement proper support for complete_all() in the LinuxKPI.

When complete_all() is called there might be multiple waiters. The
current implementation could only handle one waiter. Make sure the
completion is sticky when complete_all() is called to be compatible
with Linux.

Found by:	Johannes Lundberg <johalun0@gmail.com>
MFC after:	1 week
Sponsored by:	Mellanox Technologies
Sponsored by:	Limelight Networks
This commit is contained in:
Hans Petter Selasky 2018-03-09 12:16:55 +00:00
parent d1b671061b
commit be15e1332d

View File

@ -1779,11 +1779,14 @@ linux_complete_common(struct completion *c, int all)
int wakeup_swapper;
sleepq_lock(c);
c->done++;
if (all)
if (all) {
c->done = UINT_MAX;
wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
else
} else {
if (c->done != UINT_MAX)
c->done++;
wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
}
sleepq_release(c);
if (wakeup_swapper)
kick_proc0();
@ -1825,7 +1828,8 @@ linux_wait_for_common(struct completion *c, int flags)
} else
sleepq_wait(c, 0);
}
c->done--;
if (c->done != UINT_MAX)
c->done--;
sleepq_release(c);
intr:
@ -1878,7 +1882,8 @@ linux_wait_for_timeout_common(struct completion *c, int timeout, int flags)
goto done;
}
}
c->done--;
if (c->done != UINT_MAX)
c->done--;
sleepq_release(c);
/* return how many jiffies are left */
@ -1894,12 +1899,10 @@ linux_try_wait_for_completion(struct completion *c)
{
int isdone;
isdone = 1;
sleepq_lock(c);
if (c->done)
isdone = (c->done != 0);
if (c->done != 0 && c->done != UINT_MAX)
c->done--;
else
isdone = 0;
sleepq_release(c);
return (isdone);
}
@ -1909,10 +1912,8 @@ linux_completion_done(struct completion *c)
{
int isdone;
isdone = 1;
sleepq_lock(c);
if (c->done == 0)
isdone = 0;
isdone = (c->done != 0);
sleepq_release(c);
return (isdone);
}