Blame src/posix-lock.c

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
}