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