-/* Copyright (c) 2012 Nicira, Inc.
+/* Copyright (c) 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
VLOG_DEFINE_THIS_MODULE(worker);
+/* ovs_assert() logs the assertion message and logging sometimes goes through a
+ * worker, so using ovs_assert() in this source file could cause recursion. */
+#undef ovs_assert
+#define ovs_assert use_assert_instead_of_ovs_assert_in_this_module
+
/* Header for an RPC request. */
struct worker_request {
size_t request_len; /* Length of the payload in bytes. */
size_t sent = 0;
for (;;) {
+ struct pollfd pfd;
int error;
/* Try to send the rest of the request. */
/* Process replies to avoid deadlock. */
worker_run();
- poll_fd_wait(client_sock, POLLIN | POLLOUT);
- poll_block();
+ /* Wait for 'client_sock' to become ready before trying again. We
+ * can't use poll_block() because it sometimes calls into vlog, which
+ * calls indirectly into worker_send_iovec(). To be usable here,
+ * poll_block() would therefore need to be reentrant, but it isn't
+ * (calling it recursively causes memory corruption and an eventual
+ * crash). */
+ pfd.fd = client_sock;
+ pfd.events = POLLIN | POLLOUT;
+ do {
+ error = poll(&pfd, 1, -1) < 0 ? errno : 0;
+ } while (error == EINTR);
+ if (error) {
+ worker_broke();
+ VLOG_ABORT("poll failed (%s)", strerror(error));
+ }
}
}
worker_request_func *request_cb,
worker_reply_func *reply_cb, void *aux)
{
+ static bool recursing = false;
struct worker_request rq;
struct iovec *all_iovs;
int error;
assert(worker_is_running());
+ assert(!recursing);
+ recursing = true;
rq.request_len = iovec_len(iovs, n_iovs);
rq.request_cb = request_cb;
VLOG_ABORT("send failed (%s)", strerror(error));
}
free(all_iovs);
+
+ recursing = false;
}
/* Closes the client socket, if any, so that worker_is_running() will return
* to avoid missing log messages. */
VLOG_INFO("send failed (%s)", strerror(error));
} else if (error) {
- VLOG_ABORT("send failed (%s)", strerror(error));
+ VLOG_FATAL("send failed (%s)", strerror(error));
}
free(all_iovs);
server_sock = fd;
subprogram_name = "worker";
- proctitle_set("%s: worker process for pid %lu",
- program_name, (unsigned long int) getppid());
+ proctitle_set("worker process for pid %lu", (unsigned long int) getppid());
VLOG_INFO("worker process started");
rxbuf_init(&rx);
/* Main process closed the IPC socket. Exit cleanly. */
break;
} else if (error != EAGAIN) {
- VLOG_ABORT("RPC receive failed (%s)", strerror(error));
+ VLOG_FATAL("RPC receive failed (%s)", ovs_retval_to_string(error));
}
poll_fd_wait(server_sock, POLLIN);
}
}
}
-
- return EAGAIN;
}
static struct iovec *