Skip to content

Commit

Permalink
Made event and temporary string memory thread-local and added SDL_Fre…
Browse files Browse the repository at this point in the history
…eEventMemory()

Fixes libsdl-org#10283
  • Loading branch information
slouken committed Jul 16, 2024
1 parent 3e6a248 commit 0bcdea2
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 49 deletions.
19 changes: 18 additions & 1 deletion include/SDL3/SDL_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,7 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_EventEnabled(Uint32 type);
extern SDL_DECLSPEC Uint32 SDLCALL SDL_RegisterEvents(int numevents);

/**
* Allocate dynamic memory for an SDL event.
* Allocate temporary memory for an SDL event.
*
* You can use this to allocate memory for user events that will be
* automatically freed after the event is processed.
Expand All @@ -1419,9 +1419,26 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_RegisterEvents(int numevents);
* \threadsafety It is safe to call this function from any thread.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_FreeEventMemory
*/
extern SDL_DECLSPEC void * SDLCALL SDL_AllocateEventMemory(size_t size);

/**
* Free temporary event memory allocated by SDL.
*
* This function frees temporary memory allocated for events and APIs that return temporary strings. This memory is local to the thread that creates it and is automatically freed for the main thread when pumping the event loop. For other threads you may want to call this function periodically to free any temporary memory created by that thread.
*
* Note that if you call SDL_AllocateEventMemory() on one thread and pass it to another thread, e.g. via a user event, then you should be sure the other thread has finished processing it before calling this function.
*
* \threadsafety It is safe to call this function from any thread.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_AllocateEventMemory
*/
extern SDL_DECLSPEC void SDLCALL SDL_FreeEventMemory(void);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
Expand Down
1 change: 0 additions & 1 deletion src/SDL.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,6 @@ void SDL_Quit(void)
*/
SDL_memset(SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount));

SDL_FlushEventMemory(0);
SDL_FreeEnvironmentMemory();

