📄 event_sig.c
字号:
/************************************************************************* event_sig.c** Code for handling signals nicely (synchronously) and for dealing* with reaping child processes.** Copyright (C) 2002 by Roaring Penguin Software Inc.** This software may be distributed under the terms of the GNU General* Public License, Version 2, or (at your option) any later version.** LIC: GPL************************************************************************/static char const RCSID[] ="$Id: event_sig.c,v 1.5 2002/07/05 19:37:26 dfs Exp $";#define _POSIX_SOURCE 1 /* For sigaction defines */#define _BSD_SOURCE 1 /* For SA_RESTART */#include <signal.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.h>#include <stddef.h>#include "event.h"#include "hash.h"/* Kludge for figuring out NSIG */#ifdef NSIG#define MAX_SIGNALS NSIG#elif defined(_NSIG)#define MAX_SIGNALS _NSIG#else#define MAX_SIGNALS 256 /* Should be safe... */#endif/* A structure for a "synchronous" signal handler */struct SynchronousSignalHandler { int fired; /* Have we received this signal? */ void (*handler)(int sig); /* Handler function */};/* A structure for calling back when a child dies */struct ChildEntry { hash_bucket hash; void (*handler)(pid_t pid, int status, void *data); pid_t pid; void *data;};static struct SynchronousSignalHandler SignalHandlers[MAX_SIGNALS];static int Pipe[2] = {-1, -1};static EventHandler *PipeHandler = NULL;static sig_atomic_t PipeFull = 0;static hash_table child_process_table;static unsigned int child_hash(void *data){ return (unsigned int) ((struct ChildEntry *) data)->pid;}static int child_compare(void *d1, void *d2){ return ((struct ChildEntry *)d1)->pid != ((struct ChildEntry *)d2)->pid;}/*********************************************************************** %FUNCTION: DoPipe* %ARGUMENTS:* es -- event selector* fd -- readable file descriptor* flags -- flags from event system* data -- ignored* %RETURNS:* Nothing* %DESCRIPTION:* Called when an async signal handler wants attention. This function* fires all "synchronous" signal handlers.***********************************************************************/static voidDoPipe(EventSelector *es, int fd, unsigned int flags, void *data){ char buf[64]; int i; /* Clear buffer */ read(fd, buf, 64); PipeFull = 0; /* Fire handlers */ for (i=0; i<MAX_SIGNALS; i++) { if (SignalHandlers[i].fired && SignalHandlers[i].handler) { SignalHandlers[i].handler(i); } SignalHandlers[i].fired = 0; }}/*********************************************************************** %FUNCTION: sig_handler* %ARGUMENTS:* sig -- signal number* %RETURNS:* Nothing* %DESCRIPTION:* Marks a signal as having "fired"; fills IPC pipe.***********************************************************************/static voidsig_handler(int sig){ if (sig <0 || sig > MAX_SIGNALS) { /* Ooops... */ return; } SignalHandlers[sig].fired = 1; if (!PipeFull) { write(Pipe[1], &sig, 1); PipeFull = 1; }}/*********************************************************************** %FUNCTION: child_handler* %ARGUMENTS:* sig -- signal number (whoop-dee-doo)* %RETURNS:* Nothing* %DESCRIPTION:* Called *SYNCHRONOUSLY* to reap dead children.***********************************************************************/static voidchild_handler(int sig){ int status; int pid; struct ChildEntry *ce; struct ChildEntry candidate; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { candidate.pid = (pid_t) pid; ce = hash_find(&child_process_table, &candidate); if (ce) { if (ce->handler) { ce->handler(pid, status, ce->data); } hash_remove(&child_process_table, ce); free(ce); } }}/*********************************************************************** %FUNCTION: SetupPipes (static)* %ARGUMENTS:* es -- event selector* %RETURNS:* 0 on success; -1 on failure* %DESCRIPTION:* Sets up pipes with an event handler to handle IPC from a signal handler***********************************************************************/static intSetupPipes(EventSelector *es){ /* If already done, do nothing */ if (PipeHandler) return 0; /* Initialize the child-process hash table */ hash_init(&child_process_table, offsetof(struct ChildEntry, hash), child_hash, child_compare); /* Open pipe to self */ if (pipe(Pipe) < 0) { return -1; } PipeHandler = Event_AddHandler(es, Pipe[0], EVENT_FLAG_READABLE, DoPipe, NULL); if (!PipeHandler) { int old_errno = errno; close(Pipe[0]); close(Pipe[1]); errno = old_errno; return -1; } return 0;}/*********************************************************************** %FUNCTION: Event_HandleSignal* %ARGUMENTS:* es -- event selector* sig -- signal number* handler -- handler to call when signal is raised. Handler is called* "synchronously" as events are processed by event loop.* %RETURNS:* 0 on success, -1 on error.* %DESCRIPTION:* Sets up a "synchronous" signal handler.***********************************************************************/intEvent_HandleSignal(EventSelector *es, int sig, void (*handler)(int sig)){ struct sigaction act; if (SetupPipes(es) < 0) return -1; act.sa_handler = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0;#ifdef SA_RESTART act.sa_flags |= SA_RESTART;#endif if (sig == SIGCHLD) { act.sa_flags |= SA_NOCLDSTOP; } if (sigaction(sig, &act, NULL) < 0) return -1; SignalHandlers[sig].handler = handler; return 0;}/*********************************************************************** %FUNCTION: Event_HandleChildExit* %ARGUMENTS:* es -- event selector* pid -- process-ID of child to wait for* handler -- function to call when child exits* data -- data to pass to handler when child exits* %RETURNS:* 0 on success, -1 on failure.* %DESCRIPTION:* Sets things up so that when a child exits, handler() will be called* with the pid of the child and "data" as arguments. The call will* be synchronous (part of the normal event loop on es).***********************************************************************/intEvent_HandleChildExit(EventSelector *es, pid_t pid, void (*handler)(pid_t, int, void *), void *data){ struct ChildEntry *ce; if (Event_HandleSignal(es, SIGCHLD, child_handler) < 0) return -1; ce = malloc(sizeof(struct ChildEntry)); if (!ce) return -1; ce->pid = pid; ce->data = data; ce->handler = handler; hash_insert(&child_process_table, ce); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -