|
Packit |
fc043f |
/* posix-lock.c - GPGRT lock functions for POSIX systems
|
|
Packit |
fc043f |
Copyright (C) 2005-2009 Free Software Foundation, Inc.
|
|
Packit |
fc043f |
Copyright (C) 2014 g10 Code GmbH
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
This file is part of libgpg-error.
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
libgpg-error is free software; you can redistribute it and/or
|
|
Packit |
fc043f |
modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
fc043f |
as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
fc043f |
the License, or (at your option) any later version.
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
libgpg-error is distributed in the hope that it will be useful, but
|
|
Packit |
fc043f |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
fc043f |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
fc043f |
Lesser General Public License for more details.
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
fc043f |
License along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
Parts of the code, in particular use_pthreads_p, are based on code
|
|
Packit |
fc043f |
from gettext, written by Bruno Haible <bruno@clisp.org>, 2005.
|
|
Packit |
fc043f |
*/
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if HAVE_CONFIG_H
|
|
Packit |
fc043f |
#include <config.h>
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#ifdef HAVE_W32_SYSTEM
|
|
Packit |
fc043f |
# error This module may not be build for Windows.
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#include <stdlib.h>
|
|
Packit |
fc043f |
#include <stdio.h>
|
|
Packit |
fc043f |
#include <string.h>
|
|
Packit |
fc043f |
#include <errno.h>
|
|
Packit |
fc043f |
#include <assert.h>
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
# include <pthread.h>
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#include "gpgrt-int.h"
|
|
Packit |
fc043f |
#include "lock.h"
|
|
Packit |
fc043f |
#include "posix-lock-obj.h"
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
# if USE_POSIX_THREADS_WEAK
|
|
Packit |
fc043f |
/* On ELF systems it is easy to use pthreads using weak
|
|
Packit |
fc043f |
references. Take care not to test the address of a weak
|
|
Packit |
fc043f |
referenced function we actually use; some GCC versions have a
|
|
Packit |
fc043f |
bug were &foo != NULL is always evaluated to true in PIC mode. */
|
|
Packit |
fc043f |
# pragma weak pthread_cancel
|
|
Packit |
fc043f |
# pragma weak pthread_mutex_init
|
|
Packit |
fc043f |
# pragma weak pthread_mutex_lock
|
|
Packit |
fc043f |
# pragma weak pthread_mutex_trylock
|
|
Packit |
fc043f |
# pragma weak pthread_mutex_unlock
|
|
Packit |
fc043f |
# pragma weak pthread_mutex_destroy
|
|
Packit |
fc043f |
# if ! PTHREAD_IN_USE_DETECTION_HARD
|
|
Packit |
fc043f |
# define use_pthread_p() (!!pthread_cancel)
|
|
Packit |
fc043f |
# endif
|
|
Packit |
fc043f |
# else /*!USE_POSIX_THREADS_WEAK*/
|
|
Packit |
fc043f |
# if ! PTHREAD_IN_USE_DETECTION_HARD
|
|
Packit |
fc043f |
# define use_pthread_p() (1)
|
|
Packit |
fc043f |
# endif
|
|
Packit |
fc043f |
# endif /*!USE_POSIX_THREADS_WEAK*/
|
|
Packit |
fc043f |
# if PTHREAD_IN_USE_DETECTION_HARD
|
|
Packit |
fc043f |
/* The function to be executed by a dummy thread. */
|
|
Packit |
fc043f |
static void *
|
|
Packit |
fc043f |
dummy_thread_func (void *arg)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
return arg;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
static int
|
|
Packit |
fc043f |
use_pthread_p (void)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
static int tested;
|
|
Packit |
fc043f |
static int result; /* 1: linked with -lpthread, 0: only with libc */
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
if (!tested)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
pthread_t thread;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
if (pthread_create (&thread, NULL, dummy_thread_func, NULL))
|
|
Packit |
fc043f |
result = 0; /* Thread creation failed. */
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Thread creation works. */
|
|
Packit |
fc043f |
void *retval;
|
|
Packit |
fc043f |
if (pthread_join (thread, &retval) != 0)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
assert (!"pthread_join");
|
|
Packit |
fc043f |
abort ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
result = 1;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
tested = 1;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
return result;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
#endif /*PTHREAD_IN_USE_DETECTION_HARD*/
|
|
Packit |
fc043f |
#endif /*USE_POSIX_THREADS*/
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
static _gpgrt_lock_t *
|
|
Packit |
fc043f |
get_lock_object (gpgrt_lock_t *lockhd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
if (lock->vers != LOCK_ABI_VERSION)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
assert (!"lock ABI version");
|
|
Packit |
fc043f |
abort ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
assert (!"sizeof lock obj");
|
|
Packit |
fc043f |
abort ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return lock;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_lock_init (gpgrt_lock_t *lockhd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
|
|
Packit |
fc043f |
int rc;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* If VERS is zero we assume that no static initialization has been
|
|
Packit |
fc043f |
done, so we setup our ABI version right here. The caller might
|
|
Packit |
fc043f |
have called us to test whether lock support is at all available. */
|
|
Packit |
fc043f |
if (!lock->vers)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
assert (!"sizeof lock obj");
|
|
Packit |
fc043f |
abort ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
lock->vers = LOCK_ABI_VERSION;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else /* Run the usual check. */
|
|
Packit |
fc043f |
lock = get_lock_object (lockhd);
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
if (use_pthread_p())
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
rc = pthread_mutex_init (&lock->u.mtx, NULL);
|
|
Packit |
fc043f |
if (rc)
|
|
Packit |
fc043f |
rc = _gpg_err_code_from_errno (rc);
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
rc = 0; /* Threads are not used. */
|
|
Packit |
fc043f |
#else /* Unknown thread system. */
|
|
Packit |
fc043f |
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
|
|
Packit |
fc043f |
#endif /* Unknown thread system. */
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return rc;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_lock_lock (gpgrt_lock_t *lockhd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_lock_t *lock = get_lock_object (lockhd);
|
|
Packit |
fc043f |
int rc;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
if (use_pthread_p())
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_pre_syscall ();
|
|
Packit |
fc043f |
rc = pthread_mutex_lock (&lock->u.mtx);
|
|
Packit |
fc043f |
if (rc)
|
|
Packit |
fc043f |
rc = _gpg_err_code_from_errno (rc);
|
|
Packit |
fc043f |
_gpgrt_post_syscall ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
rc = 0; /* Threads are not used. */
|
|
Packit |
fc043f |
#else /* Unknown thread system. */
|
|
Packit |
fc043f |
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
|
|
Packit |
fc043f |
#endif /* Unknown thread system. */
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return rc;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_lock_trylock (gpgrt_lock_t *lockhd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_lock_t *lock = get_lock_object (lockhd);
|
|
Packit |
fc043f |
int rc;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
if (use_pthread_p())
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
rc = pthread_mutex_trylock (&lock->u.mtx);
|
|
Packit |
fc043f |
if (rc)
|
|
Packit |
fc043f |
rc = _gpg_err_code_from_errno (rc);
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
rc = 0; /* Threads are not used. */
|
|
Packit |
fc043f |
#else /* Unknown thread system. */
|
|
Packit |
fc043f |
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
|
|
Packit |
fc043f |
#endif /* Unknown thread system. */
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return rc;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_lock_t *lock = get_lock_object (lockhd);
|
|
Packit |
fc043f |
int rc;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
if (use_pthread_p())
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
rc = pthread_mutex_unlock (&lock->u.mtx);
|
|
Packit |
fc043f |
if (rc)
|
|
Packit |
fc043f |
rc = _gpg_err_code_from_errno (rc);
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
rc = 0; /* Threads are not used. */
|
|
Packit |
fc043f |
#else /* Unknown thread system. */
|
|
Packit |
fc043f |
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
|
|
Packit |
fc043f |
#endif /* Unknown thread system. */
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return rc;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* Note: Use this function only if no other thread holds or waits for
|
|
Packit |
fc043f |
this lock. */
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpgrt_lock_t *lock = get_lock_object (lockhd);
|
|
Packit |
fc043f |
int rc;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#if USE_POSIX_THREADS
|
|
Packit |
fc043f |
if (use_pthread_p())
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
rc = pthread_mutex_destroy (&lock->u.mtx);
|
|
Packit |
fc043f |
if (rc)
|
|
Packit |
fc043f |
rc = _gpg_err_code_from_errno (rc);
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Re-init the mutex so that it can be re-used. */
|
|
Packit |
fc043f |
gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
|
|
Packit |
fc043f |
memcpy (lockhd, &tmp, sizeof tmp);
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
rc = 0; /* Threads are not used. */
|
|
Packit |
fc043f |
#else /* Unknown thread system. */
|
|
Packit |
fc043f |
rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
|
|
Packit |
fc043f |
#endif /* Unknown thread system. */
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return rc;
|
|
Packit |
fc043f |
}
|