GCC Code Coverage Report


Directory: src/
File: src/LB_comm/shmem_barrier.c
Date: 2024-11-22 17:07:10
Exec Total Coverage
Lines: 197 213 92.5%
Functions: 15 16 93.8%
Branches: 87 122 71.3%

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