]> vgcfreebox.myrthtech.pt Git - ue-pp-terminationdetectionalgorithm.git/blobdiff - control.c
race conditionn fix
[ue-pp-terminationdetectionalgorithm.git] / control.c
index e58ba34936332059d4dd2effe9f3f8e1df94d187..3bcb8c894a988b1fe617f346c312bfbc6b6ec14b 100644 (file)
--- a/control.c
+++ b/control.c
 // 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