Home | History | Annotate | Line # | Download | only in crypto
      1 /*
      2  * Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the OpenSSL license (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #if defined(_WIN32)
     11 # include <windows.h>
     12 #endif
     13 
     14 #include <openssl/crypto.h>
     15 
     16 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && defined(OPENSSL_SYS_WINDOWS)
     17 
     18 CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
     19 {
     20     CRYPTO_RWLOCK *lock;
     21 
     22     if ((lock = OPENSSL_zalloc(sizeof(CRITICAL_SECTION))) == NULL) {
     23         /* Don't set error, to avoid recursion blowup. */
     24         return NULL;
     25     }
     26 
     27 # if !defined(_WIN32_WCE)
     28     /* 0x400 is the spin count value suggested in the documentation */
     29     if (!InitializeCriticalSectionAndSpinCount(lock, 0x400)) {
     30         OPENSSL_free(lock);
     31         return NULL;
     32     }
     33 # else
     34     InitializeCriticalSection(lock);
     35 # endif
     36 
     37     return lock;
     38 }
     39 
     40 int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
     41 {
     42     EnterCriticalSection(lock);
     43     return 1;
     44 }
     45 
     46 int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
     47 {
     48     EnterCriticalSection(lock);
     49     return 1;
     50 }
     51 
     52 int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
     53 {
     54     LeaveCriticalSection(lock);
     55     return 1;
     56 }
     57 
     58 void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
     59 {
     60     if (lock == NULL)
     61         return;
     62 
     63     DeleteCriticalSection(lock);
     64     OPENSSL_free(lock);
     65 
     66     return;
     67 }
     68 
     69 #  define ONCE_UNINITED     0
     70 #  define ONCE_ININIT       1
     71 #  define ONCE_DONE         2
     72 
     73 /*
     74  * We don't use InitOnceExecuteOnce because that isn't available in WinXP which
     75  * we still have to support.
     76  */
     77 int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
     78 {
     79     LONG volatile *lock = (LONG *)once;
     80     LONG result;
     81 
     82     if (*lock == ONCE_DONE)
     83         return 1;
     84 
     85     do {
     86         result = InterlockedCompareExchange(lock, ONCE_ININIT, ONCE_UNINITED);
     87         if (result == ONCE_UNINITED) {
     88             init();
     89             *lock = ONCE_DONE;
     90             return 1;
     91         }
     92     } while (result == ONCE_ININIT);
     93 
     94     return (*lock == ONCE_DONE);
     95 }
     96 
     97 int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
     98 {
     99     *key = TlsAlloc();
    100     if (*key == TLS_OUT_OF_INDEXES)
    101         return 0;
    102 
    103     return 1;
    104 }
    105 
    106 void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
    107 {
    108     DWORD last_error;
    109     void *ret;
    110 
    111     /*
    112      * TlsGetValue clears the last error even on success, so that callers may
    113      * distinguish it successfully returning NULL or failing. It is documented
    114      * to never fail if the argument is a valid index from TlsAlloc, so we do
    115      * not need to handle this.
    116      *
    117      * However, this error-mangling behavior interferes with the caller's use of
    118      * GetLastError. In particular SSL_get_error queries the error queue to
    119      * determine whether the caller should look at the OS's errors. To avoid
    120      * destroying state, save and restore the Windows error.
    121      *
    122      * https://msdn.microsoft.com/en-us/library/windows/desktop/ms686812(v=vs.85).aspx
    123      */
    124     last_error = GetLastError();
    125     ret = TlsGetValue(*key);
    126     SetLastError(last_error);
    127     return ret;
    128 }
    129 
    130 int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
    131 {
    132     if (TlsSetValue(*key, val) == 0)
    133         return 0;
    134 
    135     return 1;
    136 }
    137 
    138 int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
    139 {
    140     if (TlsFree(*key) == 0)
    141         return 0;
    142 
    143     return 1;
    144 }
    145 
    146 CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
    147 {
    148     return GetCurrentThreadId();
    149 }
    150 
    151 int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
    152 {
    153     return (a == b);
    154 }
    155 
    156 int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
    157 {
    158     *ret = (int)InterlockedExchangeAdd((long volatile *)val, (long)amount) + amount;
    159     return 1;
    160 }
    161 
    162 int openssl_init_fork_handlers(void)
    163 {
    164     return 0;
    165 }
    166 
    167 int openssl_get_fork_id(void)
    168 {
    169     return 0;
    170 }
    171 #endif
    172