From 5a02743c0c9563f41a8c3821a7bbce4fc3b0b839 Mon Sep 17 00:00:00 2001 From: Aargh Rai Date: Thu, 27 Aug 2026 17:41:07 +0530 Subject: bug fixes --- src/engine/thread.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'src/engine/thread.c') diff --git a/src/engine/thread.c b/src/engine/thread.c index 5891558..1bb9a83 100644 --- a/src/engine/thread.c +++ b/src/engine/thread.c @@ -40,7 +40,7 @@ void threads_go(struct threads *handler) { void *child_thread(void *_args) { struct child_thread_args *args = (struct child_thread_args*)_args; - args->stop = 0; + atomic_store(&args->stop, 0); atomic_bool stop = false; u64 nodes = 0; @@ -71,7 +71,7 @@ void *child_thread(void *_args) { // iteration's block or the search is stopped if (sp == NULL) { static _Thread_local int spins = 0; - if (++spins == 5000000) fprintf(stderr, "CHILD %d STUCK stop=%d\n", args->id, atomic_load(&args->stop)); + if (++spins == 5000000) fprintf(stderr, "CHILD %d STUCK stop=%d (ptr=%p)\n", args->id, atomic_load(&args->stop), (void*)&args->stop); sched_yield(); continue; } @@ -89,8 +89,14 @@ void *child_thread(void *_args) { position_t child = sp->position_snapshot; position_make_move(&child, move); + u64 prev_nodes = nodes; search_result_t res = search(child, sp->depth - 1, alpha, beta, &ctx); + // §2.1 thrashing guard: track how many nodes were searched at this + // split point so that split_point_worth_sharing() can refuse HELP + // on very shallow / barely-searched blocks. + atomic_fetch_add(&sp->nodes_searched, (int)(nodes - prev_nodes)); + // Share (§2.8): negamax — our value flips sign for the parent side split_point_share(sp, -res.score, move); if (-res.score > best_score) { @@ -125,7 +131,7 @@ void *child_thread(void *_args) { // tree void *root_thread(void *_args) { struct root_thread_args *args = (struct root_thread_args*)_args; - args->stop = 0; + atomic_store(&args->stop, 0); atomic_bool stop = false; u64 nodes = 0; @@ -149,6 +155,12 @@ void *root_thread(void *_args) { // iterative deepening: search at increasing depths, publishing an info // message per completed depth so the UCI thread can emit `info ... pv`. for (int depth = 1; depth <= max_depth; depth++) { + // propagate external stop signal into the search context so that + // search_should_stop() picks it up at the next node. + if (atomic_load(&args->stop)) { + atomic_store(&stop, true); + break; + } if (atomic_load(&stop)) break; // root move list (DTS §3.4: splitting at the root is always safe/PV) @@ -156,7 +168,8 @@ void *root_thread(void *_args) { moves_init(&moves); get_legal_moves(&moves, *args->position); - bool can_split = moves.length > 1 && args->split_points != NULL; + bool can_split = moves.length > 1 && args->split_points != NULL + && depth >= 3; // §2.1 thrashing guard: don't split at depth < 3 split_point_t *sp = can_split ? __pool_alloc(args->split_points, args->sp_pool_capacity) : NULL; @@ -221,6 +234,7 @@ void *root_thread(void *_args) { result.score = atomic_load(&sp->best_score); result.best_move = sp->best_move; + moves_deinit(sp->moves); // the move list now belongs to the pool block (released on its next // reuse), so there is nothing to free here } else { @@ -230,17 +244,28 @@ void *root_thread(void *_args) { } if (atomic_load(&stop)) break; + if (atomic_load(&args->stop)) { + atomic_store(&stop, true); + break; + } message->depth = depth; message->nodes = nodes > INT_MAX ? INT_MAX : (int)nodes; message->score_cp = result.score; message->mate = __score_to_mate(result.score); - // pv is already initialized by engine_message_init / handler_push. message->pv.count = 0; - add_ipc_move(&message->pv, (ipc_move_t) { - result.best_move.from, - result.best_move.to, - }); + move_t pv_buf[32]; + int pv_len = reconstruct_pv(*args->position, *args->ttable, pv_buf, 32); + if (pv_len > 0) { + for (int i = 0; i < pv_len; i++) { + add_ipc_move(&message->pv, (ipc_move_t) { pv_buf[i].from, pv_buf[i].to }); + } + } else { + add_ipc_move(&message->pv, (ipc_move_t) { + result.best_move.from, + result.best_move.to, + }); + } if (!should_continue(message, args->go_args)) { break; @@ -257,8 +282,8 @@ void *root_thread(void *_args) { engine_message_mark_ready(message); // signal workers to stop their loops, then mark this thread as finished. - for (int i = 0; i < args->workers_count; i++) { - atomic_store(&args->workers_stop[i], 1); + for (int i = 1; i <= args->workers_count; i++) { + atomic_store(&args->handler->args[i].child_thread_args.stop, 1); } atomic_store(&args->stop, 1); atomic_store(&args->finished, 1); @@ -291,6 +316,7 @@ static bool __root_thread_run( ttable_t tt; ttable_init(&tt, ttable_log); + args->ttable = &tt; root_thread(args); @@ -350,7 +376,7 @@ bool test_root_thread_emits_info_and_bestmove() { // every published message must have a valid depth and on-board pv move. for (engine_message_t *m = messages; m != NULL; m = m->next) { ok &= m->depth >= 1 && m->depth <= 3; - ok &= m->pv.count == 1; + ok &= m->pv.count >= 1; ok &= m->pv.data[0].from >= 0 && m->pv.data[0].from < 64; ok &= m->pv.data[0].to >= 0 && m->pv.data[0].to < 64; } @@ -694,6 +720,7 @@ static void __root_split_env_deinit( engine_message_handler_deinit(&env->message_handlers[i]); } ttable_deinit(env->handler.ttable); + threads_cleanup(&env->handler); threads_deinit(&env->handler); } -- cgit v1.2.3