/*
* Maketool - GTK-based front end for gmake
* Copyright (c) 1999-2003 Greg Banks
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "common.h"
#include "glib_extra.h"
#include <signal.h>
#include <sys/poll.h>
CVSID("$Id: glib_extra.c,v 1.20 2003/10/29 12:39:18 gnb Exp $");
typedef struct
{
pid_t pid;
GUnixReapFunc reaper;
gpointer user_data;
} GPidData;
static GHashTable *g_unix_piddata = 0;
static gboolean g_unix_got_signal = FALSE;
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* Handle registering signals. Ideally we want BSD signal semantics
* where we can register a handler once, it's suppressed during
* delivery so we can't get recursive delivery, and it's never
* automatically un-registered. On some OSes we get that for free,
* on some OSes we need to perform a little dance with sigaction()
* or sigvec() to achieve that; on yet other OSes we only get the
* screwed up SysV signal semantics. Maketool will probably cause
* recursive signal delivery and a stack blowout on those platforms.
*
* register_sighandler
* Called to register the signal handler the first time only
*
* reregister_sighandler
* Called in the signal handler to re-register the signal
* handler if necessary (in the ideal case this is empty).
*/
#if SIGNAL_SEMANTICS == SIGNAL_SEMANTICS_SIGACTION
static void
register_sighandler(int sig, RETSIGTYPE (*handler)(int sig))
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = handler;
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
sigaction(sig, &act, 0);
}
#define reregister_sighandler(sig, handler)
#elif SIGNAL_SEMANTICS == SIGNAL_SEMANTICS_SIGVEC
static void
register_sighandler(int sig, RETSIGTYPE (*handler)(int sig))
{
struct sigvec vec;
memset(&vec, 0, sizeof(vec));
vec.sv_handler = handler;
sigvec(sig, &vec, 0);
}
#define reregister_sighandler(sig, handler)
#elif SIGNAL_SEMANTICS == SIGNAL_SEMANTICS_SYSV
#define register_sighandler(sig, handler) \
signal(sig, handler)
#define reregister_sighandler(sig, handler) \
register_sighandler(sig, handler)
#elif SIGNAL_SEMANTICS == SIGNAL_SEMANTICS_BSD
#define register_sighandler(sig, handler) \
signal(sig, handler)
#define reregister_sighandler(sig, handler)
#endif /* SIGNAL_SEMANTICS_BSD */
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
g_unix_default_reaper(pid_t pid, int status, struct rusage *usg, gpointer data)
{
#if DEBUG
if (WIFEXITED(status) || WIFSIGNALED(status))
fprintf(stderr, "g_unix_default_reaper: reaped pid %d\n", (int)pid);
#endif
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
g_unix_dispatch_reapers(void)
{
GPidData *pd;
pid_t pid;
int status = 0;
struct rusage usage;
#if DEBUG
fprintf(stderr, "g_unix_dispatch_reapers()\n");
#endif
for (;;)
{
int flags = WNOHANG;
#if HAVE_BSD_JOB_CONTROL
flags |= WUNTRACED;
#endif
#if HAVE_WAIT3
pid = wait3(&status, flags, &usage);
#else
memset(&usage, 0, sizeof(usage)); /* nothing to see here */
pid = waitpid(-1, &status, flags);
#endif
#if DEBUG
fprintf(stderr, "g_unix_check_processes(): pid = %d\n", (int)pid);
#endif
if (pid <= 0)
break;
pd = (GPidData *)g_hash_table_lookup(g_unix_piddata, GINT_TO_POINTER(pid));
if (pd != 0)
{
(*pd->reaper)(pid, status, &usage, pd->user_data);
if (WIFEXITED(status) || WIFSIGNALED(status))
{
g_hash_table_remove(g_unix_piddata, GINT_TO_POINTER(pid));
g_free(pd);
}
}
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static RETSIGTYPE
g_unix_signal_handler(int sig)
{
#if DEBUG > 50
static const char msg[] = "g_unix_signal_handler(): called\n";
write(2, msg, sizeof(msg)-1);
#endif
g_unix_got_signal = TRUE;
reregister_sighandler(SIGCHLD, g_unix_signal_handler);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static gboolean
g_unix_source_prepare(
#if GLIB2
GSource *source,
gint *timeout
#else
gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data
#endif
)
{
#if DEBUG > 5
fprintf(stderr, "g_unix_source_prepare(): returning %d\n", (int)g_unix_got_signal);
#endif
return g_unix_got_signal;
}
static gboolean
g_unix_source_check(
#if GLIB2
GSource *source
#else
gpointer source_data,
GTimeVal *current_time,
gpointer user_data
#endif
)
{
#if DEBUG > 5
fprintf(stderr, "g_unix_source_check(): returning %d\n", (int)g_unix_got_signal);
#endif
return g_unix_got_signal;
}
static gboolean
g_unix_source_dispatch(
#if GLIB2
GSource *source,
GSourceFunc callback,
gpointer user_data
#else
gpointer source_data,
GTimeVal *current_time,
gpointer user_data
#endif
)
{
#if DEBUG > 5
fprintf(stderr, "g_unix_source_dispatch(): called\n");
#endif
g_unix_got_signal = FALSE;
g_unix_dispatch_reapers();
return TRUE;
}
static void
g_unix_source_destroy(
#if GLIB2
GSource *source
#else
gpointer data
#endif
)
{
#if DEBUG
fprintf(stderr, "g_unix_source_destroy(): called\n");
#endif
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static GSourceFuncs reaper_source_funcs =
{
g_unix_source_prepare,
g_unix_source_check,
g_unix_source_dispatch,
g_unix_source_destroy
};
/*
* TODO: there is some bizarre subtle problem with either my code
* or one of gtk or gdk which causes strange display bugs when
* this priority is made equal to 1. This needs to be properly
* tracked down and exterminated, but for the time being making
* the priority equal to G_PRIORITY_DEFAULT works -- Greg, 3Jan2000.
*/
#define G_UNIX_REAP_PRIORITY G_PRIORITY_DEFAULT
void
g_unix_reap_init(void)
{
static gboolean first = TRUE;
if (first)
{
#if GLIB2
GSource *source;
#endif
first = FALSE;
register_sighandler(SIGCHLD, g_unix_signal_handler);
g_unix_piddata = g_hash_table_new(g_direct_hash, g_direct_equal);
#if GLIB2
source = g_source_new(&reaper_source_funcs, sizeof(GSource));
g_source_set_can_recurse(source, TRUE);
g_source_set_priority(source, G_UNIX_REAP_PRIORITY);
g_source_attach(source, g_main_context_default());
#else
g_source_add(
G_UNIX_REAP_PRIORITY, /* priority */
TRUE, /* can_recurse */
&reaper_source_funcs,
(gpointer)0, /* source_data */
(gpointer)0, /* user_data */
(GDestroyNotify)0);
#endif
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*TODO:return a gint tag for removal*/
void
g_unix_add_reap_func(
pid_t pid,
GUnixReapFunc reaper,
gpointer user_data)
{
GPidData *pd;
if (reaper == 0)
reaper = g_unix_default_reaper;
pd = g_new(GPidData, 1);
pd->pid = pid;
pd->reaper = reaper;
pd->user_data = user_data;
g_hash_table_insert(g_unix_piddata, GINT_TO_POINTER(pid), (gpointer)pd);
#if DEBUG
fprintf(stderr, "g_unix_add_reaper(): pid = %d\n", (int)pid);
#endif
}
/* TODO:
void
g_unix_remove_reap_func(gint tag)
*/
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*END*/
syntax highlighted by Code2HTML, v. 0.9.1