SDL_QuitMainThread();
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ SDL3_0.0.0 {
SDL_FlushEvent;
SDL_FlushEvents;
SDL_FlushRenderer;
SDL_FreeEventMemory;
SDL_GDKSuspendComplete;
SDL_GL_CreateContext;
SDL_GL_DestroyContext;
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
#define SDL_FlushEvent SDL_FlushEvent_REAL
#define SDL_FlushEvents SDL_FlushEvents_REAL
#define SDL_FlushRenderer SDL_FlushRenderer_REAL
#define SDL_FreeEventMemory SDL_FreeEventMemory_REAL
#define SDL_GDKSuspendComplete SDL_GDKSuspendComplete_REAL
#define SDL_GL_CreateContext SDL_GL_CreateContext_REAL
#define SDL_GL_DestroyContext SDL_GL_DestroyContext_REAL
Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ SDL_DYNAPI_PROC(int,SDL_FlushAudioStream,(SDL_AudioStream *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_FlushEvent,(Uint32 a),(a),)
SDL_DYNAPI_PROC(void,SDL_FlushEvents,(Uint32 a, Uint32 b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_FlushRenderer,(SDL_Renderer *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_FreeEventMemory,(void),(),)
SDL_DYNAPI_PROC(void,SDL_GDKSuspendComplete,(void),(),)
SDL_DYNAPI_PROC(SDL_GLContext,SDL_GL_CreateContext,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GL_DestroyContext,(SDL_GLContext a),(a),return)
Expand Down
132 changes: 86 additions & 46 deletions src/events/SDL_events.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,35 +97,79 @@ typedef struct SDL_EventMemory
struct SDL_EventMemory *next;
} SDL_EventMemory;

static SDL_Mutex *SDL_event_memory_lock;
static SDL_EventMemory *SDL_event_memory_head;
static SDL_EventMemory *SDL_event_memory_tail;
typedef struct SDL_EventMemoryState
{
SDL_EventMemory *head;
SDL_EventMemory *tail;
} SDL_EventMemoryState;

static SDL_TLSID SDL_event_memory;


static void SDL_CleanupEventMemory(void *data)
{
SDL_EventMemoryState *state = (SDL_EventMemoryState *)data;

while (state->head) {
SDL_EventMemory *entry = state->head;
state->head = entry->next;
SDL_free(entry->memory);
SDL_free(entry);
}
SDL_free(state);
}

static SDL_EventMemoryState *SDL_GetEventMemoryState(SDL_bool create)
{
SDL_EventMemoryState *state;

state = SDL_GetTLS(&SDL_event_memory);
if (!state) {
if (!create) {
return NULL;
}

state = (SDL_EventMemoryState *)SDL_calloc(1, sizeof(*state));
if (!state) {
return NULL;
}

if (SDL_SetTLS(&SDL_event_memory, state, SDL_CleanupEventMemory) < 0) {
SDL_free(state);
return NULL;
}
}
return state;
}

void *SDL_FreeLater(void *memory)
{
SDL_EventMemoryState *state;

if (memory == NULL) {
return NULL;
}

state = SDL_GetEventMemoryState(SDL_TRUE);
if (!state) {
return memory; // this is now a leak, but you probably have bigger problems if malloc failed.
}

SDL_EventMemory *entry = (SDL_EventMemory *)SDL_malloc(sizeof(*entry));
if (!entry) {
return memory; // this is now a leak, but you probably have bigger problems if malloc failed. We could probably pool up and reuse entries, though.
}

SDL_LockMutex(SDL_event_memory_lock);
{
entry->eventID = SDL_last_event_id;
entry->memory = memory;
entry->next = NULL;
entry->eventID = SDL_last_event_id;
entry->memory = memory;
entry->next = NULL;

if (SDL_event_memory_tail) {
SDL_event_memory_tail->next = entry;
} else {
SDL_event_memory_head = entry;
}
SDL_event_memory_tail = entry;
if (state->tail) {
state->tail->next = entry;
} else {
state->head = entry;
}
SDL_UnlockMutex(SDL_event_memory_lock);
state->tail = entry;

return memory;
}
Expand All @@ -143,31 +187,39 @@ const char *SDL_AllocateEventString(const char *string)
return NULL;
}

void SDL_FlushEventMemory(Uint32 eventID)
static void SDL_FlushEventMemory(Uint32 eventID)
{
SDL_LockMutex(SDL_event_memory_lock);
{
if (SDL_event_memory_head) {
while (SDL_event_memory_head) {
SDL_EventMemory *entry = SDL_event_memory_head;
SDL_EventMemoryState *state;

if (eventID && (Sint32)(eventID - entry->eventID) < 0) {
break;
}
state = SDL_GetEventMemoryState(SDL_FALSE);
if (!state) {
return;
}

/* If you crash here, your application has memory corruption
* or freed memory in an event, which is no longer necessary.
*/
SDL_event_memory_head = entry->next;
SDL_free(entry->memory);
SDL_free(entry);
}
if (!SDL_event_memory_head) {
SDL_event_memory_tail = NULL;
if (state->head) {
while (state->head) {
SDL_EventMemory *entry = state->head;

if (eventID && (Sint32)(eventID - entry->eventID) < 0) {
break;
}

/* If you crash here, your application has memory corruption
* or freed memory in an event, which is no longer necessary.
*/
state->head = entry->next;
SDL_free(entry->memory);
SDL_free(entry);
}
if (!state->head) {
state->tail = NULL;
}
}
SDL_UnlockMutex(SDL_event_memory_lock);
}

void SDL_FreeEventMemory(void)
{
SDL_FlushEventMemory(0);
}

#ifndef SDL_JOYSTICK_DISABLED
Expand Down Expand Up @@ -697,10 +749,6 @@ void SDL_StopEventLoop(void)
SDL_disabled_events[i] = NULL;
}

if (SDL_event_memory_lock) {
SDL_DestroyMutex(SDL_event_memory_lock);
SDL_event_memory_lock = NULL;
}
if (SDL_event_watchers_lock) {
SDL_DestroyMutex(SDL_event_watchers_lock);
SDL_event_watchers_lock = NULL;
Expand Down Expand Up @@ -746,14 +794,6 @@ int SDL_StartEventLoop(void)
return -1;
}
}

if (SDL_event_memory_lock == NULL) {
SDL_event_memory_lock = SDL_CreateMutex();
if (SDL_event_memory_lock == NULL) {
SDL_UnlockMutex(SDL_EventQ.lock);
return -1;
}
}
#endif /* !SDL_THREADS_DISABLED */

SDL_EventQ.active = SDL_TRUE;
Expand Down
1 change: 0 additions & 1 deletion src/events/SDL_events_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
/* Start and stop the event processing loop */
extern int SDL_StartEventLoop(void);
extern void SDL_StopEventLoop(void);
extern void SDL_FlushEventMemory(Uint32 eventID);
extern void SDL_QuitInterrupt(void);

extern const char *SDL_AllocateEventString(const char *string);
Expand Down

0 comments on commit 0bcdea2

Please sign in to comment.