324 lines
7.9 KiB
C
324 lines
7.9 KiB
C
|
/* ath.c - A Thread-safeness library.
|
|||
|
* Copyright (C) 2002, 2003, 2004, 2011 Free Software Foundation, Inc.
|
|||
|
*
|
|||
|
* This file is part of Libgcrypt.
|
|||
|
*
|
|||
|
* Libgcrypt is free software; you can redistribute it and/or modify
|
|||
|
* it under the terms of the GNU Lesser general Public License as
|
|||
|
* published by the Free Software Foundation; either version 2.1 of
|
|||
|
* the License, or (at your option) any later version.
|
|||
|
*
|
|||
|
* Libgcrypt is distributed in the hope that it will be useful,
|
|||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
* GNU Lesser General Public License for more details.
|
|||
|
*
|
|||
|
* You should have received a copy of the GNU Lesser General Public
|
|||
|
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef HAVE_CONFIG_H
|
|||
|
#include <config.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include <stdlib.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <errno.h>
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
# include <pthread.h>
|
|||
|
#endif
|
|||
|
|
|||
|
#include "ath.h"
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* On an ELF system it is easy to use pthreads using weak references.
|
|||
|
Take care not to test the address of a weak referenced function we
|
|||
|
actually use; some GCC versions have a bug were &foo != NULL is
|
|||
|
always evaluated to true in PIC mode. USING_PTHREAD_AS_DEFAULT is
|
|||
|
used by ath_install to detect the default usage of pthread. */
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
# pragma weak pthread_cancel
|
|||
|
# pragma weak pthread_mutex_init
|
|||
|
# pragma weak pthread_mutex_lock
|
|||
|
# pragma weak pthread_mutex_unlock
|
|||
|
# pragma weak pthread_mutex_destroy
|
|||
|
#endif
|
|||
|
|
|||
|
/* For the dummy interface. The MUTEX_NOTINIT value is used to check
|
|||
|
that a mutex has been initialized. Because its value is there is
|
|||
|
no need to explicit initialized a mutex variable because it is
|
|||
|
anyway static and we store a pointer to allocated memory there
|
|||
|
after initialization. The same thing works with other thread
|
|||
|
models. */
|
|||
|
#define MUTEX_NOTINIT ((ath_mutex_t) 0)
|
|||
|
#define MUTEX_UNLOCKED ((ath_mutex_t) 1)
|
|||
|
#define MUTEX_LOCKED ((ath_mutex_t) 2)
|
|||
|
#define MUTEX_DESTROYED ((ath_mutex_t) 3)
|
|||
|
|
|||
|
|
|||
|
/* Return the thread type from the option field. */
|
|||
|
#define GET_OPTION(a) ((a) & 0xff)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
enum ath_thread_model {
|
|||
|
ath_model_undefined = 0,
|
|||
|
ath_model_none, /* No thread support. */
|
|||
|
ath_model_pthreads_weak, /* POSIX threads using weak symbols. */
|
|||
|
ath_model_pthreads, /* POSIX threads directly linked. */
|
|||
|
ath_model_w32 /* Microsoft Windows threads. */
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/* The thread model in use. */
|
|||
|
static enum ath_thread_model thread_model;
|
|||
|
|
|||
|
|
|||
|
/* Initialize the ath subsystem. This is called as part of the
|
|||
|
Libgcrypt initialization. It's purpose is to initialize the
|
|||
|
locking system. It returns 0 on sucess or an ERRNO value on error.
|
|||
|
In the latter case it is not defined whether ERRNO was changed.
|
|||
|
|
|||
|
Note: This should be called as early as possible because it is not
|
|||
|
always possible to detect the thread model to use while already
|
|||
|
running multi threaded. */
|
|||
|
int
|
|||
|
ath_init (void)
|
|||
|
{
|
|||
|
int err = 0;
|
|||
|
|
|||
|
if (thread_model)
|
|||
|
return 0; /* Already initialized - no error. */
|
|||
|
|
|||
|
if (0)
|
|||
|
;
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
else if (pthread_cancel)
|
|||
|
{
|
|||
|
thread_model = ath_model_pthreads_weak;
|
|||
|
}
|
|||
|
#endif
|
|||
|
else
|
|||
|
{
|
|||
|
/* Assume a single threaded application. */
|
|||
|
thread_model = ath_model_none;
|
|||
|
}
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Return the used thread model as string for display purposes an if
|
|||
|
R_MODEL is not null store its internal number at R_MODEL. */
|
|||
|
const char *
|
|||
|
ath_get_model (int *r_model)
|
|||
|
{
|
|||
|
if (r_model)
|
|||
|
*r_model = thread_model;
|
|||
|
switch (thread_model)
|
|||
|
{
|
|||
|
case ath_model_undefined: return "undefined";
|
|||
|
case ath_model_none: return "none";
|
|||
|
case ath_model_pthreads_weak: return "pthread(weak)";
|
|||
|
case ath_model_pthreads: return "pthread";
|
|||
|
case ath_model_w32: return "w32";
|
|||
|
default: return "?";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* This function was used in old Libgcrypt versions (via
|
|||
|
GCRYCTL_SET_THREAD_CBS) to register the thread callback functions.
|
|||
|
It is not anymore required. However to allow existing code to
|
|||
|
continue to work, we keep this function and check that no user
|
|||
|
defined callbacks are used and that the requested thread system
|
|||
|
matches the one Libgcrypt is using. */
|
|||
|
gpg_err_code_t
|
|||
|
ath_install (struct ath_ops *ath_ops)
|
|||
|
{
|
|||
|
unsigned int thread_option;
|
|||
|
|
|||
|
/* Check if the requested thread option is compatible to the
|
|||
|
thread option we are already committed to. */
|
|||
|
thread_option = ath_ops? GET_OPTION (ath_ops->option) : 0;
|
|||
|
|
|||
|
/* Return an error if the requested thread model does not match the
|
|||
|
configured one. */
|
|||
|
if (0)
|
|||
|
;
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
else if (thread_model == ath_model_pthreads_weak)
|
|||
|
{
|
|||
|
if (thread_option == ATH_THREAD_OPTION_PTHREAD)
|
|||
|
return 0; /* Okay - compatible. */
|
|||
|
}
|
|||
|
#endif /*USE_POSIX_THREADS_WEAK*/
|
|||
|
else if (thread_option == ATH_THREAD_OPTION_DEFAULT)
|
|||
|
return 0; /* No thread support requested. */
|
|||
|
|
|||
|
return GPG_ERR_NOT_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Initialize a new mutex. This function returns 0 on success or an
|
|||
|
system error code (i.e. an ERRNO value). ERRNO may or may not be
|
|||
|
changed on error. */
|
|||
|
int
|
|||
|
ath_mutex_init (ath_mutex_t *lock)
|
|||
|
{
|
|||
|
int err;
|
|||
|
|
|||
|
switch (thread_model)
|
|||
|
{
|
|||
|
case ath_model_none:
|
|||
|
*lock = MUTEX_UNLOCKED;
|
|||
|
err = 0;
|
|||
|
break;
|
|||
|
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
case ath_model_pthreads_weak:
|
|||
|
{
|
|||
|
pthread_mutex_t *plck;
|
|||
|
|
|||
|
plck = malloc (sizeof *plck);
|
|||
|
if (!plck)
|
|||
|
err = errno? errno : ENOMEM;
|
|||
|
else
|
|||
|
{
|
|||
|
err = pthread_mutex_init (plck, NULL);
|
|||
|
if (err)
|
|||
|
free (plck);
|
|||
|
else
|
|||
|
*lock = (void*)plck;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
#endif /*USE_POSIX_THREADS_WEAK*/
|
|||
|
|
|||
|
default:
|
|||
|
err = EINVAL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Destroy a mutex. This function is a NOP if LOCK is NULL. If the
|
|||
|
mutex is still locked it can't be destroyed and the function
|
|||
|
returns EBUSY. ERRNO may or may not be changed on error. */
|
|||
|
int
|
|||
|
ath_mutex_destroy (ath_mutex_t *lock)
|
|||
|
{
|
|||
|
int err;
|
|||
|
|
|||
|
if (!*lock)
|
|||
|
return 0;
|
|||
|
|
|||
|
switch (thread_model)
|
|||
|
{
|
|||
|
case ath_model_none:
|
|||
|
if (*lock != MUTEX_UNLOCKED)
|
|||
|
err = EBUSY;
|
|||
|
else
|
|||
|
{
|
|||
|
*lock = MUTEX_DESTROYED;
|
|||
|
err = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
case ath_model_pthreads_weak:
|
|||
|
{
|
|||
|
pthread_mutex_t *plck = (pthread_mutex_t*)lock;
|
|||
|
|
|||
|
err = pthread_mutex_destroy (plck);
|
|||
|
if (!err)
|
|||
|
{
|
|||
|
free (plck);
|
|||
|
lock = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
#endif /*USE_POSIX_THREADS_WEAK*/
|
|||
|
|
|||
|
default:
|
|||
|
err = EINVAL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* Lock the mutex LOCK. On success the function returns 0; on error
|
|||
|
an error code. ERRNO may or may not be changed on error. */
|
|||
|
int
|
|||
|
ath_mutex_lock (ath_mutex_t *lock)
|
|||
|
{
|
|||
|
int err;
|
|||
|
|
|||
|
switch (thread_model)
|
|||
|
{
|
|||
|
case ath_model_none:
|
|||
|
if (*lock == MUTEX_NOTINIT)
|
|||
|
err = EINVAL;
|
|||
|
else if (*lock == MUTEX_UNLOCKED)
|
|||
|
{
|
|||
|
*lock = MUTEX_LOCKED;
|
|||
|
err = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
err = EDEADLK;
|
|||
|
break;
|
|||
|
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
case ath_model_pthreads_weak:
|
|||
|
err = pthread_mutex_lock ((pthread_mutex_t*)lock);
|
|||
|
break;
|
|||
|
#endif /*USE_POSIX_THREADS_WEAK*/
|
|||
|
|
|||
|
default:
|
|||
|
err = EINVAL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return err;
|
|||
|
}
|
|||
|
|
|||
|
/* Unlock the mutex LOCK. On success the function returns 0; on error
|
|||
|
an error code. ERRNO may or may not be changed on error. */
|
|||
|
int
|
|||
|
ath_mutex_unlock (ath_mutex_t *lock)
|
|||
|
{
|
|||
|
int err;
|
|||
|
|
|||
|
switch (thread_model)
|
|||
|
{
|
|||
|
case ath_model_none:
|
|||
|
if (*lock == MUTEX_NOTINIT)
|
|||
|
err = EINVAL;
|
|||
|
else if (*lock == MUTEX_LOCKED)
|
|||
|
{
|
|||
|
*lock = MUTEX_UNLOCKED;
|
|||
|
err = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
err = EPERM;
|
|||
|
break;
|
|||
|
|
|||
|
#if USE_POSIX_THREADS_WEAK
|
|||
|
case ath_model_pthreads_weak:
|
|||
|
err = pthread_mutex_unlock ((pthread_mutex_t*)lock);
|
|||
|
break;
|
|||
|
#endif /*USE_POSIX_THREADS_WEAK*/
|
|||
|
|
|||
|
default:
|
|||
|
err = EINVAL;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return err;
|
|||
|
}
|