initthread.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (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. #include <openssl/crypto.h>
  10. #include "internal/cryptlib_int.h"
  11. typedef struct thread_event_handler_st THREAD_EVENT_HANDLER;
  12. struct thread_event_handler_st {
  13. OPENSSL_CTX *ctx;
  14. ossl_thread_stop_handler_fn handfn;
  15. THREAD_EVENT_HANDLER *next;
  16. };
  17. /*
  18. * Since per-thread-specific-data destructors are not universally
  19. * available, i.e. not on Windows, only below CRYPTO_THREAD_LOCAL key
  20. * is assumed to have destructor associated. And then an effort is made
  21. * to call this single destructor on non-pthread platform[s].
  22. *
  23. * Initial value is "impossible". It is used as guard value to shortcut
  24. * destructor for threads terminating before libcrypto is initialized or
  25. * after it's de-initialized. Access to the key doesn't have to be
  26. * serialized for the said threads, because they didn't use libcrypto
  27. * and it doesn't matter if they pick "impossible" or derefernce real
  28. * key value and pull NULL past initialization in the first thread that
  29. * intends to use libcrypto.
  30. */
  31. static union {
  32. long sane;
  33. CRYPTO_THREAD_LOCAL value;
  34. } destructor_key = { -1 };
  35. static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands);
  36. static void ossl_init_thread_destructor(void *hands)
  37. {
  38. ossl_init_thread_stop((THREAD_EVENT_HANDLER **)hands);
  39. }
  40. int init_thread(void)
  41. {
  42. if (!CRYPTO_THREAD_init_local(&destructor_key.value,
  43. ossl_init_thread_destructor))
  44. return 0;
  45. return 1;
  46. }
  47. void cleanup_thread(void)
  48. {
  49. CRYPTO_THREAD_cleanup_local(&destructor_key.value);
  50. destructor_key.sane = -1;
  51. }
  52. static THREAD_EVENT_HANDLER **ossl_init_get_thread_local(int alloc)
  53. {
  54. THREAD_EVENT_HANDLER **hands =
  55. CRYPTO_THREAD_get_local(&destructor_key.value);
  56. if (alloc) {
  57. if (hands == NULL
  58. && (hands = OPENSSL_zalloc(sizeof(*hands))) != NULL
  59. && !CRYPTO_THREAD_set_local(&destructor_key.value, hands)) {
  60. OPENSSL_free(hands);
  61. return NULL;
  62. }
  63. } else {
  64. CRYPTO_THREAD_set_local(&destructor_key.value, NULL);
  65. }
  66. return hands;
  67. }
  68. static void ossl_init_thread_stop(THREAD_EVENT_HANDLER **hands)
  69. {
  70. THREAD_EVENT_HANDLER *curr, *prev = NULL;
  71. /* Can't do much about this */
  72. if (hands == NULL)
  73. return;
  74. curr = *hands;
  75. while (curr != NULL) {
  76. curr->handfn(curr->ctx);
  77. prev = curr;
  78. curr = curr->next;
  79. OPENSSL_free(prev);
  80. }
  81. OPENSSL_free(hands);
  82. }
  83. void OPENSSL_thread_stop(void)
  84. {
  85. if (destructor_key.sane != -1)
  86. ossl_init_thread_stop(ossl_init_get_thread_local(0));
  87. }
  88. int ossl_init_thread_start(OPENSSL_CTX *ctx, ossl_thread_stop_handler_fn handfn)
  89. {
  90. THREAD_EVENT_HANDLER **hands;
  91. THREAD_EVENT_HANDLER *hand;
  92. if (!OPENSSL_init_crypto(0, NULL))
  93. return 0;
  94. hands = ossl_init_get_thread_local(1);
  95. if (hands == NULL)
  96. return 0;
  97. hand = OPENSSL_malloc(sizeof(*hand));
  98. if (hand == NULL)
  99. return 0;
  100. hand->handfn = handfn;
  101. hand->ctx = ctx;
  102. hand->next = *hands;
  103. *hands = hand;
  104. return 1;
  105. }