GCC Code Coverage Report


Directory: src/
File: src/LB_comm/shmem_barrier.c
Date: 2026-09-15 07:37:49
Exec Total Coverage
Lines: 227 252 90.1%
Functions: 17 18 94.4%
Branches: 106 150 70.7%

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 132 static void open_shmem(const char *shmem_key, int shmem_size_multiplier) {
93
94 132 max_barriers = mu_get_system_size() * shmem_size_multiplier;
95 264 shm_handler = shmem_init((void**)&shdata,
96 132 &(const shmem_props_t) {
97 132 .size = shmem_barrier__size(),
98 .name = shmem_name,
99 .key = shmem_key,
100 .version = SHMEM_BARRIER_VERSION,
101 .cleanup_fn = cleanup_shmem,
102 });
103 132 }
104
105 161 int shmem_barrier__init(const char *shmem_key, int shmem_size_multiplier) {
106
107
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 131 times.
161 if (shm_handler != NULL) return DLB_ERR_NOMEM;
108
109 131 open_shmem(shmem_key, shmem_size_multiplier);
110
111 131 int error = DLB_SUCCESS;
112 131 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 89 times.
✓ Branch 1 taken 42 times.
131 if (!shdata->initialized) {
116 89 shdata->initialized = true;
117 89 shdata->num_barriers = 0;
118 89 shdata->max_barriers = max_barriers;
119 } else {
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (shdata->max_barriers != max_barriers) {
121 error = DLB_ERR_INIT;
122 }
123 }
124 }
125 131 shmem_unlock(shm_handler);
126
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131 times.
131 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 131 times.
✗ Branch 1 not taken.
131 if (error == DLB_SUCCESS) {
135
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 123 times.
131 verbose(VB_BARRIER, "Barrier Module initialized.");
136 }
137
138 131 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 161 void shmem_barrier__finalize(const char *shmem_key, int shmem_size_multiplier) {
149
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 130 times.
161 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
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 122 times.
130 verbose(VB_BARRIER, "Finalizing Barrier Module");
160
161 130 shmem_finalize(shm_handler, NULL /* do not check if empty */);
162 130 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 138 int shmem_barrier__get_max_barriers(void) {
180 138 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 169 barrier_t* shmem_barrier__register(const char *barrier_name, bool lewi) {
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
169 if (shm_handler == NULL) return NULL;
228
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 168 times.
169 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 168 int participants = -1;
236 168 barrier_t *barrier = NULL;
237 168 shmem_lock(shm_handler);
238 {
239 /* Find a new spot, or an already registered barrier */
240 168 barrier_t *empty_spot = NULL;
241 168 int num_barriers = shdata->num_barriers;
242
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 109 times.
209 for (int i = 0; i < num_barriers; ++i) {
243
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 if (empty_spot == NULL
244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 && shdata->barriers[i].participants == 0
245 && !shdata->barriers[i].flags.initialized) {
246 empty_spot = &shdata->barriers[i];
247 }
248
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 else if (shdata->barriers[i].participants > 0
249
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 && shdata->barriers[i].flags.initialized
250
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 41 times.
100 && strncmp(shdata->barriers[i].name, barrier_name,
251 BARRIER_NAME_MAX-1) == 0) {
252 59 barrier = &shdata->barriers[i];
253 59 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 109 times.
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 109 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 107 times.
✓ Branch 5 taken 2 times.
168 if (barrier == NULL && empty_spot == NULL && num_barriers < max_barriers) {
259 107 empty_spot = &shdata->barriers[num_barriers];
260 107 ++shdata->num_barriers;
261 }
262
263 /* New barrier, lock first and initialize required fields */
264
4/4
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 2 times.
275 if (barrier == NULL && empty_spot != NULL) {
265 107 barrier = empty_spot;
266 107 *barrier = (const barrier_t){};
267
268 pthread_rwlockattr_t rwlockattr;
269 107 pthread_rwlockattr_init(&rwlockattr);
270 107 pthread_rwlockattr_setpshared(&rwlockattr, PTHREAD_PROCESS_SHARED);
271 107 pthread_rwlock_init(&barrier->rwlock, &rwlockattr);
272 107 pthread_rwlockattr_destroy(&rwlockattr);
273
274 /* Initialize only once the lock is acquired */
275 107 pthread_rwlock_wrlock(&barrier->rwlock);
276 {
277 107 barrier->flags = (const barrier_flags_t) {
278 .initialized = true,
279 .lewi = lewi,
280 };
281 107 barrier->participants = 1;
282 107 participants = 1;
283 107 snprintf(barrier->name, BARRIER_NAME_MAX, "%s", barrier_name);
284 pthread_barrierattr_t barrierattr;
285 107 pthread_barrierattr_init(&barrierattr);
286 107 pthread_barrierattr_setpshared(&barrierattr, PTHREAD_PROCESS_SHARED);
287 107 pthread_barrier_init(&barrier->barrier, &barrierattr, barrier->participants);
288 107 pthread_barrierattr_destroy(&barrierattr);
289 }
290 107 pthread_rwlock_unlock(&barrier->rwlock);
291
292
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 2 times.
61 } 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 59 get_time_real(&timeout);
297 59 timeout.tv_sec += SHMEM_TIMEOUT_SECONDS;
298 59 int timedwrlock_error = pthread_rwlock_timedwrlock(&barrier->rwlock, &timeout);
299
1/2
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
59 if (likely(timedwrlock_error == 0)) {
300 /* Update participants */
301 59 participants = ++barrier->participants;
302
303 /* Create new barrier with the number of participants updated */
304 59 pthread_barrier_destroy(&barrier->barrier);
305 pthread_barrierattr_t attr;
306 59 pthread_barrierattr_init(&attr);
307 59 pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
308 59 pthread_barrier_init(&barrier->barrier, &attr, barrier->participants);
309 59 pthread_barrierattr_destroy(&attr);
310
311 59 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 168 shmem_unlock(shm_handler);
325
326
2/2
✓ Branch 0 taken 166 times.
✓ Branch 1 taken 2 times.
168 if (barrier != NULL) {
327 /* Attach if needed and print number of participants */
328
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 150 times.
166 verbose(VB_BARRIER, "Attached to barrier %s. Participants: %d",
329 barrier->name, participants);
330 }
331
332 168 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 1586 int shmem_barrier__detach(barrier_t *barrier) {
381
2/2
✓ Branch 0 taken 1414 times.
✓ Branch 1 taken 172 times.
1586 if (barrier == NULL) return DLB_ERR_UNKNOWN;
382
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 133 times.
172 if (shm_handler == NULL) return DLB_ERR_NOSHMEM;
383
384 #ifdef DEBUG_VERSION
385 133 int count = -1;
386 #endif
387 133 int participants = -1;
388
389 133 shmem_lock(shm_handler);
390 {
391 struct timespec timeout;
392 133 get_time_real(&timeout);
393 133 timeout.tv_sec += SHMEM_TIMEOUT_SECONDS;
394 133 int timedwrlock_error = pthread_rwlock_timedwrlock(&barrier->rwlock, &timeout);
395
1/2
✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
133 if (likely(timedwrlock_error == 0)) {
396
397
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 1 times.
133 if (!barrier->flags.initialized
398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 || 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 132 count = barrier->count;
406 #endif
407 /* Both locks are acquired and barrier is valid, detach: */
408
409 /* Update participants */
410 132 participants = --barrier->participants;
411
412
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 75 times.
132 if (participants > 0) {
413 /* Create new barrier with the number of participants updated */
414 57 pthread_barrier_destroy(&barrier->barrier);
415 pthread_barrierattr_t attr;
416 57 pthread_barrierattr_init(&attr);
417 57 pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
418 57 pthread_barrier_init(&barrier->barrier, &attr, barrier->participants);
419 57 pthread_barrierattr_destroy(&attr);
420
421 57 pthread_rwlock_unlock(&barrier->rwlock);
422 } else {
423 /* If this is the last participant, uninitialize barrier */
424 75 pthread_rwlock_unlock(&barrier->rwlock);
425 75 pthread_barrier_destroy(&barrier->barrier);
426 75 pthread_rwlock_destroy(&barrier->rwlock);
427 75 *barrier = (const barrier_t){};
428
429 /* Try to compact barrier list */
430
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 62 times.
150 for (int i = shdata->num_barriers - 1; i >= 0; --i) {
431
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 13 times.
88 if (!shdata->barriers[i].flags.initialized) {
432 75 --shdata->num_barriers;
433 } else {
434 13 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 132 shmem_unlock(shm_handler);
449
450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 ensure(count == 0, "Barrier Shared memory inconsistency while attaching "
451 "barrier (count = %d).\n" "Please, report at " PACKAGE_BUGREPORT,
452 count);
453
454 132 return participants;
455 }
456
457 77 void shmem_barrier__barrier(barrier_t *barrier) {
458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 if (unlikely(shm_handler == NULL)) return;
459
460 77 pthread_rwlock_rdlock(&barrier->rwlock);
461 {
462
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 76 times.
77 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 76 unsigned int participant_number = DLB_ATOMIC_ADD_FETCH(&barrier->count, 1);
469 76 bool last_in = participant_number == barrier->participants;
470
471
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
76 verbose(VB_BARRIER, "Entering barrier %s%s", barrier->name, last_in ? " (last)" : "");
472
473
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 29 times.
76 if (last_in) {
474 // Barrier
475 47 pthread_barrier_wait(&barrier->barrier);
476
477 // Increase ntimes counter
478 47 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 29 sync_call_flags_t flags = (const sync_call_flags_t) {
482 .is_dlb_barrier = true,
483 .is_blocking = true,
484 .is_collective = true,
485 29 .do_lewi = barrier->flags.lewi,
486 };
487 29 into_sync_call(flags);
488
489 // Barrier
490 29 pthread_barrier_wait(&barrier->barrier);
491
492 // End blocking call
493 29 out_of_sync_call(flags);
494 }
495
496 76 unsigned int participants_left = DLB_ATOMIC_SUB_FETCH(&barrier->count, 1);
497 76 bool last_out = participants_left == 0;
498
499
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
76 verbose(VB_BARRIER, "Leaving barrier %s%s", barrier->name, last_out ? " (last)" : "");
500
501 /* WARNING: There may be a race condition with the 'count' value in
502 * consecutive barriers (A -> B), if one process increases the
503 * 'count' value after entering B, while another process still
504 * hasn't decreased it in B. Anyway, this is completely harmless
505 * since it only affects the verbose message.
506 */
507 }
508 76 pthread_rwlock_unlock(&barrier->rwlock);
509 }
510
511 8 void shmem_barrier__print_info(const char *shmem_key, int shmem_size_multiplier) {
512
513 /* If the shmem is not opened, obtain a temporary fd */
514 8 bool temporary_shmem = shm_handler == NULL;
515
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (temporary_shmem) {
516 1 shmem_barrier_ext__init(shmem_key, shmem_size_multiplier);
517 }
518
519 /* Make a full copy of the shared memory */
520 8 shdata_t *shdata_copy = malloc(shmem_barrier__size());
521 8 shmem_lock(shm_handler);
522 {
523 8 memcpy(shdata_copy, shdata, shmem_barrier__size());
524 }
525 8 shmem_unlock(shm_handler);
526
527 /* Close shmem if needed */
528
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (temporary_shmem) {
529 1 shmem_barrier_ext__finalize();
530 }
531
532 /* Initialize buffer */
533 print_buffer_t buffer;
534 8 printbuffer_init(&buffer);
535
536 /* Set up line buffer */
537 enum { MAX_LINE_LEN = 128 };
538 char line[MAX_LINE_LEN];
539
540 8 int num_barriers = shdata_copy->num_barriers;
541
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 for (int i = 0; i < num_barriers; ++i) {
542 8 barrier_t *barrier = &shdata_copy->barriers[i];
543
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (barrier->flags.initialized) {
544
545 /* Append line to buffer */
546 8 snprintf(line, MAX_LINE_LEN,
547 " | %14s | %12u | %12u | %12u |",
548 8 barrier->name, barrier->participants, barrier->count, barrier->ntimes);
549 8 printbuffer_append(&buffer, line);
550 }
551 }
552
553
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 if (buffer.addr[0] != '\0' ) {
554 7 info0("=== Barriers ===\n"
555 " | Barrier Name | Participants | Num. blocked | Times compl. |\n"
556 "%s", buffer.addr);
557 }
558 8 printbuffer_destroy(&buffer);
559 8 free(shdata_copy);
560 8 }
561
562 8 bool shmem_barrier__exists(void) {
563 8 return shm_handler != NULL;
564 }
565
566 1 int shmem_barrier__version(void) {
567 1 return SHMEM_BARRIER_VERSION;
568 }
569
570 150 size_t shmem_barrier__size(void) {
571 // max_barriers contains a value once shmem is initialized,
572 // otherwise return default size
573 150 return sizeof(shdata_t) + sizeof(barrier_t) * (
574
2/2
✓ Branch 0 taken 149 times.
✓ Branch 1 taken 1 times.
150 max_barriers > 0 ? max_barriers : mu_get_system_size());
575 }
576
577 void shmem_barrier__reset_after_fork(void) {
578 if (shm_handler != NULL) {
579 shmem_detach_after_fork(shm_handler);
580 shdata = NULL;
581 shm_handler = NULL;
582 }
583 }
584