edfaada66da19f7584822bc9bdb2a40135a428dd
[libgcrypt.git] / src / ath.c
1 /* ath.c - Thread-safeness library.
2    Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3
4    This file is part of Libgcrypt.
5  
6    Libgcrypt is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10  
11    Libgcrypt is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    General Public License for more details.
15  
16    You should have received a copy of the GNU Lesser General Public
17    License along with Libgcrypt; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19    02111-1307, USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <assert.h>
26 #include <unistd.h>
27 #ifdef HAVE_SYS_SELECT_H
28 # include <sys/select.h>
29 #else
30 # include <sys/time.h>
31 #endif
32 #include <sys/types.h>
33 #ifndef _WIN32
34 #include <sys/wait.h>
35 #endif
36 #include <errno.h>
37
38 #include "ath.h"
39
40
41 \f
42 /* The interface table.  */
43 static struct ath_ops ops;
44
45 /* True if we should use the external callbacks.  */
46 static int ops_set;
47
48
49 /* For the dummy interface.  */
50 #define MUTEX_UNLOCKED  ((ath_mutex_t) 0)
51 #define MUTEX_LOCKED    ((ath_mutex_t) 1)
52 #define MUTEX_DESTROYED ((ath_mutex_t) 2)
53
54
55 /* Return the thread type from the option field. */
56 #define GET_OPTION(a)    ((a) & 0xff)
57 /* Return the version number from the option field.  */
58 #define GET_VERSION(a)   (((a) >> 8)& 0xff)
59
60
61 \f
62 /* The lock we take while checking for lazy lock initialization.  */
63 static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER;
64
65 int
66 ath_init (void)
67 {
68   int err = 0;
69
70   if (ops_set)
71     {
72       if (ops.init)
73         err = (*ops.init) ();
74       if (err)
75         return err;
76       err = (*ops.mutex_init) (&check_init_lock);
77     }
78   return err;
79 }
80
81
82 /* Initialize the locking library.  Returns 0 if the operation was
83    successful, EINVAL if the operation table was invalid and EBUSY if
84    we already were initialized.  */
85 gpg_err_code_t
86 ath_install (struct ath_ops *ath_ops, int check_only)
87 {
88   if (check_only)
89     {
90       unsigned int option = 0;
91       
92       /* Check if the requested thread option is compatible to the
93          thread option we are already committed to.  */
94       if (ath_ops)
95         option = ath_ops->option;
96
97       if (!ops_set && GET_OPTION (option))
98         return GPG_ERR_NOT_SUPPORTED;
99
100       if (GET_OPTION (ops.option) == ATH_THREAD_OPTION_USER
101           || GET_OPTION (option) == ATH_THREAD_OPTION_USER
102           || GET_OPTION (ops.option) != GET_OPTION (option)
103           || GET_VERSION (ops.option) != GET_VERSION (option))
104         return GPG_ERR_NOT_SUPPORTED;
105
106       return 0;
107     }
108     
109   if (ath_ops)
110     {
111       /* It is convenient to not require DESTROY.  */
112       if (!ath_ops->mutex_init || !ath_ops->mutex_lock
113           || !ath_ops->mutex_unlock)
114         return GPG_ERR_INV_ARG;
115
116       ops = *ath_ops;
117       ops_set = 1;
118     }
119   else
120     ops_set = 0;
121
122   return 0;
123 }
124
125
126 static int
127 mutex_init (ath_mutex_t *lock, int just_check)
128 {
129   int err = 0;
130
131   if (just_check)
132     (*ops.mutex_lock) (&check_init_lock);
133   if (*lock == ATH_MUTEX_INITIALIZER || !just_check)
134     err = (*ops.mutex_init) (lock);
135   if (just_check)
136     (*ops.mutex_unlock) (&check_init_lock);
137   return err;
138 }
139
140
141 int
142 ath_mutex_init (ath_mutex_t *lock)
143 {
144   if (ops_set)
145     return mutex_init (lock, 0);
146
147 #ifndef NDEBUG
148   *lock = MUTEX_UNLOCKED;
149 #endif
150   return 0;
151 }
152
153
154 int
155 ath_mutex_destroy (ath_mutex_t *lock)
156 {
157   if (ops_set)
158     {
159       if (!ops.mutex_destroy)
160         return 0;
161
162       (*ops.mutex_lock) (&check_init_lock);
163       if (*lock == ATH_MUTEX_INITIALIZER)
164         {
165           (*ops.mutex_unlock) (&check_init_lock);
166           return 0;
167         }
168       (*ops.mutex_unlock) (&check_init_lock);
169       return (*ops.mutex_destroy) (lock);
170     }
171
172 #ifndef NDEBUG
173   assert (*lock == MUTEX_UNLOCKED);
174
175   *lock = MUTEX_DESTROYED;
176 #endif
177   return 0;
178 }
179
180
181 int
182 ath_mutex_lock (ath_mutex_t *lock)
183 {
184   if (ops_set)
185     {
186       int ret = mutex_init (lock, 1);
187       if (ret)
188         return ret;
189       return (*ops.mutex_lock) (lock);
190     }
191
192 #ifndef NDEBUG
193   assert (*lock == MUTEX_UNLOCKED);
194
195   *lock = MUTEX_LOCKED;
196 #endif
197   return 0;
198 }
199
200
201 int
202 ath_mutex_unlock (ath_mutex_t *lock)
203 {
204   if (ops_set)
205     {
206       int ret = mutex_init (lock, 1);
207       if (ret)
208         return ret;
209       return (*ops.mutex_unlock) (lock);
210     }
211
212 #ifndef NDEBUG
213   assert (*lock == MUTEX_LOCKED);
214
215   *lock = MUTEX_UNLOCKED;
216 #endif
217   return 0;
218 }
219
220
221 ssize_t
222 ath_read (int fd, void *buf, size_t nbytes)
223 {
224   if (ops_set && ops.read)
225     return (*ops.read) (fd, buf, nbytes);
226   else
227     return read (fd, buf, nbytes);
228 }
229
230
231 ssize_t
232 ath_write (int fd, const void *buf, size_t nbytes)
233 {
234   if (ops_set && ops.write)
235     return (*ops.write) (fd, buf, nbytes);
236   else
237     return write (fd, buf, nbytes);
238 }
239
240
241 ssize_t
242 #ifdef _WIN32
243 ath_select (int nfd, void *rset, void *wset, void *eset,
244             struct timeval *timeout)
245 #else
246 ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
247             struct timeval *timeout)
248 #endif
249 {
250   if (ops_set && ops.select)
251     return (*ops.select) (nfd, rset, wset, eset, timeout);
252   else
253 #ifdef _WIN32
254     return -1;
255 #else
256     return select (nfd, rset, wset, eset, timeout);
257 #endif
258 }
259
260  
261 ssize_t
262 ath_waitpid (pid_t pid, int *status, int options)
263 {
264   if (ops_set && ops.waitpid)
265     return (*ops.waitpid) (pid, status, options);
266   else
267 #ifdef _WIN32
268     return -1;
269 #else
270     return waitpid (pid, status, options);
271 #endif
272 }
273
274
275 int
276 #ifdef _WIN32
277 ath_accept (int s, void *addr, int *length_ptr)
278 #else
279 ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
280 #endif
281 {
282   if (ops_set && ops.accept)
283     return (*ops.accept) (s, addr, length_ptr);
284   else
285 #ifdef _WIN32
286     return -1;
287 #else
288     return accept (s, addr, length_ptr);
289 #endif
290 }
291
292
293 int
294 #ifdef _WIN32
295 ath_connect (int s, void *addr, int length)
296 #else
297 ath_connect (int s, struct sockaddr *addr, socklen_t length)
298 #endif
299 {
300   if (ops_set && ops.connect)
301     return (*ops.connect) (s, addr, length);
302   else
303 #ifdef _WIN32
304     return -1;
305 #else
306     return connect (s, addr, length);
307 #endif
308 }
309
310
311 int
312 #ifdef _WIN32
313 ath_sendmsg (int s, const void *msg, int flags)
314 #else
315 ath_sendmsg (int s, const struct msghdr *msg, int flags)
316 #endif
317 {
318   if (ops_set && ops.sendmsg)
319     return (*ops.sendmsg) (s, msg, flags);
320   else
321 #ifdef _WIN32
322     return -1;
323 #else
324     return sendmsg (s, msg, flags);
325 #endif
326 }
327
328
329 int
330 #ifdef _WIN32
331 ath_recvmsg (int s, void *msg, int flags)
332 #else
333 ath_recvmsg (int s, struct msghdr *msg, int flags)
334 #endif
335 {
336   if (ops_set && ops.recvmsg)
337     return (*ops.recvmsg) (s, msg, flags);
338   else
339 #ifdef _WIN32
340     return -1;
341 #else
342     return recvmsg (s, msg, flags);
343 #endif
344 }
345