Re: [gtk-list] Handling OS signals?
- From: Tim Janik <timj gtk org>
- To: gtk-list redhat com
- Subject: Re: [gtk-list] Handling OS signals?
- Date: Thu, 18 Feb 1999 01:31:16 +0100 (CET)
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]