arch.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright 2019-2023 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/configuration.h>
  10. #include <internal/thread_arch.h>
  11. CRYPTO_THREAD *ossl_crypto_thread_native_start(CRYPTO_THREAD_ROUTINE routine,
  12. void *data, int joinable)
  13. {
  14. CRYPTO_THREAD *handle;
  15. if (routine == NULL)
  16. return NULL;
  17. handle = OPENSSL_zalloc(sizeof(*handle));
  18. if (handle == NULL)
  19. return NULL;
  20. if ((handle->lock = ossl_crypto_mutex_new()) == NULL)
  21. goto fail;
  22. if ((handle->statelock = ossl_crypto_mutex_new()) == NULL)
  23. goto fail;
  24. if ((handle->condvar = ossl_crypto_condvar_new()) == NULL)
  25. goto fail;
  26. handle->data = data;
  27. handle->routine = routine;
  28. handle->joinable = joinable;
  29. if (ossl_crypto_thread_native_spawn(handle) == 1)
  30. return handle;
  31. fail:
  32. ossl_crypto_condvar_free(&handle->condvar);
  33. ossl_crypto_mutex_free(&handle->statelock);
  34. ossl_crypto_mutex_free(&handle->lock);
  35. OPENSSL_free(handle);
  36. return NULL;
  37. }
  38. int ossl_crypto_thread_native_join(CRYPTO_THREAD *thread, CRYPTO_THREAD_RETVAL *retval)
  39. {
  40. uint64_t req_state_mask;
  41. if (thread == NULL)
  42. return 0;
  43. ossl_crypto_mutex_lock(thread->statelock);
  44. req_state_mask = CRYPTO_THREAD_FINISHED | CRYPTO_THREAD_JOINED;
  45. while (!CRYPTO_THREAD_GET_STATE(thread, req_state_mask))
  46. ossl_crypto_condvar_wait(thread->condvar, thread->statelock);
  47. if (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
  48. goto pass;
  49. /* Await concurrent join completion, if any. */
  50. while (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT)) {
  51. if (!CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
  52. ossl_crypto_condvar_wait(thread->condvar, thread->statelock);
  53. if (CRYPTO_THREAD_GET_STATE(thread, CRYPTO_THREAD_JOINED))
  54. goto pass;
  55. }
  56. CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
  57. ossl_crypto_mutex_unlock(thread->statelock);
  58. if (ossl_crypto_thread_native_perform_join(thread, retval) == 0)
  59. goto fail;
  60. ossl_crypto_mutex_lock(thread->statelock);
  61. pass:
  62. CRYPTO_THREAD_UNSET_ERROR(thread, CRYPTO_THREAD_JOINED);
  63. CRYPTO_THREAD_SET_STATE(thread, CRYPTO_THREAD_JOINED);
  64. /*
  65. * Signal join completion. It is important to signal even if we haven't
  66. * performed an actual join. Multiple threads could be awaiting the
  67. * CRYPTO_THREAD_JOIN_AWAIT -> CRYPTO_THREAD_JOINED transition, but signal
  68. * on actual join would wake only one. Signalling here will always wake one.
  69. */
  70. ossl_crypto_condvar_signal(thread->condvar);
  71. ossl_crypto_mutex_unlock(thread->statelock);
  72. if (retval != NULL)
  73. *retval = thread->retval;
  74. return 1;
  75. fail:
  76. ossl_crypto_mutex_lock(thread->statelock);
  77. CRYPTO_THREAD_SET_ERROR(thread, CRYPTO_THREAD_JOINED);
  78. /* Have another thread that's awaiting join retry to avoid that
  79. * thread deadlock. */
  80. CRYPTO_THREAD_UNSET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
  81. ossl_crypto_condvar_signal(thread->condvar);
  82. ossl_crypto_mutex_unlock(thread->statelock);
  83. return 0;
  84. }
  85. int ossl_crypto_thread_native_clean(CRYPTO_THREAD *handle)
  86. {
  87. uint64_t req_state_mask;
  88. if (handle == NULL)
  89. return 0;
  90. req_state_mask = 0;
  91. req_state_mask |= CRYPTO_THREAD_FINISHED;
  92. req_state_mask |= CRYPTO_THREAD_JOINED;
  93. ossl_crypto_mutex_lock(handle->statelock);
  94. if (CRYPTO_THREAD_GET_STATE(handle, req_state_mask) == 0) {
  95. ossl_crypto_mutex_unlock(handle->statelock);
  96. return 0;
  97. }
  98. ossl_crypto_mutex_unlock(handle->statelock);
  99. ossl_crypto_mutex_free(&handle->lock);
  100. ossl_crypto_mutex_free(&handle->statelock);
  101. ossl_crypto_condvar_free(&handle->condvar);
  102. OPENSSL_free(handle->handle);
  103. OPENSSL_free(handle);
  104. return 1;
  105. }