141 lines
4.2 KiB
Diff
141 lines
4.2 KiB
Diff
From 37ce70d4400a2ab6b59ee432b41d4ffcc9d136ff Mon Sep 17 00:00:00 2001
|
|
From: Paul Adenot <paul@paul.cx>
|
|
Date: Thu, 10 Nov 2016 21:45:14 +0100
|
|
Subject: [PATCH] Bail out safely from the rendering loop if we could not join
|
|
the rendering thread in time (#187)
|
|
|
|
Bail out safely from the rendering loop if we could not join the rendering thread in time.
|
|
---
|
|
src/cubeb_wasapi.cpp | 41 ++++++++++++++++++++++++++++++++++++-----
|
|
1 file changed, 36 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/src/cubeb_wasapi.cpp b/src/cubeb_wasapi.cpp
|
|
index 9e689b9..519d5ca 100644
|
|
--- a/src/cubeb_wasapi.cpp
|
|
+++ b/src/cubeb_wasapi.cpp
|
|
@@ -22,6 +22,7 @@
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <limits>
|
|
+#include <atomic>
|
|
|
|
#include "cubeb/cubeb.h"
|
|
#include "cubeb-internal.h"
|
|
@@ -220,9 +221,11 @@ struct cubeb_stream
|
|
float volume;
|
|
/* True if the stream is draining. */
|
|
bool draining;
|
|
+ /* True when we've destroyed the stream. This pointer is leaked on stream
|
|
+ * destruction if we could not join the thread. */
|
|
+ std::atomic<std::atomic<bool>*> emergency_bailout;
|
|
};
|
|
|
|
-
|
|
class wasapi_endpoint_notification_client : public IMMNotificationClient
|
|
{
|
|
public:
|
|
@@ -781,6 +784,7 @@ static unsigned int __stdcall
|
|
wasapi_stream_render_loop(LPVOID stream)
|
|
{
|
|
cubeb_stream * stm = static_cast<cubeb_stream *>(stream);
|
|
+ std::atomic<bool> * emergency_bailout = stm->emergency_bailout;
|
|
|
|
bool is_playing = true;
|
|
HANDLE wait_array[4] = {
|
|
@@ -820,6 +824,10 @@ wasapi_stream_render_loop(LPVOID stream)
|
|
wait_array,
|
|
FALSE,
|
|
1000);
|
|
+ if (*emergency_bailout) {
|
|
+ delete emergency_bailout;
|
|
+ return 0;
|
|
+ }
|
|
if (waitResult != WAIT_TIMEOUT) {
|
|
timeout_count = 0;
|
|
}
|
|
@@ -1134,12 +1142,13 @@ int wasapi_init(cubeb ** context, char const * context_name)
|
|
}
|
|
|
|
namespace {
|
|
-void stop_and_join_render_thread(cubeb_stream * stm)
|
|
+bool stop_and_join_render_thread(cubeb_stream * stm)
|
|
{
|
|
+ bool rv = true;
|
|
LOG("Stop and join render thread.");
|
|
if (!stm->thread) {
|
|
LOG("No thread present.");
|
|
- return;
|
|
+ return true;
|
|
}
|
|
|
|
BOOL ok = SetEvent(stm->shutdown_event);
|
|
@@ -1153,11 +1162,15 @@ void stop_and_join_render_thread(cubeb_stream * stm)
|
|
if (r == WAIT_TIMEOUT) {
|
|
/* Something weird happened, leak the thread and continue the shutdown
|
|
* process. */
|
|
+ *(stm->emergency_bailout) = true;
|
|
LOG("Destroy WaitForSingleObject on thread timed out,"
|
|
" leaking the thread: %d", GetLastError());
|
|
+ rv = false;
|
|
}
|
|
if (r == WAIT_FAILED) {
|
|
+ *(stm->emergency_bailout) = true;
|
|
LOG("Destroy WaitForSingleObject on thread failed: %d", GetLastError());
|
|
+ rv = false;
|
|
}
|
|
|
|
LOG("Closing thread.");
|
|
@@ -1167,6 +1180,8 @@ void stop_and_join_render_thread(cubeb_stream * stm)
|
|
|
|
CloseHandle(stm->shutdown_event);
|
|
stm->shutdown_event = 0;
|
|
+
|
|
+ return rv;
|
|
}
|
|
|
|
void wasapi_destroy(cubeb * context)
|
|
@@ -1775,7 +1790,16 @@ void wasapi_stream_destroy(cubeb_stream * stm)
|
|
{
|
|
XASSERT(stm);
|
|
|
|
- stop_and_join_render_thread(stm);
|
|
+ // Only free stm->emergency_bailout if we could not join the thread.
|
|
+ // If we could not join the thread, stm->emergency_bailout is true
|
|
+ // and is still alive until the thread wakes up and exits cleanly.
|
|
+ if (stop_and_join_render_thread(stm)) {
|
|
+ delete stm->emergency_bailout.load();
|
|
+ stm->emergency_bailout = nullptr;
|
|
+ } else {
|
|
+ // If we're leaking, it must be that this is true.
|
|
+ assert(*(stm->emergency_bailout));
|
|
+ }
|
|
|
|
unregister_notification_client(stm);
|
|
|
|
@@ -1844,6 +1868,8 @@ int wasapi_stream_start(cubeb_stream * stm)
|
|
|
|
auto_lock lock(stm->stream_reset_lock);
|
|
|
|
+ stm->emergency_bailout = new std::atomic<bool>(false);
|
|
+
|
|
if (stm->output_client) {
|
|
int rv = stream_start_one_side(stm, OUTPUT);
|
|
if (rv != CUBEB_OK) {
|
|
@@ -1903,7 +1929,12 @@ int wasapi_stream_stop(cubeb_stream * stm)
|
|
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
|
}
|
|
|
|
- stop_and_join_render_thread(stm);
|
|
+ if (stop_and_join_render_thread(stm)) {
|
|
+ if (stm->emergency_bailout.load()) {
|
|
+ delete stm->emergency_bailout.load();
|
|
+ stm->emergency_bailout = nullptr;
|
|
+ }
|
|
+ }
|
|
|
|
return CUBEB_OK;
|
|
}
|
|
--
|
|
2.7.4
|
|
|