Skip to content

Commit a3d4647

Browse files
committed
Eliminate ThreadSanitizer warnings in JIT T2C mode
This fixes data races detected by ThreadSanitizer when running with JIT compilation enabled: 1. Fix quit flag data race: - Change 'volatile bool quit' to '_Atomic bool quit' - Use atomic_store() for writes and atomic_load() for reads 2. Fix TOCTOU race in wait_queue access: - Move list_empty() check inside mutex-protected critical section - Hold mutex during entire queue manipulation These changes ensure thread-safe communication between the main thread and T2C compilation thread, eliminating all TSAN warning while improving CPU efficiency by avoiding busy-waiting.
1 parent f521ca5 commit a3d4647

File tree

3 files changed

+35
-15
lines changed

3 files changed

+35
-15
lines changed

src/emulate.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,7 @@ void rv_step(void *arg)
11321132
entry->block = block;
11331133
pthread_mutex_lock(&rv->wait_queue_lock);
11341134
list_add(&entry->list, &rv->wait_queue);
1135+
pthread_cond_signal(&rv->wait_queue_cond);
11351136
pthread_mutex_unlock(&rv->wait_queue_lock);
11361137
}
11371138
#endif

src/riscv.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,30 @@ static pthread_t t2c_thread;
206206
static void *t2c_runloop(void *arg)
207207
{
208208
riscv_t *rv = (riscv_t *) arg;
209-
while (!rv->quit) {
210-
if (!list_empty(&rv->wait_queue)) {
211-
queue_entry_t *entry =
212-
list_last_entry(&rv->wait_queue, queue_entry_t, list);
213-
pthread_mutex_lock(&rv->wait_queue_lock);
214-
list_del_init(&entry->list);
215-
pthread_mutex_unlock(&rv->wait_queue_lock);
216-
pthread_mutex_lock(&rv->cache_lock);
217-
t2c_compile(rv, entry->block);
218-
pthread_mutex_unlock(&rv->cache_lock);
219-
free(entry);
220-
}
209+
pthread_mutex_lock(&rv->wait_queue_lock);
210+
while (!atomic_load(&rv->quit)) {
211+
/* Wait for work or quit signal */
212+
while (list_empty(&rv->wait_queue) && !atomic_load(&rv->quit))
213+
pthread_cond_wait(&rv->wait_queue_cond, &rv->wait_queue_lock);
214+
215+
/* Check if we should quit */
216+
if (atomic_load(&rv->quit))
217+
break;
218+
219+
/* Process the queue entry */
220+
queue_entry_t *entry =
221+
list_last_entry(&rv->wait_queue, queue_entry_t, list);
222+
list_del_init(&entry->list);
223+
pthread_mutex_unlock(&rv->wait_queue_lock);
224+
225+
pthread_mutex_lock(&rv->cache_lock);
226+
t2c_compile(rv, entry->block);
227+
pthread_mutex_unlock(&rv->cache_lock);
228+
free(entry);
229+
230+
pthread_mutex_lock(&rv->wait_queue_lock);
221231
}
232+
pthread_mutex_unlock(&rv->wait_queue_lock);
222233
return NULL;
223234
}
224235
#endif
@@ -727,11 +738,12 @@ riscv_t *rv_create(riscv_user_t rv_attr)
727738
rv->block_cache = cache_create(BLOCK_MAP_CAPACITY_BITS);
728739
assert(rv->block_cache);
729740
#if RV32_HAS(T2C)
730-
rv->quit = false;
741+
atomic_init(&rv->quit, false);
731742
rv->jit_cache = jit_cache_init();
732743
/* prepare wait queue. */
733744
pthread_mutex_init(&rv->wait_queue_lock, NULL);
734745
pthread_mutex_init(&rv->cache_lock, NULL);
746+
pthread_cond_init(&rv->wait_queue_cond, NULL);
735747
INIT_LIST_HEAD(&rv->wait_queue);
736748
/* activate the background compilation thread. */
737749
pthread_create(&t2c_thread, NULL, t2c_runloop, rv);
@@ -836,10 +848,14 @@ void rv_delete(riscv_t *rv)
836848
block_map_destroy(rv);
837849
#else
838850
#if RV32_HAS(T2C)
839-
rv->quit = true;
851+
pthread_mutex_lock(&rv->wait_queue_lock);
852+
atomic_store(&rv->quit, true);
853+
pthread_cond_signal(&rv->wait_queue_cond);
854+
pthread_mutex_unlock(&rv->wait_queue_lock);
840855
pthread_join(t2c_thread, NULL);
841856
pthread_mutex_destroy(&rv->wait_queue_lock);
842857
pthread_mutex_destroy(&rv->cache_lock);
858+
pthread_cond_destroy(&rv->wait_queue_cond);
843859
jit_cache_exit(rv->jit_cache);
844860
#endif
845861
jit_state_exit(rv->jit_state);

src/riscv_private.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#pragma once
7+
#include <stdatomic.h>
78
#include <stdbool.h>
89

910
#if RV32_HAS(GDBSTUB)
@@ -197,7 +198,9 @@ struct riscv_internal {
197198
#if RV32_HAS(T2C)
198199
struct list_head wait_queue;
199200
pthread_mutex_t wait_queue_lock, cache_lock;
200-
volatile bool quit; /**< Determine the main thread is terminated or not */
201+
pthread_cond_t
202+
wait_queue_cond; /**< Condition variable to signal new work */
203+
_Atomic bool quit; /**< Determine the main thread is terminated or not */
201204
#endif
202205
void *jit_state;
203206
void *jit_cache;

0 commit comments

Comments
 (0)