Re: Unix signals in GLib



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]