#if HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_W32_SYSTEM
# error This module may not be build for Windows.
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#if USE_POSIX_THREADS
# include <pthread.h>
#endif
#include "gpg-error.h"
#include "lock.h"
#include "posix-lock-obj.h"
static void (*pre_lock_func)(void);
static void (*post_lock_func)(void);
#if USE_POSIX_THREADS
# if USE_POSIX_THREADS_WEAK
# pragma weak pthread_cancel
# pragma weak pthread_mutex_init
# pragma weak pthread_mutex_lock
# pragma weak pthread_mutex_trylock
# pragma weak pthread_mutex_unlock
# pragma weak pthread_mutex_destroy
# if ! PTHREAD_IN_USE_DETECTION_HARD
# define use_pthread_p() (!!pthread_cancel)
# endif
# else
# if ! PTHREAD_IN_USE_DETECTION_HARD
# define use_pthread_p() (1)
# endif
# endif
# if PTHREAD_IN_USE_DETECTION_HARD
static void *
dummy_thread_func (void *arg)
{
return arg;
}
static int
use_pthread_p (void)
{
static int tested;
static int result;
if (!tested)
{
pthread_t thread;
if (pthread_create (&thread, NULL, dummy_thread_func, NULL))
result = 0;
else
{
void *retval;
if (pthread_join (thread, &retval) != 0)
{
assert (!"pthread_join");
abort ();
}
result = 1;
}
tested = 1;
}
return result;
}
#endif
#endif
void
_gpgrt_lock_set_lock_clamp (void (*pre)(void), void (*post)(void))
{
pre_lock_func = pre;
post_lock_func = post;
}
static _gpgrt_lock_t *
get_lock_object (gpgrt_lock_t *lockhd)
{
_gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
if (lock->vers != LOCK_ABI_VERSION)
{
assert (!"lock ABI version");
abort ();
}
if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
{
assert (!"sizeof lock obj");
abort ();
}
return lock;
}
gpg_err_code_t
_gpgrt_lock_init (gpgrt_lock_t *lockhd)
{
_gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
int rc;
if (!lock->vers)
{
if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
{
assert (!"sizeof lock obj");
abort ();
}
lock->vers = LOCK_ABI_VERSION;
}
else
lock = get_lock_object (lockhd);
#if USE_POSIX_THREADS
if (use_pthread_p())
{
rc = pthread_mutex_init (&lock->u.mtx, NULL);
if (rc)
rc = gpg_err_code_from_errno (rc);
}
else
rc = 0;
#else
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
#endif
return rc;
}
gpg_err_code_t
_gpgrt_lock_lock (gpgrt_lock_t *lockhd)
{
_gpgrt_lock_t *lock = get_lock_object (lockhd);
int rc;
#if USE_POSIX_THREADS
if (use_pthread_p())
{
if (pre_lock_func)
pre_lock_func ();
rc = pthread_mutex_lock (&lock->u.mtx);
if (rc)
rc = gpg_err_code_from_errno (rc);
if (post_lock_func)
post_lock_func ();
}
else
rc = 0;
#else
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
#endif
return rc;
}
gpg_err_code_t
_gpgrt_lock_trylock (gpgrt_lock_t *lockhd)
{
_gpgrt_lock_t *lock = get_lock_object (lockhd);
int rc;
#if USE_POSIX_THREADS
if (use_pthread_p())
{
rc = pthread_mutex_trylock (&lock->u.mtx);
if (rc)
rc = gpg_err_code_from_errno (rc);
}
else
rc = 0;
#else
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
#endif
return rc;
}
gpg_err_code_t
_gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
{
_gpgrt_lock_t *lock = get_lock_object (lockhd);
int rc;
#if USE_POSIX_THREADS
if (use_pthread_p())
{
rc = pthread_mutex_unlock (&lock->u.mtx);
if (rc)
rc = gpg_err_code_from_errno (rc);
}
else
rc = 0;
#else
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
#endif
return rc;
}
gpg_err_code_t
_gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
{
_gpgrt_lock_t *lock = get_lock_object (lockhd);
int rc;
#if USE_POSIX_THREADS
if (use_pthread_p())
{
rc = pthread_mutex_destroy (&lock->u.mtx);
if (rc)
rc = gpg_err_code_from_errno (rc);
else
{
gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
memcpy (lockhd, &tmp, sizeof tmp);
}
}
else
rc = 0;
#else
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
#endif
return rc;
}