X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/3af7813d88284b99c550f1a20696536ebc579b32..ad0c0f361be0:/lib/event.c
diff --git a/lib/event.c b/lib/event.c
index 4c3e9af..64f1bdb 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -2,26 +2,24 @@
* This file is part of DisOrder.
* Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
*
- * This program is free software; you can redistribute it and/or modify
+ * 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
+ * the Free Software Foundation, either version 3 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.
- *
+ *
+ * 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
+ * along with this program. If not, see .
*/
/** @file lib/event.c
* @brief DisOrder event loop
*/
-#include
+#include "common.h"
#include
#include
@@ -31,15 +29,11 @@
#include
#include
#include
-#include
#include
#include
-#include
-#include
#include
#include
#include
-#include
#include "event.h"
#include "mem.h"
#include "log.h"
@@ -249,7 +243,7 @@ int ev_run(ev_source *ev) {
} while(n < 0 && errno == EINTR);
xsigprocmask(SIG_BLOCK, &ev->sigmask, 0);
if(n < 0) {
- error(errno, "error calling select");
+ disorder_error(errno, "error calling select");
if(errno == EBADF) {
/* If there's a bad FD in the mix then check them all and log what we
* find, to ease debugging */
@@ -259,13 +253,13 @@ int ev_run(ev_source *ev) {
if(FD_ISSET(fd, &ev->mode[mode].enabled)
&& fstat(fd, &sb) < 0)
- error(errno, "mode %s fstat %d (%s)",
- modenames[mode], fd, ev->mode[mode].fds[n].what);
+ disorder_error(errno, "mode %s fstat %d (%s)",
+ modenames[mode], fd, ev->mode[mode].fds[n].what);
}
for(n = 0; n <= maxfd; ++n)
if(FD_ISSET(n, &ev->mode[mode].enabled)
&& fstat(n, &sb) < 0)
- error(errno, "mode %s fstat %d", modenames[mode], n);
+ disorder_error(errno, "mode %s fstat %d", modenames[mode], n);
}
}
return -1;
@@ -317,6 +311,8 @@ int ev_fd(ev_source *ev,
D(("registering %s fd %d callback %p %p", modenames[mode], fd,
(void *)callback, u));
+ if(fd >= FD_SETSIZE)
+ return -1;
assert(mode < ev_nmodes);
if(ev->mode[mode].nfds >= ev->mode[mode].fdslots) {
ev->mode[mode].fdslots = (ev->mode[mode].fdslots
@@ -523,7 +519,9 @@ static void sighandler(int s) {
/* probably the reader has stopped listening for some reason */
if(write(sigfd[s], &sc, 1) < 0) {
- write(2, errmsg, sizeof errmsg - 1);
+ /* do the best we can as we're about to abort; shut _up_, gcc */
+ int _ignore = write(2, errmsg, sizeof errmsg - 1);
+ (void)_ignore;
abort();
}
}
@@ -541,7 +539,7 @@ static int signal_read(ev_source *ev,
return ret;
assert(n != 0);
if(n < 0 && (errno != EINTR && errno != EAGAIN)) {
- error(errno, "error reading from signal pipe %d", ev->sigpipe[0]);
+ disorder_error(errno, "error reading from signal pipe %d", ev->sigpipe[0]);
return -1;
}
return 0;
@@ -682,8 +680,8 @@ static int sigchld_callback(ev_source *ev,
* want the disorder server to bomb out because of it. So we just log
* the problem and ignore it.
*/
- error(errno, "error calling wait4 for PID %lu (broken ptrace?)",
- (unsigned long)ev->children[n].pid);
+ disorder_error(errno, "error calling wait4 for PID %lu (broken ptrace?)",
+ (unsigned long)ev->children[n].pid);
if(errno != ECHILD)
return -1;
}
@@ -756,6 +754,36 @@ int ev_child_cancel(ev_source *ev,
return 0;
}
+/** @brief Terminate and wait for all child processes
+ * @param ev Event loop
+ *
+ * Does *not* call the completion callbacks. Only used during teardown.
+ */
+void ev_child_killall(ev_source *ev) {
+ int n, rc, w;
+
+ for(n = 0; n < ev->nchildren; ++n) {
+ if(kill(ev->children[n].pid, SIGTERM) < 0) {
+ disorder_error(errno, "sending SIGTERM to pid %lu",
+ (unsigned long)ev->children[n].pid);
+ ev->children[n].pid = -1;
+ }
+ }
+ for(n = 0; n < ev->nchildren; ++n) {
+ if(ev->children[n].pid == -1)
+ continue;
+ do {
+ rc = waitpid(ev->children[n].pid, &w, 0);
+ } while(rc < 0 && errno == EINTR);
+ if(rc < 0) {
+ disorder_error(errno, "waiting for pid %lu",
+ (unsigned long)ev->children[n].pid);
+ continue;
+ }
+ }
+ ev->nchildren = 0;
+}
+
/* socket listeners ***********************************************************/
/** @brief State for a socket listener */
@@ -791,22 +819,22 @@ static int listen_callback(ev_source *ev, int fd, void *u) {
break;
#ifdef ECONNABORTED
case ECONNABORTED:
- error(errno, "error calling accept");
+ disorder_error(errno, "error calling accept");
break;
#endif
#ifdef EPROTO
case EPROTO:
/* XXX on some systems EPROTO should be fatal, but we don't know if
* we're running on one of them */
- error(errno, "error calling accept");
+ disorder_error(errno, "error calling accept");
break;
#endif
default:
- fatal(errno, "error calling accept");
+ disorder_fatal(errno, "error calling accept");
break;
}
if(errno != EINTR && errno != EAGAIN)
- error(errno, "error calling accept");
+ disorder_error(errno, "error calling accept");
return 0;
}
@@ -990,8 +1018,8 @@ static int writer_timebound_exceeded(ev_source *ev,
if(!w->abandoned) {
w->abandoned = 1;
- error(0, "abandoning writer '%s' because no writes within %ds",
- w->what, w->timebound);
+ disorder_error(0, "abandoning writer '%s' because no writes within %ds",
+ w->what, w->timebound);
w->error = ETIMEDOUT;
}
return writer_shutdown(ev, now, u);
@@ -1063,15 +1091,15 @@ static int ev_writer_write(struct sink *sk, const void *s, int n) {
if(!n)
return 0; /* avoid silliness */
if(w->fd == -1)
- error(0, "ev_writer_write on %s after shutdown", w->what);
+ disorder_error(0, "ev_writer_write on %s after shutdown", w->what);
if(w->spacebound && w->b.end - w->b.start + n > w->spacebound) {
/* The new buffer contents will exceed the space bound. We assume that the
* remote client has gone away and TCP hasn't noticed yet, or that it's got
* hopelessly stuck. */
if(!w->abandoned) {
w->abandoned = 1;
- error(0, "abandoning writer '%s' because buffer has reached %td bytes",
- w->what, w->b.end - w->b.start);
+ disorder_error(0, "abandoning writer '%s' because buffer has reached %td bytes",
+ w->what, w->b.end - w->b.start);
ev_fd_disable(w->ev, ev_write, w->fd);
w->error = EPIPE;
return ev_timeout(w->ev, 0, 0, writer_shutdown, w);
@@ -1180,7 +1208,7 @@ int ev_writer_space_bound(ev_writer *w,
*/
struct sink *ev_writer_sink(ev_writer *w) {
if(!w)
- fatal(0, "ev_write_sink called with null writer");
+ disorder_fatal(0, "ev_write_sink called with null writer");
return &w->s;
}