From df5d391823a04906ddacef09ad616a5025fd1b61 Mon Sep 17 00:00:00 2001 From: vitler Date: Sun, 28 Jun 2026 15:41:29 +0100 Subject: [PATCH 1/1] race conditionn fix --- control.c | 78 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/control.c b/control.c index e58ba34..3bcb8c8 100644 --- a/control.c +++ b/control.c @@ -17,9 +17,15 @@ // Tag for control messages. Distinct from basic algorithm's tags. #define CONTROL_SIGNAL 99 -// Type for control messages (empty payload, just a signal) +// Message types for control routing +typedef enum { + MSG_ACK, + MSG_KILL +} msg_type_t; + +// Type for control messages typedef struct { - int dummy; + msg_type_t type; } control_message_t; // Node operational states @@ -34,23 +40,24 @@ static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER; static node_state_t state = PASSIVE_STATE; static int parent = -1; // -1 indicates null/no parent static int deficit = 0; // C_i counter (unacknowledged messages) -static bool initiator = false; +static bool is_initiator = false; +static bool started = false; // RACE CONDITION FIX // --- HELPER FUNCTION --- // MUST BE DECLARED ABOVE THE OTHER FUNCTIONS! // Evaluates if the node can detach from the tree. Caller must hold state_mutex. static void try_resolve_tree(int my_id) { - if (state == PASSIVE_STATE && deficit == 0) + if (started && state == PASSIVE_STATE && deficit == 0) { - if (initiator) { + if (is_initiator) { // Root is passive and deficit is 0 -> Global Termination! return; } if (parent != -1) { - control_message_t sig = {0}; + control_message_t sig = { MSG_ACK }; // Send acknowledgment signal up the tree to our parent MPI_Send(&sig, sizeof(control_message_t), MPI_BYTE, parent, CONTROL_SIGNAL, MPI_COMM_WORLD); @@ -68,18 +75,28 @@ void *detect_termination(void *_args) { thread_args_t *args = _args; int id = args->id; - initiator = args->initiator; - - // (Removed unused 'processes' variable to fix compiler warning) + int processes = args->processes; // Needed for the KILL broadcast + is_initiator = args->initiator; while (true) { pthread_mutex_lock(&state_mutex); // CHECK GLOBAL TERMINATION CONDITION - if (initiator && state == PASSIVE_STATE && deficit == 0) + // Only evaluate if the basic algorithm has officially started + if (started && is_initiator && state == PASSIVE_STATE && deficit == 0) { trace("%d: [CONTROL] GLOBAL TERMINATION DETECTED!\n", id); + + // Broadcast KILL signal to unblock all other control threads + control_message_t kill_sig = { MSG_KILL }; + for (int p = 0; p < processes; p++) { + if (p != id) { + MPI_Send(&kill_sig, sizeof(control_message_t), MPI_BYTE, p, + CONTROL_SIGNAL, MPI_COMM_WORLD); + } + } + pthread_mutex_unlock(&state_mutex); break; // Breaks loop, tells main() to shut down } @@ -97,13 +114,19 @@ void *detect_termination(void *_args) MPI_Recv(&sig, sizeof(control_message_t), MPI_BYTE, status.MPI_SOURCE, CONTROL_SIGNAL, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - pthread_mutex_lock(&state_mutex); - deficit--; // Rule D: A child finished its work and reported back - trace("%d: [CONTROL] Got signal from %d (New Deficit: %d)\n", - id, status.MPI_SOURCE, deficit); - - try_resolve_tree(id); - pthread_mutex_unlock(&state_mutex); + if (sig.type == MSG_KILL) { + trace("%d: [CONTROL] Received KILL signal. Shutting down.\n", id); + break; + } + else if (sig.type == MSG_ACK) { + pthread_mutex_lock(&state_mutex); + deficit--; // Rule D: A child finished its work and reported back + trace("%d: [CONTROL] Got signal from %d (New Deficit: %d)\n", + id, status.MPI_SOURCE, deficit); + + try_resolve_tree(id); + pthread_mutex_unlock(&state_mutex); + } } else { @@ -121,9 +144,11 @@ void *detect_termination(void *_args) void control_basic_start_hook(int id) { pthread_mutex_lock(&state_mutex); - state = initiator ? ACTIVE_STATE : PASSIVE_STATE; + is_initiator = (id == 0); + state = is_initiator ? ACTIVE_STATE : PASSIVE_STATE; parent = -1; deficit = 0; + started = true; // Signal the control thread that it is safe to check for termination pthread_mutex_unlock(&state_mutex); } @@ -167,21 +192,22 @@ void control_basic_receive_hook(int id, int peer) { pthread_mutex_lock(&state_mutex); - if (parent == -1) + // A node is only "out of the tree" if parent == -1. + // It can be PASSIVE but still in the tree if it is waiting for children (deficit > 0). + if (parent == -1 && !is_initiator) { - // Rule B (Case 1): Woken up from passive state - state = ACTIVE_STATE; - parent = peer; // Adopt sender as parent in the tree + // Not in the tree -> Join it + parent = peer; trace("%d: [CONTROL] Joined tree under parent %d\n", id, parent); } else { - // Rule B (Case 2): Already active! Reject parent change, immediately signal back - control_message_t sig = {0}; + // Already in the tree (or is root) -> Reject parent change, immediately signal back + control_message_t sig = { MSG_ACK }; MPI_Send(&sig, sizeof(control_message_t), MPI_BYTE, peer, CONTROL_SIGNAL, MPI_COMM_WORLD); - trace("%d: [CONTROL] Rejected parent %d (Already Active)\n", id, peer); + trace("%d: [CONTROL] Rejected parent %d (Already in tree or Root)\n", id, peer); } pthread_mutex_unlock(&state_mutex); -} +} \ No newline at end of file -- 2.47.3