mirror of https://github.com/libsdl-org/SDL.git
Wake the main thread for main function dispatch
Also added a test case to catch the main thread waiting indefinitely when a function is pending. Fixes https://github.com/libsdl-org/SDL/issues/12390
This commit is contained in:
parent
f0f593f04b
commit
049a7a04de
|
|
@ -1371,6 +1371,9 @@ bool SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool w
|
||||||
}
|
}
|
||||||
SDL_UnlockMutex(SDL_main_callbacks_lock);
|
SDL_UnlockMutex(SDL_main_callbacks_lock);
|
||||||
|
|
||||||
|
// If the main thread is waiting for events, wake it up
|
||||||
|
SDL_SendWakeupEvent();
|
||||||
|
|
||||||
if (!wait_complete) {
|
if (!wait_complete) {
|
||||||
// Queued for execution, wait not requested
|
// Queued for execution, wait not requested
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -211,48 +211,93 @@ static int SDLCALL events_addDelEventWatchWithUserdata(void *arg)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef struct IncrementCounterData_t
|
||||||
|
{
|
||||||
|
Uint32 delay;
|
||||||
|
int counter;
|
||||||
|
} IncrementCounterData_t;
|
||||||
|
|
||||||
static void SDLCALL IncrementCounter(void *userdata)
|
static void SDLCALL IncrementCounter(void *userdata)
|
||||||
{
|
{
|
||||||
int *value = (int *)userdata;
|
IncrementCounterData_t *data = (IncrementCounterData_t *)userdata;
|
||||||
*value = *value + 1;
|
++data->counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SDL_PLATFORM_EMSCRIPTEN /* Emscripten doesn't have threads */
|
#ifndef SDL_PLATFORM_EMSCRIPTEN /* Emscripten doesn't have threads */
|
||||||
static int SDLCALL IncrementCounterThread(void *userdata)
|
static int SDLCALL IncrementCounterThread(void *userdata)
|
||||||
{
|
{
|
||||||
|
IncrementCounterData_t *data = (IncrementCounterData_t *)userdata;
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
SDL_assert(!SDL_IsMainThread());
|
SDL_assert(!SDL_IsMainThread());
|
||||||
SDL_RunOnMainThread(IncrementCounter, userdata, false);
|
|
||||||
SDL_RunOnMainThread(IncrementCounter, userdata, true);
|
if (data->delay > 0) {
|
||||||
|
SDL_Delay(data->delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SDL_RunOnMainThread(IncrementCounter, userdata, false)) {
|
||||||
|
SDLTest_LogError("Couldn't run IncrementCounter asynchronously on main thread: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
if (!SDL_RunOnMainThread(IncrementCounter, userdata, true)) {
|
||||||
|
SDLTest_LogError("Couldn't run IncrementCounter synchronously on main thread: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send an event to unblock the main thread, which is waiting in SDL_WaitEvent() */
|
||||||
|
event.type = SDL_EVENT_USER;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* !SDL_PLATFORM_EMSCRIPTEN */
|
#endif /* !SDL_PLATFORM_EMSCRIPTEN */
|
||||||
|
|
||||||
static int SDLCALL events_mainThreadCallbacks(void *arg)
|
static int SDLCALL events_mainThreadCallbacks(void *arg)
|
||||||
{
|
{
|
||||||
int counter = 0;
|
IncrementCounterData_t data = { 0, 0 };
|
||||||
|
|
||||||
/* Make sure we're on the main thread */
|
/* Make sure we're on the main thread */
|
||||||
SDLTest_AssertCheck(SDL_IsMainThread(), "Verify we're on the main thread");
|
SDLTest_AssertCheck(SDL_IsMainThread(), "Verify we're on the main thread");
|
||||||
|
|
||||||
SDL_RunOnMainThread(IncrementCounter, &counter, true);
|
SDL_RunOnMainThread(IncrementCounter, &data, true);
|
||||||
SDLTest_AssertCheck(counter == 1, "Incremented counter on main thread, expected 1, got %d", counter);
|
SDLTest_AssertCheck(data.counter == 1, "Incremented counter on main thread, expected 1, got %d", data.counter);
|
||||||
|
|
||||||
#ifndef SDL_PLATFORM_EMSCRIPTEN /* Emscripten doesn't have threads */
|
#ifndef SDL_PLATFORM_EMSCRIPTEN /* Emscripten doesn't have threads */
|
||||||
{
|
{
|
||||||
|
SDL_Window *window;
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
thread = SDL_CreateThread(IncrementCounterThread, NULL, &counter);
|
window = SDL_CreateWindow("test", 0, 0, SDL_WINDOW_HIDDEN);
|
||||||
|
SDLTest_AssertCheck(window != NULL, "Create window, expected non-NULL, got %p", window);
|
||||||
|
|
||||||
|
/* Flush any pending events */
|
||||||
|
SDL_PumpEvents();
|
||||||
|
SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||||
|
|
||||||
|
/* Increment the counter on a thread, waiting for both calls to be queued */
|
||||||
|
thread = SDL_CreateThread(IncrementCounterThread, NULL, &data);
|
||||||
SDLTest_AssertCheck(thread != NULL, "Create counter thread");
|
SDLTest_AssertCheck(thread != NULL, "Create counter thread");
|
||||||
|
|
||||||
/* Wait for both increment calls to be queued up */
|
/* Wait for both increment calls to be queued up */
|
||||||
SDL_Delay(100);
|
SDL_Delay(100);
|
||||||
|
|
||||||
/* Run the main callbacks */
|
/* Run the main callbacks */
|
||||||
while (counter < 3) {
|
SDL_WaitEvent(&event);
|
||||||
SDL_PumpEvents();
|
SDLTest_AssertCheck(event.type == SDL_EVENT_USER, "Expected user event (0x%.4x), got 0x%.4x", SDL_EVENT_USER, (int)event.type);
|
||||||
}
|
|
||||||
SDL_WaitThread(thread, NULL);
|
SDL_WaitThread(thread, NULL);
|
||||||
SDLTest_AssertCheck(counter == 3, "Incremented counter on main thread, expected 3, got %d", counter);
|
SDLTest_AssertCheck(data.counter == 3, "Incremented counter on main thread, expected 3, got %d", data.counter);
|
||||||
|
|
||||||
|
/* Try again, but this time delay the calls until we've started waiting for events */
|
||||||
|
data.delay = 100;
|
||||||
|
thread = SDL_CreateThread(IncrementCounterThread, NULL, &data);
|
||||||
|
SDLTest_AssertCheck(thread != NULL, "Create counter thread");
|
||||||
|
|
||||||
|
/* Run the main callbacks */
|
||||||
|
SDL_WaitEvent(&event);
|
||||||
|
SDLTest_AssertCheck(event.type == SDL_EVENT_USER, "Expected user event (0x%.4x), got 0x%.4x", SDL_EVENT_USER, (int)event.type);
|
||||||
|
SDL_WaitThread(thread, NULL);
|
||||||
|
SDLTest_AssertCheck(data.counter == 5, "Incremented counter on main thread, expected 5, got %d", data.counter);
|
||||||
|
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
}
|
}
|
||||||
#endif /* !SDL_PLATFORM_EMSCRIPTEN */
|
#endif /* !SDL_PLATFORM_EMSCRIPTEN */
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue