Home | History | Annotate | Download | only in crypto
      1 /* Copyright (c) 2015, Google Inc.
      2  *
      3  * Permission to use, copy, modify, and/or distribute this software for any
      4  * purpose with or without fee is hereby granted, provided that the above
      5  * copyright notice and this permission notice appear in all copies.
      6  *
      7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
     14 
     15 #include "internal.h"
     16 
     17 #include <stdio.h>
     18 
     19 
     20 #if !defined(OPENSSL_NO_THREADS)
     21 
     22 #if defined(OPENSSL_WINDOWS)
     23 
     24 #pragma warning(push, 3)
     25 #include <windows.h>
     26 #pragma warning(pop)
     27 
     28 typedef HANDLE thread_t;
     29 
     30 static DWORD WINAPI thread_run(LPVOID arg) {
     31   void (*thread_func)(void);
     32   /* VC really doesn't like casting between data and function pointers. */
     33   memcpy(&thread_func, &arg, sizeof(thread_func));
     34   thread_func();
     35   return 0;
     36 }
     37 
     38 static int run_thread(thread_t *out_thread, void (*thread_func)(void)) {
     39   void *arg;
     40   /* VC really doesn't like casting between data and function pointers. */
     41   memcpy(&arg, &thread_func, sizeof(arg));
     42 
     43   *out_thread = CreateThread(NULL /* security attributes */,
     44                              0 /* default stack size */, thread_run, arg,
     45                              0 /* run immediately */, NULL /* ignore id */);
     46   return *out_thread != NULL;
     47 }
     48 
     49 static int wait_for_thread(thread_t thread) {
     50   return WaitForSingleObject(thread, INFINITE) == 0;
     51 }
     52 
     53 #else
     54 
     55 #include <pthread.h>
     56 
     57 typedef pthread_t thread_t;
     58 
     59 static void *thread_run(void *arg) {
     60   void (*thread_func)(void) = arg;
     61   thread_func();
     62   return NULL;
     63 }
     64 
     65 static int run_thread(thread_t *out_thread, void (*thread_func)(void)) {
     66   return pthread_create(out_thread, NULL /* default attributes */, thread_run,
     67                         thread_func) == 0;
     68 }
     69 
     70 static int wait_for_thread(thread_t thread) {
     71   return pthread_join(thread, NULL) == 0;
     72 }
     73 
     74 #endif  /* OPENSSL_WINDOWS */
     75 
     76 static unsigned g_once_init_called = 0;
     77 
     78 static void once_init(void) {
     79   g_once_init_called++;
     80 }
     81 
     82 static CRYPTO_once_t g_test_once = CRYPTO_ONCE_INIT;
     83 
     84 static void call_once_thread(void) {
     85   CRYPTO_once(&g_test_once, once_init);
     86 }
     87 
     88 static int test_once(void) {
     89   if (g_once_init_called != 0) {
     90     fprintf(stderr, "g_once_init_called was non-zero at start.\n");
     91     return 0;
     92   }
     93 
     94   thread_t thread;
     95   if (!run_thread(&thread, call_once_thread) ||
     96       !wait_for_thread(thread)) {
     97     fprintf(stderr, "thread failed.\n");
     98     return 0;
     99   }
    100 
    101   CRYPTO_once(&g_test_once, once_init);
    102 
    103   if (g_once_init_called != 1) {
    104     fprintf(stderr, "Expected init function to be called once, but found %u.\n",
    105             g_once_init_called);
    106     return 0;
    107   }
    108 
    109   return 1;
    110 }
    111 
    112 
    113 static int g_test_thread_ok = 0;
    114 static unsigned g_destructor_called_count = 0;
    115 
    116 static void thread_local_destructor(void *arg) {
    117   if (arg == NULL) {
    118     return;
    119   }
    120 
    121   unsigned *count = arg;
    122   (*count)++;
    123 }
    124 
    125 static void thread_local_test_thread(void) {
    126   void *ptr = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST);
    127   if (ptr != NULL) {
    128     return;
    129   }
    130 
    131   if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_TEST,
    132                                &g_destructor_called_count,
    133                                thread_local_destructor)) {
    134     return;
    135   }
    136 
    137   if (CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST) !=
    138       &g_destructor_called_count) {
    139     return;
    140   }
    141 
    142   g_test_thread_ok = 1;
    143 }
    144 
    145 static void thread_local_test2_thread(void) {}
    146 
    147 static int test_thread_local(void) {
    148   void *ptr = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_TEST);
    149   if (ptr != NULL) {
    150     fprintf(stderr, "Thread-local data was non-NULL at start.\n");
    151   }
    152 
    153   thread_t thread;
    154   if (!run_thread(&thread, thread_local_test_thread) ||
    155       !wait_for_thread(thread)) {
    156     fprintf(stderr, "thread failed.\n");
    157     return 0;
    158   }
    159 
    160   if (!g_test_thread_ok) {
    161     fprintf(stderr, "Thread-local data didn't work in thread.\n");
    162     return 0;
    163   }
    164 
    165   if (g_destructor_called_count != 1) {
    166     fprintf(stderr,
    167             "Destructor should have been called once, but actually called %u "
    168             "times.\n",
    169             g_destructor_called_count);
    170     return 0;
    171   }
    172 
    173   /* thread_local_test2_thread doesn't do anything, but it tests that the
    174    * thread destructor function works even if thread-local storage wasn't used
    175    * for a thread. */
    176   if (!run_thread(&thread, thread_local_test2_thread) ||
    177       !wait_for_thread(thread)) {
    178     fprintf(stderr, "thread failed.\n");
    179     return 0;
    180   }
    181 
    182   return 1;
    183 }
    184 
    185 int main(int argc, char **argv) {
    186   if (!test_once() ||
    187       !test_thread_local()) {
    188     return 1;
    189   }
    190 
    191   printf("PASS\n");
    192   return 0;
    193 }
    194 
    195 #else  /* OPENSSL_NO_THREADS */
    196 
    197 int main(int argc, char **argv) {
    198   printf("PASS\n");
    199   return 0;
    200 }
    201 
    202 #endif
    203