1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2014-2020 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights
* reserved.
* Copyright (c) 2017-2022 IBM Corporation. All rights reserved.
* Copyright (c) 2019 Sandia National Laboratories. All rights reserved.
* Copyright (c) 2021 Argonne National Laboratory. All rights reserved.
*
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal/mca/threads/wait_sync.h"
static opal_mutex_t wait_sync_lock = OPAL_MUTEX_STATIC_INIT;
ompi_wait_sync_t *opal_threads_base_wait_sync_list = NULL; /* not static for inline "wait_sync_st" */
void opal_threads_base_wait_sync_global_wakeup_st(int status)
{
ompi_wait_sync_t *sync;
for (sync = opal_threads_base_wait_sync_list; sync != NULL; sync = sync->next) {
wait_sync_update(sync, 0, status);
}
}
void opal_threads_base_wait_sync_global_wakeup_mt(int status)
{
ompi_wait_sync_t *sync;
opal_mutex_lock(&wait_sync_lock);
for (sync = opal_threads_base_wait_sync_list; sync != NULL; sync = sync->next) {
/* sync_update is going to take the sync->lock from within
* the wait_sync_lock. Thread lightly here: Idealy we should
* find a way to not take a lock in a lock as this is deadlock prone,
* but as of today we are the only place doing this so it is safe.
*/
wait_sync_update(sync, 0, status);
if (sync->next == opal_threads_base_wait_sync_list) {
break; /* special case for rings */
}
}
opal_mutex_unlock(&wait_sync_lock);
}
static opal_atomic_int32_t num_thread_in_progress = 0;
#define WAIT_SYNC_PASS_OWNERSHIP(who) \
do { \
opal_thread_internal_mutex_lock(&(who)->lock); \
opal_thread_internal_cond_signal(&(who)->condition); \
opal_thread_internal_mutex_unlock(&(who)->lock); \
} while (0)
int ompi_sync_wait_mt(ompi_wait_sync_t *sync)
{
/* Don't stop if the waiting synchronization is completed. We avoid the
* race condition around the release of the synchronization using the
* signaling field.
*/
if (sync->count <= 0) {
return (0 == sync->status) ? OPAL_SUCCESS : OPAL_ERROR;
}
/* lock so nobody can signal us during the list updating */
opal_thread_internal_mutex_lock(&sync->lock);
/* Now that we hold the lock make sure another thread has not already
* call cond_signal.
*/
if (sync->count <= 0) {
opal_thread_internal_mutex_unlock(&sync->lock);
return (0 == sync->status) ? OPAL_SUCCESS : OPAL_ERROR;
}
/* Insert sync on the list of pending synchronization constructs */
OPAL_THREAD_LOCK(&wait_sync_lock);
if (NULL == opal_threads_base_wait_sync_list) {
sync->next = sync->prev = sync;
opal_threads_base_wait_sync_list = sync;
} else {
sync->prev = opal_threads_base_wait_sync_list->prev;
sync->prev->next = sync;
sync->next = opal_threads_base_wait_sync_list;
opal_threads_base_wait_sync_list->prev = sync;
}
OPAL_THREAD_UNLOCK(&wait_sync_lock);
/**
* If we are not responsible for progressing, go silent until something
* worth noticing happen:
* - this thread has been promoted to take care of the progress
* - our sync has been triggered.
*/
check_status:
if (sync != opal_threads_base_wait_sync_list && num_thread_in_progress >= opal_max_thread_in_progress) {
opal_thread_internal_cond_wait(&sync->condition, &sync->lock);
/**
* At this point either the sync was completed in which case
* we should remove it from the wait list, or/and I was
* promoted as the progress manager.
*/
if (sync->count <= 0) { /* Completed? */
opal_thread_internal_mutex_unlock(&sync->lock);
goto i_am_done;
}
/* either promoted, or spurious wakeup ! */
goto check_status;
}
opal_thread_internal_mutex_unlock(&sync->lock);
OPAL_THREAD_ADD_FETCH32(&num_thread_in_progress, 1);
while (sync->count > 0) { /* progress till completion */
/* don't progress with the sync lock locked or you'll deadlock */
opal_progress();
}
OPAL_THREAD_ADD_FETCH32(&num_thread_in_progress, -1);
i_am_done:
/* My sync is now complete. Trim the list: remove self, wake next */
OPAL_THREAD_LOCK(&wait_sync_lock);
sync->prev->next = sync->next;
sync->next->prev = sync->prev;
/* In case I am the progress manager, pass the duties on */
if (sync == opal_threads_base_wait_sync_list) {
opal_threads_base_wait_sync_list = (sync == sync->next) ? NULL : sync->next;
if (NULL != opal_threads_base_wait_sync_list) {
WAIT_SYNC_PASS_OWNERSHIP(opal_threads_base_wait_sync_list);
}
}
OPAL_THREAD_UNLOCK(&wait_sync_lock);
return (0 == sync->status) ? OPAL_SUCCESS : OPAL_ERROR;
}
|