+
+ if(w->fd == -1)
+ return 0; /* already shut down */
+ 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) {
+ 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 {
+ D(("no tied reader"));
+ /* There's no reader so we are free to close the FD */
+ xclose(w->fd);
+ }
+ w->fd = -1;
+ return w->callback(ev, w->error, w->u);
+}
+
+/** @brief Called when a writer's @p timebound expires */
+static int writer_timebound_exceeded(ev_source *ev,
+ const struct timeval *now,
+ void *u) {
+ ev_writer *const w = u;
+
+ 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);
+}
+
+/** @brief Set the time bound callback (if not set already) */
+static void writer_set_timebound(ev_writer *w) {
+ if(w->timebound && !w->timeout) {
+ struct timeval when;
+ ev_source *const ev = w->ev;
+
+ xgettimeofday(&when, 0);
+ when.tv_sec += w->timebound;
+ ev_timeout(ev, &w->timeout, &when, writer_timebound_exceeded, w);
+ }
+}
+
+/** @brief Called when a writer's file descriptor is writable */
+static int writer_callback(ev_source *ev, int fd, void *u) {
+ ev_writer *const w = u;