Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 'atexit'-based cleanup on Windows #849

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions miniaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -16187,7 +16187,7 @@ static void ma_thread_wait__posix(ma_thread* pThread)
static ma_result ma_mutex_init__posix(ma_mutex* pMutex)
{
int result;

if (pMutex == NULL) {
return MA_INVALID_ARGS;
}
Expand Down Expand Up @@ -42402,8 +42402,27 @@ MA_API ma_result ma_device_stop(ma_device* pDevice)
/*
We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
the one who puts the device into the stopped state. Don't call ma_device__set_state() here.

When using miniaudio through a shared library on Windows, registering cleanup operations such as `ma_engine_uninit` via
`atexit` will result in a deadlock because all threads will be forcefully terminated without any thread-detach notification
by the Win32 runtime as part of `ExitProcess`.

To prevent the deadlock and support `atexit`-based cleanup (e.g. using miniaudio via C++ `static` objects), we only wait
for the stop event signal if the thread was not forcefully terminated.

Further reading: https://www.luke1410.de/blog/2017/02/the-trouble-of-separate-module-atexit-stacks/
*/
ma_event_wait(&pDevice->stopEvent);

#if defined(MA_WIN32)
const ma_bool32 shouldWait = WaitForSingleObject(pDevice->thread, 0) == WAIT_TIMEOUT;
#else
const ma_bool32 shouldWait = MA_TRUE;
#endif

if (shouldWait) {
ma_event_wait(&pDevice->stopEvent);
}

result = MA_SUCCESS;
}

Expand Down