]> vgcfreebox.myrthtech.pt Git - ue-pp-terminationdetectionalgorithm.git/blob - control-skeleton.c
ae25b2fcf5dfe44e64dbab1a5e6a9a5084ec2524
[ue-pp-terminationdetectionalgorithm.git] / control-skeleton.c
1 /*
2 Parallel Programming - 2026/2027
3
4 Skeleton of an implementation of a termination detection algorithm
5 */
6
7 #include <mpi.h>
8 #include <pthread.h>
9
10 #include <stdio.h>
11 #include <stdbool.h>
12 #include <unistd.h>
13
14 #include "global.h"
15 #include "control.h"
16 #include "util.h"
17
18 // the tag(s) of the control messages
19 #define CONTROL_SIGNAL 99 // --> must be distinct from BASIC_MESSAGE = 1
20
21 // type for control messages
22 typedef struct {
23 int ping;
24 } control_message_t;
25
26 // Node operational states
27 typedef enum {
28 ACTIVE_STATE,
29 PASSIVE_STATE
30 } node_state_t;
31
32
33 // Shared Local State (Protected by state_mutex)
34 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
35 static node_state_t state = PASSIVE_STATE;
36 static int parent = -1; // -1 indicates null/no parent
37 static int deficit = 0; // C_i counter
38 static bool is_initiator = false;
39
40
41 /*
42 Main loop of the termination detection algorithm.
43
44 When termination is detected, it must end (returning NULL or another
45 appropriate value), which signals the main thread that the basic
46 algorithm has terminated.
47
48 The arguments of the termination detection algorithm are the ID of
49 the process, the number of PROCESSES running the basic algorithm,
50 and whether the process is an initiator.
51 */
52 void *detect_termination(void *_args){
53 thread_args_t *args = _args;
54 int id = args->id;
55 int processes = args->processes;
56 bool initiator = args->initiator;
57
58 while (true){
59 pthread_mutex_lock(&state_mutex);
60
61 // CHECK GLOBAL TERMINATION CONDITION (only happens at root)
62 if (initiator && state == PASSIVE_STATE && deficit == 0)
63 {
64 trace("%d: [CONTROL] GLOBAL TERMINATION DETECTED!\n", id);
65 pthread_mutex_unlock(&state_mutex);
66 break; // Breaks loop, returns NULL, tells main() to shut down
67 }
68
69 pthread_mutex_unlock(&state_mutex);
70
71 // Check network for incoming child signals (non-blocking with MPI_Iprobe)
72 int flag = 0;
73 MPI_Status status;
74 MPI_Iprobe(MPI_ANY_SOURCE, CONTROL_SIGNAL, MPI_COMM_WORLD, &flag, &status);
75
76 if (flag){
77 control_message_t sig;
78 MPI_Recv(&sig, sizeof(control_message_t), MPI_BYTE, status.MPI_SOURCE,
79 CONTROL_SIGNAL, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
80
81 pthread_mutex_lock(&state_mutex);
82 deficit--;
83 trace("%d: [CONTROL] Got signal from %d (New Deficit: %d)\n",
84 id, status.MPI_SOURCE, deficit);
85
86 try_resolve_tree(id);
87 pthread_mutex_unlock(&state_mutex);
88 }
89 else{
90 // Sleep for 1 millisecond to prevent this while(true) loop
91 // from pinning the CPU core at 100% usage
92 usleep(1000);
93 }
94 }
95
96 return NULL;
97 }
98
99 /*
100 Called at startup of the basic algorithm in process ID.
101 */
102 void control_basic_start_hook(int id)
103 {
104 }
105
106 /*
107 Called when the basic algorithm process ID becomes passive.
108 */
109 void control_become_passive_hook(int id)
110 {
111 }
112
113 /*
114 Called when the basic algorithm process ID becomes active.
115 */
116 void control_become_active_hook(int id)
117 {
118 }
119
120 /*
121 Called when the basic algorithm process ID sends a basic message to
122 process PEER.
123 */
124 void control_basic_send_hook(int id, int peer)
125 {
126 }
127
128 /*
129 Called when the basic algorithm process ID receives a basic message
130 from process PEER.
131 */
132 void control_basic_receive_hook(int id, int peer)
133 {
134 }