Re: [gtk-list] Handling OS signals?



On Thu, 18 Feb 1999, Drazen Kacar wrote:

> I have an application that forks off several child processes and then sleeps
> most of the time, but it should show how many children exist at a given time.
> I can receive SIGCHLD when a child exits, but I don't know of an elegant
> way to tell GTK that I want my function called after the signal handler
> returns.
> 
> GTK sleeps in GLib's poll() and any OS signal will invoke my signal handler
> and then interrupt poll(). GLib will then look if there are events to be
> dispatched and if none found, return to poll(). I could do processing in
> OS signal handler, but that's not advisable, since most OS functions
> are not guaranteed to be async safe. So I'd like to set a variable or two,
> register one callback and return. Upon return, GLib should invoke that
> callback to do the actual job. The problem is that I don't know which
> (if any) function for callback registration is reentrant and safe to call
> from an OS signal handler.
> 
> I could use timers or something, but that's ugly and inefficient.

glib currently contains no functions that cover this specific need,
basically none of its functions are truely reentrant from every point.

however, some time ago i wrote up a few small functions that add an extra
unix-signal handler source to glib's main loop. with that you notify glib
of the occourance of a unix signal through g_signal_notify() from within
the unix-signal handler and later, after the signal handler returned, glib's
main loop will invoke the callbacks that you setup for this signal.
here's a small test program:

#include        "gsignal.h"
#include        "gsignal.c"
/* unix signal handler that notifies glib */
static void
unix_sigh (int sig)
{
  signal (sig, unix_sigh); /* on linux we need to reset the signal handler */

  g_signal_notify (sig); /* notify glib that a signal ocoured, this function
                            is truely reentrant */
}
/* glib unix-signal handler, invoked from the main loop right
 * after unix_sigh() returned
 */
static gboolean
g_sigh (gint8    sig,
        gpointer data)
{
  g_print ("glib signal handler called: %s\n", g_strsignal (sig));

  return TRUE;
}

and in main() you setup callbacks for specific signals:

int
main (int argc, char *argv[])
{
  GMainLoop *loop;
  gint i;

  /* setup unix_sigh, but still exit on SIGQUIT ;) */
  for (i = 0; i < 32; i++)
    signal (i, unix_sigh);
  signal (SIGQUIT, NULL);

  loop = g_main_new (TRUE);

  g_print ("pid=%d\n", getpid ());

  /* setup glib callbacks for specific signals */
  for (i = -128; i < 128; i++)
    g_signal_add (i, g_sigh, NULL);

  /* run the main loop, we safely await unix-signals now */
  g_main_run (loop);

  g_main_destroy (loop);

  return 0;
}


note that from within gtk, you don't need to do the extra glib loop
setup steps, because gtk_main() pretty much does
  GMainLoop *loop;
  loop = g_main_new (TRUE);
  g_main_run (loop);
  g_main_destroy (loop);
already.

i've appended gsignal.h and gsignal.c below signature, these files, or
something pretty close to that, will get included in glib 1.3.

> 
> -- 
>  .-.   .-.    Life is a sexually transmitted disease.
> (_  \ /  _)
>      |        dave@srce.hr
>      |        dave@fly.cc.fer.hr
> 

---
ciaoTJ

------------------------- gsignal.h ------------------------------------

typedef gboolean (*GSignalFunc) (gint8		signal,
				 gpointer	data);
guint	g_signal_add		(gint8		signal,
				 GSignalFunc	function,
				 gpointer    	data);
guint   g_signal_add_full       (gint           priority,
				 gint8          signal,
				 GSignalFunc    function,
				 gpointer       data,
				 GDestroyNotify destroy);
void    g_signal_notify         (gint8          signal);

------------------------- gsignal.c ------------------------------------

typedef struct _GSignalData GSignalData;
struct _GSignalData
{
  guint8      index;
  guint8      shift;
  GSignalFunc callback;
};

static gboolean g_signal_prepare  (gpointer  source_data,
				   GTimeVal *current_time,
				   gint     *timeout);
static gboolean g_signal_check    (gpointer  source_data,
				   GTimeVal *current_time);
static gboolean g_signal_dispatch (gpointer  source_data,
				   GTimeVal *current_time,
				   gpointer  user_data);

static GSourceFuncs signal_funcs = {
  g_signal_prepare,
  g_signal_check,
  g_signal_dispatch,
  g_free
};
static	guint32	signals_notified[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

static gboolean
g_signal_prepare (gpointer  source_data,
		  GTimeVal *current_time,
		  gint     *timeout)
{
  GSignalData *signal_data = source_data;
  
  return signals_notified[signal_data->index] & (1 << signal_data->shift);
}

static gboolean
g_signal_check (gpointer  source_data,
		GTimeVal *current_time)
{
  GSignalData *signal_data = source_data;
  
  return signals_notified[signal_data->index] & (1 << signal_data->shift);
}

static gboolean
g_signal_dispatch (gpointer  source_data,
		   GTimeVal *current_time,
		   gpointer  user_data)
{
  GSignalData *signal_data = source_data;
  
  signals_notified[signal_data->index] &= ~(1 << signal_data->shift);
  
  return signal_data->callback (-128 + signal_data->index * 32 + signal_data->shift, user_data);
}

guint
g_signal_add (gint8	  signal,
	      GSignalFunc function,
	      gpointer    data)
{
  return g_signal_add_full (G_PRIORITY_DEFAULT, signal, function, data, NULL);
}

guint
g_signal_add_full (gint           priority,
		   gint8          signal,
		   GSignalFunc    function,
		   gpointer       data,
		   GDestroyNotify destroy)
{
  GSignalData *signal_data;
  guint s = 128 + signal;
  
  g_return_val_if_fail (function != NULL, 0);
  
  signal_data = g_new (GSignalData, 1);
  signal_data->index = s / 32;
  signal_data->shift = s % 32;
  signal_data->callback = function;
  
  return g_source_add (priority, TRUE, &signal_funcs, signal_data, data, destroy);
}

void
g_signal_notify (gint8 signal)
{
  guint index, shift;
  guint s = 128 + signal;
  
  index = s / 32;
  shift = s % 32;
  
  signals_notified[index] |= 1 << shift;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]