mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +01:00 
			
		
		
		
	gmain: Guarantee handler dispatch after receiving UNIX signal
Guarantee that user signal callback is dispatched _after_ receiving a signal as long as the handler expresses continued interest in receiving such a notification. Previously if a signal has been received during user callback dispatch but before pending flag had been cleared then the signal would be irrevocably lost. This is a very useful guarantee to have in cases where signals are used to signify a need for synchronization with external resources. For example: reloading configuration file after SIGUSR1 or retrieving a terminal size after SIGWINCH.
This commit is contained in:
		@@ -5214,10 +5214,10 @@ g_unix_signal_watch_dispatch (GSource    *source,
 | 
			
		||||
      return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  again = (callback) (user_data);
 | 
			
		||||
 | 
			
		||||
  g_atomic_int_set (&unix_signal_source->pending, FALSE);
 | 
			
		||||
 | 
			
		||||
  again = (callback) (user_data);
 | 
			
		||||
 | 
			
		||||
  return again;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -245,6 +245,56 @@ test_sighup_nested (void)
 | 
			
		||||
  g_main_loop_unref (mainloop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
on_sigwinch_received (gpointer data)
 | 
			
		||||
{
 | 
			
		||||
  GMainLoop *loop = (GMainLoop *) data;
 | 
			
		||||
 | 
			
		||||
  sig_counter ++;
 | 
			
		||||
 | 
			
		||||
  if (sig_counter == 1)
 | 
			
		||||
    kill (getpid (), SIGWINCH);
 | 
			
		||||
  else if (sig_counter == 2)
 | 
			
		||||
    g_main_loop_quit (loop);
 | 
			
		||||
  else if (sig_counter > 2)
 | 
			
		||||
    g_assert_not_reached ();
 | 
			
		||||
 | 
			
		||||
  /* Increase the time window in which an issue could happen. */
 | 
			
		||||
  g_usleep (G_USEC_PER_SEC);
 | 
			
		||||
 | 
			
		||||
  return G_SOURCE_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_callback_after_signal (void)
 | 
			
		||||
{
 | 
			
		||||
  /* Checks that user signal callback is invoked *after* receiving a signal.
 | 
			
		||||
   * In other words a new signal is never merged with the one being currently
 | 
			
		||||
   * dispatched or whose dispatch had already finished. */
 | 
			
		||||
 | 
			
		||||
  GMainLoop *mainloop;
 | 
			
		||||
  GMainContext *context;
 | 
			
		||||
  GSource *source;
 | 
			
		||||
 | 
			
		||||
  sig_counter = 0;
 | 
			
		||||
 | 
			
		||||
  context = g_main_context_new ();
 | 
			
		||||
  mainloop = g_main_loop_new (context, FALSE);
 | 
			
		||||
 | 
			
		||||
  source = g_unix_signal_source_new (SIGWINCH);
 | 
			
		||||
  g_source_set_callback (source, on_sigwinch_received, mainloop, NULL);
 | 
			
		||||
  g_source_attach (source, context);
 | 
			
		||||
  g_source_unref (source);
 | 
			
		||||
 | 
			
		||||
  g_assert_cmpint (sig_counter, ==, 0);
 | 
			
		||||
  kill (getpid (), SIGWINCH);
 | 
			
		||||
  g_main_loop_run (mainloop);
 | 
			
		||||
  g_assert_cmpint (sig_counter, ==, 2);
 | 
			
		||||
 | 
			
		||||
  g_main_loop_unref (mainloop);
 | 
			
		||||
  g_main_context_unref (context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int   argc,
 | 
			
		||||
      char *argv[])
 | 
			
		||||
@@ -259,6 +309,7 @@ main (int   argc,
 | 
			
		||||
  g_test_add_func ("/glib-unix/sighup_again", test_sighup);
 | 
			
		||||
  g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove);
 | 
			
		||||
  g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested);
 | 
			
		||||
  g_test_add_func ("/glib-unix/callback_after_signal", test_callback_after_signal);
 | 
			
		||||
 | 
			
		||||
  return g_test_run();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user