Skip to content

Commit c69de51

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 - Initialize with atomic_init() 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 5d9599e commit c69de51

File tree

3 files changed

+36
-14
lines changed

3 files changed

+36
-14
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: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,32 @@ 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);
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);
220214
}
215+
216+
/* Check if we should quit */
217+
if (atomic_load(&rv->quit)) {
218+
break;
219+
}
220+
221+
/* Process the queue entry */
222+
queue_entry_t *entry =
223+
list_last_entry(&rv->wait_queue, queue_entry_t, list);
224+
list_del_init(&entry->list);
225+
pthread_mutex_unlock(&rv->wait_queue_lock);
226+
227+
pthread_mutex_lock(&rv->cache_lock);
228+
t2c_compile(rv, entry->block);
229+
pthread_mutex_unlock(&rv->cache_lock);
230+
free(entry);
231+
232+
pthread_mutex_lock(&rv->wait_queue_lock);
221233
}
234+
pthread_mutex_unlock(&rv->wait_queue_lock);
222235
return NULL;
223236
}
224237
#endif
@@ -727,11 +740,12 @@ riscv_t *rv_create(riscv_user_t rv_attr)
727740
rv->block_cache = cache_create(BLOCK_MAP_CAPACITY_BITS);
728741
assert(rv->block_cache);
729742
#if RV32_HAS(T2C)
730-
rv->quit = false;
743+
atomic_init(&rv->quit, false);
731744
rv->jit_cache = jit_cache_init();
732745
/* prepare wait queue. */
733746
pthread_mutex_init(&rv->wait_queue_lock, NULL);
734747
pthread_mutex_init(&rv->cache_lock, NULL);
748+
pthread_cond_init(&rv->wait_queue_cond, NULL);
735749
INIT_LIST_HEAD(&rv->wait_queue);
736750
/* activate the background compilation thread. */
737751
pthread_create(&t2c_thread, NULL, t2c_runloop, rv);
@@ -836,10 +850,14 @@ void rv_delete(riscv_t *rv)
836850
block_map_destroy(rv);
837851
#else
838852
#if RV32_HAS(T2C)
839-
rv->quit = true;
853+
pthread_mutex_lock(&rv->wait_queue_lock);
854+
atomic_store(&rv->quit, true);
855+
pthread_cond_signal(&rv->wait_queue_cond);
856+
pthread_mutex_unlock(&rv->wait_queue_lock);
840857
pthread_join(t2c_thread, NULL);
841858
pthread_mutex_destroy(&rv->wait_queue_lock);
842859
pthread_mutex_destroy(&rv->cache_lock);
860+
pthread_cond_destroy(&rv->wait_queue_cond);
843861
jit_cache_exit(rv->jit_cache);
844862
#endif
845863
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)