From c39c9e1a87fc6a7026432f8599bb3ed2d40d8558 Mon Sep 17 00:00:00 2001 From: lloyd konneker Date: Fri, 17 Jan 2025 09:10:03 -0500 Subject: [PATCH 1/3] app/plug-in: fix #12711 app hang on MacOS IO event on empty pipe This is a bandaid for a situation on MacOS. When plugin facade in core receives IO event on read pipe from remote plugin process, check the plugin is in a state where an IO event is expected i.e. sane. Otherwise, ignore the event and assume the read pipe is empty. --- app/plug-in/gimpplugin.c | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/app/plug-in/gimpplugin.c b/app/plug-in/gimpplugin.c index b4e66c0795d..b5f354be067 100644 --- a/app/plug-in/gimpplugin.c +++ b/app/plug-in/gimpplugin.c @@ -107,6 +107,10 @@ static gboolean gimp_plug_in_write (GIOChannel *channel, static gboolean gimp_plug_in_flush (GIOChannel *channel, gpointer data); +#ifdef __APPLE__ +static gboolean gimp_plug_in_should_recv_message (GimpPlugIn *plug_in); +#endif + #if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER static void gimp_plug_in_set_dll_directory (const gchar *path); #endif @@ -199,6 +203,12 @@ gimp_plug_in_recv_message (GIOChannel *channel, if (plug_in->my_read == NULL) return TRUE; +#ifdef __APPLE__ + /* Workaround for #12711 */ + if (! gimp_plug_in_should_recv_message (plug_in)) + return TRUE; +#endif + g_object_ref (plug_in); if (cond & (G_IO_IN | G_IO_PRI)) @@ -337,6 +347,59 @@ gimp_plug_in_flush (GIOChannel *channel, return TRUE; } +#ifdef __APPLE__ + +/* Is self in a state where the remote plugin process + * should be sending msgs to core on self's read pipe? + * + * This is only necessary for #12711, + * where spurious IO events are sent when the pipe is empty + * i.e. no actual msg to receive. + * This might not be correct for any other use. + * + * Self is-a plugin facade in core to a remote plugin process. + * Is self: + * - to a persistent plugin + * - has called the main proc of the remote + * - not waiting for the remote persistent plugin to ack ready + * - has called no temporary procs of the remote + * Typically facade to plugin script-fu with main proc extension-script-fu. + * Then the plugin should not be sending messages. + * A persistent plugin remote process after it has acked "ready" + * should only send messages when self has called + * a temporary proc and that proc is RPC'ing back a different PDB proc, a "run" msg, + * or when the temporary proc completes, sending a "return" msg. + */ +static gboolean +gimp_plug_in_should_recv_message (GimpPlugIn *plug_in) +{ + /* Plugin is persistent when its main proc has type PERSISTENT. + * Plugin has acked ready when ext_main_loop is NULL. + * Self has not called a remote temporary procedure when self's stack + * (actually a list) of temporary procedure calls frames is empty. + */ + if ( (plug_in->ext_main_loop == NULL) && + (plug_in->main_proc_frame.procedure != NULL) && + (plug_in->main_proc_frame.procedure->proc_type == GIMP_PDB_PROC_TYPE_PERSISTENT) && + (plug_in->temp_proc_frames == NULL)) + { + g_debug ("%s persistent plugin %s in idle but ready state", + G_STRFUNC, gimp_object_get_name (plug_in->main_proc_frame.procedure)); + return FALSE; + } + else + { + /* The remote process is not persistent, + * or is persistent but not ready, + * or is persistent and ready and one of its temp procs was called. + * Can expect remote process to send msgs: a new RPC from the remote + * or a return from an RPC to the remote. + */ + return TRUE; + } +} +#endif + #if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER static void gimp_plug_in_set_dll_directory (const gchar *path) -- GitLab From 10025e0a8a1f7c9f6a60f864a4678dc7b1c515a5 Mon Sep 17 00:00:00 2001 From: Lukas Oberhuber Date: Sun, 2 Feb 2025 17:16:18 +0000 Subject: [PATCH 2/3] gimpplugin: Tiny style tweaks --- app/plug-in/gimpplugin.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/plug-in/gimpplugin.c b/app/plug-in/gimpplugin.c index b5f354be067..862119ecfc5 100644 --- a/app/plug-in/gimpplugin.c +++ b/app/plug-in/gimpplugin.c @@ -378,13 +378,13 @@ gimp_plug_in_should_recv_message (GimpPlugIn *plug_in) * Self has not called a remote temporary procedure when self's stack * (actually a list) of temporary procedure calls frames is empty. */ - if ( (plug_in->ext_main_loop == NULL) && - (plug_in->main_proc_frame.procedure != NULL) && - (plug_in->main_proc_frame.procedure->proc_type == GIMP_PDB_PROC_TYPE_PERSISTENT) && - (plug_in->temp_proc_frames == NULL)) + if ((plug_in->ext_main_loop == NULL) && + (plug_in->main_proc_frame.procedure != NULL) && + (plug_in->main_proc_frame.procedure->proc_type == GIMP_PDB_PROC_TYPE_PERSISTENT) && + (plug_in->temp_proc_frames == NULL)) { g_debug ("%s persistent plugin %s in idle but ready state", - G_STRFUNC, gimp_object_get_name (plug_in->main_proc_frame.procedure)); + G_STRFUNC, gimp_object_get_name (plug_in->main_proc_frame.procedure)); return FALSE; } else -- GitLab From 0c10c415441eb72a2f8092678b3735d304728075 Mon Sep 17 00:00:00 2001 From: Lukas Oberhuber Date: Sun, 2 Feb 2025 17:22:18 +0000 Subject: [PATCH 3/3] gimpplugin: Add upstream bug --- app/plug-in/gimpplugin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/app/plug-in/gimpplugin.c b/app/plug-in/gimpplugin.c index 862119ecfc5..c3835160975 100644 --- a/app/plug-in/gimpplugin.c +++ b/app/plug-in/gimpplugin.c @@ -356,6 +356,7 @@ gimp_plug_in_flush (GIOChannel *channel, * where spurious IO events are sent when the pipe is empty * i.e. no actual msg to receive. * This might not be correct for any other use. + * Upstream bug: https://gitlab.gnome.org/GNOME/glib/-/issues/3454 * * Self is-a plugin facade in core to a remote plugin process. * Is self: -- GitLab