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>  /* Right: We need to use assert and not gcry_assert.  */
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
42/* The interface table.  */
43static struct ath_ops ops;
44
45/* True if we should use the external callbacks.  */
46static 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
62/* The lock we take while checking for lazy lock initialization.  */
63static ath_mutex_t check_init_lock = ATH_MUTEX_INITIALIZER;
64
65int
66ath_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.  */
85gpg_err_code_t
86ath_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
126static int
127mutex_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
141int
142ath_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
154int
155ath_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
181int
182ath_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
201int
202ath_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
221ssize_t
222ath_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
231ssize_t
232ath_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
241ssize_t
242#ifdef _WIN32
243ath_select (int nfd, void *rset, void *wset, void *eset,
244	    struct timeval *timeout)
245#else
246ath_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
261ssize_t
262ath_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
275int
276#ifdef _WIN32
277ath_accept (int s, void *addr, int *length_ptr)
278#else
279ath_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
293int
294#ifdef _WIN32
295ath_connect (int s, void *addr, int length)
296#else
297ath_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
311int
312#ifdef _WIN32
313ath_sendmsg (int s, const void *msg, int flags)
314#else
315ath_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
329int
330#ifdef _WIN32
331ath_recvmsg (int s, void *msg, int flags)
332#else
333ath_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