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 IBM Corporation. All rights reserved.
9 * $COPYRIGHT$
10 *
11 * Additional copyrights may follow
12 *
13 * $HEADER$
14 */
15 #include "wait_sync.h"
16
17 static opal_mutex_t wait_sync_lock = OPAL_MUTEX_STATIC_INIT;
18 static ompi_wait_sync_t* wait_sync_list = NULL;
19
20 static opal_atomic_int32_t num_thread_in_progress = 0;
21
22 #define WAIT_SYNC_PASS_OWNERSHIP(who) \
23 do { \
24 pthread_mutex_lock( &(who)->lock); \
25 pthread_cond_signal( &(who)->condition ); \
26 pthread_mutex_unlock( &(who)->lock); \
27 } while(0)
28
29 int ompi_sync_wait_mt(ompi_wait_sync_t *sync)
30 {
31 /* Don't stop if the waiting synchronization is completed. We avoid the
32 * race condition around the release of the synchronization using the
33 * signaling field.
34 */
35 if(sync->count <= 0)
36 return (0 == sync->status) ? OPAL_SUCCESS : OPAL_ERROR;
37
38 /* lock so nobody can signal us during the list updating */
39 pthread_mutex_lock(&sync->lock);
40
41 /* Now that we hold the lock make sure another thread has not already
42 * call cond_signal.
43 */
44 if(sync->count <= 0) {
45 pthread_mutex_unlock(&sync->lock);
46 return (0 == sync->status) ? OPAL_SUCCESS : OPAL_ERROR;
47 }
48
49 /* Insert sync on the list of pending synchronization constructs */
50 OPAL_THREAD_LOCK(&wait_sync_lock);
51 if( NULL == wait_sync_list ) {
52 sync->next = sync->prev = sync;
53 wait_sync_list = sync;
54 } else {
55 sync->prev = wait_sync_list->prev;
56 sync->prev->next = sync;
57 sync->next = wait_sync_list;
58 wait_sync_list->prev = sync;
59 }
60 OPAL_THREAD_UNLOCK(&wait_sync_lock);
61
62 /**
63 * If we are not responsible for progresing, go silent until something worth noticing happen:
64 * - this thread has been promoted to take care of the progress
65 * - our sync has been triggered.
66 */
67 check_status:
68 if( sync != wait_sync_list && num_thread_in_progress >= opal_max_thread_in_progress) {
69 pthread_cond_wait(&sync->condition, &sync->lock);
70
71 /**
72 * At this point either the sync was completed in which case
73 * we should remove it from the wait list, or/and I was
74 * promoted as the progress manager.
75 */
76
77 if( sync->count <= 0 ) { /* Completed? */
78 pthread_mutex_unlock(&sync->lock);
79 goto i_am_done;
80 }
81 /* either promoted, or spurious wakeup ! */
82 goto check_status;
83 }
84 pthread_mutex_unlock(&sync->lock);
85
86 OPAL_THREAD_ADD_FETCH32(&num_thread_in_progress, 1);
87 while(sync->count > 0) { /* progress till completion */
88 opal_progress(); /* don't progress with the sync lock locked or you'll deadlock */
89 }
90 OPAL_THREAD_ADD_FETCH32(&num_thread_in_progress, -1);
91
92 i_am_done:
93 /* My sync is now complete. Trim the list: remove self, wake next */
94 OPAL_THREAD_LOCK(&wait_sync_lock);
95 sync->prev->next = sync->next;
96 sync->next->prev = sync->prev;
97 /* In case I am the progress manager, pass the duties on */
98 if( sync == wait_sync_list ) {
99 wait_sync_list = (sync == sync->next) ? NULL : sync->next;
100 if( NULL != wait_sync_list )
101 WAIT_SYNC_PASS_OWNERSHIP(wait_sync_list);
102 }
103 OPAL_THREAD_UNLOCK(&wait_sync_lock);
104
105 return (0 == sync->status) ? OPAL_SUCCESS : OPAL_ERROR;
106 }