1169695Skan/* Copyright (C) 2005 Free Software Foundation, Inc. 2169695Skan Contributed by Richard Henderson <rth@redhat.com>. 3169695Skan 4169695Skan This file is part of the GNU OpenMP Library (libgomp). 5169695Skan 6169695Skan Libgomp is free software; you can redistribute it and/or modify it 7169695Skan under the terms of the GNU Lesser General Public License as published by 8169695Skan the Free Software Foundation; either version 2.1 of the License, or 9169695Skan (at your option) any later version. 10169695Skan 11169695Skan Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 12169695Skan WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13169695Skan FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 14169695Skan more details. 15169695Skan 16169695Skan You should have received a copy of the GNU Lesser General Public License 17169695Skan along with libgomp; see the file COPYING.LIB. If not, write to the 18169695Skan Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 19169695Skan MA 02110-1301, USA. */ 20169695Skan 21169695Skan/* As a special exception, if you link this library with other files, some 22169695Skan of which are compiled with GCC, to produce an executable, this library 23169695Skan does not by itself cause the resulting executable to be covered by the 24169695Skan GNU General Public License. This exception does not however invalidate 25169695Skan any other reasons why the executable file might be covered by the GNU 26169695Skan General Public License. */ 27169695Skan 28169695Skan/* This file handles the CRITICAL construct. */ 29169695Skan 30169695Skan#include "libgomp.h" 31169695Skan#include <stdlib.h> 32169695Skan 33169695Skan 34169695Skanstatic gomp_mutex_t default_lock; 35169695Skan 36169695Skanvoid 37169695SkanGOMP_critical_start (void) 38169695Skan{ 39169695Skan gomp_mutex_lock (&default_lock); 40169695Skan} 41169695Skan 42169695Skanvoid 43169695SkanGOMP_critical_end (void) 44169695Skan{ 45169695Skan gomp_mutex_unlock (&default_lock); 46169695Skan} 47169695Skan 48169695Skan#ifndef HAVE_SYNC_BUILTINS 49169695Skanstatic gomp_mutex_t create_lock_lock; 50169695Skan#endif 51169695Skan 52169695Skanvoid 53169695SkanGOMP_critical_name_start (void **pptr) 54169695Skan{ 55169695Skan gomp_mutex_t *plock; 56169695Skan 57169695Skan /* If a mutex fits within the space for a pointer, and is zero initialized, 58169695Skan then use the pointer space directly. */ 59169695Skan if (GOMP_MUTEX_INIT_0 60169695Skan && sizeof (gomp_mutex_t) <= sizeof (void *) 61169695Skan && __alignof (gomp_mutex_t) <= sizeof (void *)) 62169695Skan plock = (gomp_mutex_t *)pptr; 63169695Skan 64169695Skan /* Otherwise we have to be prepared to malloc storage. */ 65169695Skan else 66169695Skan { 67169695Skan plock = *pptr; 68169695Skan 69169695Skan if (plock == NULL) 70169695Skan { 71169695Skan#ifdef HAVE_SYNC_BUILTINS 72169695Skan gomp_mutex_t *nlock = gomp_malloc (sizeof (gomp_mutex_t)); 73169695Skan gomp_mutex_init (nlock); 74169695Skan 75169695Skan plock = __sync_val_compare_and_swap (pptr, NULL, nlock); 76169695Skan if (plock != NULL) 77169695Skan { 78169695Skan gomp_mutex_destroy (nlock); 79169695Skan free (nlock); 80169695Skan } 81169695Skan else 82169695Skan plock = nlock; 83169695Skan#else 84169695Skan gomp_mutex_lock (&create_lock_lock); 85169695Skan plock = *pptr; 86169695Skan if (plock == NULL) 87169695Skan { 88169695Skan plock = gomp_malloc (sizeof (gomp_mutex_t)); 89169695Skan gomp_mutex_init (plock); 90169695Skan __sync_synchronize (); 91169695Skan *pptr = plock; 92169695Skan } 93169695Skan gomp_mutex_unlock (&create_lock_lock); 94169695Skan#endif 95169695Skan } 96169695Skan } 97169695Skan 98169695Skan gomp_mutex_lock (plock); 99169695Skan} 100169695Skan 101169695Skanvoid 102169695SkanGOMP_critical_name_end (void **pptr) 103169695Skan{ 104169695Skan gomp_mutex_t *plock; 105169695Skan 106169695Skan /* If a mutex fits within the space for a pointer, and is zero initialized, 107169695Skan then use the pointer space directly. */ 108169695Skan if (GOMP_MUTEX_INIT_0 109169695Skan && sizeof (gomp_mutex_t) <= sizeof (void *) 110169695Skan && __alignof (gomp_mutex_t) <= sizeof (void *)) 111169695Skan plock = (gomp_mutex_t *)pptr; 112169695Skan else 113169695Skan plock = *pptr; 114169695Skan 115169695Skan gomp_mutex_unlock (plock); 116169695Skan} 117169695Skan 118169695Skan/* This mutex is used when atomic operations don't exist for the target 119169695Skan in the mode requested. The result is not globally atomic, but works so 120169695Skan long as all parallel references are within #pragma omp atomic directives. 121169695Skan According to responses received from omp@openmp.org, appears to be within 122169695Skan spec. Which makes sense, since that's how several other compilers 123169695Skan handle this situation as well. */ 124169695Skan 125169695Skanstatic gomp_mutex_t atomic_lock; 126169695Skan 127169695Skanvoid 128169695SkanGOMP_atomic_start (void) 129169695Skan{ 130169695Skan gomp_mutex_lock (&atomic_lock); 131169695Skan} 132169695Skan 133169695Skanvoid 134169695SkanGOMP_atomic_end (void) 135169695Skan{ 136169695Skan gomp_mutex_unlock (&atomic_lock); 137169695Skan} 138169695Skan 139169695Skan#if !GOMP_MUTEX_INIT_0 140169695Skanstatic void __attribute__((constructor)) 141169695Skaninitialize_critical (void) 142169695Skan{ 143169695Skan gomp_mutex_init (&default_lock); 144169695Skan gomp_mutex_init (&atomic_lock); 145169695Skan#ifndef HAVE_SYNC_BUILTINS 146169695Skan gomp_mutex_init (&create_lock_lock); 147169695Skan#endif 148169695Skan} 149169695Skan#endif 150