changeset 2703:829205a9647a default tip

Pump events and allow debug window interaction while paused in CPU debugger on Windows
author Michael Pavone <pavone@retrodev.com>
date Fri, 04 Jul 2025 21:24:15 -0700
parents 0a6d644c47aa
children
files debug.c util.c util.h
diffstat 3 files changed, 100 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/debug.c	Fri Jul 04 21:23:48 2025 -0700
+++ b/debug.c	Fri Jul 04 21:24:15 2025 -0700
@@ -2296,6 +2296,18 @@
 	END
 };
 
+static void read_wait_progress(void)
+{
+	process_events();
+#ifndef IS_LIB
+	render_update_display();
+	vdp_context *vdp = current_system->get_vdp(current_system);
+	if (vdp) {
+		vdp_update_per_frame_debug(vdp);
+	}
+#endif
+}
+
 static uint8_t read_parse_command(debug_root *root, parsed_command *out, int indent_level)
 {
 	++indent_level;
@@ -2305,35 +2317,9 @@
 	}
 	putchar(' ');
 	fflush(stdout);
-#ifdef _WIN32
-#define wait 0
-#else
-	int wait = 1;
-	fd_set read_fds;
-	FD_ZERO(&read_fds);
-	struct timeval timeout;
-#endif
-	do {
-		process_events();
-#ifndef IS_LIB
-		render_update_display();
-		vdp_context *vdp = current_system->get_vdp(current_system);
-		if (vdp) {
-			vdp_update_per_frame_debug(vdp);
-		}
-#endif
-#ifndef _WIN32
-		timeout.tv_sec = 0;
-		timeout.tv_usec = 16667;
-		FD_SET(fileno(stdin), &read_fds);
-		if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) >= 1) {
-			wait = 0;
-		}
-#endif
-	} while (wait);
-
+	read_wait_progress();
 	char input_buf[1024];
-	if (!fgets(input_buf, sizeof(input_buf), stdin)) {
+	if (!fgets_timeout(input_buf, sizeof(input_buf), stdin, 16667, read_wait_progress)) {
 		fputs("fgets failed", stderr);
 		return READ_FAILED;
 	}
--- a/util.c	Fri Jul 04 21:23:48 2025 -0700
+++ b/util.c	Fri Jul 04 21:24:15 2025 -0700
@@ -757,6 +757,70 @@
 	return WSAGetLastError() == WSAEWOULDBLOCK;
 }
 
+typedef struct {
+	HANDLE           request_event;
+	HANDLE           reply_event;
+	CRITICAL_SECTION lock;
+	FILE             *f;
+	char             *dst;
+	size_t           size;
+} stdio_timeout_state;
+
+static DWORD WINAPI stdio_timeout_thread(LPVOID param)
+{
+	stdio_timeout_state *state = param;
+	EnterCriticalSection(&state->lock);
+		for(;;)
+		{
+			while (!state->f)
+			{
+				LeaveCriticalSection(&state->lock);
+				WaitForSingleObject(state->request_event, INFINITE);
+				EnterCriticalSection(&state->lock);
+			}
+			char *dst = state->dst;
+			size_t size = state->size;
+			FILE *f = state->f;
+			LeaveCriticalSection(&state->lock);
+			dst = fgets(dst, size, f);
+			EnterCriticalSection(&state->lock);
+			state->dst = dst;
+			state->f = NULL;
+			SetEvent(&state->reply_event);
+		}
+	LeaveCriticalSection(&state->lock);
+	
+	return 0;
+}
+
+char *fgets_timeout(char *dst, size_t size, FILE *f, uint64_t timeout_usec, void (*timeout_cb)(void))
+{
+	static HANDLE workerThread;
+	static stdio_timeout_state state;
+	if (!workerThread) {
+		InitializeCriticalSection(&state.lock);
+		state.request_event = CreateEventA(NULL, FALSE, FALSE, NULL);
+		state.reply_event = CreateEventA(NULL, FALSE, FALSE, NULL);
+		workerThread = CreateThread(NULL, 64 * 1024, stdio_timeout_thread, &state, 0, NULL);
+	}
+	EnterCriticalSection(&state.lock);
+		state.f = f;
+		state.dst = dst;
+		state.size = size;
+		SetEvent(state.request_event);
+		while (state.f)
+		{
+			LeaveCriticalSection(&state.lock);
+			WaitForSingleObject(state.reply_event, timeout_usec / 1000);
+			EnterCriticalSection(&state.lock);
+			if (state.f) {
+				timeout_cb();
+			}
+		}
+	LeaveCriticalSection(&state.lock);
+	return state.dst;
+}
+
 #else
 #include <fcntl.h>
 #include <signal.h>
@@ -864,6 +928,26 @@
 	}
 	return exe_dir;
 }
+
+char *fgets_timeout(char *dst, size_t size, FILE *f, uint64_t timeout_usec, void (*timeout_cb)(void))
+{
+	int wait = 1;
+	fd_set read_fds;
+	FD_ZERO(&read_fds);
+	struct timeval timeout;
+	do {
+		timeout.tv_sec = timeout_usec / 1000000;
+		timeout.tv_usec = timeout_usec % 1000000;
+		FD_SET(fileno(stdin), &read_fds);
+		if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) >= 1) {
+			wait = 0;
+		} else {
+			timeout_cb();
+		}
+	} while (wait);
+	return fgets(dst, size, f);
+}
+
 #include <dirent.h>
 
 #ifdef __ANDROID__
--- a/util.h	Fri Jul 04 21:23:48 2025 -0700
+++ b/util.h	Fri Jul 04 21:24:15 2025 -0700
@@ -108,6 +108,8 @@
 int socket_last_error(void);
 //Returns if the last socket error was EAGAIN/EWOULDBLOCK
 int socket_error_is_wouldblock(void);
+//works like fgets, but calls timeout_cb every timeout_usec microseconds while waiting for input
+char *fgets_timeout(char *dst, size_t size, FILE *f, uint64_t timeout_usec, void (*timeout_cb)(void));
 #if defined(__ANDROID__) && !defined(IS_LIB)
 FILE* fopen_wrapper(const char *path, const char *mode);
 #ifndef DISABLE_ZLIB