Re: Unix signals in GLib
- From: Matthew Bucknall <matt mattbucknall com>
- To: Xavier Bestel <xavier bestel free fr>
- Cc: Andy Wingo <wingo pobox com>, Gtk+ Developers <gtk-devel-list gnome org>, stef memberwebs com
- Subject: Re: Unix signals in GLib
- Date: Fri, 30 Apr 2010 19:38:22 +0100
Find attached an excerpt from an application of mine. Not entirely
self-contained, but you should get a general idea of what is going on.
Using the attached code, my application calls app_signal_block_unused()
early on during initialization. The signal listening thread is
initialized and started by app_signal_init(). The thread is stopped (in
case it has not already stopped) by calling app_signal_cleanup() as the
application finalizes.
You'll notice in read_handler() I call a function called
app_context_stop(). Replace this function with whatever you need to stop
your application's main loop.
Matt.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "app-context.h"
#include "app-error.h"
#include "app-log.h"
#include "app-signal.h"
#include "app-utils.h"
static GThread *signal_thread;
static int pipe_fds[2] = {-1, -1};
static GIOChannel *read_channel;
static guint read_id;
void app_signal_block_unused (sigset_t *old_set)
{
sigset_t signal_set;
sigfillset (&signal_set);
sigdelset (&signal_set, SIGCHLD);
pthread_sigmask (SIG_BLOCK, &signal_set, old_set);
}
static gpointer signal_thread_func (gpointer data)
{
static const gchar c = '!';
for(;;)
{
sigset_t signal_set;
gint sig_num;
sigfillset (&signal_set);
sigwait (&signal_set, &sig_num);
switch (sig_num)
{
case SIGTERM:
case SIGINT:
case SIGQUIT:
case SIGHUP:
g_printerr ("\r");
app_info ("%s signal received", strsignal (sig_num));
while ( write (pipe_fds[1], &c, 1) == 0 );
return NULL;
default:
break;
}
}
return NULL;
}
static gboolean read_handler (GIOChannel *source, GIOCondition condition, gpointer data)
{
gchar ignore[16];
gsize ignore_count;
while ( g_io_channel_read_chars (read_channel, ignore, 16, &ignore_count, NULL) == G_IO_STATUS_NORMAL )
{
if ( ignore_count != 16 ) break;
}
app_context_stop ();
return FALSE;
}
gboolean app_signal_init (GError **error)
{
g_assert (!signal_thread);
g_assert ((pipe_fds[0] == -1) && (pipe_fds[1] == -1));
gboolean ret_val = TRUE;
GError *temp_error = NULL;
int result;
result = pipe (pipe_fds);
if ( !app_check_libc_call (result, &temp_error, "Cannot create signal pipe") ) goto fail;
result = fcntl (pipe_fds[0], F_SETFL, O_NONBLOCK);
if ( !app_check_libc_call (result, &temp_error, "Cannot make signal pipe non-blocking") ) goto fail;
read_channel = g_io_channel_unix_new (pipe_fds[0]);
read_id = app_io_watch_source_new (read_channel, G_IO_IN, read_handler, NULL);
signal_thread = g_thread_create_full (
signal_thread_func,
NULL,
8192,
TRUE,
TRUE,
G_THREAD_PRIORITY_HIGH,
error
);
if ( !signal_thread )
{
app_error_cannot_create_thread (&temp_error, "signal");
goto fail;
}
return TRUE;
fail:
app_signal_cleanup ();
return FALSE;
}
void app_signal_cleanup (void)
{
if ( signal_thread )
{
kill (0, SIGTERM);
g_thread_join (signal_thread);
signal_thread = NULL;
}
if ( read_id )
{
app_source_destroy (read_id);
read_id = 0;
}
if ( read_channel )
{
g_io_channel_unref (read_channel);
read_channel = NULL;
}
for (guint i = 0; i < 2; i++)
{
if ( pipe_fds[i] >= 0 )
{
close (pipe_fds[i]);
pipe_fds[i] = -1;
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]