aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarat Dukhan <maratek@gmail.com>2020-04-10 16:49:59 -0700
committerMarat Dukhan <maratek@gmail.com>2020-04-10 16:49:59 -0700
commit52a2f5706db7f9f805c2e0b5bfc56477b08b841a (patch)
tree6f464f57c6da6f1c936782a673a501a81616df72 /src
parent8f8dd879d20af72cf11344aa432f1cab21630f67 (diff)
downloadpthreadpool-52a2f5706db7f9f805c2e0b5bfc56477b08b841a.tar.gz
Fix race condition in Windows implementation
The command event for the next command must be reset before write-release of the new command, because as soon as the worker threads observe the new command, they may complete it and switch to waiting on the next command event
Diffstat (limited to 'src')
-rw-r--r--src/windows.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/src/windows.c b/src/windows.c
index 310945b..2bea3bc 100644
--- a/src/windows.c
+++ b/src/windows.c
@@ -254,6 +254,17 @@ PTHREADPOOL_INTERNAL void pthreadpool_parallelize(
const uint32_t new_command = ~(old_command | THREADPOOL_COMMAND_MASK) | threadpool_command_parallelize;
/*
+ * Reset the command event for the next command.
+ * It is important to reset the event before writing out the new command, because as soon as the worker threads
+ * observe the new command, they may process it and switch to waiting on the next command event.
+ *
+ * Note: the event is different from the command event signalled in this update.
+ */
+ const uint32_t event_index = (old_command >> 31);
+ BOOL reset_event_status = ResetEvent(threadpool->command_event[event_index ^ 1]);
+ assert(reset_event_status != FALSE);
+
+ /*
* Store the command with release semantics to guarantee that if a worker thread observes
* the new command value, it also observes the updated command parameters.
*
@@ -267,7 +278,6 @@ PTHREADPOOL_INTERNAL void pthreadpool_parallelize(
* Event in use must be switched after every submitted command to avoid race conditions.
* Choose the event based on the high bit of the command, which is flipped on every update.
*/
- const uint32_t event_index = (old_command >> 31);
const BOOL set_event_status = SetEvent(threadpool->command_event[event_index]);
assert(set_event_status != FALSE);
@@ -293,11 +303,9 @@ PTHREADPOOL_INTERNAL void pthreadpool_parallelize(
wait_worker_threads(threadpool, event_index ^ 1);
/*
- * Reset events for the next command.
- * Note: the reset events are different from the events used for synchronization in this update.
+ * Reset the completion event for the next command.
+ * Note: the event is different from the one used for waiting in this update.
*/
- BOOL reset_event_status = ResetEvent(threadpool->command_event[event_index ^ 1]);
- assert(reset_event_status != FALSE);
reset_event_status = ResetEvent(threadpool->completion_event[event_index]);
assert(reset_event_status != FALSE);