X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fworker.c;h=4c947a422aa057751139c1e6130e0005145ca128;hb=4816a18f33380a33d381b77d41df39113c94500d;hp=f2b896e881f64b7ea8962b134a9ea62317dd874a;hpb=d86a6c099ff4a1e0c7d1b437fa4ff0a9684fcdb9;p=sliver-openvswitch.git diff --git a/lib/worker.c b/lib/worker.c index f2b896e88..4c947a422 100644 --- a/lib/worker.c +++ b/lib/worker.c @@ -1,4 +1,4 @@ -/* 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. @@ -37,6 +37,11 @@ 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. */ @@ -96,6 +101,9 @@ worker_start(void) xset_nonblocking(work_fds[0]); xset_nonblocking(work_fds[1]); + /* Don't let the worker process own the responsibility to delete + * the pidfile. Register it again after the fork. */ + remove_pidfile_from_unlink(); if (!fork_and_clean_up()) { /* In child (worker) process. */ daemonize_post_detach(); @@ -105,6 +113,7 @@ worker_start(void) } /* In parent (main) process. */ + add_pidfile_to_unlink(); close(work_fds[1]); client_sock = work_fds[0]; rxbuf_init(&client_rx); @@ -198,6 +207,7 @@ worker_send_iovec(const struct iovec iovs[], size_t n_iovs, size_t sent = 0; for (;;) { + struct pollfd pfd; int error; /* Try to send the rest of the request. */ @@ -210,8 +220,21 @@ worker_send_iovec(const struct iovec iovs[], size_t n_iovs, /* 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)); + } } } @@ -223,11 +246,14 @@ worker_request_iovec(const struct iovec iovs[], size_t n_iovs, 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; @@ -241,6 +267,8 @@ worker_request_iovec(const struct iovec iovs[], size_t n_iovs, 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 @@ -321,7 +349,7 @@ worker_reply_iovec(const struct iovec *iovs, size_t n_iovs, * 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); @@ -355,7 +383,7 @@ worker_main(int fd) /* 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); @@ -428,8 +456,6 @@ rxbuf_run(struct rxbuf *rx, int sock, size_t header_len) } } } - - return EAGAIN; } static struct iovec *