commit ee22ec99d6908133e41c1bfb90ffd153d6b0493f
parent 6be54040f35dfad1eade7443e0801ed28ca3fcc8
Author: Joris Vink <joris@coders.se>
Date:   Fri, 24 Apr 2015 14:20:02 +0200
Task improvements.
Do not blindly close the sockets created by socketpair() when
finishing up or destroying a task.
Under heavy load this could turn into a race condition where
the task thread closes its endpoint when at the same time
a new task is registered and socketpair() returns the recently
closed socket back to a new task.
When the task that finished then gets destroyed it closes
the endpoint registered to a new task instead causing Kore
to fatal() out when attempting to read from said socket.
Diffstat:
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/src/tasks.c b/src/tasks.c
@@ -66,7 +66,7 @@ kore_task_create(struct kore_task *t, int (*entry)(struct kore_task *))
 	t->state = KORE_TASK_STATE_CREATED;
 	pthread_rwlock_init(&(t->lock), NULL);
 
-	if (socketpair(AF_UNIX, SOCK_STREAM, 0,t->fds) == -1)
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, t->fds) == -1)
 		fatal("kore_task_create: socketpair() %s", errno_s);
 }
 
@@ -114,9 +114,19 @@ kore_task_destroy(struct kore_task *t)
 		LIST_REMOVE(t, rlist);
 	}
 
-	close(t->fds[0]);
-	close(t->fds[1]);		/* This might already be closed. */
+	pthread_rwlock_wrlock(&(t->lock));
+
+	if (t->fds[0] != -1) {
+		(void)close(t->fds[0]);
+		t->fds[0] = -1;
+	}
 
+	if (t->fds[1] != -1) {
+		(void)close(t->fds[1]);
+		t->fds[1] = -1;
+	}
+
+	pthread_rwlock_unlock(&(t->lock));
 	pthread_rwlock_destroy(&(t->lock));
 }
 
@@ -130,7 +140,15 @@ void
 kore_task_finish(struct kore_task *t)
 {
 	kore_debug("kore_task_finished: %p (%d)", t, t->result);
-	close(t->fds[1]);
+
+	pthread_rwlock_wrlock(&(t->lock));
+
+	if (t->fds[1] != -1) {
+		(void)close(t->fds[1]);
+		t->fds[1] = -1;
+	}
+
+	pthread_rwlock_unlock(&(t->lock));
 }
 
 void
@@ -139,7 +157,6 @@ kore_task_channel_write(struct kore_task *t, void *data, u_int32_t len)
 	int		fd;
 
 	kore_debug("kore_task_channel_write: %p <- %p (%ld)", t, data, len);
-
 	THREAD_FD_ASSIGN(t->thread->tid, fd, t->fds[1], t->fds[0]);
 	task_channel_write(fd, &len, sizeof(len));
 	task_channel_write(fd, data, len);