GCC Code Coverage Report


Directory: src/
File: src/LB_comm/shmem_barrier.c
Date: 2026-06-05 08:54:23
Exec Total Coverage
Lines: 229 249 92.0%
Functions: 17 17 100.0%
Branches: 101 152 66.4%

Line Branch Exec Source
1 /*********************************************************************************/
2 /* Copyright 2009-2026 Barcelona Supercomputing Center */
3 /* */
4 /* This file is part of the DLB library. */
5 /* */
6 /* DLB is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU Lesser General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* DLB is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU Lesser General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU Lesser General Public License */
17 /* along with DLB. If not, see <https://www.gnu.org/licenses/>. */
18 /*********************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "LB_comm/shmem_barrier.h"
25
26 #include "LB_core/DLB_kernel.h"
27 #include "LB_comm/shmem.h"
28 #include "apis/dlb_errors.h"
29 #include "support/atomic.h"
30 #include "support/debug.h"
31 #include "support/mask_utils.h"
32 #include "support/mytime.h"
33 #include "support/types.h"
34 #include "talp/talp.h"
35
36 #include <errno.h>
37 #include <pthread.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41
42 typedef struct barrier_flags {
43 bool initialized:1;
44 bool lewi:1;
45 } barrier_flags_t;
46
47 typedef struct barrier_t {
48 char name[BARRIER_NAME_MAX];
49 barrier_flags_t flags;
50 unsigned int participants;
51 atomic_uint ntimes;
52 atomic_uint count;
53 pthread_barrier_t barrier;
54 pthread_rwlock_t rwlock;
55 } barrier_t;
56
57 typedef struct {
58 bool initialized;
59 int max_barriers; // capacity
60 int num_barriers; // size, although detached may be counted
61 barrier_t barriers[];
62 } shdata_t;
63
64 enum { SHMEM_BARRIER_VERSION = 7 };
65 enum { SHMEM_TIMEOUT_SECONDS = 1 };
66
67 static int max_barriers = 0;
68 static shmem_handler_t *shm_handler = NULL;
69 static shdata_t *shdata = NULL;
70 static const char *shmem_name = "barrier";
71
72 1 static void cleanup_shmem(void *shdata_ptr, int pid) {
73
74 1 bool shmem_empty = true;
75 1 shdata_t *shared_data = shdata_ptr;
76 1 int num_barriers = shared_data->num_barriers;
77
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (int i = 0; i < num_barriers; i++) {
78 1 barrier_t *barrier = &shared_data->barriers[i];
79
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (--barrier->participants == 0) {
80 1 *barrier = (const barrier_t){};
81 } else {
82 shmem_empty = false;
83 }
84 }
85
86 /* If there are no registered barriers, make sure shmem is reset */
87
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (shmem_empty) {
88 1 memset(shared_data, 0, shmem_barrier__size());
89 }
90 1 }
91
92 116 static void open_shmem(const char *shmem_key, int shmem_size_multiplier) {
93
94 116 max_barriers = mu_get_system_size() * shmem_size_multiplier;
95 232 shm_handler = shmem_init((void**)&shdata,
96 116 &(const shmem_props_t) {
97 116 .size = shmem_barrier__size(),
98 .name = shmem_name,
99 .key = shmem_key,
100 .version = SHMEM_BARRIER_VERSION,
101 .cleanup_fn = cleanup_shmem,
102 });
103 116 }
104
105 145 int shmem_barrier__init(const char *shmem_key, int shmem_size_multiplier) {
106
107
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 115 times.
145 if (shm_handler != NULL) return DLB_ERR_NOMEM;
108
109 115 open_shmem(shmem_key, shmem_size_multiplier);
110
111 115 int error = DLB_SUCCESS;
112 115 shmem_lock(shm_handler);
113 {
114 // Initialize some values if this is the 1st process attached to the shmem
115
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 35 times.
115 if (!shdata->initialized) {
116 80 shdata->initialized = true;
117 80 shdata->num_barriers = 0;
118 80 shdata->max_barriers = max_barriers;
119 } else {
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 if (shdata->max_barriers != max_barriers) {
121 error = DLB_ERR_INIT;
122 }
123 }
124 }
125 115 shmem_unlock(shm_handler);
126
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
115 if (error == DLB_ERR_INIT) {
128 warning("Cannot attach to Barrier shmem because existing size differ."
129 " Existing shmem size: %d, expected: %d."
130 " Check for DLB_ARGS consistency among processes or clean up shared memory.",
131 shdata->max_barriers, max_barriers);
132 }
133
134
1/2
✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
115 if (error == DLB_SUCCESS) {
135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
115 verbose(VB_BARRIER, "Barrier Module initialized.");
136 }
137
138 115 return error;
139 }
140
141 1 void shmem_barrier_ext__init(const char *shmem_key, int shmem_size_multiplier) {
142
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (shm_handler != NULL) return;
144
145 1 open_shmem(shmem_key, shmem_size_multiplier);
146 }
147
148 145 void shmem_barrier__finalize(const char *shmem_key, int shmem_size_multiplier) {
149
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 114 times.
145 if (shm_handler == NULL) {
150 /* barrier_finalize may be called to finalize existing process
151 * even if the file descriptor is not opened. (DLB_PreInit + forc-exec case) */
152
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
31 if (shmem_exists(shmem_name, shmem_key)) {
153 shmem_barrier_ext__init(shmem_key, shmem_size_multiplier);
154 } else {
155 31 return;
156 }
157 }
158
159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 verbose(VB_BARRIER, "Finalizing Barrier Module");
160
161 114 shmem_finalize(shm_handler, NULL /* do not check if empty */);
162 114 shm_handler = NULL;
163 }
164
165 1 int shmem_barrier_ext__finalize(void) {
166 // Protect double finalization
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (shm_handler == NULL) {
168 return DLB_ERR_NOSHMEM;
169 }
170
171 // Shared memory destruction
172 1 shmem_finalize(shm_handler, NULL /* do not check if empty */);
173 1 shm_handler = NULL;
174 1 shdata = NULL;
175
176 1 return DLB_SUCCESS;
177 }
178
179 122 int shmem_barrier__get_max_barriers(void) {
180 122 return max_barriers;
181 }
182
183 // Basically for testing purposes, num_barriers is not decremented if a barrier
184 // in the middle is detached, so we count the number of initialized barriers.
185 6 int shmem_barrier__get_num_barriers(void) {
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (shdata == NULL) return -1;
187
188 6 int real_num_barriers = 0;
189 6 shmem_lock(shm_handler);
190 {
191 6 int num_barriers = shdata->num_barriers;
192
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 for (int i = 0; i < num_barriers; ++i) {
193
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (shdata->barriers[i].flags.initialized) {
194 10 ++real_num_barriers;
195 }
196 }
197 }
198 6 shmem_unlock(shm_handler);
199
200 6 return real_num_barriers;
201 }
202
203 /* Given a barrier_name, find whether the barrier is registered in the shared
204 * memory. Note that this function is not thread-safe */
205 10 barrier_t* shmem_barrier__find(const char *barrier_name) {
206
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (shm_handler == NULL) return NULL;
207
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (barrier_name == NULL) return NULL;
208
209 6 int num_barriers = shdata->num_barriers;
210
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 for (int i = 0; i < num_barriers; ++i) {
211
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (shdata->barriers[i].participants > 0
212
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 && shdata->barriers[i].flags.initialized
213
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 && strncmp(shdata->barriers[i].name, barrier_name,
214 BARRIER_NAME_MAX-1) == 0) {
215 3 return &shdata->barriers[i];
216 }
217 }
218
219 3 return NULL;
220 }
221
222 /* Register and attach process to barrier.
223 * barrier_name: barrier name
224 * lewi: whether this barrier does lewi
225 */
226 139 barrier_t* shmem_barrier__register(const char *barrier_name, bool lewi) {
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
139 if (shm_handler == NULL) return NULL;
228
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 138 times.
139 if (barrier_name == NULL) return NULL;
229
230 /* Obtain the shared memory lock to find the appropriate place for the new
231 * barrier. If the barrier is not created, the first process must
232 * initialize it before releasing the lock. If the barrier was already
233 * created, new processes may attach after acquiring both the shmem and the
234 * barrier specific lock. */
235 138 int participants = -1;
236 138 barrier_t *barrier = NULL;
237 138 shmem_lock(shm_handler);
238 {
239 /* Find a new spot, or an already registered barrier */
240 138 barrier_t *empty_spot = NULL;
241 138 int num_barriers = shdata->num_barriers;
242
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 93 times.
165 for (int i = 0; i < num_barriers; ++i) {
243
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 if (empty_spot == NULL
244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 && shdata->barriers[i].participants == 0
245 && !shdata->barriers[i].flags.initialized) {
246 empty_spot = &shdata->barriers[i];
247 }
248
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 else if (shdata->barriers[i].participants > 0
249
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 && shdata->barriers[i].flags.initialized
250
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 27 times.
72 && strncmp(shdata->barriers[i].name, barrier_name,
251 BARRIER_NAME_MAX-1) == 0) {
252 45 barrier = &shdata->barriers[i];
253 45 break;
254 }
255 }
256
257 /* If barrier nor empty_spot are found, try to get a new position from the end */
258
5/6
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✓ Branch 5 taken 2 times.
138 if (barrier == NULL && empty_spot == NULL && num_barriers < max_barriers) {
259 91 empty_spot = &shdata->barriers[num_barriers];
260 91 ++shdata->num_barriers;
261 }
262
263 /* New barrier, lock first and initialize required fields */
264
4/4
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 2 times.
229 if (barrier == NULL && empty_spot != NULL) {
265 91 barrier = empty_spot;
266 91 *barrier = (const barrier_t){};
267
268 pthread_rwlockattr_t rwlockattr;
269 91 pthread_rwlockattr_init(&rwlockattr);
270 91 pthread_rwlockattr_setpshared(&rwlockattr, PTHREAD_PROCESS_SHARED);
271 91 pthread_rwlock_init(&barrier->rwlock, &rwlockattr);
272 91 pthread_rwlockattr_destroy(&rwlockattr);
273
274 /* Initialize only once the lock is acquired */
275 91 pthread_rwlock_wrlock(&barrier->rwlock);
276 {
277 91 barrier->flags = (const barrier_flags_t) {
278 .initialized = true,
279 .lewi = lewi,
280 };
281 91 barrier->participants = 1;
282 91 participants = 1;
283 91 snprintf(barrier->name, BARRIER_NAME_MAX, "%s", barrier_name);
284 pthread_barrierattr_t barrierattr;
285 91 pthread_barrierattr_init(&barrierattr);
286 91 pthread_barrierattr_setpshared(&barrierattr, PTHREAD_PROCESS_SHARED);
287 91 pthread_barrier_init(&barrier->barrier, &barrierattr, barrier->participants);
288 91 pthread_barrierattr_destroy(&barrierattr);
289 }
290 91 pthread_rwlock_unlock(&barrier->rwlock);
291
292
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 2 times.
47 } else if (barrier != NULL){
293 /* Barrier was created by another participant, attach.
294 * (timedlock is used to avoid potential deadlocks) */
295 struct timespec timeout;
296 45 get_time_real(&timeout);
297 45 timeout.tv_sec += SHMEM_TIMEOUT_SECONDS;
298 45 int timedwrlock_error = pthread_rwlock_timedwrlock(&barrier->rwlock, &timeout);
299
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 if (likely(timedwrlock_error == 0)) {
300 /* Update participants */
301 45 participants = ++barrier->participants;
302
303 /* Create new barrier with the number of participants updated */
304 45 pthread_barrier_destroy(&barrier->barrier);
305 pthread_barrierattr_t attr;
306 45 pthread_barrierattr_init(&attr);
307 45 pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
308 45 pthread_barrier_init(&barrier->barrier, &attr, barrier->participants);
309 45 pthread_barrierattr_destroy(&attr);
310
311 45 pthread_rwlock_unlock(&barrier->rwlock);
312
313 } else if (timedwrlock_error == ETIMEDOUT || timedwrlock_error == EDEADLK) {
314 shmem_unlock(shm_handler);
315 fatal("Timed out while creating shmem_barrier.\n"
316 "Please, report at " PACKAGE_BUGREPORT);
317 } else if (timedwrlock_error == EINVAL) {
318 shmem_unlock(shm_handler);
319 fatal("Error acquiring timedwrlock while creating shmem_barrier.\n"
320 "Please, report at " PACKAGE_BUGREPORT);
321 }
322 }
323 }
324 138 shmem_unlock(shm_handler);
325
326
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 2 times.
138 if (barrier != NULL) {
327 /* Attach if needed and print number of participants */
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 verbose(VB_BARRIER, "Attached to barrier %s. Participants: %d",
329 barrier->name, participants);
330 }
331
332 138 return barrier;
333 }
334
335 /* The attach function should not have any races with the global shared memory.
336 * At most, 'barrier' points to an unitialized barrier and error is returned.
337 * */
338 8 int shmem_barrier__attach(barrier_t *barrier) {
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (barrier == NULL) return DLB_ERR_UNKNOWN;
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
341
342 #ifdef DEBUG_VERSION
343 int count;
344 #endif
345 int participants;
346 8 pthread_rwlock_wrlock(&barrier->rwlock);
347 {
348
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 if (!barrier->flags.initialized
349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 || barrier->participants == 0) {
350 1 pthread_rwlock_unlock(&barrier->rwlock);
351 1 return DLB_ERR_PERM;
352 }
353
354 /* Update participants */
355 7 participants = ++barrier->participants;
356
357 /* Create new barrier with the number of participants updated */
358 7 pthread_barrier_destroy(&barrier->barrier);
359 pthread_barrierattr_t attr;
360 7 pthread_barrierattr_init(&attr);
361 7 pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
362 7 pthread_barrier_init(&barrier->barrier, &attr, barrier->participants);
363 7 pthread_barrierattr_destroy(&attr);
364
365 #ifdef DEBUG_VERSION
366 7 count = barrier->count;
367 #endif
368 }
369 7 pthread_rwlock_unlock(&barrier->rwlock);
370
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 ensure(count == 0, "Barrier Shared memory inconsistency while attaching "
372 "barrier (count = %d).\n" "Please, report at " PACKAGE_BUGREPORT,
373 count);
374
375 7 return participants;
376 }
377
378 /* The detach function may remove the barrier if 'participants' reaches 0 and
379 * compete with a barrier creation. This function needs to acquire both locks. */
380 1010 int shmem_barrier__detach(barrier_t *barrier) {
381
2/2
✓ Branch 0 taken 868 times.
✓ Branch 1 taken 142 times.
1010 if (barrier == NULL) return DLB_ERR_UNKNOWN;
382
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 103 times.
142 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
383
384 #ifdef DEBUG_VERSION
385 103 int count = -1;
386 #endif
387 103 int participants = -1;
388
389 103 shmem_lock(shm_handler);
390 {
391 struct timespec timeout;
392 103 get_time_real(&timeout);
393 103 timeout.tv_sec += SHMEM_TIMEOUT_SECONDS;
394 103 int timedwrlock_error = pthread_rwlock_timedwrlock(&barrier->rwlock, &timeout);
395
1/2
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
103 if (likely(timedwrlock_error == 0)) {
396
397
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 1 times.
103 if (!barrier->flags.initialized
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 || barrier->participants == 0) {
399 1 pthread_rwlock_unlock(&barrier->rwlock);
400 1 shmem_unlock(shm_handler);
401 1 return DLB_ERR_PERM;
402 }
403
404 #ifdef DEBUG_VERSION
405 102 count = barrier->count;
406 #endif
407 /* Both locks are acquired and barrier is valid, detach: */
408
409 /* Update participants */
410 102 participants = --barrier->participants;
411
412
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 59 times.
102 if (participants > 0) {
413 /* Create new barrier with the number of participants updated */
414 43 pthread_barrier_destroy(&barrier->barrier);
415 pthread_barrierattr_t attr;
416 43 pthread_barrierattr_init(&attr);
417 43 pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
418 43 pthread_barrier_init(&barrier->barrier, &attr, barrier->participants);
419 43 pthread_barrierattr_destroy(&attr);
420
421 43 pthread_rwlock_unlock(&barrier->rwlock);
422 } else {
423 /* If this is the last participant, uninitialize barrier */
424 59 pthread_rwlock_unlock(&barrier->rwlock);
425 59 pthread_barrier_destroy(&barrier->barrier);
426 59 pthread_rwlock_destroy(&barrier->rwlock);
427 59 *barrier = (const barrier_t){};
428
429 /* Try to compact barrier list */
430
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 53 times.
118 for (int i = shdata->num_barriers - 1; i >= 0; --i) {
431
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 6 times.
65 if (!shdata->barriers[i].flags.initialized) {
432 59 --shdata->num_barriers;
433 } else {
434 6 break;
435 }
436 }
437 }
438 } else if (timedwrlock_error == ETIMEDOUT || timedwrlock_error == EDEADLK) {
439 shmem_unlock(shm_handler);
440 fatal("Timed out while detaching barrier.\n"
441 "Please, report at " PACKAGE_BUGREPORT);
442 } else if (timedwrlock_error == EINVAL) {
443 shmem_unlock(shm_handler);
444 fatal("Error acquiring timedwrlock while detaching barrier.\n"
445 "Please, report at " PACKAGE_BUGREPORT);
446 }
447 }
448 102 shmem_unlock(shm_handler);
449
450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 ensure(count == 0, "Barrier Shared memory inconsistency while attaching "
451 "barrier (count = %d).\n" "Please, report at " PACKAGE_BUGREPORT,
452 count);
453
454 102 return participants;
455 }
456
457 48 void shmem_barrier__barrier(barrier_t *barrier) {
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (unlikely(shm_handler == NULL)) return;
459
460 48 pthread_rwlock_rdlock(&barrier->rwlock);
461 {
462
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 47 times.
48 if (unlikely(!barrier->flags.initialized)) {
463 1 warning("Trying to use a non initialized barrier");
464 1 pthread_rwlock_unlock(&barrier->rwlock);
465 1 return;
466 }
467
468 47 unsigned int participant_number = DLB_ATOMIC_ADD_FETCH(&barrier->count, 1);
469 47 bool last_in = participant_number == barrier->participants;
470
471
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
47 verbose(VB_BARRIER, "Entering barrier %s%s", barrier->name, last_in ? " (last)" : "");
472
473
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 15 times.
47 if (last_in) {
474 // Barrier
475 32 pthread_barrier_wait(&barrier->barrier);
476
477 // Increase ntimes counter
478 32 DLB_ATOMIC_ADD_RLX(&barrier->ntimes, 1);
479 } else {
480 // Only if this process is not the last one, act as a blocking call
481
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8 times.
15 if (barrier->flags.lewi) {
482 7 sync_call_flags_t mpi_flags = (const sync_call_flags_t) {
483 .is_dlb_barrier = true,
484 .is_blocking = true,
485 .is_collective = true,
486 .do_lewi = true,
487 };
488 7 into_sync_call(mpi_flags);
489 }
490
491 // Barrier
492 15 pthread_barrier_wait(&barrier->barrier);
493
494 // Recover resources for those processes that simulated a blocking call
495
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8 times.
15 if (barrier->flags.lewi) {
496 7 sync_call_flags_t mpi_flags = (const sync_call_flags_t) {
497 .is_dlb_barrier = true,
498 .is_blocking = true,
499 .is_collective = true,
500 .do_lewi = true,
501 };
502 7 out_of_sync_call(mpi_flags);
503 }
504 }
505
506 47 unsigned int participants_left = DLB_ATOMIC_SUB_FETCH(&barrier->count, 1);
507 47 bool last_out = participants_left == 0;
508
509
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
47 verbose(VB_BARRIER, "Leaving barrier %s%s", barrier->name, last_out ? " (last)" : "");
510
511 /* WARNING: There may be a race condition with the 'count' value in
512 * consecutive barriers (A -> B), if one process increases the
513 * 'count' value after entering B, while another process still
514 * hasn't decreased it in B. Anyway, this is completely harmless
515 * since it only affects the verbose message.
516 */
517 }
518 47 pthread_rwlock_unlock(&barrier->rwlock);
519 }
520
521 8 void shmem_barrier__print_info(const char *shmem_key, int shmem_size_multiplier) {
522
523 /* If the shmem is not opened, obtain a temporary fd */
524 8 bool temporary_shmem = shm_handler == NULL;
525
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (temporary_shmem) {
526 1 shmem_barrier_ext__init(shmem_key, shmem_size_multiplier);
527 }
528
529 /* Make a full copy of the shared memory */
530 8 shdata_t *shdata_copy = malloc(shmem_barrier__size());
531 8 shmem_lock(shm_handler);
532 {
533 8 memcpy(shdata_copy, shdata, shmem_barrier__size());
534 }
535 8 shmem_unlock(shm_handler);
536
537 /* Close shmem if needed */
538
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (temporary_shmem) {
539 1 shmem_barrier_ext__finalize();
540 }
541
542 /* Initialize buffer */
543 print_buffer_t buffer;
544 8 printbuffer_init(&buffer);
545
546 /* Set up line buffer */
547 enum { MAX_LINE_LEN = 128 };
548 char line[MAX_LINE_LEN];
549
550 8 int num_barriers = shdata_copy->num_barriers;
551
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 for (int i = 0; i < num_barriers; ++i) {
552 8 barrier_t *barrier = &shdata_copy->barriers[i];
553
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (barrier->flags.initialized) {
554
555 /* Append line to buffer */
556 8 snprintf(line, MAX_LINE_LEN,
557 " | %14s | %12u | %12u | %12u |",
558 8 barrier->name, barrier->participants, barrier->count, barrier->ntimes);
559 8 printbuffer_append(&buffer, line);
560 }
561 }
562
563
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 if (buffer.addr[0] != '\0' ) {
564 7 info0("=== Barriers ===\n"
565 " | Barrier Name | Participants | Num. blocked | Times compl. |\n"
566 "%s", buffer.addr);
567 }
568 8 printbuffer_destroy(&buffer);
569 8 free(shdata_copy);
570 8 }
571
572 8 bool shmem_barrier__exists(void) {
573 8 return shm_handler != NULL;
574 }
575
576 1 int shmem_barrier__version(void) {
577 1 return SHMEM_BARRIER_VERSION;
578 }
579
580 134 size_t shmem_barrier__size(void) {
581 // max_barriers contains a value once shmem is initialized,
582 // otherwise return default size
583 134 return sizeof(shdata_t) + sizeof(barrier_t) * (
584
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 1 times.
134 max_barriers > 0 ? max_barriers : mu_get_system_size());
585 }
586