fix: use _Atomic flag for sel_alloc_thread_id registration, move reg before loop, add wrong-thread guard test
This commit is contained in:
parent
b722e5cb3d
commit
1eb4eb1335
3 changed files with 61 additions and 13 deletions
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
#define UNIT_TEST 1
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -2252,6 +2253,52 @@ test_sel_register_alloc_thread(void)
|
|||
sel_optimize_test_reset();
|
||||
}
|
||||
|
||||
/* ── Task 8: wrong-thread ownership guard test ───────────────────────────*/
|
||||
|
||||
/* shared state for the wrong-thread sweep test */
|
||||
static int g_wrong_thread_sweep_ran = 0;
|
||||
|
||||
static void* wrong_thread_sweep(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
/* calling gc_sweep from the wrong thread must hit the ownership guard
|
||||
* and return without sweeping — nodes must remain intact */
|
||||
gc_sweep_select_nodes(NULL, 0);
|
||||
g_wrong_thread_sweep_ran = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
test_sel_wrong_thread_guard(void)
|
||||
{
|
||||
sel_optimize_test_reset();
|
||||
sel_optimize_set(1);
|
||||
sel_node_table_init();
|
||||
|
||||
/* Register THIS thread as the allocator */
|
||||
sel_register_alloc_thread();
|
||||
|
||||
/* Allocate a node that should survive the wrong-thread sweep */
|
||||
xce_select_node_t* n = makeSelectNode(SEL_TRUE, 0, 0);
|
||||
TEST_ASSERT_NOT_NULL(n);
|
||||
|
||||
/* Spawn a different thread to call gc_sweep — guard must block it */
|
||||
pthread_t tid;
|
||||
g_wrong_thread_sweep_ran = 0;
|
||||
int rc = pthread_create(&tid, NULL, wrong_thread_sweep, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
pthread_join(tid, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(1, g_wrong_thread_sweep_ran);
|
||||
|
||||
/* Node must still exist (wrong-thread sweep was blocked) */
|
||||
/* GC from correct thread: mark then sweep normally */
|
||||
gc_clear_marks();
|
||||
gc_sweep_select_nodes(NULL, 0);
|
||||
|
||||
sel_node_table_fini();
|
||||
sel_optimize_test_reset();
|
||||
}
|
||||
|
||||
/* ── Top-level runner ─────────────────────────────────────────────────────*/
|
||||
|
||||
void
|
||||
|
|
@ -2365,6 +2412,7 @@ test_select(void)
|
|||
|
||||
/* ── Task 8: sel_alloc_thread_id ownership check ─────────────────── */
|
||||
RUN_TEST(test_sel_register_alloc_thread);
|
||||
RUN_TEST(test_sel_wrong_thread_guard);
|
||||
|
||||
xstring_table_fini();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@
|
|||
|
||||
/* ── optimize level ───────────────────────────────────────────────────── */
|
||||
|
||||
static _Atomic int g_sel_optimize_level = -1; /* -1 = unset */
|
||||
static pthread_t sel_alloc_thread_id; /* 0 = unregistered — skip checks */
|
||||
static _Atomic int g_sel_optimize_level = -1; /* -1 = unset */
|
||||
static pthread_t sel_alloc_thread_id;
|
||||
static _Atomic int sel_alloc_thread_registered = 0; /* 1 after sel_register_alloc_thread() */
|
||||
|
||||
void sel_optimize_set(int level)
|
||||
{
|
||||
|
|
@ -186,12 +187,14 @@ void sel_optimize_test_reset(void)
|
|||
{
|
||||
sel_node_table_fini();
|
||||
atomic_store_explicit(&g_sel_optimize_level, -1, memory_order_seq_cst);
|
||||
sel_alloc_thread_id = 0;
|
||||
atomic_store_explicit(&sel_alloc_thread_registered, 0, memory_order_seq_cst);
|
||||
/* sel_alloc_thread_id left as-is; only checked when registered flag is set */
|
||||
}
|
||||
|
||||
void sel_register_alloc_thread(void)
|
||||
{
|
||||
sel_alloc_thread_id = pthread_self();
|
||||
atomic_store_explicit(&sel_alloc_thread_registered, 1, memory_order_release);
|
||||
}
|
||||
|
||||
/* ── node construction ───────────────────────────────────────────────── */
|
||||
|
|
@ -651,7 +654,8 @@ int eval_select(const xce_select_node_t* node, select_eval_ctx_t* ctx)
|
|||
if (sel_get_optimize_level() <= 0) {
|
||||
ERROR("eval_select called with optimize_level <= 0"); abort();
|
||||
}
|
||||
if (sel_alloc_thread_id != 0 && !pthread_equal(pthread_self(), sel_alloc_thread_id)) {
|
||||
if (atomic_load_explicit(&sel_alloc_thread_registered, memory_order_acquire)
|
||||
&& !pthread_equal(pthread_self(), sel_alloc_thread_id)) {
|
||||
ERROR("eval_select called from non-allocator thread");
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -875,7 +879,8 @@ void gc_sweep_select_nodes(const xce_sched_job_t** live_jobs, size_t njobs)
|
|||
if (sel_node_table.table == NULL) {
|
||||
return;
|
||||
}
|
||||
if (sel_alloc_thread_id != 0 && !pthread_equal(pthread_self(), sel_alloc_thread_id)) {
|
||||
if (atomic_load_explicit(&sel_alloc_thread_registered, memory_order_acquire)
|
||||
&& !pthread_equal(pthread_self(), sel_alloc_thread_id)) {
|
||||
ERROR("gc_sweep_select_nodes called from non-allocator thread");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,16 +117,11 @@ int main(int argc, char* argv[])
|
|||
|
||||
INFO("xce scheduler is running");
|
||||
|
||||
/* Register this thread as the sole eval/GC allocator thread (write-once) */
|
||||
sel_register_alloc_thread();
|
||||
|
||||
while (1) {
|
||||
sched_update(&sched);
|
||||
|
||||
/* Register this thread as the sole eval/GC allocator thread (write-once) */
|
||||
static int sel_thread_registered = 0;
|
||||
if (!sel_thread_registered) {
|
||||
sel_register_alloc_thread();
|
||||
sel_thread_registered = 1;
|
||||
}
|
||||
|
||||
sched_begin_session(&sched);
|
||||
sched_go(&sched);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue