fix a GLib critical from cancelling the pick probe's timeout
The lifetime fix in ffec797 removes the UDPSCOPE_PROBE_PICK_MS timeout after
the nested loop returns, so a row picked before the delay elapsed cannot leave
an armed source pointing at a gone stack frame. But the probe returns
G_SOURCE_REMOVE on every path, so on the ordinary run -- the probe fires, picks
row 0 and the loop quits -- the id was already stale and the removal printed
"Source ID N was not found when attempting to remove it" on every probe run.
The id moves onto the Chooser and pick_probe clears it on entry, so the
cancellation applies only to a probe that never fired.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
ffec797462
commit
53815ad8bc
1 file changed
+10
-3
+10
-3
@@ -60,6 +60,10 @@ struct Chooser {
|
||||
GtkWidget* form_group = nullptr;
|
||||
GtkWidget* form_iface = nullptr;
|
||||
GtkWidget* form_connect = nullptr;
|
||||
/// `UDPSCOPE_PROBE_PICK_MS`'s timeout, kept so a pick made before it fires can cancel it. The
|
||||
/// probe clears it when it runs: `g_source_remove()` on an id whose source already returned
|
||||
/// `G_SOURCE_REMOVE` is a GLib critical, not a no-op.
|
||||
guint pick_source = 0;
|
||||
};
|
||||
|
||||
void chooser_finish(Chooser& c, bool chosen) {
|
||||
@@ -294,6 +298,10 @@ gboolean on_chooser_key(GtkEventControllerKey*, guint keyval, guint, GdkModifier
|
||||
/// `UDPSCOPE_PROBE_FIELDS_MS` is in `ui.cpp`.
|
||||
gboolean pick_probe(gpointer user) {
|
||||
Chooser& c = *static_cast<Chooser*>(user);
|
||||
// Every path below returns `G_SOURCE_REMOVE`, so the source is gone the moment this returns and
|
||||
// its id is stale. Clear it here rather than on each path: `choose_source()`'s cancel-the-pending
|
||||
// -probe call would otherwise be a GLib critical on every run that let the probe fire.
|
||||
c.pick_source = 0;
|
||||
|
||||
// `UDPSCOPE_PROBE_NEWHOST=host:port` drives the form instead of a row.
|
||||
if (const char* spec = g_getenv("UDPSCOPE_PROBE_NEWHOST")) {
|
||||
@@ -397,16 +405,15 @@ bool choose_source(Config& cfg) {
|
||||
// Keep the timeout id so it can be cancelled if the chooser finishes before it fires. A row
|
||||
// clicked before UDPSCOPE_PROBE_PICK_MS elapses would otherwise leave an armed source on the
|
||||
// default main context pointing at the now-gone stack frame.
|
||||
guint pick_probe_id = 0;
|
||||
if (const char* env = g_getenv("UDPSCOPE_PROBE_PICK_MS")) {
|
||||
pick_probe_id = g_timeout_add(static_cast<guint>(std::atoi(env)), pick_probe, &c);
|
||||
c.pick_source = g_timeout_add(static_cast<guint>(std::atoi(env)), pick_probe, &c);
|
||||
}
|
||||
|
||||
c.loop = g_main_loop_new(nullptr, FALSE);
|
||||
g_main_loop_run(c.loop);
|
||||
g_main_loop_unref(c.loop);
|
||||
c.loop = nullptr;
|
||||
if (pick_probe_id != 0) g_source_remove(pick_probe_id);
|
||||
if (c.pick_source != 0) g_source_remove(c.pick_source);
|
||||
return c.chosen;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user