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 |