1 /* Copyright (C) 2005-2018 Free Software Foundation, Inc.
2    Contributed by Richard Henderson <rth@redhat.com>.
3 
4    This file is part of the GNU Offloading and Multi Processing Library
5    (libgomp).
6 
7    Libgomp is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15    more details.
16 
17    Under Section 7 of GPL version 3, you are granted additional
18    permissions described in the GCC Runtime Library Exception, version
19    3.1, as published by the Free Software Foundation.
20 
21    You should have received a copy of the GNU General Public License and
22    a copy of the GCC Runtime Library Exception along with this program;
23    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24    <http://www.gnu.org/licenses/>.  */
25 
26 /* This is a Linux specific implementation of the public OpenMP locking
27    primitives.  This implementation uses atomic instructions and the futex
28    syscall.  */
29 
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/syscall.h>
33 #include "wait.h"
34 
35 /* Reuse the generic implementation in terms of gomp_mutex_t.  */
36 #include "../../lock.c"
37 
38 #ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
39 /* gomp_mutex_* can be safely locked in one thread and
40    unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0
41    non-nested locks can be the same.  */
strong_alias(gomp_init_lock_30,gomp_init_lock_25)42 strong_alias (gomp_init_lock_30, gomp_init_lock_25)
43 strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25)
44 strong_alias (gomp_set_lock_30, gomp_set_lock_25)
45 strong_alias (gomp_unset_lock_30, gomp_unset_lock_25)
46 strong_alias (gomp_test_lock_30, gomp_test_lock_25)
47 
48 /* The external recursive omp_nest_lock_25_t form requires additional work.  */
49 
50 /* We need an integer to uniquely identify this thread.  Most generally
51    this is the thread's TID, which ideally we'd get this straight from
52    the TLS block where glibc keeps it.  Unfortunately, we can't get at
53    that directly.
54 
55    If we don't support (or have disabled) TLS, one function call is as
56    good (or bad) as any other.  Use the syscall all the time.
57 
58    On an ILP32 system (defined here as not LP64), we can make do with
59    any thread-local pointer.  Ideally we'd use the TLS base address,
60    since that requires the least amount of arithmetic, but that's not
61    always available directly.  Make do with the gomp_thread pointer
62    since it's handy.  */
63 
64 # if !defined (HAVE_TLS)
65 static inline int gomp_tid (void)
66 {
67   return syscall (SYS_gettid);
68 }
69 # elif !defined(__LP64__)
70 static inline int gomp_tid (void)
71 {
72   return (int) gomp_thread ();
73 }
74 # else
75 static __thread int tid_cache;
76 static inline int gomp_tid (void)
77 {
78   int tid = tid_cache;
79   if (__builtin_expect (tid == 0, 0))
80     tid_cache = tid = syscall (SYS_gettid);
81   return tid;
82 }
83 # endif
84 
85 
86 void
gomp_init_nest_lock_25(omp_nest_lock_25_t * lock)87 gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
88 {
89   memset (lock, 0, sizeof (*lock));
90 }
91 
92 void
gomp_destroy_nest_lock_25(omp_nest_lock_25_t * lock)93 gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
94 {
95 }
96 
97 void
gomp_set_nest_lock_25(omp_nest_lock_25_t * lock)98 gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
99 {
100   int otid, tid = gomp_tid ();
101 
102   while (1)
103     {
104       otid = 0;
105       if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false,
106 				       MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
107 	{
108 	  lock->count = 1;
109 	  return;
110 	}
111       if (otid == tid)
112 	{
113 	  lock->count++;
114 	  return;
115 	}
116 
117       do_wait (&lock->owner, otid);
118     }
119 }
120 
121 void
gomp_unset_nest_lock_25(omp_nest_lock_25_t * lock)122 gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
123 {
124   /* ??? Validate that we own the lock here.  */
125 
126   if (--lock->count == 0)
127     {
128       __atomic_store_n (&lock->owner, 0, MEMMODEL_RELEASE);
129       futex_wake (&lock->owner, 1);
130     }
131 }
132 
133 int
gomp_test_nest_lock_25(omp_nest_lock_25_t * lock)134 gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
135 {
136   int otid, tid = gomp_tid ();
137 
138   otid = 0;
139   if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false,
140 				   MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
141     {
142       lock->count = 1;
143       return 1;
144     }
145   if (otid == tid)
146     return ++lock->count;
147 
148   return 0;
149 }
150 
151 omp_lock_symver (omp_init_lock)
152 omp_lock_symver (omp_destroy_lock)
153 omp_lock_symver (omp_set_lock)
154 omp_lock_symver (omp_unset_lock)
155 omp_lock_symver (omp_test_lock)
156 omp_lock_symver (omp_init_nest_lock)
157 omp_lock_symver (omp_destroy_nest_lock)
158 omp_lock_symver (omp_set_nest_lock)
159 omp_lock_symver (omp_unset_nest_lock)
160 omp_lock_symver (omp_test_nest_lock)
161 
162 #else
163 
164 ialias (omp_init_lock)
165 ialias (omp_init_nest_lock)
166 ialias (omp_destroy_lock)
167 ialias (omp_destroy_nest_lock)
168 ialias (omp_set_lock)
169 ialias (omp_set_nest_lock)
170 ialias (omp_unset_lock)
171 ialias (omp_unset_nest_lock)
172 ialias (omp_test_lock)
173 ialias (omp_test_nest_lock)
174 
175 #endif
176