1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2014-2016 The University of Tennessee and The University
4 * of Tennessee Research Foundation. All rights
5 * reserved.
6 * Copyright (c) 2016 Los Alamos National Security, LLC. All rights
7 * reserved.
8 * Copyright (c) 2017 Intel, Inc. All rights reserved.
9 * $COPYRIGHT$
10 *
11 * Additional copyrights may follow
12 *
13 * $HEADER$
14 */
15 #include "wait_sync.h"
16
17 static pmix_mutex_t wait_sync_lock = PMIX_MUTEX_STATIC_INIT;
18 static pmix_wait_sync_t* wait_sync_list = NULL;
19
20 #define PMIX_WAIT_SYNC_PASS_OWNERSHIP(who) \
21 do { \
22 pthread_mutex_lock( &(who)->lock); \
23 pthread_cond_signal( &(who)->condition ); \
24 pthread_mutex_unlock( &(who)->lock); \
25 } while(0)
26
27 int pmix_sync_wait_mt(pmix_wait_sync_t *sync)
28 {
29 /* Don't stop if the waiting synchronization is completed. We avoid the
30 * race condition around the release of the synchronization using the
31 * signaling field.
32 */
33 if(sync->count <= 0)
34 return (0 == sync->status) ? PMIX_SUCCESS : PMIX_ERROR;
35
36 /* lock so nobody can signal us during the list updating */
37 pthread_mutex_lock(&sync->lock);
38
39 /* Now that we hold the lock make sure another thread has not already
40 * call cond_signal.
41 */
42 if(sync->count <= 0) {
43 pthread_mutex_unlock(&sync->lock);
44 return (0 == sync->status) ? PMIX_SUCCESS : PMIX_ERROR;
45 }
46
47 /* Insert sync on the list of pending synchronization constructs */
48 pmix_mutex_lock(&wait_sync_lock);
49 if( NULL == wait_sync_list ) {
50 sync->next = sync->prev = sync;
51 wait_sync_list = sync;
52 } else {
53 sync->prev = wait_sync_list->prev;
54 sync->prev->next = sync;
55 sync->next = wait_sync_list;
56 wait_sync_list->prev = sync;
57 }
58 pmix_mutex_unlock(&wait_sync_lock);
59
60 /**
61 * If we are not responsible for progresing, go silent until something worth noticing happen:
62 * - this thread has been promoted to take care of the progress
63 * - our sync has been triggered.
64 */
65 check_status:
66 if( sync != wait_sync_list ) {
67 pthread_cond_wait(&sync->condition, &sync->lock);
68
69 /**
70 * At this point either the sync was completed in which case
71 * we should remove it from the wait list, or/and I was
72 * promoted as the progress manager.
73 */
74
75 if( sync->count <= 0 ) { /* Completed? */
76 pthread_mutex_unlock(&sync->lock);
77 goto i_am_done;
78 }
79 /* either promoted, or spurious wakeup ! */
80 goto check_status;
81 }
82
83 pthread_mutex_unlock(&sync->lock);
84 while(sync->count > 0) { /* progress till completion */
85 }
86 assert(sync == wait_sync_list);
87
88 i_am_done:
89 /* My sync is now complete. Trim the list: remove self, wake next */
90 pmix_mutex_lock(&wait_sync_lock);
91 sync->prev->next = sync->next;
92 sync->next->prev = sync->prev;
93 /* In case I am the progress manager, pass the duties on */
94 if( sync == wait_sync_list ) {
95 wait_sync_list = (sync == sync->next) ? NULL : sync->next;
96 if( NULL != wait_sync_list )
97 PMIX_WAIT_SYNC_PASS_OWNERSHIP(wait_sync_list);
98 }
99 pmix_mutex_unlock(&wait_sync_lock);
100
101 return (0 == sync->status) ? PMIX_SUCCESS : PMIX_ERROR;
102 }