summaryrefslogtreecommitdiff
path: root/lib/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/thread.c')
-rw-r--r--lib/thread.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/lib/thread.c b/lib/thread.c
index 7489be5c2d..2e7b0ca0ef 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -1238,12 +1238,31 @@ static struct thread *thread_run(struct thread_master *m, struct thread *thread,
}
static int thread_process_io_helper(struct thread_master *m,
- struct thread *thread, short state, int pos)
+ struct thread *thread, short state,
+ short actual_state, int pos)
{
struct thread **thread_array;
- if (!thread)
+ /*
+ * poll() clears the .events field, but the pollfd array we
+ * pass to poll() is a copy of the one used to schedule threads.
+ * We need to synchronize state between the two here by applying
+ * the same changes poll() made on the copy of the "real" pollfd
+ * array.
+ *
+ * This cleans up a possible infinite loop where we refuse
+ * to respond to a poll event but poll is insistent that
+ * we should.
+ */
+ m->handler.pfds[pos].events &= ~(state);
+
+ if (!thread) {
+ if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP)
+ flog_err(EC_LIB_NO_THREAD,
+ "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!\n",
+ m->handler.pfds[pos].fd, actual_state);
return 0;
+ }
if (thread->type == THREAD_READ)
thread_array = m->read;
@@ -1253,9 +1272,7 @@ static int thread_process_io_helper(struct thread_master *m,
thread_array[thread->u.fd] = NULL;
thread_list_add_tail(&m->ready, thread);
thread->type = THREAD_READY;
- /* if another pthread scheduled this file descriptor for the event we're
- * responding to, no problem; we're getting to it now */
- thread->master->handler.pfds[pos].events &= ~(state);
+
return 1;
}
@@ -1291,12 +1308,13 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
* there's no need to update it. Similarily, barring deletion,
* the fd
* should still be a valid index into the master's pfds. */
- if (pfds[i].revents & (POLLIN | POLLHUP))
+ if (pfds[i].revents & (POLLIN | POLLHUP)) {
thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
- i);
+ pfds[i].revents, i);
+ }
if (pfds[i].revents & POLLOUT)
thread_process_io_helper(m, m->write[pfds[i].fd],
- POLLOUT, i);
+ POLLOUT, pfds[i].revents, i);
/* if one of our file descriptors is garbage, remove the same
* from