GNOME Bugzilla – Bug 742065
Clutter main_quit() does not terminate GJS programs
Last modified: 2018-01-27 11:58:49 UTC
a simple example: const Clutter = imports.gi.Clutter; const Mainloop = imports.mainloop; Clutter.init(null); let s = new Clutter.Stage({ width: 200, height: 200, }); s.connect('destroy', function() { Clutter.main_quit(); }); s.show(); Clutter.main(); if I run it with gjs, and press the window's close button, gjs won't quit after the control has been returned to it. this does not happen when using GTK+, or when using the Mainloop module instead of Clutter.main()/main_quit(). the equivalent C and Python code does not exhibit issues either.
you can verify that the control is returned to gjs after Clutter.main() just by adding a `log('foo')` after it.
Ugh, gjs has /* First, get rid of anything left over on the main context */ while (g_main_context_pending(NULL) && g_atomic_int_get(&pending_idle_toggles) > 0) { g_main_context_iteration(NULL, FALSE); } Which happens when the GjsContext is destroyed. Unfortunately, this conflicts with Clutter locking (because it does not hold the clutter lock around the context_pending() call), and causes a deadlock. That code was added in be5c12c4dc156712a296044916a4108011fe7b3c, Fix assertions during context dispose, by Colin (cced).
Shutdown cleanup is a nasty business... Can you post the stack trace?
(In reply to comment #2) > Unfortunately, this conflicts with Clutter locking (because it does not hold > the clutter lock around the context_pending() call), and causes a deadlock. it does not explain why this does not deadlock GTK's main loop, since the code is not holding the GDK lock either.
*** Bug 744082 has been marked as a duplicate of this bug. ***
I think that's because of the master clock. Its GSource is going to kick back in while gjs is running its cleanup. The GSource takes the clutter global lock, which is already locked upon leaving clutter_main(). In #744082 I suggested to maybe remove the GSource of the master clock, when leaving clutter_main(). It feels like Clutter's internal should stop running when exiting. Any thoughts?
the main issue is that main() → main_quit() → main() is a supported use case, so calling main_quit() should not tear down the global state, unless it can be set up again once main() is called.
So digging more into this, I take back what I wrote about Gtk. You can make Gtk+ dead lock has well : const Gdk = imports.gi.Gdk; const Gtk = imports.gi.Gtk; const Mainloop = imports.mainloop; Gtk.init(null, null); Gdk.threads_init(); let win = new Gtk.Window(); win.show(); Mainloop.timeout_add(50, function() { Gtk.main_quit(); }); Gtk.main(); The key difference, is that Gtk+ doesn't initialize its threads lock by default, so all gdk_threads_enter/leave() calls have no effect. Is this something we could consider for Clutter too?
Just noticed that this bug moved to gjs. Here is a Gtk+ example that deadlocks entirely on its own : const Gdk = imports.gi.Gdk; const Gtk = imports.gi.Gtk; const Mainloop = imports.mainloop; Gtk.init(null, null); Gdk.threads_init(); let win = new Gtk.Window(); win.show(); Mainloop.timeout_add(50, function() { Gtk.main(); }); Mainloop.timeout_add(100, function() { Gtk.main_quit(); }); Gtk.main(); I don't think this is a gjs bug.
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gjs/issues/91.