config/linux/lock.c

Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2008, 2009 Free Software Foundation, Inc.
00002    Contributed by Richard Henderson <rth@redhat.com>.
00003 
00004    This file is part of the GNU OpenMP Library (libgomp).
00005 
00006    Libgomp is free software; you can redistribute it and/or modify it
00007    under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 3, or (at your option)
00009    any later version.
00010 
00011    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
00012    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00014    more details.
00015 
00016    Under Section 7 of GPL version 3, you are granted additional
00017    permissions described in the GCC Runtime Library Exception, version
00018    3.1, as published by the Free Software Foundation.
00019 
00020    You should have received a copy of the GNU General Public License and
00021    a copy of the GCC Runtime Library Exception along with this program;
00022    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023    <http://www.gnu.org/licenses/>.  */
00024 
00025 /* This is a Linux specific implementation of the public OpenMP locking
00026    primitives.  This implementation uses atomic instructions and the futex
00027    syscall.  */
00028 
00029 #include <string.h>
00030 #include <unistd.h>
00031 #include <sys/syscall.h>
00032 #include "wait.h"
00033 
00034 
00035 /* The internal gomp_mutex_t and the external non-recursive omp_lock_t
00036    have the same form.  Re-use it.  */
00037 
00038 void
00039 gomp_init_lock_30 (omp_lock_t *lock)
00040 {
00041   gomp_mutex_init (lock);
00042 }
00043 
00044 void
00045 gomp_destroy_lock_30 (omp_lock_t *lock)
00046 {
00047   gomp_mutex_destroy (lock);
00048 }
00049 
00050 void
00051 gomp_set_lock_30 (omp_lock_t *lock)
00052 {
00053   gomp_mutex_lock (lock);
00054 }
00055 
00056 void
00057 gomp_unset_lock_30 (omp_lock_t *lock)
00058 {
00059   gomp_mutex_unlock (lock);
00060 }
00061 
00062 int
00063 gomp_test_lock_30 (omp_lock_t *lock)
00064 {
00065   return __sync_bool_compare_and_swap (lock, 0, 1);
00066 }
00067 
00068 void
00069 gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
00070 {
00071   memset (lock, '\0', sizeof (*lock));
00072 }
00073 
00074 void
00075 gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
00076 {
00077 }
00078 
00079 void
00080 gomp_set_nest_lock_30 (omp_nest_lock_t *lock)
00081 {
00082   void *me = gomp_icv (true);
00083 
00084   if (lock->owner != me)
00085     {
00086       gomp_mutex_lock (&lock->lock);
00087       lock->owner = me;
00088     }
00089 
00090   lock->count++;
00091 }
00092 
00093 void
00094 gomp_unset_nest_lock_30 (omp_nest_lock_t *lock)
00095 {
00096   if (--lock->count == 0)
00097     {
00098       lock->owner = NULL;
00099       gomp_mutex_unlock (&lock->lock);
00100     }
00101 }
00102 
00103 int
00104 gomp_test_nest_lock_30 (omp_nest_lock_t *lock)
00105 {
00106   void *me = gomp_icv (true);
00107 
00108   if (lock->owner == me)
00109     return ++lock->count;
00110 
00111   if (__sync_bool_compare_and_swap (&lock->lock, 0, 1))
00112     {
00113       lock->owner = me;
00114       lock->count = 1;
00115       return 1;
00116     }
00117 
00118   return 0;
00119 }
00120 
00121 #ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
00122 /* gomp_mutex_* can be safely locked in one thread and
00123    unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0
00124    non-nested locks can be the same.  */
00125 strong_alias (gomp_init_lock_30, gomp_init_lock_25)
00126 strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25)
00127 strong_alias (gomp_set_lock_30, gomp_set_lock_25)
00128 strong_alias (gomp_unset_lock_30, gomp_unset_lock_25)
00129 strong_alias (gomp_test_lock_30, gomp_test_lock_25)
00130 
00131 /* The external recursive omp_nest_lock_25_t form requires additional work.  */
00132 
00133 /* We need an integer to uniquely identify this thread.  Most generally
00134    this is the thread's TID, which ideally we'd get this straight from
00135    the TLS block where glibc keeps it.  Unfortunately, we can't get at
00136    that directly.
00137 
00138    If we don't support (or have disabled) TLS, one function call is as
00139    good (or bad) as any other.  Use the syscall all the time.
00140 
00141    On an ILP32 system (defined here as not LP64), we can make do with
00142    any thread-local pointer.  Ideally we'd use the TLS base address,
00143    since that requires the least amount of arithmetic, but that's not
00144    always available directly.  Make do with the gomp_thread pointer
00145    since it's handy.  */
00146 
00147 # if !defined (HAVE_TLS)
00148 static inline int gomp_tid (void)
00149 {
00150   return syscall (SYS_gettid);
00151 }
00152 # elif !defined(__LP64__)
00153 static inline int gomp_tid (void)
00154 {
00155   return (int) gomp_thread ();
00156 }
00157 # else
00158 static __thread int tid_cache;
00159 static inline int gomp_tid (void)
00160 {
00161   int tid = tid_cache;
00162   if (__builtin_expect (tid == 0, 0))
00163     tid_cache = tid = syscall (SYS_gettid);
00164   return tid;
00165 }
00166 # endif
00167 
00168 
00169 void
00170 gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
00171 {
00172   memset (lock, 0, sizeof (lock));
00173 }
00174 
00175 void
00176 gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
00177 {
00178 }
00179 
00180 void
00181 gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
00182 {
00183   int otid, tid = gomp_tid ();
00184 
00185   while (1)
00186     {
00187       otid = __sync_val_compare_and_swap (&lock->owner, 0, tid);
00188       if (otid == 0)
00189     {
00190       lock->count = 1;
00191       return;
00192     }
00193       if (otid == tid)
00194     {
00195       lock->count++;
00196       return;
00197     }
00198 
00199       do_wait (&lock->owner, otid);
00200     }
00201 }
00202 
00203 void
00204 gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
00205 {
00206   /* ??? Validate that we own the lock here.  */
00207 
00208   if (--lock->count == 0)
00209     {
00210       __sync_lock_release (&lock->owner);
00211       futex_wake (&lock->owner, 1);
00212     }
00213 }
00214 
00215 int
00216 gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
00217 {
00218   int otid, tid = gomp_tid ();
00219 
00220   otid = __sync_val_compare_and_swap (&lock->owner, 0, tid);
00221   if (otid == 0)
00222     {
00223       lock->count = 1;
00224       return 1;
00225     }
00226   if (otid == tid)
00227     return ++lock->count;
00228 
00229   return 0;
00230 }
00231 
00232 omp_lock_symver (omp_init_lock)
00233 omp_lock_symver (omp_destroy_lock)
00234 omp_lock_symver (omp_set_lock)
00235 omp_lock_symver (omp_unset_lock)
00236 omp_lock_symver (omp_test_lock)
00237 omp_lock_symver (omp_init_nest_lock)
00238 omp_lock_symver (omp_destroy_nest_lock)
00239 omp_lock_symver (omp_set_nest_lock)
00240 omp_lock_symver (omp_unset_nest_lock)
00241 omp_lock_symver (omp_test_nest_lock)
00242 
00243 #else
00244 
00245 ialias (omp_init_lock)
00246 ialias (omp_init_nest_lock)
00247 ialias (omp_destroy_lock)
00248 ialias (omp_destroy_nest_lock)
00249 ialias (omp_set_lock)
00250 ialias (omp_set_nest_lock)
00251 ialias (omp_unset_lock)
00252 ialias (omp_unset_nest_lock)
00253 ialias (omp_test_lock)
00254 ialias (omp_test_nest_lock)
00255 
00256 #endif

Generated on Fri Apr 5 05:38:09 2013 for Libgomp by  doxygen 1.4.7