tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

compat_winthreads.c (4046B)


      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_winthreads.c
      8 *
      9 * \brief Implementation for the windows-based multithreading backend
     10 * functions.
     11 */
     12 
     13 #include "orconfig.h"
     14 
     15 #ifdef _WIN32
     16 /* For condition variable support */
     17 #ifndef WINVER
     18 #error "orconfig.h didn't define WINVER"
     19 #endif
     20 #ifndef _WIN32_WINNT
     21 #error "orconfig.h didn't define _WIN32_WINNT"
     22 #endif
     23 #if WINVER < 0x0600
     24 #error "winver too low"
     25 #endif
     26 #if _WIN32_WINNT < 0x0600
     27 #error "winver too low"
     28 #endif
     29 
     30 #include <windows.h>
     31 #include <process.h>
     32 #include <time.h>
     33 
     34 #include "lib/thread/threads.h"
     35 #include "lib/log/log.h"
     36 #include "lib/log/util_bug.h"
     37 #include "lib/log/win32err.h"
     38 
     39 /** Minimalist interface to run a void function in the background.  On
     40 * Unix calls fork, on win32 calls beginthread.  Returns -1 on failure.
     41 * func should not return, but rather should call spawn_exit.
     42 *
     43 * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
     44 * since in a multithreaded environment, there is no way to be sure that
     45 * the caller's stack will still be around when the called function is
     46 * running.
     47 */
     48 int
     49 spawn_func(void (*func)(void *), void *data)
     50 {
     51  int rv;
     52  rv = (int)_beginthread(func, 0, data);
     53  if (rv == (int)-1)
     54    return -1;
     55  return 0;
     56 }
     57 
     58 /** End the current thread/process.
     59 */
     60 void
     61 spawn_exit(void)
     62 {
     63  _endthread();
     64  // LCOV_EXCL_START
     65  //we should never get here. my compiler thinks that _endthread returns, this
     66  //is an attempt to fool it.
     67  tor_assert(0);
     68  _exit(0); // exit ok: unreachable.
     69  // LCOV_EXCL_STOP
     70 }
     71 
     72 unsigned long
     73 tor_get_thread_id(void)
     74 {
     75  return (unsigned long)GetCurrentThreadId();
     76 }
     77 
     78 int
     79 tor_cond_init(tor_cond_t *cond)
     80 {
     81  InitializeConditionVariable(&cond->cond);
     82  return 0;
     83 }
     84 void
     85 tor_cond_uninit(tor_cond_t *cond)
     86 {
     87  (void) cond;
     88 }
     89 
     90 void
     91 tor_cond_signal_one(tor_cond_t *cond)
     92 {
     93  WakeConditionVariable(&cond->cond);
     94 }
     95 void
     96 tor_cond_signal_all(tor_cond_t *cond)
     97 {
     98  WakeAllConditionVariable(&cond->cond);
     99 }
    100 
    101 int
    102 tor_threadlocal_init(tor_threadlocal_t *threadlocal)
    103 {
    104  threadlocal->index = TlsAlloc();
    105  return (threadlocal->index == TLS_OUT_OF_INDEXES) ? -1 : 0;
    106 }
    107 
    108 void
    109 tor_threadlocal_destroy(tor_threadlocal_t *threadlocal)
    110 {
    111  TlsFree(threadlocal->index);
    112  memset(threadlocal, 0, sizeof(tor_threadlocal_t));
    113 }
    114 
    115 void *
    116 tor_threadlocal_get(tor_threadlocal_t *threadlocal)
    117 {
    118  void *value = TlsGetValue(threadlocal->index);
    119  if (value == NULL) {
    120    DWORD err = GetLastError();
    121    if (err != ERROR_SUCCESS) {
    122      char *msg = format_win32_error(err);
    123      log_err(LD_GENERAL, "Error retrieving thread-local value: %s", msg);
    124      tor_free(msg);
    125      tor_assert(err == ERROR_SUCCESS);
    126    }
    127  }
    128  return value;
    129 }
    130 
    131 void
    132 tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
    133 {
    134  BOOL ok = TlsSetValue(threadlocal->index, value);
    135  if (!ok) {
    136    DWORD err = GetLastError();
    137    char *msg = format_win32_error(err);
    138    log_err(LD_GENERAL, "Error adjusting thread-local value: %s", msg);
    139    tor_free(msg);
    140    tor_assert(ok);
    141  }
    142 }
    143 
    144 int
    145 tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv)
    146 {
    147  // recursive SRW locks are not supported because they need extra logic for
    148  // acquiring and releasing but SleepConditionVariableSRW will use the OS
    149  // lock release function which lacks our extra logic
    150  tor_assert(lock_->type == NON_RECURSIVE);
    151  SRWLOCK *lock = &lock_->mutex;
    152  DWORD ms = INFINITE;
    153  if (tv) {
    154    ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000;
    155  }
    156 
    157  BOOL ok = SleepConditionVariableSRW(&cond->cond, lock, ms, 0);
    158  if (!ok) {
    159    DWORD err = GetLastError();
    160    if (err == ERROR_TIMEOUT) {
    161      return 1;
    162    }
    163    char *msg = format_win32_error(err);
    164    log_err(LD_GENERAL, "Error waiting for condition variable: %s", msg);
    165    tor_free(msg);
    166    return -1;
    167  }
    168  return 0;
    169 }
    170 
    171 void
    172 tor_threads_init(void)
    173 {
    174  set_main_thread();
    175 }
    176 
    177 #endif /* defined(_WIN32) */