/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2005, 2007 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
*
* 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
/** @brief Greater-than-or-equal comparison for timevals
*
- * Ought to be in @file lib/timeval.h
+ * Ought to be in @ref lib/timeval.h
*/
static inline int ge(const struct timeval *a, const struct timeval *b) {
return !gt(b, a);
* cancelled.
*/
int ev_fd_enable(ev_source *ev, ev_fdmode mode, int fd) {
+ assert(fd >= 0);
D(("enabling mode %s fd %d", modenames[mode], fd));
FD_SET(fd, &ev->mode[mode].enabled);
return 0;
struct dynstr d[1];
char b[4096];
+ if(!debugging)
+ return;
dynstr_init(d);
for(mode = 0; mode < ev_nmodes; ++mode) {
- info("mode %s maxfd %d", modenames[mode], ev->mode[mode].maxfd);
+ D(("mode %s maxfd %d", modenames[mode], ev->mode[mode].maxfd));
for(n = 0; n < ev->mode[mode].nfds; ++n) {
fd = ev->mode[mode].fds[n].fd;
- info("fd %s %d%s%s (%s)", modenames[mode], fd,
- FD_ISSET(fd, &ev->mode[mode].enabled) ? " enabled" : "",
- FD_ISSET(fd, &ev->mode[mode].tripped) ? " tripped" : "",
- ev->mode[mode].fds[n].what);
+ D(("fd %s %d%s%s (%s)", modenames[mode], fd,
+ FD_ISSET(fd, &ev->mode[mode].enabled) ? " enabled" : "",
+ FD_ISSET(fd, &ev->mode[mode].tripped) ? " tripped" : "",
+ ev->mode[mode].fds[n].what));
}
d->nvec = 0;
for(fd = 0; fd <= ev->mode[mode].maxfd; ++fd) {
dynstr_append_string(d, b);
}
dynstr_terminate(d);
- info("%s enabled:%s", modenames[mode], d->vec);
+ D(("%s enabled:%s", modenames[mode], d->vec));
}
}
/** @brief Register a timeout
* @param ev Event source
- * @param handle Where to store timeout handle, or @c NULL
+ * @param handlep Where to store timeout handle, or @c NULL
* @param when Earliest time to call @p callback, or @c NULL
* @param callback Function to call at or after @p when
* @param u Passed to @p callback
/** @brief Tied reader or 0 */
ev_reader *reader;
+
+ /** @brief Set when abandoned */
+ int abandoned;
};
/** @brief State structure for a buffered reader */
if(w->fd == -1)
return 0; /* already shut down */
- info("writer_shutdown fd=%d", w->fd);
+ D(("writer_shutdown fd=%d error=%d", w->fd, w->error));
ev_timeout_cancel(ev, w->timeout);
ev_fd_cancel(ev, ev_write, w->fd);
w->timeout = 0;
if(w->reader) {
- info("found a tied reader");
+ D(("found a tied reader"));
/* If there is a reader still around we just untie it */
w->reader->writer = 0;
shutdown(w->fd, SHUT_WR); /* there'll be no more writes */
} else {
- info("no tied reader");
+ D(("no tied reader"));
/* There's no reader so we are free to close the FD */
xclose(w->fd);
}
void *u) {
ev_writer *const w = u;
- error(0, "abandoning writer %s because no writes within %ds",
- w->what, w->timebound);
- w->error = ETIMEDOUT;
+ if(!w->abandoned) {
+ w->abandoned = 1;
+ error(0, "abandoning writer '%s' because no writes within %ds",
+ w->what, w->timebound);
+ w->error = ETIMEDOUT;
+ }
return writer_shutdown(ev, now, u);
}
if(!n)
return 0; /* avoid silliness */
+ if(w->fd == -1)
+ 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. */
- 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);
+ 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);
+ ev_fd_disable(w->ev, ev_write, w->fd);
+ w->error = EPIPE;
+ return ev_timeout(w->ev, 0, 0, writer_shutdown, w);
+ } else
+ return 0;
}
/* Make sure there is space */
buffer_space(&w->b, n);
/* buffered reader ************************************************************/
-/** @brief Shut down a reader*
+/** @brief Shut down a reader
*
* This is the only path through which we cancel and close the file descriptor.
* As with the writer case it is given timeout signature to allow it be
if(r->fd == -1)
return 0; /* already shut down */
- info("reader_shutdown fd=%d", r->fd);
+ D(("reader_shutdown fd=%d", r->fd));
ev_fd_cancel(ev, ev_read, r->fd);
r->eof = 1;
if(r->writer) {
- info("found a tied writer");
+ D(("found a tied writer"));
/* If there is a writer still around we just untie it */
r->writer->reader = 0;
shutdown(r->fd, SHUT_RD); /* there'll be no more reads */
} else {
- info("no tied writer found");
+ D(("no tied writer found"));
/* There's no writer so we are free to close the FD */
xclose(r->fd);
}