bar.c revision 1.3
1168515Sgshapiro/* Copyright (C) 2005-2013 Free Software Foundation, Inc. 2168515Sgshapiro Contributed by Richard Henderson <rth@redhat.com>. 3168515Sgshapiro 4168515Sgshapiro This file is part of the GNU OpenMP Library (libgomp). 5168515Sgshapiro 6168515Sgshapiro Libgomp is free software; you can redistribute it and/or modify it 7168515Sgshapiro under the terms of the GNU General Public License as published by 8168515Sgshapiro the Free Software Foundation; either version 3, or (at your option) 9168515Sgshapiro any later version. 10168515Sgshapiro 11168515Sgshapiro Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 12168515Sgshapiro WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13168515Sgshapiro FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14168515Sgshapiro more details. 15168515Sgshapiro 16168515Sgshapiro Under Section 7 of GPL version 3, you are granted additional 17168515Sgshapiro permissions described in the GCC Runtime Library Exception, version 18168515Sgshapiro 3.1, as published by the Free Software Foundation. 19168515Sgshapiro 20168515Sgshapiro You should have received a copy of the GNU General Public License and 21168515Sgshapiro a copy of the GCC Runtime Library Exception along with this program; 22168515Sgshapiro see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23168515Sgshapiro <http://www.gnu.org/licenses/>. */ 24168515Sgshapiro 25168515Sgshapiro/* This is a Linux specific implementation of a barrier synchronization 26168515Sgshapiro mechanism for libgomp. This type is private to the library. This 27168515Sgshapiro implementation uses atomic instructions and the futex syscall. */ 28168515Sgshapiro 29168515Sgshapiro#include <limits.h> 30168515Sgshapiro#include "wait.h" 31168515Sgshapiro 32168515Sgshapiro 33168515Sgshapirovoid 34168515Sgshapirogomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state) 35168515Sgshapiro{ 36168515Sgshapiro if (__builtin_expect ((state & 1) != 0, 0)) 37168515Sgshapiro { 38168515Sgshapiro /* Next time we'll be awaiting TOTAL threads again. */ 39266692Sgshapiro bar->awaited = bar->total; 40173340Sgshapiro __atomic_store_n (&bar->generation, bar->generation + 4, 41168515Sgshapiro MEMMODEL_RELEASE); 42168515Sgshapiro futex_wake ((int *) &bar->generation, INT_MAX); 43173340Sgshapiro } 44173340Sgshapiro else 45168515Sgshapiro { 46168515Sgshapiro do 47168515Sgshapiro do_wait ((int *) &bar->generation, state); 48168515Sgshapiro while (__atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE) == state); 49168515Sgshapiro } 50168515Sgshapiro} 51168515Sgshapiro 52168515Sgshapirovoid 53168515Sgshapirogomp_barrier_wait (gomp_barrier_t *bar) 54168515Sgshapiro{ 55168515Sgshapiro gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar)); 56168515Sgshapiro} 57168515Sgshapiro 58168515Sgshapiro/* Like gomp_barrier_wait, except that if the encountering thread 59168515Sgshapiro is not the last one to hit the barrier, it returns immediately. 60168515Sgshapiro The intended usage is that a thread which intends to gomp_barrier_destroy 61168515Sgshapiro this barrier calls gomp_barrier_wait, while all other threads 62168515Sgshapiro call gomp_barrier_wait_last. When gomp_barrier_wait returns, 63168515Sgshapiro the barrier can be safely destroyed. */ 64168515Sgshapiro 65168515Sgshapirovoid 66168515Sgshapirogomp_barrier_wait_last (gomp_barrier_t *bar) 67168515Sgshapiro{ 68168515Sgshapiro gomp_barrier_state_t state = gomp_barrier_wait_start (bar); 69168515Sgshapiro if (state & 1) 70168515Sgshapiro gomp_barrier_wait_end (bar, state); 71168515Sgshapiro} 72244833Sgshapiro 73244833Sgshapirovoid 74168515Sgshapirogomp_team_barrier_wake (gomp_barrier_t *bar, int count) 75168515Sgshapiro{ 76168515Sgshapiro futex_wake ((int *) &bar->generation, count == 0 ? INT_MAX : count); 77168515Sgshapiro} 78168515Sgshapiro 79168515Sgshapirovoid 80168515Sgshapirogomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state) 81168515Sgshapiro{ 82168515Sgshapiro unsigned int generation, gen; 83168515Sgshapiro 84168515Sgshapiro if (__builtin_expect ((state & 1) != 0, 0)) 85168515Sgshapiro { 86168515Sgshapiro /* Next time we'll be awaiting TOTAL threads again. */ 87168515Sgshapiro struct gomp_thread *thr = gomp_thread (); 88168515Sgshapiro struct gomp_team *team = thr->ts.team; 89168515Sgshapiro 90168515Sgshapiro bar->awaited = bar->total; 91168515Sgshapiro if (__builtin_expect (team->task_count, 0)) 92168515Sgshapiro { 93168515Sgshapiro gomp_barrier_handle_tasks (state); 94168515Sgshapiro state &= ~1; 95168515Sgshapiro } 96168515Sgshapiro else 97168515Sgshapiro { 98168515Sgshapiro __atomic_store_n (&bar->generation, state + 3, MEMMODEL_RELEASE); 99168515Sgshapiro futex_wake ((int *) &bar->generation, INT_MAX); 100168515Sgshapiro return; 101168515Sgshapiro } 102168515Sgshapiro } 103168515Sgshapiro 104168515Sgshapiro generation = state; 105168515Sgshapiro do 106168515Sgshapiro { 107168515Sgshapiro do_wait ((int *) &bar->generation, generation); 108168515Sgshapiro gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE); 109168515Sgshapiro if (__builtin_expect (gen & 1, 0)) 110168515Sgshapiro { 111168515Sgshapiro gomp_barrier_handle_tasks (state); 112168515Sgshapiro gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE); 113168515Sgshapiro } 114168515Sgshapiro if ((gen & 2) != 0) 115168515Sgshapiro generation |= 2; 116168515Sgshapiro } 117168515Sgshapiro while (gen != state + 4); 118168515Sgshapiro} 119168515Sgshapiro 120168515Sgshapirovoid 121168515Sgshapirogomp_team_barrier_wait (gomp_barrier_t *bar) 122168515Sgshapiro{ 123168515Sgshapiro gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar)); 124168515Sgshapiro} 125168515Sgshapiro