Updating to version 1.13. Libgcrypt depends on libgpg-error
[platform/upstream/libgpg-error.git] / src / posix-lock.c
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 <http://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
37 #if USE_POSIX_THREADS
38 # include <pthread.h>
39 #endif
40
41 #include "gpg-error.h"
42 #include "lock.h"
43 #include "posix-lock-obj.h"
44
45
46 #if USE_POSIX_THREADS
47 # if USE_POSIX_THREADS_WEAK
48    /* On ELF systems it is easy to use pthreads using weak
49       references.  Take care not to test the address of a weak
50       referenced function we actually use; some GCC versions have a
51       bug were &foo != NULL is always evaluated to true in PIC mode.  */
52 #  pragma weak pthread_cancel
53 #  pragma weak pthread_mutex_init
54 #  pragma weak pthread_mutex_lock
55 #  pragma weak pthread_mutex_unlock
56 #  pragma weak pthread_mutex_destroy
57 #  if ! PTHREAD_IN_USE_DETECTION_HARD
58 #   define use_pthread_p() (!!pthread_cancel)
59 #  endif
60 # else /*!USE_POSIX_THREADS_WEAK*/
61 #  if ! PTHREAD_IN_USE_DETECTION_HARD
62 #   define use_pthread_p() (1)
63 #  endif
64 # endif /*!USE_POSIX_THREADS_WEAK*/
65 # if PTHREAD_IN_USE_DETECTION_HARD
66 /* The function to be executed by a dummy thread.  */
67 static void *
68 dummy_thread_func (void *arg)
69 {
70   return arg;
71 }
72
73 static int
74 use_pthread_p (void)
75 {
76   static int tested;
77   static int result; /* 1: linked with -lpthread, 0: only with libc */
78
79   if (!tested)
80     {
81       pthread_t thread;
82
83       if (pthread_create (&thread, NULL, dummy_thread_func, NULL))
84         result = 0; /* Thread creation failed.  */
85       else
86         {
87           /* Thread creation works.  */
88           void *retval;
89           if (pthread_join (thread, &retval) != 0)
90             abort ();
91           result = 1;
92         }
93       tested = 1;
94     }
95   return result;
96 }
97 #endif /*PTHREAD_IN_USE_DETECTION_HARD*/
98 #endif /*USE_POSIX_THREADS*/
99
100
101
102 static _gpgrt_lock_t *
103 get_lock_object (gpgrt_lock_t *lockhd)
104 {
105   _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
106
107   if (lock->vers != LOCK_ABI_VERSION)
108     abort ();
109   if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
110     abort ();
111
112   return lock;
113 }
114
115
116 gpg_err_code_t
117 gpgrt_lock_init (gpgrt_lock_t *lockhd)
118 {
119   _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
120   int rc;
121
122   /* If VERS is zero we assume that no static initialization has been
123      done, so we setup our ABI version right here.  The caller might
124      have called us to test whether lock support is at all available. */
125   if (!lock->vers)
126     {
127       if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
128         abort ();
129       lock->vers = LOCK_ABI_VERSION;
130     }
131   else /* Run the usual check.  */
132     lock = get_lock_object (lockhd);
133
134 #if USE_POSIX_THREADS
135   if (use_pthread_p())
136     {
137       rc = pthread_mutex_init (&lock->u.mtx, NULL);
138       if (rc)
139         rc = gpg_err_code_from_errno (rc);
140     }
141   else
142     rc = 0; /* Threads are not used.  */
143 #else /* Unknown thread system.  */
144   rc = GPG_ERR_NOT_IMPLEMENTED;
145 #endif /* Unknown thread system.  */
146
147   return rc;
148 }
149
150
151 gpg_err_code_t
152 gpgrt_lock_lock (gpgrt_lock_t *lockhd)
153 {
154   _gpgrt_lock_t *lock = get_lock_object (lockhd);
155   int rc;
156
157 #if USE_POSIX_THREADS
158   if (use_pthread_p())
159     {
160       rc = pthread_mutex_lock (&lock->u.mtx);
161       if (rc)
162         rc = gpg_err_code_from_errno (rc);
163     }
164   else
165     rc = 0; /* Threads are not used.  */
166 #else /* Unknown thread system.  */
167   rc = GPG_ERR_NOT_IMPLEMENTED;
168 #endif /* Unknown thread system.  */
169
170   return rc;
171 }
172
173
174 gpg_err_code_t
175 gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
176 {
177   _gpgrt_lock_t *lock = get_lock_object (lockhd);
178   int rc;
179
180 #if USE_POSIX_THREADS
181   if (use_pthread_p())
182     {
183       rc = pthread_mutex_unlock (&lock->u.mtx);
184       if (rc)
185         rc = gpg_err_code_from_errno (rc);
186     }
187   else
188     rc = 0; /* Threads are not used.  */
189 #else /* Unknown thread system.  */
190   rc = GPG_ERR_NOT_IMPLEMENTED;
191 #endif /* Unknown thread system.  */
192
193   return rc;
194 }
195
196
197 /* Note: Use this function only if no other thread holds or waits for
198    this lock.  */
199 gpg_err_code_t
200 gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
201 {
202   _gpgrt_lock_t *lock = get_lock_object (lockhd);
203   int rc;
204
205 #if USE_POSIX_THREADS
206   if (use_pthread_p())
207     {
208       rc = pthread_mutex_destroy (&lock->u.mtx);
209       if (rc)
210         rc = gpg_err_code_from_errno (rc);
211       else
212         {
213           /* Re-init the mutex so that it can be re-used.  */
214           gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
215           memcpy (lockhd, &tmp, sizeof tmp);
216         }
217     }
218   else
219     rc = 0; /* Threads are not used.  */
220 #else /* Unknown thread system.  */
221   rc = GPG_ERR_NOT_IMPLEMENTED;
222 #endif /* Unknown thread system.  */
223
224   return rc;
225 }