from trunk: provide event_reinit() to reinitialized an event_base after fork - necessary for epoll/kqueue

svn:r557
This commit is contained in:
Niels Provos 2007-11-27 06:15:36 +00:00
parent 5ff1fd7a99
commit 7717cec719
7 changed files with 114 additions and 13 deletions

View File

@ -6,6 +6,7 @@ Changes in current version:
o better documentation for event_base_loopexit; from Scott Lamb.
o Make kqueue have the same behavior as other backends when a signal is caught between event_add() and event_loop(). Previously, it would catch and ignore such signals.
o Make kqueue restore signal handlers correctly when event_del() is called.
o provide event_reinit() to reintialize an event_base after fork
Changes in 1.4.0-beta:

View File

@ -83,7 +83,8 @@ struct eventop epollops = {
epoll_del,
epoll_recalc,
epoll_dispatch,
epoll_dealloc
epoll_dealloc,
1 /* need reinit */
};
#ifdef HAVE_SETFD

View File

@ -35,6 +35,18 @@ extern "C" {
#include "min_heap.h"
#include "evsignal.h"
struct eventop {
const char *name;
void *(*init)(struct event_base *);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
int (*recalc)(struct event_base *, void *, int);
int (*dispatch)(struct event_base *, void *, struct timeval *);
void (*dealloc)(struct event_base *, void *);
/* set if we need to reinitialize the event base */
int need_reinit;
};
struct event_base {
const struct eventop *evsel;
void *evbase;

27
event.c
View File

@ -250,6 +250,33 @@ event_base_free(struct event_base *base)
free(base);
}
/* reinitialized the event base after a fork */
int
event_reinit(struct event_base *base)
{
const struct eventop *evsel = base->evsel;
int res = 0;
struct event *ev;
/* check if this event mechanism requires reinit */
if (!evsel->need_reinit)
return (0);
if (base->evsel->dealloc != NULL)
base->evsel->dealloc(base, base->evbase);
base->evbase = evsel->init(base);
if (base->evbase == NULL)
event_errx(1, "%s: could not reinitialize event mechanism",
__func__);
TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
if (evsel->add(base, ev) == -1)
res = -1;
}
return (res);
}
int
event_priority_init(int npriorities)
{

23
event.h
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
* Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -257,16 +257,6 @@ TAILQ_HEAD (event_list, event);
TAILQ_HEAD (evkeyvalq, evkeyval);
#endif /* _EVENT_DEFINED_TQENTRY */
struct eventop {
const char *name;
void *(*init)(struct event_base *);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
int (*recalc)(struct event_base *, void *, int);
int (*dispatch)(struct event_base *, void *, struct timeval *);
void (*dealloc)(struct event_base *, void *);
};
/**
Initialize the event API.
@ -289,6 +279,17 @@ struct event_base *event_base_new(void);
*/
struct event_base *event_init(void);
/**
Reinitialized the event base after a fork
Some event mechanisms do not survive across fork. The event base needs
to be reinitialized with the event_reinit() function.
@param base the event base that needs to be re-initialized
@return 0 if successful, or -1 if some events could not be re-added.
@see event_base_new(), event_init()
*/
int event_reinit(struct event_base *base);
/**
Loop to process events.

View File

@ -58,6 +58,7 @@
#endif
#include "event.h"
#include "event-internal.h"
#include "log.h"
#include "event-internal.h"
@ -88,7 +89,8 @@ const struct eventop kqops = {
kq_del,
kq_recalc,
kq_dispatch,
kq_dealloc
kq_dealloc,
1 /* need reinit */
};
void *

View File

@ -42,6 +42,7 @@
#include <sys/queue.h>
#ifndef WIN32
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include <unistd.h>
#include <netdb.h>
@ -446,6 +447,58 @@ test_simpletimeout(void)
}
#ifndef WIN32
void
test_fork(void)
{
int status;
struct event ev;
pid_t pid;
setup_test("After fork: ");
write(pair[0], TEST1, strlen(TEST1)+1);
event_set(&ev, pair[1], EV_READ, simple_read_cb, &ev);
if (event_add(&ev, NULL) == -1)
exit(1);
if ((pid = fork()) == 0) {
/* in the child */
extern struct event_base *current_base;
if (event_reinit(current_base) == -1) {
fprintf(stderr, "FAILED (reinit)\n");
exit(1);
}
event_dispatch();
exit(test_ok == 0);
}
/* wait for the child to read the data */
sleep(1);
write(pair[0], TEST1, strlen(TEST1)+1);
if (waitpid(pid, &status, 0) == -1) {
fprintf(stderr, "FAILED (fork)\n");
exit(1);
}
if (WEXITSTATUS(status) != 0) {
fprintf(stderr, "FAILED\n");
exit(1);
}
/* test that the current event loop still works */
write(pair[0], TEST1, strlen(TEST1)+1);
shutdown(pair[0], SHUT_WR);
event_dispatch();
cleanup_test();
}
void
test_simplesignal(void)
{
@ -1199,6 +1252,10 @@ main (int argc, char **argv)
dns_suite();
#ifndef WIN32
test_fork();
#endif
test_simpleread();
test_simplewrite();