LCOV - code coverage report
Current view: top level - src - posix-lock.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 31 44 70.5 %
Date: 2016-12-01 18:27:36 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /* posix-lock.c - GPGRT lock functions for POSIX systems
       2             :    Copyright (C) 2005-2009 Free Software Foundation, Inc.
       3             :    Copyright (C) 2014 g10 Code GmbH
       4             : 
       5             :    This file is part of libgpg-error.
       6             : 
       7             :    libgpg-error is free software; you can redistribute it and/or
       8             :    modify it under the terms of the GNU Lesser General Public License
       9             :    as published by the Free Software Foundation; either version 2.1 of
      10             :    the License, or (at your option) any later version.
      11             : 
      12             :    libgpg-error is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, see <https://www.gnu.org/licenses/>.
      19             : 
      20             :    Parts of the code, in particular use_pthreads_p, are based on code
      21             :    from gettext, written by Bruno Haible <bruno@clisp.org>, 2005.
      22             :  */
      23             : 
      24             : #if HAVE_CONFIG_H
      25             : #include <config.h>
      26             : #endif
      27             : 
      28             : #ifdef HAVE_W32_SYSTEM
      29             : # error This module may not be build for Windows.
      30             : #endif
      31             : 
      32             : #include <stdlib.h>
      33             : #include <stdio.h>
      34             : #include <string.h>
      35             : #include <errno.h>
      36             : #include <assert.h>
      37             : 
      38             : #if USE_POSIX_THREADS
      39             : # include <pthread.h>
      40             : #endif
      41             : 
      42             : #include "gpg-error.h"
      43             : #include "lock.h"
      44             : #include "posix-lock-obj.h"
      45             : 
      46             : 
      47             : /*
      48             :  * Functions called before and after blocking syscalls.
      49             :  * gpgrt_set_syscall_clamp is used to set them.
      50             :  */
      51             : static void (*pre_lock_func)(void);
      52             : static void (*post_lock_func)(void);
      53             : 
      54             : 
      55             : #if USE_POSIX_THREADS
      56             : # if USE_POSIX_THREADS_WEAK
      57             :    /* On ELF systems it is easy to use pthreads using weak
      58             :       references.  Take care not to test the address of a weak
      59             :       referenced function we actually use; some GCC versions have a
      60             :       bug were &foo != NULL is always evaluated to true in PIC mode.  */
      61             : #  pragma weak pthread_cancel
      62             : #  pragma weak pthread_mutex_init
      63             : #  pragma weak pthread_mutex_lock
      64             : #  pragma weak pthread_mutex_trylock
      65             : #  pragma weak pthread_mutex_unlock
      66             : #  pragma weak pthread_mutex_destroy
      67             : #  if ! PTHREAD_IN_USE_DETECTION_HARD
      68             : #   define use_pthread_p() (!!pthread_cancel)
      69             : #  endif
      70             : # else /*!USE_POSIX_THREADS_WEAK*/
      71             : #  if ! PTHREAD_IN_USE_DETECTION_HARD
      72             : #   define use_pthread_p() (1)
      73             : #  endif
      74             : # endif /*!USE_POSIX_THREADS_WEAK*/
      75             : # if PTHREAD_IN_USE_DETECTION_HARD
      76             : /* The function to be executed by a dummy thread.  */
      77             : static void *
      78             : dummy_thread_func (void *arg)
      79             : {
      80             :   return arg;
      81             : }
      82             : 
      83             : static int
      84             : use_pthread_p (void)
      85             : {
      86             :   static int tested;
      87             :   static int result; /* 1: linked with -lpthread, 0: only with libc */
      88             : 
      89             :   if (!tested)
      90             :     {
      91             :       pthread_t thread;
      92             : 
      93             :       if (pthread_create (&thread, NULL, dummy_thread_func, NULL))
      94             :         result = 0; /* Thread creation failed.  */
      95             :       else
      96             :         {
      97             :           /* Thread creation works.  */
      98             :           void *retval;
      99             :           if (pthread_join (thread, &retval) != 0)
     100             :             {
     101             :               assert (!"pthread_join");
     102             :               abort ();
     103             :             }
     104             :           result = 1;
     105             :         }
     106             :       tested = 1;
     107             :     }
     108             :   return result;
     109             : }
     110             : #endif /*PTHREAD_IN_USE_DETECTION_HARD*/
     111             : #endif /*USE_POSIX_THREADS*/
     112             : 
     113             : 
     114             : /* Helper to set the clamp functions.  This is called as a helper from
     115             :  * _gpgrt_set_syscall_clamp to keep the function pointers local. */
     116             : void
     117           6 : _gpgrt_lock_set_lock_clamp (void (*pre)(void), void (*post)(void))
     118             : {
     119           6 :   pre_lock_func = pre;
     120           6 :   post_lock_func = post;
     121           6 : }
     122             : 
     123             : 
     124             : 
     125             : static _gpgrt_lock_t *
     126             : get_lock_object (gpgrt_lock_t *lockhd)
     127             : {
     128             :   _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
     129             : 
     130       37901 :   if (lock->vers != LOCK_ABI_VERSION)
     131             :     {
     132           0 :       assert (!"lock ABI version");
     133             :       abort ();
     134             :     }
     135             :   if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
     136             :     {
     137             :       assert (!"sizeof lock obj");
     138             :       abort ();
     139             :     }
     140             : 
     141             :   return lock;
     142             : }
     143             : 
     144             : 
     145             : gpg_err_code_t
     146           7 : _gpgrt_lock_init (gpgrt_lock_t *lockhd)
     147             : {
     148             :   _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
     149             :   int rc;
     150             : 
     151             :   /* If VERS is zero we assume that no static initialization has been
     152             :      done, so we setup our ABI version right here.  The caller might
     153             :      have called us to test whether lock support is at all available. */
     154           7 :   if (!lock->vers)
     155             :     {
     156             :       if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
     157             :         {
     158             :           assert (!"sizeof lock obj");
     159             :           abort ();
     160             :         }
     161           6 :       lock->vers = LOCK_ABI_VERSION;
     162             :     }
     163             :   else /* Run the usual check.  */
     164             :     lock = get_lock_object (lockhd);
     165             : 
     166             : #if USE_POSIX_THREADS
     167           7 :   if (use_pthread_p())
     168             :     {
     169           7 :       rc = pthread_mutex_init (&lock->u.mtx, NULL);
     170           7 :       if (rc)
     171           0 :         rc = gpg_err_code_from_errno (rc);
     172             :     }
     173             :   else
     174             :     rc = 0; /* Threads are not used.  */
     175             : #else /* Unknown thread system.  */
     176             :   rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
     177             : #endif /* Unknown thread system.  */
     178             : 
     179           7 :   return rc;
     180             : }
     181             : 
     182             : 
     183             : gpg_err_code_t
     184       18710 : _gpgrt_lock_lock (gpgrt_lock_t *lockhd)
     185             : {
     186             :   _gpgrt_lock_t *lock = get_lock_object (lockhd);
     187             :   int rc;
     188             : 
     189             : #if USE_POSIX_THREADS
     190       18710 :   if (use_pthread_p())
     191             :     {
     192       18742 :       if (pre_lock_func)
     193           0 :         pre_lock_func ();
     194       18742 :       rc = pthread_mutex_lock (&lock->u.mtx);
     195       19177 :       if (rc)
     196           0 :         rc = gpg_err_code_from_errno (rc);
     197       19177 :       if (post_lock_func)
     198           0 :         post_lock_func ();
     199             :     }
     200             :   else
     201             :     rc = 0; /* Threads are not used.  */
     202             : #else /* Unknown thread system.  */
     203             :   rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
     204             : #endif /* Unknown thread system.  */
     205             : 
     206       19145 :   return rc;
     207             : }
     208             : 
     209             : 
     210             : gpg_err_code_t
     211           0 : _gpgrt_lock_trylock (gpgrt_lock_t *lockhd)
     212             : {
     213             :   _gpgrt_lock_t *lock = get_lock_object (lockhd);
     214             :   int rc;
     215             : 
     216             : #if USE_POSIX_THREADS
     217           0 :   if (use_pthread_p())
     218             :     {
     219           0 :       rc = pthread_mutex_trylock (&lock->u.mtx);
     220           0 :       if (rc)
     221           0 :         rc = gpg_err_code_from_errno (rc);
     222             :     }
     223             :   else
     224             :     rc = 0; /* Threads are not used.  */
     225             : #else /* Unknown thread system.  */
     226             :   rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
     227             : #endif /* Unknown thread system.  */
     228             : 
     229           0 :   return rc;
     230             : }
     231             : 
     232             : 
     233             : gpg_err_code_t
     234       19181 : _gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
     235             : {
     236             :   _gpgrt_lock_t *lock = get_lock_object (lockhd);
     237             :   int rc;
     238             : 
     239             : #if USE_POSIX_THREADS
     240       19181 :   if (use_pthread_p())
     241             :     {
     242       19177 :       rc = pthread_mutex_unlock (&lock->u.mtx);
     243       18983 :       if (rc)
     244           0 :         rc = gpg_err_code_from_errno (rc);
     245             :     }
     246             :   else
     247             :     rc = 0; /* Threads are not used.  */
     248             : #else /* Unknown thread system.  */
     249             :   rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
     250             : #endif /* Unknown thread system.  */
     251             : 
     252       18987 :   return rc;
     253             : }
     254             : 
     255             : 
     256             : /* Note: Use this function only if no other thread holds or waits for
     257             :    this lock.  */
     258             : gpg_err_code_t
     259           9 : _gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
     260             : {
     261             :   _gpgrt_lock_t *lock = get_lock_object (lockhd);
     262             :   int rc;
     263             : 
     264             : #if USE_POSIX_THREADS
     265           9 :   if (use_pthread_p())
     266             :     {
     267           9 :       rc = pthread_mutex_destroy (&lock->u.mtx);
     268           9 :       if (rc)
     269           0 :         rc = gpg_err_code_from_errno (rc);
     270             :       else
     271             :         {
     272             :           /* Re-init the mutex so that it can be re-used.  */
     273           9 :           gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
     274           9 :           memcpy (lockhd, &tmp, sizeof tmp);
     275             :         }
     276             :     }
     277             :   else
     278             :     rc = 0; /* Threads are not used.  */
     279             : #else /* Unknown thread system.  */
     280             :   rc = lock->vers == LOCK_ABI_NOT_AVAILABLE? 0 : GPG_ERR_NOT_IMPLEMENTED;
     281             : #endif /* Unknown thread system.  */
     282             : 
     283           9 :   return rc;
     284             : }

Generated by: LCOV version 1.11