mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
New waitpid-handler functions to run callbacks when a child exits.
Also, move 'procmon' into libor_event library, since it uses libevent.
This commit is contained in:
parent
87e16087b7
commit
4ed03965a5
@ -57,9 +57,9 @@ LIBOR_A_SOURCES = \
|
||||
src/common/log.c \
|
||||
src/common/memarea.c \
|
||||
src/common/mempool.c \
|
||||
src/common/procmon.c \
|
||||
src/common/util.c \
|
||||
src/common/util_codedigest.c \
|
||||
src/common/util_process.c \
|
||||
src/common/sandbox.c \
|
||||
src/ext/csiphash.c \
|
||||
$(libor_extra_source)
|
||||
@ -72,7 +72,9 @@ LIBOR_CRYPTO_A_SOURCES = \
|
||||
src/common/tortls.c \
|
||||
$(libcrypto_extra_source)
|
||||
|
||||
LIBOR_EVENT_A_SOURCES = src/common/compat_libevent.c
|
||||
LIBOR_EVENT_A_SOURCES = \
|
||||
src/common/compat_libevent.c \
|
||||
src/common/procmon.c
|
||||
|
||||
src_common_libor_a_SOURCES = $(LIBOR_A_SOURCES)
|
||||
src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES)
|
||||
@ -111,7 +113,8 @@ COMMONHEADERS = \
|
||||
src/common/torint.h \
|
||||
src/common/torlog.h \
|
||||
src/common/tortls.h \
|
||||
src/common/util.h
|
||||
src/common/util.h \
|
||||
src/common/util_process.h
|
||||
|
||||
noinst_HEADERS+= $(COMMONHEADERS)
|
||||
|
||||
|
@ -162,6 +162,7 @@ tor_validate_process_specifier(const char *process_spec,
|
||||
return parse_process_specifier(process_spec, &ppspec, msg);
|
||||
}
|
||||
|
||||
/* XXXX we should use periodic_timer_new() for this stuff */
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
#define PERIODIC_TIMER_FLAGS EV_PERSIST
|
||||
#else
|
||||
|
157
src/common/util_process.c
Normal file
157
src/common/util_process.c
Normal file
@ -0,0 +1,157 @@
|
||||
/* Copyright (c) 2003-2004, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file util_process.c
|
||||
* \brief utility functions for launching processes and checking their
|
||||
* status. These functions are kept separately from procmon so that they
|
||||
* won't require linking against libevent.
|
||||
**/
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "util.h"
|
||||
#include "torlog.h"
|
||||
#include "util_process.h"
|
||||
#include "ht.h"
|
||||
|
||||
/* ================================================== */
|
||||
/* Convenience structures for handlers for waitpid().
|
||||
*
|
||||
* The tor_process_monitor*() code above doesn't use them, since it is for
|
||||
* monitoring a non-child process.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/** Mapping from a PID to a userfn/userdata pair. */
|
||||
struct waitpid_callback_t {
|
||||
HT_ENTRY(waitpid_callback_t) node;
|
||||
pid_t pid;
|
||||
|
||||
void (*userfn)(int, void *userdata);
|
||||
void *userdata;
|
||||
|
||||
unsigned running;
|
||||
};
|
||||
|
||||
static INLINE unsigned int
|
||||
process_map_entry_hash_(const waitpid_callback_t *ent)
|
||||
{
|
||||
return (unsigned) ent->pid;
|
||||
}
|
||||
|
||||
static INLINE unsigned int
|
||||
process_map_entries_eq_(const waitpid_callback_t *a, const waitpid_callback_t *b)
|
||||
{
|
||||
return a->pid == b->pid;
|
||||
}
|
||||
|
||||
static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER();
|
||||
|
||||
HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
|
||||
process_map_entries_eq_);
|
||||
HT_GENERATE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
|
||||
process_map_entries_eq_, 0.6, malloc, realloc, free);
|
||||
|
||||
/**
|
||||
* Begin monitoring the child pid <b>pid</b> to see if we get a SIGCHLD for
|
||||
* it. If we eventually do, call <b>fn</b>, passing it the exit status (as
|
||||
* yielded by waitpid) and the pointer <b>arg</b>.
|
||||
*
|
||||
* To cancel this, or clean up after it has triggered, call
|
||||
* clear_waitpid_callback().
|
||||
*/
|
||||
waitpid_callback_t *
|
||||
set_waitpid_callback(pid_t pid, void (*fn)(int, void *), void *arg)
|
||||
{
|
||||
waitpid_callback_t *old_ent;
|
||||
waitpid_callback_t *ent = tor_malloc_zero(sizeof(waitpid_callback_t));
|
||||
ent->pid = pid;
|
||||
ent->userfn = fn;
|
||||
ent->userdata = arg;
|
||||
ent->running = 1;
|
||||
|
||||
old_ent = HT_REPLACE(process_map, &process_map, ent);
|
||||
if (old_ent) {
|
||||
log_warn(LD_BUG, "Replaced a waitpid monitor on pid %u. That should be "
|
||||
"impossible.", (unsigned) pid);
|
||||
old_ent->running = 0;
|
||||
}
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a waitpid_callback_t, or clean up after one has triggered. Releases
|
||||
* all storage held by <b>ent</b>.
|
||||
*/
|
||||
void
|
||||
clear_waitpid_callback(waitpid_callback_t *ent)
|
||||
{
|
||||
waitpid_callback_t *old_ent;
|
||||
if (ent == NULL)
|
||||
return;
|
||||
|
||||
if (ent->running) {
|
||||
old_ent = HT_REMOVE(process_map, &process_map, ent);
|
||||
if (old_ent != ent) {
|
||||
log_warn(LD_BUG, "Couldn't remove waitpid monitor for pid %u.",
|
||||
(unsigned) ent->pid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tor_free(ent);
|
||||
}
|
||||
|
||||
/** Helper: find the callack for <b>pid</b>; if there is one, run it,
|
||||
* reporting the exit status as <b>status</b>. */
|
||||
static void
|
||||
notify_waitpid_callback_by_pid(pid_t pid, int status)
|
||||
{
|
||||
waitpid_callback_t search, *ent;
|
||||
|
||||
search.pid = pid;
|
||||
ent = HT_REMOVE(process_map, &process_map, &search);
|
||||
if (!ent || !ent->running) {
|
||||
log_info(LD_GENERAL, "Child process %u has exited; no callback was "
|
||||
"registered", (unsigned)pid);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info(LD_GENERAL, "Child process %u has exited; running callback.",
|
||||
(unsigned)pid);
|
||||
|
||||
ent->running = 0;
|
||||
ent->userfn(status, ent->userdata);
|
||||
}
|
||||
|
||||
/** Use waitpid() to wait for all children that have exited, and invoke any
|
||||
* callbacks registered for them. */
|
||||
void
|
||||
notify_pending_waitpid_callbacks(void)
|
||||
{
|
||||
/* I was going to call this function reap_zombie_children(), but
|
||||
* that makes it sound way more exciting than it really is. */
|
||||
pid_t child;
|
||||
int status = 0;
|
||||
|
||||
while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||
notify_waitpid_callback_by_pid(child, status);
|
||||
status = 0; /* should be needless */
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
25
src/common/util_process.h
Normal file
25
src/common/util_process.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2011-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file util_process.h
|
||||
* \brief Headers for util_process.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_UTIL_PROCESS_H
|
||||
#define TOR_UTIL_PROCESS_H
|
||||
|
||||
#ifndef _WIN32
|
||||
/** A callback structure waiting for us to get a SIGCHLD informing us that a
|
||||
* PID has been closed. Created by set_waitpid_callback. Cancelled or cleaned-
|
||||
* up from clear_waitpid_callback(). Do not access outside of the main thread;
|
||||
* do not access from inside a signal handler. */
|
||||
typedef struct waitpid_callback_t waitpid_callback_t;
|
||||
|
||||
waitpid_callback_t *set_waitpid_callback(pid_t pid,
|
||||
void (*fn)(int, void *), void *arg);
|
||||
void clear_waitpid_callback(waitpid_callback_t *ent);
|
||||
void notify_pending_waitpid_callbacks(void);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -54,6 +54,7 @@
|
||||
#include "routerparse.h"
|
||||
#include "statefile.h"
|
||||
#include "status.h"
|
||||
#include "util_process.h"
|
||||
#include "ext_orport.h"
|
||||
#ifdef USE_DMALLOC
|
||||
#include <dmalloc.h>
|
||||
@ -2097,8 +2098,7 @@ process_signal(uintptr_t sig)
|
||||
break;
|
||||
#ifdef SIGCHLD
|
||||
case SIGCHLD:
|
||||
while (waitpid(-1,NULL,WNOHANG) > 0) ; /* keep reaping until no more
|
||||
zombies */
|
||||
notify_pending_waitpid_callbacks();
|
||||
break;
|
||||
#endif
|
||||
case SIGNEWNYM: {
|
||||
|
@ -42,9 +42,6 @@
|
||||
#include <sys/param.h> /* FreeBSD needs this to know what version it is */
|
||||
#endif
|
||||
#include "torint.h"
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FCNTL_H
|
||||
#include <sys/fcntl.h>
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user