From e69e7c95bc68a90eadfbd963359737dce43d65f2 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Mon, 21 Oct 2024 22:29:33 +0200 Subject: fixed some interruptions of on Win32 * We now recreate the event loop with every call since it turned out that the idle watcher wouldn't be invoked after the event loop has been quit once. This at least fixes interruption of ECbash -c 'while true; do true; done'$. * Unfortunately, ECping -t 8.8.8.8$ still cannot be interrupted (unless you manually kill the process from the task manager). --- TODO | 7 ++----- src/spawn.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index e9bf2ac..f967b1d 100644 --- a/TODO +++ b/TODO @@ -16,11 +16,8 @@ Known Bugs: https://github.com/Bill-Gray/PDCursesMod/issues/322 * Win32: Interrupting will sometimes hang. Affects both PDCurses/WinGUI and Gtk. - In this case you have to kill the subprocess using the task manager. - Could this be a race condition when adding the process to the job object? - Perhaps the child process should be created suspended before being added - to the job object. Glib does not currently allow that. - This could already be fixed. + This no longer happens with ECbash -c 'while true; do true; done'$. + However ECping -t 8.8.8.8$ still cannot be interrupted. * dlmalloc's malloc_trim() does not seem to free any resident memory after hitting the OOM limit, eg. after <%a>. Apparently an effect of HAVE_MORECORE (sbrk()) - some allocation is diff --git a/src/spawn.c b/src/spawn.c index a1da5ff..99eb6e3 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -92,10 +92,12 @@ static void __attribute__((constructor)) teco_spawn_init(void) { memset(&teco_spawn_ctx, 0, sizeof(teco_spawn_ctx)); + /* FIXME: Cannot share these objects between calls */ +#if 0 /* * Context and loop can be reused between EC invocations. * However we should not use the default context, since it - * may be used by GTK + * may be used by GTK. */ teco_spawn_ctx.mainctx = g_main_context_new(); teco_spawn_ctx.mainloop = g_main_loop_new(teco_spawn_ctx.mainctx, FALSE); @@ -108,6 +110,7 @@ teco_spawn_init(void) g_source_set_callback(teco_spawn_ctx.idle_src, (GSourceFunc)teco_spawn_idle_cb, NULL, NULL); g_source_attach(teco_spawn_ctx.idle_src, teco_spawn_ctx.mainctx); +#endif } static gchar ** @@ -286,6 +289,20 @@ teco_state_execute_done(teco_machine_main_t *ctx, const teco_string_t *str, GErr &stdin_fd, &stdout_fd, NULL, error)) goto gerror; + /* + * FIXME: At least on Win32, we cannot resume a main loop + * after it has been quit once, which is obviously a bug. + * Therefore, we cannot cache the context, loop and idle_src. + */ + teco_spawn_ctx.mainctx = g_main_context_new(); + teco_spawn_ctx.mainloop = g_main_loop_new(teco_spawn_ctx.mainctx, FALSE); + + teco_spawn_ctx.idle_src = g_idle_source_new(); + g_source_set_priority(teco_spawn_ctx.idle_src, G_PRIORITY_LOW); + g_source_set_callback(teco_spawn_ctx.idle_src, (GSourceFunc)teco_spawn_idle_cb, + NULL, NULL); + g_source_attach(teco_spawn_ctx.idle_src, teco_spawn_ctx.mainctx); + teco_spawn_ctx.child_src = g_child_watch_source_new(pid); g_source_set_callback(teco_spawn_ctx.child_src, (GSourceFunc)teco_spawn_child_watch_cb, NULL, NULL); @@ -293,6 +310,9 @@ teco_state_execute_done(teco_machine_main_t *ctx, const teco_string_t *str, GErr teco_spawn_ctx.interrupted = FALSE; #ifdef G_OS_WIN32 + /* + * FIXME: In case of errors, we will leak memory. + */ teco_spawn_ctx.pid = CreateJobObject(NULL, NULL); if (!teco_spawn_ctx.pid) { teco_error_win32_set(error, "Cannot create job object", GetLastError()); @@ -406,6 +426,10 @@ teco_state_execute_done(teco_machine_main_t *ctx, const teco_string_t *str, GErr CloseHandle(teco_spawn_ctx.pid); #endif + g_source_unref(teco_spawn_ctx.idle_src); + g_main_loop_unref(teco_spawn_ctx.mainloop); + g_main_context_unref(teco_spawn_ctx.mainctx); + /* * NOTE: This includes interruptions following CTRL+C. * But they are reported as G_SPAWN_ERROR_FAILED and hard to filter out. @@ -828,10 +852,13 @@ teco_spawn_idle_cb(gpointer user_data) static void TECO_DEBUG_CLEANUP teco_spawn_cleanup(void) { + /* FIXME: Cannot share these objects between calls */ +#if 0 g_source_unref(teco_spawn_ctx.idle_src); g_main_loop_unref(teco_spawn_ctx.mainloop); g_main_context_unref(teco_spawn_ctx.mainctx); +#endif if (teco_spawn_ctx.error) g_error_free(teco_spawn_ctx.error); -- cgit v1.2.3