LCOV - code coverage report
Current view: top level - lib/thread - compat_pthreads.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 84 89 94.4 %
Date: 2021-11-24 03:28:48 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2003-2004, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file compat_pthreads.c
       8             :  *
       9             :  * \brief Implementation for the pthreads-based multithreading backend
      10             :  * functions.
      11             :  */
      12             : 
      13             : #include "orconfig.h"
      14             : #include "lib/thread/threads.h"
      15             : #include "lib/wallclock/timeval.h"
      16             : #include "lib/log/log.h"
      17             : #include "lib/log/util_bug.h"
      18             : 
      19             : #include <sys/time.h>
      20             : #include <pthread.h>
      21             : #include <signal.h>
      22             : #include <time.h>
      23             : #include <errno.h>
      24             : #include <string.h>
      25             : 
      26             : /** Wraps a void (*)(void*) function and its argument so we can
      27             :  * invoke them in a way pthreads would expect.
      28             :  */
      29             : typedef struct tor_pthread_data_t {
      30             :   void (*func)(void *);
      31             :   void *data;
      32             : } tor_pthread_data_t;
      33             : /** Given a tor_pthread_data_t <b>_data</b>, call _data-&gt;func(d-&gt;data)
      34             :  * and free _data.  Used to make sure we can call functions the way pthread
      35             :  * expects. */
      36             : static void *
      37          66 : tor_pthread_helper_fn(void *_data)
      38             : {
      39          66 :   tor_pthread_data_t *data = _data;
      40          66 :   void (*func)(void*);
      41          66 :   void *arg;
      42             :   /* mask signals to worker threads to avoid SIGPIPE, etc */
      43          66 :   sigset_t sigs;
      44             :   /* We're in a subthread; don't handle any signals here. */
      45          66 :   sigfillset(&sigs);
      46          66 :   pthread_sigmask(SIG_SETMASK, &sigs, NULL);
      47             : 
      48          66 :   func = data->func;
      49          66 :   arg = data->data;
      50          66 :   tor_free(_data);
      51          66 :   func(arg);
      52          50 :   return NULL;
      53             : }
      54             : /**
      55             :  * A pthread attribute to make threads start detached.
      56             :  */
      57             : static pthread_attr_t attr_detached;
      58             : /** True iff we've called tor_threads_init() */
      59             : static int threads_initialized = 0;
      60             : 
      61             : /** Minimalist interface to run a void function in the background.  On
      62             :  * Unix calls pthread_create, on win32 calls beginthread.  Returns -1 on
      63             :  * failure.
      64             :  * func should not return, but rather should call spawn_exit.
      65             :  *
      66             :  * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
      67             :  * since in a multithreaded environment, there is no way to be sure that
      68             :  * the caller's stack will still be around when the called function is
      69             :  * running.
      70             :  */
      71             : int
      72          66 : spawn_func(void (*func)(void *), void *data)
      73             : {
      74          66 :   pthread_t thread;
      75          66 :   tor_pthread_data_t *d;
      76          66 :   if (PREDICT_UNLIKELY(!threads_initialized)) {
      77           7 :     tor_threads_init();
      78             :   }
      79          66 :   d = tor_malloc(sizeof(tor_pthread_data_t));
      80          66 :   d->data = data;
      81          66 :   d->func = func;
      82          66 :   if (pthread_create(&thread, &attr_detached, tor_pthread_helper_fn, d)) {
      83           0 :     tor_free(d);
      84           0 :     return -1;
      85             :   }
      86             : 
      87             :   return 0;
      88             : }
      89             : 
      90             : /** End the current thread/process.
      91             :  */
      92             : void
      93          10 : spawn_exit(void)
      94             : {
      95          10 :   pthread_exit(NULL);
      96             : }
      97             : 
      98             : /** Return an integer representing this thread. */
      99             : unsigned long
     100        5602 : tor_get_thread_id(void)
     101             : {
     102        5602 :   union {
     103             :     pthread_t thr;
     104             :     unsigned long id;
     105             :   } r;
     106        5602 :   r.thr = pthread_self();
     107        5602 :   return r.id;
     108             : }
     109             : 
     110             : /* Conditions. */
     111             : 
     112             : /** Initialize an already-allocated condition variable. */
     113             : int
     114           9 : tor_cond_init(tor_cond_t *cond)
     115             : {
     116           9 :   pthread_condattr_t condattr;
     117             : 
     118           9 :   memset(cond, 0, sizeof(tor_cond_t));
     119             :   /* Default condition attribute. Might be used if clock monotonic is
     120             :    * available else this won't affect anything. */
     121           9 :   if (pthread_condattr_init(&condattr)) {
     122             :     return -1;
     123             :   }
     124             : 
     125             : #if defined(HAVE_CLOCK_GETTIME)
     126             : #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
     127             :   defined(CLOCK_MONOTONIC)
     128             :   /* Use monotonic time so when we timedwait() on it, any clock adjustment
     129             :    * won't affect the timeout value. */
     130           9 :   if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) {
     131             :     return -1;
     132             :   }
     133             : #define USE_COND_CLOCK CLOCK_MONOTONIC
     134             : #else /* !(defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ...) */
     135             :   /* On OSX Sierra, there is no pthread_condattr_setclock, so we are stuck
     136             :    * with the realtime clock.
     137             :    */
     138             : #define USE_COND_CLOCK CLOCK_REALTIME
     139             : #endif /* defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ... */
     140             : #endif /* defined(HAVE_CLOCK_GETTIME) */
     141           9 :   if (pthread_cond_init(&cond->cond, &condattr)) {
     142           0 :     return -1;
     143             :   }
     144             :   return 0;
     145             : }
     146             : 
     147             : /** Release all resources held by <b>cond</b>, but do not free <b>cond</b>
     148             :  * itself. */
     149             : void
     150           2 : tor_cond_uninit(tor_cond_t *cond)
     151             : {
     152           2 :   if (pthread_cond_destroy(&cond->cond)) {
     153             :     // LCOV_EXCL_START
     154             :     log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
     155             :     return;
     156             :     // LCOV_EXCL_STOP
     157             :   }
     158             : }
     159             : /** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
     160             :  * (If <b>tv</b> is set, and that amount of time passes with no signal to
     161             :  * <b>cond</b>, return anyway.  All waiters on the condition must wait holding
     162             :  * the same <b>mutex</b>.  All signallers should hold that mutex.  The mutex
     163             :  * needs to have been allocated with tor_mutex_init_for_cond().
     164             :  *
     165             :  * Returns 0 on success, -1 on failure, 1 on timeout. */
     166             : int
     167         244 : tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv)
     168             : {
     169         244 :   int r;
     170         244 :   if (tv == NULL) {
     171         235 :     while (1) {
     172         235 :       r = pthread_cond_wait(&cond->cond, &mutex->mutex);
     173         235 :       if (r == EINTR) {
     174             :         /* EINTR should be impossible according to POSIX, but POSIX, like the
     175             :          * Pirate's Code, is apparently treated "more like what you'd call
     176             :          * guidelines than actual rules." */
     177             :         continue; // LCOV_EXCL_LINE
     178             :       }
     179         235 :       return r ? -1 : 0;
     180             :     }
     181             :   } else {
     182           9 :     struct timeval tvnow, tvsum;
     183           9 :     struct timespec ts;
     184           9 :     while (1) {
     185             : #if defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)
     186           9 :       if (clock_gettime(USE_COND_CLOCK, &ts) < 0) {
     187             :         return -1;
     188             :       }
     189           9 :       tvnow.tv_sec = ts.tv_sec;
     190           9 :       tvnow.tv_usec = (int)(ts.tv_nsec / 1000);
     191           9 :       timeradd(tv, &tvnow, &tvsum);
     192             : #else /* !(defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)) */
     193             :       if (gettimeofday(&tvnow, NULL) < 0)
     194             :         return -1;
     195             :       timeradd(tv, &tvnow, &tvsum);
     196             : #endif /* defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK) */
     197             : 
     198           9 :       ts.tv_sec = tvsum.tv_sec;
     199           9 :       ts.tv_nsec = tvsum.tv_usec * 1000;
     200             : 
     201           9 :       r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts);
     202           9 :       if (r == 0)
     203             :         return 0;
     204           2 :       else if (r == ETIMEDOUT)
     205             :         return 1;
     206           0 :       else if (r == EINTR)
     207           0 :         continue;
     208             :       else
     209             :         return -1;
     210             :     }
     211             :   }
     212             : }
     213             : /** Wake up one of the waiters on <b>cond</b>. */
     214             : void
     215       70011 : tor_cond_signal_one(tor_cond_t *cond)
     216             : {
     217       70011 :   pthread_cond_signal(&cond->cond);
     218       70011 : }
     219             : /** Wake up all of the waiters on <b>cond</b>. */
     220             : void
     221          11 : tor_cond_signal_all(tor_cond_t *cond)
     222             : {
     223          11 :   pthread_cond_broadcast(&cond->cond);
     224          11 : }
     225             : 
     226             : int
     227        5575 : tor_threadlocal_init(tor_threadlocal_t *threadlocal)
     228             : {
     229        5575 :   int err = pthread_key_create(&threadlocal->key, NULL);
     230        5575 :   return err ? -1 : 0;
     231             : }
     232             : 
     233             : void
     234         235 : tor_threadlocal_destroy(tor_threadlocal_t *threadlocal)
     235             : {
     236         235 :   pthread_key_delete(threadlocal->key);
     237         235 :   memset(threadlocal, 0, sizeof(tor_threadlocal_t));
     238         235 : }
     239             : 
     240             : void *
     241    12695047 : tor_threadlocal_get(tor_threadlocal_t *threadlocal)
     242             : {
     243    12695047 :   return pthread_getspecific(threadlocal->key);
     244             : }
     245             : 
     246             : void
     247         207 : tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
     248             : {
     249         207 :   int err = pthread_setspecific(threadlocal->key, value);
     250         207 :   tor_assert(err == 0);
     251         207 : }
     252             : 
     253             : /** Set up common structures for use by threading. */
     254             : void
     255        5560 : tor_threads_init(void)
     256             : {
     257        5560 :   if (!threads_initialized) {
     258        5560 :     tor_locking_init();
     259        5560 :     const int ret1 = pthread_attr_init(&attr_detached);
     260        5560 :     tor_assert(ret1 == 0);
     261             : #ifndef PTHREAD_CREATE_DETACHED
     262             : #define PTHREAD_CREATE_DETACHED 1
     263             : #endif
     264        5560 :     const int ret2 =
     265        5560 :       pthread_attr_setdetachstate(&attr_detached, PTHREAD_CREATE_DETACHED);
     266        5560 :     tor_assert(ret2 == 0);
     267        5560 :     threads_initialized = 1;
     268             :   }
     269        5560 :   set_main_thread();
     270        5560 : }

Generated by: LCOV version 1.14