Better AES performance.
[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 \f
56 /* The lock we take while checking for lazy lock initialization.  */
57 static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER;
58
59 int
60 ath_init (void)
61 {
62   int err = 0;
63
64   if (ops_set)
65     {
66       if (ops.init)
67         err = (*ops.init) ();
68       if (err)
69         return err;
70       err = (*ops.mutex_init) (&check_init_lock);
71     }
72   return err;
73 }
74
75
76 /* Initialize the locking library.  Returns 0 if the operation was
77    successful, EINVAL if the operation table was invalid and EBUSY if
78    we already were initialized.  */
79 gpg_err_code_t
80 ath_install (struct ath_ops *ath_ops, int check_only)
81 {
82   if (check_only)
83     {
84       enum ath_thread_option option = ATH_THREAD_OPTION_DEFAULT;
85       
86       /* Check if the requested thread option is compatible to the
87          thread option we are already committed to.  */
88       if (ath_ops)
89         option = ath_ops->option;
90
91       if (!ops_set && option)
92         return GPG_ERR_NOT_SUPPORTED;
93
94       if (ops.option == ATH_THREAD_OPTION_USER
95           || option == ATH_THREAD_OPTION_USER
96           || ops.option != option)
97         return GPG_ERR_NOT_SUPPORTED;
98
99       return 0;
100     }
101     
102   if (ath_ops)
103     {
104       /* It is convenient to not require DESTROY.  */
105       if (!ath_ops->mutex_init || !ath_ops->mutex_lock
106           || !ath_ops->mutex_unlock)
107         return GPG_ERR_INV_ARG;
108
109       ops = *ath_ops;
110       ops_set = 1;
111     }
112   else
113     ops_set = 0;
114
115   return 0;
116 }
117
118
119 static int
120 mutex_init (ath_mutex_t *lock, int just_check)
121 {
122   int err = 0;
123
124   if (just_check)
125     (*ops.mutex_lock) (&check_init_lock);
126   if (*lock == ATH_MUTEX_INITIALIZER || !just_check)
127     err = (*ops.mutex_init) (lock);
128   if (just_check)
129     (*ops.mutex_unlock) (&check_init_lock);
130   return err;
131 }
132
133
134 int
135 ath_mutex_init (ath_mutex_t *lock)
136 {
137   if (ops_set)
138     return mutex_init (lock, 0);
139
140 #ifndef NDEBUG
141   *lock = MUTEX_UNLOCKED;
142 #endif
143   return 0;
144 }
145
146
147 int
148 ath_mutex_destroy (ath_mutex_t *lock)
149 {
150   if (ops_set)
151     {
152       if (!ops.mutex_destroy)
153         return 0;
154
155       (*ops.mutex_lock) (&check_init_lock);
156       if (*lock == ATH_MUTEX_INITIALIZER)
157         {
158           (*ops.mutex_unlock) (&check_init_lock);
159           return 0;
160         }
161       (*ops.mutex_unlock) (&check_init_lock);
162       return (*ops.mutex_destroy) (lock);
163     }
164
165 #ifndef NDEBUG
166   assert (*lock == MUTEX_UNLOCKED);
167
168   *lock = MUTEX_DESTROYED;
169 #endif
170   return 0;
171 }
172
173
174 int
175 ath_mutex_lock (ath_mutex_t *lock)
176 {
177   if (ops_set)
178     {
179       int ret = mutex_init (lock, 1);
180       if (ret)
181         return ret;
182       return (*ops.mutex_lock) (lock);
183     }
184
185 #ifndef NDEBUG
186   assert (*lock == MUTEX_UNLOCKED);
187
188   *lock = MUTEX_LOCKED;
189 #endif
190   return 0;
191 }
192
193
194 int
195 ath_mutex_unlock (ath_mutex_t *lock)
196 {
197   if (ops_set)
198     {
199       int ret = mutex_init (lock, 1);
200       if (ret)
201         return ret;
202       return (*ops.mutex_unlock) (lock);
203     }
204
205 #ifndef NDEBUG
206   assert (*lock == MUTEX_LOCKED);
207
208   *lock = MUTEX_UNLOCKED;
209 #endif
210   return 0;
211 }
212
213
214 ssize_t
215 ath_read (int fd, void *buf, size_t nbytes)
216 {
217   if (ops_set && ops.read)
218     return (*ops.read) (fd, buf, nbytes);
219   else
220     return read (fd, buf, nbytes);
221 }
222
223
224 ssize_t
225 ath_write (int fd, const void *buf, size_t nbytes)
226 {
227   if (ops_set && ops.write)
228     return (*ops.write) (fd, buf, nbytes);
229   else
230     return write (fd, buf, nbytes);
231 }
232
233
234 ssize_t
235 #ifdef _WIN32
236 ath_select (int nfd, void *rset, void *wset, void *eset,
237             struct timeval *timeout)
238 #else
239 ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
240             struct timeval *timeout)
241 #endif
242 {
243   if (ops_set && ops.select)
244     return (*ops.select) (nfd, rset, wset, eset, timeout);
245   else
246 #ifdef _WIN32
247     return -1;
248 #else
249     return select (nfd, rset, wset, eset, timeout);
250 #endif
251 }
252
253  
254 ssize_t
255 ath_waitpid (pid_t pid, int *status, int options)
256 {
257   if (ops_set && ops.waitpid)
258     return (*ops.waitpid) (pid, status, options);
259   else
260 #ifdef _WIN32
261     return -1;
262 #else
263     return waitpid (pid, status, options);
264 #endif
265 }
266
267
268 int
269 #ifdef _WIN32
270 ath_accept (int s, void *addr, int *length_ptr)
271 #else
272 ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
273 #endif
274 {
275   if (ops_set && ops.accept)
276     return (*ops.accept) (s, addr, length_ptr);
277   else
278 #ifdef _WIN32
279     return -1;
280 #else
281     return accept (s, addr, length_ptr);
282 #endif
283 }
284
285
286 int
287 #ifdef _WIN32
288 ath_connect (int s, void *addr, int length)
289 #else
290 ath_connect (int s, struct sockaddr *addr, socklen_t length)
291 #endif
292 {
293   if (ops_set && ops.connect)
294     return (*ops.connect) (s, addr, length);
295   else
296 #ifdef _WIN32
297     return -1;
298 #else
299     return connect (s, addr, length);
300 #endif
301 }
302
303
304 int
305 #ifdef _WIN32
306 ath_sendmsg (int s, const void *msg, int flags)
307 #else
308 ath_sendmsg (int s, const struct msghdr *msg, int flags)
309 #endif
310 {
311   if (ops_set && ops.sendmsg)
312     return (*ops.sendmsg) (s, msg, flags);
313   else
314 #ifdef _WIN32
315     return -1;
316 #else
317     return sendmsg (s, msg, flags);
318 #endif
319 }
320
321
322 int
323 #ifdef _WIN32
324 ath_recvmsg (int s, void *msg, int flags)
325 #else
326 ath_recvmsg (int s, struct msghdr *msg, int flags)
327 #endif
328 {
329   if (ops_set && ops.recvmsg)
330     return (*ops.recvmsg) (s, msg, flags);
331   else
332 #ifdef _WIN32
333     return -1;
334 #else
335     return recvmsg (s, msg, flags);
336 #endif
337 }
338