freebsd11_network: Fix race condition leading to lock of deleted mutex.
* Initialize "status" to B_NO_INIT, which will skip the main 'if' the first go-around and go straight to the acquire_sem_etc(), as we will have be invoked from the callout initializer, and so there will of course be no callouts. * Actually check the return code of mutex_lock, and do another loop iteration (which skips this main 'if' as status will not be one of those things.) * Correct failure deinitialization order in init_callout(). * Destroy the mutex after the worker thread exits (this is the real fix.) Fixes #14660, and other "hang on cursor" / "hang on black screen" / or possibly even a "hang on rocket" introduced in yesterday's builds.
This commit is contained in:
@@ -37,14 +37,15 @@ static bigtime_t sTimeout;
|
|||||||
static status_t
|
static status_t
|
||||||
callout_thread(void* /*data*/)
|
callout_thread(void* /*data*/)
|
||||||
{
|
{
|
||||||
status_t status = B_OK;
|
status_t status = B_NO_INIT;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
bigtime_t timeout = B_INFINITE_TIMEOUT;
|
bigtime_t timeout = B_INFINITE_TIMEOUT;
|
||||||
|
|
||||||
if (status == B_TIMED_OUT || status == B_OK) {
|
if (status == B_TIMED_OUT || status == B_OK) {
|
||||||
// scan timers for new timeout and/or execute a timer
|
// scan timers for new timeout and/or execute a timer
|
||||||
mutex_lock(&sLock);
|
if ((status = mutex_lock(&sLock)) != B_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
struct callout* c = NULL;
|
struct callout* c = NULL;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -71,7 +72,8 @@ callout_thread(void* /*data*/)
|
|||||||
&& (c->c_flags & CALLOUT_RETURNUNLOCKED) == 0)
|
&& (c->c_flags & CALLOUT_RETURNUNLOCKED) == 0)
|
||||||
mtx_unlock(mutex);
|
mtx_unlock(mutex);
|
||||||
|
|
||||||
mutex_lock(&sLock);
|
if ((status = mutex_lock(&sLock)) != B_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
sCurrentCallout = NULL;
|
sCurrentCallout = NULL;
|
||||||
c = NULL;
|
c = NULL;
|
||||||
@@ -127,10 +129,10 @@ init_callout(void)
|
|||||||
|
|
||||||
return resume_thread(sThread);
|
return resume_thread(sThread);
|
||||||
|
|
||||||
err1:
|
|
||||||
mutex_destroy(&sLock);
|
|
||||||
err2:
|
err2:
|
||||||
delete_sem(sWaitSem);
|
delete_sem(sWaitSem);
|
||||||
|
err1:
|
||||||
|
mutex_destroy(&sLock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,12 +141,11 @@ void
|
|||||||
uninit_callout(void)
|
uninit_callout(void)
|
||||||
{
|
{
|
||||||
delete_sem(sWaitSem);
|
delete_sem(sWaitSem);
|
||||||
|
|
||||||
|
wait_for_thread(sThread, NULL);
|
||||||
|
|
||||||
mutex_lock(&sLock);
|
mutex_lock(&sLock);
|
||||||
|
|
||||||
mutex_destroy(&sLock);
|
mutex_destroy(&sLock);
|
||||||
|
|
||||||
status_t status;
|
|
||||||
wait_for_thread(sThread, &status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user