From ea14d8a186c342fa8cce02cd0134230dba7e71b3 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Sun, 31 Mar 2019 01:12:22 +0100 Subject: [PATCH] gdb: avoid race conditions --- sysmodules/rosalina/include/gdb/server.h | 4 +++ sysmodules/rosalina/source/gdb/server.c | 32 +++++++++++++------ .../rosalina/source/menus/process_list.c | 18 +++++++++-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/sysmodules/rosalina/include/gdb/server.h b/sysmodules/rosalina/include/gdb/server.h index 77817e0..248eae2 100644 --- a/sysmodules/rosalina/include/gdb/server.h +++ b/sysmodules/rosalina/include/gdb/server.h @@ -47,6 +47,10 @@ void GDB_IncrementServerReferenceCount(GDBServer *server); void GDB_DecrementServerReferenceCount(GDBServer *server); void GDB_RunServer(GDBServer *server); + +void GDB_LockAllContexts(GDBServer *server); +void GDB_UnlockAllContexts(GDBServer *server); + GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPort); int GDB_AcceptClient(GDBContext *ctx); diff --git a/sysmodules/rosalina/source/gdb/server.c b/sysmodules/rosalina/source/gdb/server.c index 9e894d0..c6075bc 100644 --- a/sysmodules/rosalina/source/gdb/server.c +++ b/sysmodules/rosalina/source/gdb/server.c @@ -90,18 +90,35 @@ void GDB_RunServer(GDBServer *server) server_run(&server->super); } +void GDB_LockAllContexts(GDBServer *server) +{ + for (u32 i = 0; i < MAX_DEBUG; i++) + RecursiveLock_Lock(&server->ctxs[i].lock); +} + +void GDB_UnlockAllContexts(GDBServer *server) +{ + for (u32 i = MAX_DEBUG; i > 0; i--) + RecursiveLock_Unlock(&server->ctxs[i - 1].lock); +} + GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPort) { GDBContext *ctx; u16 port; + GDB_LockAllContexts(server); + // Get a context u32 id; for(id = 0; id < MAX_DEBUG && (server->ctxs[id].flags & GDB_FLAG_SELECTED); id++); if(id < MAX_DEBUG) ctx = &server->ctxs[id]; else + { + GDB_UnlockAllContexts(server); return NULL; + } // Get a port for (port = minPort; port < maxPort; port++) @@ -119,20 +136,17 @@ GDBContext *GDB_SelectAvailableContext(GDBServer *server, u16 minPort, u16 maxPo if (port >= maxPort) { - RecursiveLock_Lock(&ctx->lock); ctx->flags = ~GDB_FLAG_SELECTED; - RecursiveLock_Unlock(&ctx->lock); - return NULL; + ctx = NULL; } - else { - RecursiveLock_Lock(&ctx->lock); ctx->flags |= GDB_FLAG_SELECTED; ctx->localPort = port; - RecursiveLock_Unlock(&ctx->lock); - return ctx; } + + GDB_UnlockAllContexts(server); + return ctx; } int GDB_AcceptClient(GDBContext *ctx) @@ -201,6 +215,7 @@ int GDB_CloseClient(GDBContext *ctx) GDBContext *GDB_GetClient(GDBServer *server, u16 port) { + GDB_LockAllContexts(server); GDBContext *ctx = NULL; if (port >= GDB_PORT_BASE && port < GDB_PORT_BASE + MAX_DEBUG) { @@ -216,12 +231,11 @@ GDBContext *GDB_GetClient(GDBServer *server, u16 port) if (ctx != NULL) { - RecursiveLock_Lock(&ctx->lock); ctx->flags |= GDB_FLAG_USED; ctx->state = GDB_STATE_CONNECTED; - RecursiveLock_Unlock(&ctx->lock); } + GDB_UnlockAllContexts(server); return ctx; } diff --git a/sysmodules/rosalina/source/menus/process_list.c b/sysmodules/rosalina/source/menus/process_list.c index 9c3ae6f..d67f13e 100644 --- a/sysmodules/rosalina/source/menus/process_list.c +++ b/sysmodules/rosalina/source/menus/process_list.c @@ -52,9 +52,16 @@ extern GDBServer gdbServer; static inline int ProcessListMenu_FormatInfoLine(char *out, const ProcessInfo *info) { const char *checkbox; - u32 id; - for(id = 0; id < MAX_DEBUG && (!(gdbServer.ctxs[id].flags & GDB_FLAG_SELECTED) || gdbServer.ctxs[id].pid != info->pid); id++); - checkbox = !gdbServer.super.running ? "" : (id < MAX_DEBUG ? "(x) " : "( ) "); + u32 id = 0; + + if(gdbServer.super.running) + { + GDB_LockAllContexts(&gdbServer); + for(id = 0; id < MAX_DEBUG && (!(gdbServer.ctxs[id].flags & GDB_FLAG_SELECTED) || gdbServer.ctxs[id].pid != info->pid); id++); + checkbox = id < MAX_DEBUG ? "(x) " : "( ) "; + } + else + checkbox = ""; char commentBuf[23 + 1] = { 0 }; // exactly the size of "Remote: 255.255.255.255" memset(commentBuf, ' ', 23); @@ -77,6 +84,8 @@ static inline int ProcessListMenu_FormatInfoLine(char *out, const ProcessInfo *i } } + if (gdbServer.super.running) + GDB_UnlockAllContexts(&gdbServer); return sprintf(out, "%s%-4lu %-8.8s %s", checkbox, info->pid, info->name, commentBuf); // Theoritically PIDs are 32-bit ints, but we'll only justify 4 digits } @@ -581,6 +590,7 @@ static inline void ProcessListMenu_HandleSelected(const ProcessInfo *info) return; } + GDB_LockAllContexts(&gdbServer); u32 id; for(id = 0; id < MAX_DEBUG && (!(gdbServer.ctxs[id].flags & GDB_FLAG_SELECTED) || gdbServer.ctxs[id].pid != info->pid); id++); @@ -610,6 +620,8 @@ static inline void ProcessListMenu_HandleSelected(const ProcessInfo *info) if (ctx != NULL) ctx->pid = info->pid; } + + GDB_UnlockAllContexts(&gdbServer); } s32 ProcessListMenu_FetchInfo(void)