commit dd92906c0ff9e753b4586c50deae420d128a4aef
parent 45edc59caa435d2bcd444ebeb40fc822d5629978
Author: David Goulet <dgoulet@torproject.org>
Date: Wed, 10 Sep 2025 13:07:16 -0400
Merge branch 'maint-0.4.8'
Diffstat:
4 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/changes/bug41109 b/changes/bug41109
@@ -0,0 +1,3 @@
+ o Minor bugfixes (threads):
+ - Make thread control POSIX compliant.
+ Fixes bug 41109; bugfix on 0.4.8.17-dev.
diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c
@@ -38,6 +38,7 @@
#include "lib/net/alertsock.h"
#include "lib/net/socket.h"
#include "lib/thread/threads.h"
+#include "lib/time/compat_time.h"
#include "ext/tor_queue.h"
#include <event2/event.h>
@@ -278,6 +279,7 @@ static void
worker_thread_main(void *thread_)
{
static int n_worker_threads_running = 0;
+ static unsigned long control_lock_owner = 0;
workerthread_t *thread = thread_;
threadpool_t *pool = thread->in_pool;
workqueue_entry_t *work;
@@ -297,6 +299,14 @@ worker_thread_main(void *thread_)
* pool->lock must be prelocked here. */
tor_mutex_acquire(&pool->lock);
+ if (control_lock_owner == 0) {
+ /* pool->control_lock stays locked. This is required for the main thread
+ * to wait for the worker threads to exit on shutdown, so the memory
+ * clean up won't begin before all threads have exited. */
+ tor_mutex_acquire(&pool->control_lock);
+ control_lock_owner = tor_get_thread_id();
+ }
+
log_debug(LD_GENERAL, "Worker thread has entered the work loop [TID: %lu].",
tor_get_thread_id());
@@ -362,11 +372,22 @@ exit:
pool->n_threads_max - n_worker_threads_running + 1,
pool->n_threads_max, tor_get_thread_id());
- if (--n_worker_threads_running == 0)
+ if (tor_get_thread_id() == control_lock_owner) {
+ /* Wait for the other worker threads to exit so we
+ * can safely unlock pool->control_lock. */
+ while (n_worker_threads_running > 1) {
+ tor_mutex_release(&pool->lock);
+ tor_sleep_msec(10);
+ tor_mutex_acquire(&pool->lock);
+ }
+
+ tor_mutex_release(&pool->lock);
/* Let the main thread know, the last worker thread has exited. */
tor_mutex_release(&pool->control_lock);
-
- tor_mutex_release(&pool->lock);
+ } else {
+ --n_worker_threads_running;
+ tor_mutex_release(&pool->lock);
+ }
}
/** Put a reply on the reply queue. The reply must not currently be on
@@ -623,9 +644,9 @@ check_status:
/* Let worker threads enter the work loop. */
tor_mutex_release(&pool->lock);
-
- /* pool->control_lock stays locked. This is required for the main thread
- * to wait for the worker threads to exit on shutdown. */
+ /* Let one of the worker threads take the ownership of pool->control_lock.
+ * This is required for compliance with POSIX. */
+ tor_mutex_release(&pool->control_lock);
return status;
}
diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2021, The Tor Project, Inc. */
+ * Copyright (c) 2007-2025, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -53,13 +53,15 @@
#undef HAVE_CLOCK_GETTIME
#endif
-#ifdef TOR_UNIT_TESTS
-/** Delay for <b>msec</b> milliseconds. Only used in tests. */
+/** Delay for <b>msec</b> milliseconds. */
void
tor_sleep_msec(int msec)
{
#ifdef _WIN32
Sleep(msec);
+#elif defined(HAVE_TIME_H)
+ struct timespec ts = {msec / 1000, (msec % 1000) * 1000 * 1000};
+ while (nanosleep(&ts, &ts) == -1 && errno == EINTR);
#elif defined(HAVE_USLEEP)
sleep(msec / 1000);
/* Some usleep()s hate sleeping more than 1 sec */
@@ -71,7 +73,6 @@ tor_sleep_msec(int msec)
sleep(CEIL_DIV(msec, 1000));
#endif /* defined(_WIN32) || ... */
}
-#endif /* defined(TOR_UNIT_TESTS) */
#define ONE_MILLION ((int64_t) (1000 * 1000))
#define ONE_BILLION ((int64_t) (1000 * 1000 * 1000))
diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2021, The Tor Project, Inc. */
+ * Copyright (c) 2007-2025, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -361,9 +361,9 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start,
#endif /* SIZEOF_VOID_P == 8 */
}
-#ifdef TOR_UNIT_TESTS
void tor_sleep_msec(int msec);
+#ifdef TOR_UNIT_TESTS
void monotime_enable_test_mocking(void);
void monotime_disable_test_mocking(void);
void monotime_set_mock_time_nsec(int64_t);