Line data Source code
1 : /* posix-lock.c - GPGRT lock functions for POSIX systems
2 : Copyright (C) 2005-2009 Free Software Foundation, Inc.
3 : Copyright (C) 2014 g10 Code GmbH
4 :
5 : This file is part of libgpg-error.
6 :
7 : libgpg-error is free software; you can redistribute it and/or
8 : modify it under the terms of the GNU Lesser General Public License
9 : as published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : libgpg-error is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, see <https://www.gnu.org/licenses/>.
19 :
20 : Parts of the code, in particular use_pthreads_p, are based on code
21 : from gettext, written by Bruno Haible <bruno@clisp.org>, 2005.
22 : */
23 :
24 : #if HAVE_CONFIG_H
25 : #include <config.h>
26 : #endif
27 :
28 : #ifdef HAVE_W32_SYSTEM
29 : # error This module may not be build for Windows.
30 : #endif
31 :
32 : #include <stdlib.h>
33 : #include <stdio.h>
34 : #include <string.h>
35 : #include <errno.h>
36 : #include <assert.h>
37 :
38 : #if USE_POSIX_THREADS
39 : # include <pthread.h>
40 : #endif
41 :
42 : #include "gpg-error.h"
43 : #include "lock.h"
44 : #include "posix-lock-obj.h"
45 :
46 :
47 : #if USE_POSIX_THREADS
48 : # if USE_POSIX_THREADS_WEAK
49 : /* On ELF systems it is easy to use pthreads using weak
50 : references. Take care not to test the address of a weak
51 : referenced function we actually use; some GCC versions have a
52 : bug were &foo != NULL is always evaluated to true in PIC mode. */
53 : # pragma weak pthread_cancel
54 : # pragma weak pthread_mutex_init
55 : # pragma weak pthread_mutex_lock
56 : # pragma weak pthread_mutex_trylock
57 : # pragma weak pthread_mutex_unlock
58 : # pragma weak pthread_mutex_destroy
59 : # if ! PTHREAD_IN_USE_DETECTION_HARD
60 : # define use_pthread_p() (!!pthread_cancel)
61 : # endif
62 : # else /*!USE_POSIX_THREADS_WEAK*/
63 : # if ! PTHREAD_IN_USE_DETECTION_HARD
64 : # define use_pthread_p() (1)
65 : # endif
66 : # endif /*!USE_POSIX_THREADS_WEAK*/
67 : # if PTHREAD_IN_USE_DETECTION_HARD
68 : /* The function to be executed by a dummy thread. */
69 : static void *
70 : dummy_thread_func (void *arg)
71 : {
72 : return arg;
73 : }
74 :
75 : static int
76 : use_pthread_p (void)
77 : {
78 : static int tested;
79 : static int result; /* 1: linked with -lpthread, 0: only with libc */
80 :
81 : if (!tested)
82 : {
83 : pthread_t thread;
84 :
85 : if (pthread_create (&thread, NULL, dummy_thread_func, NULL))
86 : result = 0; /* Thread creation failed. */
87 : else
88 : {
89 : /* Thread creation works. */
90 : void *retval;
91 : if (pthread_join (thread, &retval) != 0)
92 : {
93 : assert (!"pthread_join");
94 : abort ();
95 : }
96 : result = 1;
97 : }
98 : tested = 1;
99 : }
100 : return result;
101 : }
102 : #endif /*PTHREAD_IN_USE_DETECTION_HARD*/
103 : #endif /*USE_POSIX_THREADS*/
104 :
105 :
106 :
107 : static _gpgrt_lock_t *
108 : get_lock_object (gpgrt_lock_t *lockhd)
109 : {
110 : _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
111 :
112 38038 : if (lock->vers != LOCK_ABI_VERSION)
113 : {
114 0 : assert (!"lock ABI version");
115 : abort ();
116 : }
117 : if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
118 : {
119 : assert (!"sizeof lock obj");
120 : abort ();
121 : }
122 :
123 : return lock;
124 : }
125 :
126 :
127 : gpg_err_code_t
128 7 : _gpgrt_lock_init (gpgrt_lock_t *lockhd)
129 : {
130 : _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
131 : int rc;
132 :
133 : /* If VERS is zero we assume that no static initialization has been
134 : done, so we setup our ABI version right here. The caller might
135 : have called us to test whether lock support is at all available. */
136 7 : if (!lock->vers)
137 : {
138 : if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
139 : {
140 : assert (!"sizeof lock obj");
141 : abort ();
142 : }
143 6 : lock->vers = LOCK_ABI_VERSION;
144 : }
145 : else /* Run the usual check. */
146 : lock = get_lock_object (lockhd);
147 :
148 : #if USE_POSIX_THREADS
149 7 : if (use_pthread_p())
150 : {
151 7 : rc = pthread_mutex_init (&lock->u.mtx, NULL);
152 7 : if (rc)
153 0 : rc = gpg_err_code_from_errno (rc);
154 : }
155 : else
156 : rc = 0; /* Threads are not used. */
157 : #else /* Unknown thread system. */
158 : rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
159 : #endif /* Unknown thread system. */
160 :
161 7 : return rc;
162 : }
163 :
164 :
165 : gpg_err_code_t
166 18790 : _gpgrt_lock_lock (gpgrt_lock_t *lockhd)
167 : {
168 : _gpgrt_lock_t *lock = get_lock_object (lockhd);
169 : int rc;
170 :
171 : #if USE_POSIX_THREADS
172 18790 : if (use_pthread_p())
173 : {
174 18809 : rc = pthread_mutex_lock (&lock->u.mtx);
175 19236 : if (rc)
176 0 : rc = gpg_err_code_from_errno (rc);
177 : }
178 : else
179 : rc = 0; /* Threads are not used. */
180 : #else /* Unknown thread system. */
181 : rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
182 : #endif /* Unknown thread system. */
183 :
184 19217 : return rc;
185 : }
186 :
187 :
188 : gpg_err_code_t
189 0 : _gpgrt_lock_trylock (gpgrt_lock_t *lockhd)
190 : {
191 : _gpgrt_lock_t *lock = get_lock_object (lockhd);
192 : int rc;
193 :
194 : #if USE_POSIX_THREADS
195 0 : if (use_pthread_p())
196 : {
197 0 : rc = pthread_mutex_trylock (&lock->u.mtx);
198 0 : if (rc)
199 0 : rc = gpg_err_code_from_errno (rc);
200 : }
201 : else
202 : rc = 0; /* Threads are not used. */
203 : #else /* Unknown thread system. */
204 : rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
205 : #endif /* Unknown thread system. */
206 :
207 0 : return rc;
208 : }
209 :
210 :
211 : gpg_err_code_t
212 19238 : _gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
213 : {
214 : _gpgrt_lock_t *lock = get_lock_object (lockhd);
215 : int rc;
216 :
217 : #if USE_POSIX_THREADS
218 19238 : if (use_pthread_p())
219 : {
220 19234 : rc = pthread_mutex_unlock (&lock->u.mtx);
221 18984 : if (rc)
222 0 : rc = gpg_err_code_from_errno (rc);
223 : }
224 : else
225 : rc = 0; /* Threads are not used. */
226 : #else /* Unknown thread system. */
227 : rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
228 : #endif /* Unknown thread system. */
229 :
230 18988 : return rc;
231 : }
232 :
233 :
234 : /* Note: Use this function only if no other thread holds or waits for
235 : this lock. */
236 : gpg_err_code_t
237 9 : _gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
238 : {
239 : _gpgrt_lock_t *lock = get_lock_object (lockhd);
240 : int rc;
241 :
242 : #if USE_POSIX_THREADS
243 9 : if (use_pthread_p())
244 : {
245 9 : rc = pthread_mutex_destroy (&lock->u.mtx);
246 9 : if (rc)
247 0 : rc = gpg_err_code_from_errno (rc);
248 : else
249 : {
250 : /* Re-init the mutex so that it can be re-used. */
251 9 : gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
252 9 : memcpy (lockhd, &tmp, sizeof tmp);
253 : }
254 : }
255 : else
256 : rc = 0; /* Threads are not used. */
257 : #else /* Unknown thread system. */
258 : rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
259 : #endif /* Unknown thread system. */
260 :
261 9 : return rc;
262 : }
|