1 1.12 mrg /* Copyright (C) 2005-2022 Free Software Foundation, Inc. 2 1.1 mrg Contributed by Richard Henderson <rth (at) redhat.com>. 3 1.1 mrg 4 1.5 mrg This file is part of the GNU Offloading and Multi Processing Library 5 1.5 mrg (libgomp). 6 1.1 mrg 7 1.1 mrg Libgomp is free software; you can redistribute it and/or modify it 8 1.1 mrg under the terms of the GNU General Public License as published by 9 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 10 1.1 mrg any later version. 11 1.1 mrg 12 1.1 mrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 1.1 mrg more details. 16 1.1 mrg 17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional 18 1.1 mrg permissions described in the GCC Runtime Library Exception, version 19 1.1 mrg 3.1, as published by the Free Software Foundation. 20 1.1 mrg 21 1.1 mrg You should have received a copy of the GNU General Public License and 22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program; 23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 1.1 mrg <http://www.gnu.org/licenses/>. */ 25 1.1 mrg 26 1.1 mrg /* This is the default implementation of a barrier synchronization mechanism 27 1.1 mrg for libgomp. This type is private to the library. Note that we rely on 28 1.1 mrg being able to adjust the barrier count while threads are blocked, so the 29 1.1 mrg POSIX pthread_barrier_t won't work. */ 30 1.1 mrg 31 1.1 mrg #include "libgomp.h" 32 1.1 mrg 33 1.1 mrg 34 1.1 mrg void 35 1.1 mrg gomp_barrier_init (gomp_barrier_t *bar, unsigned count) 36 1.1 mrg { 37 1.1 mrg gomp_mutex_init (&bar->mutex1); 38 1.1 mrg #ifndef HAVE_SYNC_BUILTINS 39 1.1 mrg gomp_mutex_init (&bar->mutex2); 40 1.1 mrg #endif 41 1.1 mrg gomp_sem_init (&bar->sem1, 0); 42 1.1 mrg gomp_sem_init (&bar->sem2, 0); 43 1.1 mrg bar->total = count; 44 1.1 mrg bar->arrived = 0; 45 1.1 mrg bar->generation = 0; 46 1.5 mrg bar->cancellable = false; 47 1.1 mrg } 48 1.1 mrg 49 1.1 mrg void 50 1.1 mrg gomp_barrier_destroy (gomp_barrier_t *bar) 51 1.1 mrg { 52 1.1 mrg /* Before destroying, make sure all threads have left the barrier. */ 53 1.1 mrg gomp_mutex_lock (&bar->mutex1); 54 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 55 1.1 mrg 56 1.1 mrg gomp_mutex_destroy (&bar->mutex1); 57 1.1 mrg #ifndef HAVE_SYNC_BUILTINS 58 1.1 mrg gomp_mutex_destroy (&bar->mutex2); 59 1.1 mrg #endif 60 1.1 mrg gomp_sem_destroy (&bar->sem1); 61 1.1 mrg gomp_sem_destroy (&bar->sem2); 62 1.1 mrg } 63 1.1 mrg 64 1.1 mrg void 65 1.1 mrg gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count) 66 1.1 mrg { 67 1.1 mrg gomp_mutex_lock (&bar->mutex1); 68 1.1 mrg bar->total = count; 69 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 70 1.1 mrg } 71 1.1 mrg 72 1.1 mrg void 73 1.1 mrg gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state) 74 1.1 mrg { 75 1.1 mrg unsigned int n; 76 1.1 mrg 77 1.5 mrg if (state & BAR_WAS_LAST) 78 1.1 mrg { 79 1.1 mrg n = --bar->arrived; 80 1.1 mrg if (n > 0) 81 1.1 mrg { 82 1.1 mrg do 83 1.1 mrg gomp_sem_post (&bar->sem1); 84 1.1 mrg while (--n != 0); 85 1.1 mrg gomp_sem_wait (&bar->sem2); 86 1.1 mrg } 87 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 88 1.1 mrg } 89 1.1 mrg else 90 1.1 mrg { 91 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 92 1.1 mrg gomp_sem_wait (&bar->sem1); 93 1.1 mrg 94 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 95 1.1 mrg n = __sync_add_and_fetch (&bar->arrived, -1); 96 1.1 mrg #else 97 1.1 mrg gomp_mutex_lock (&bar->mutex2); 98 1.1 mrg n = --bar->arrived; 99 1.1 mrg gomp_mutex_unlock (&bar->mutex2); 100 1.1 mrg #endif 101 1.1 mrg 102 1.1 mrg if (n == 0) 103 1.1 mrg gomp_sem_post (&bar->sem2); 104 1.1 mrg } 105 1.1 mrg } 106 1.1 mrg 107 1.1 mrg void 108 1.1 mrg gomp_barrier_wait (gomp_barrier_t *barrier) 109 1.1 mrg { 110 1.1 mrg gomp_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier)); 111 1.1 mrg } 112 1.1 mrg 113 1.1 mrg void 114 1.1 mrg gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state) 115 1.1 mrg { 116 1.1 mrg unsigned int n; 117 1.1 mrg 118 1.5 mrg state &= ~BAR_CANCELLED; 119 1.5 mrg if (state & BAR_WAS_LAST) 120 1.1 mrg { 121 1.1 mrg n = --bar->arrived; 122 1.1 mrg struct gomp_thread *thr = gomp_thread (); 123 1.1 mrg struct gomp_team *team = thr->ts.team; 124 1.1 mrg 125 1.5 mrg team->work_share_cancelled = 0; 126 1.1 mrg if (team->task_count) 127 1.1 mrg { 128 1.1 mrg gomp_barrier_handle_tasks (state); 129 1.1 mrg if (n > 0) 130 1.1 mrg gomp_sem_wait (&bar->sem2); 131 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 132 1.1 mrg return; 133 1.1 mrg } 134 1.1 mrg 135 1.5 mrg bar->generation = state + BAR_INCR - BAR_WAS_LAST; 136 1.1 mrg if (n > 0) 137 1.1 mrg { 138 1.1 mrg do 139 1.1 mrg gomp_sem_post (&bar->sem1); 140 1.1 mrg while (--n != 0); 141 1.1 mrg gomp_sem_wait (&bar->sem2); 142 1.1 mrg } 143 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 144 1.1 mrg } 145 1.1 mrg else 146 1.1 mrg { 147 1.1 mrg gomp_mutex_unlock (&bar->mutex1); 148 1.5 mrg int gen; 149 1.1 mrg do 150 1.1 mrg { 151 1.1 mrg gomp_sem_wait (&bar->sem1); 152 1.5 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE); 153 1.5 mrg if (gen & BAR_TASK_PENDING) 154 1.5 mrg { 155 1.5 mrg gomp_barrier_handle_tasks (state); 156 1.5 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE); 157 1.5 mrg } 158 1.1 mrg } 159 1.5 mrg while (gen != state + BAR_INCR); 160 1.1 mrg 161 1.1 mrg #ifdef HAVE_SYNC_BUILTINS 162 1.1 mrg n = __sync_add_and_fetch (&bar->arrived, -1); 163 1.1 mrg #else 164 1.1 mrg gomp_mutex_lock (&bar->mutex2); 165 1.1 mrg n = --bar->arrived; 166 1.1 mrg gomp_mutex_unlock (&bar->mutex2); 167 1.1 mrg #endif 168 1.1 mrg 169 1.1 mrg if (n == 0) 170 1.1 mrg gomp_sem_post (&bar->sem2); 171 1.1 mrg } 172 1.1 mrg } 173 1.1 mrg 174 1.5 mrg bool 175 1.5 mrg gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar, 176 1.5 mrg gomp_barrier_state_t state) 177 1.5 mrg { 178 1.5 mrg unsigned int n; 179 1.5 mrg 180 1.5 mrg if (state & BAR_WAS_LAST) 181 1.5 mrg { 182 1.5 mrg bar->cancellable = false; 183 1.5 mrg n = --bar->arrived; 184 1.5 mrg struct gomp_thread *thr = gomp_thread (); 185 1.5 mrg struct gomp_team *team = thr->ts.team; 186 1.5 mrg 187 1.5 mrg team->work_share_cancelled = 0; 188 1.5 mrg if (team->task_count) 189 1.5 mrg { 190 1.5 mrg gomp_barrier_handle_tasks (state); 191 1.5 mrg if (n > 0) 192 1.5 mrg gomp_sem_wait (&bar->sem2); 193 1.5 mrg gomp_mutex_unlock (&bar->mutex1); 194 1.5 mrg return false; 195 1.5 mrg } 196 1.5 mrg 197 1.5 mrg bar->generation = state + BAR_INCR - BAR_WAS_LAST; 198 1.5 mrg if (n > 0) 199 1.5 mrg { 200 1.5 mrg do 201 1.5 mrg gomp_sem_post (&bar->sem1); 202 1.5 mrg while (--n != 0); 203 1.5 mrg gomp_sem_wait (&bar->sem2); 204 1.5 mrg } 205 1.5 mrg gomp_mutex_unlock (&bar->mutex1); 206 1.5 mrg } 207 1.5 mrg else 208 1.5 mrg { 209 1.5 mrg if (state & BAR_CANCELLED) 210 1.5 mrg { 211 1.5 mrg gomp_mutex_unlock (&bar->mutex1); 212 1.5 mrg return true; 213 1.5 mrg } 214 1.5 mrg bar->cancellable = true; 215 1.5 mrg gomp_mutex_unlock (&bar->mutex1); 216 1.5 mrg int gen; 217 1.5 mrg do 218 1.5 mrg { 219 1.5 mrg gomp_sem_wait (&bar->sem1); 220 1.5 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE); 221 1.5 mrg if (gen & BAR_CANCELLED) 222 1.5 mrg break; 223 1.5 mrg if (gen & BAR_TASK_PENDING) 224 1.5 mrg { 225 1.5 mrg gomp_barrier_handle_tasks (state); 226 1.5 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE); 227 1.5 mrg if (gen & BAR_CANCELLED) 228 1.5 mrg break; 229 1.5 mrg } 230 1.5 mrg } 231 1.5 mrg while (gen != state + BAR_INCR); 232 1.5 mrg 233 1.5 mrg #ifdef HAVE_SYNC_BUILTINS 234 1.5 mrg n = __sync_add_and_fetch (&bar->arrived, -1); 235 1.5 mrg #else 236 1.5 mrg gomp_mutex_lock (&bar->mutex2); 237 1.5 mrg n = --bar->arrived; 238 1.5 mrg gomp_mutex_unlock (&bar->mutex2); 239 1.5 mrg #endif 240 1.5 mrg 241 1.5 mrg if (n == 0) 242 1.5 mrg gomp_sem_post (&bar->sem2); 243 1.5 mrg if (gen & BAR_CANCELLED) 244 1.5 mrg return true; 245 1.5 mrg } 246 1.5 mrg return false; 247 1.5 mrg } 248 1.5 mrg 249 1.1 mrg void 250 1.1 mrg gomp_team_barrier_wait (gomp_barrier_t *barrier) 251 1.1 mrg { 252 1.1 mrg gomp_team_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier)); 253 1.1 mrg } 254 1.1 mrg 255 1.1 mrg void 256 1.1 mrg gomp_team_barrier_wake (gomp_barrier_t *bar, int count) 257 1.1 mrg { 258 1.1 mrg if (count == 0) 259 1.1 mrg count = bar->total - 1; 260 1.1 mrg while (count-- > 0) 261 1.1 mrg gomp_sem_post (&bar->sem1); 262 1.1 mrg } 263 1.5 mrg 264 1.5 mrg bool 265 1.5 mrg gomp_team_barrier_wait_cancel (gomp_barrier_t *bar) 266 1.5 mrg { 267 1.5 mrg gomp_barrier_state_t state = gomp_barrier_wait_cancel_start (bar); 268 1.5 mrg return gomp_team_barrier_wait_cancel_end (bar, state); 269 1.5 mrg } 270 1.5 mrg 271 1.5 mrg void 272 1.5 mrg gomp_team_barrier_cancel (struct gomp_team *team) 273 1.5 mrg { 274 1.5 mrg if (team->barrier.generation & BAR_CANCELLED) 275 1.5 mrg return; 276 1.5 mrg gomp_mutex_lock (&team->barrier.mutex1); 277 1.5 mrg gomp_mutex_lock (&team->task_lock); 278 1.5 mrg if (team->barrier.generation & BAR_CANCELLED) 279 1.5 mrg { 280 1.5 mrg gomp_mutex_unlock (&team->task_lock); 281 1.5 mrg gomp_mutex_unlock (&team->barrier.mutex1); 282 1.5 mrg return; 283 1.5 mrg } 284 1.5 mrg team->barrier.generation |= BAR_CANCELLED; 285 1.5 mrg gomp_mutex_unlock (&team->task_lock); 286 1.5 mrg if (team->barrier.cancellable) 287 1.5 mrg { 288 1.5 mrg int n = team->barrier.arrived; 289 1.5 mrg if (n > 0) 290 1.5 mrg { 291 1.5 mrg do 292 1.5 mrg gomp_sem_post (&team->barrier.sem1); 293 1.5 mrg while (--n != 0); 294 1.5 mrg gomp_sem_wait (&team->barrier.sem2); 295 1.5 mrg } 296 1.5 mrg team->barrier.cancellable = false; 297 1.5 mrg } 298 1.5 mrg gomp_mutex_unlock (&team->barrier.mutex1); 299 1.5 mrg } 300