arch.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright 2019-2021 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. * Broadcast join completion. It is important to broadcast even if
  66. * we haven't performed an actual join. Multiple threads could be
  67. * awaiting the CRYPTO_THREAD_JOIN_AWAIT -> CRYPTO_THREAD_JOINED
  68. * transition, but broadcast on actual join would wake only one.
  69. * Broadcasing here will always wake one.
  70. */
  71. ossl_crypto_condvar_broadcast(thread->condvar);
  72. ossl_crypto_mutex_unlock(thread->statelock);
  73. if (retval != NULL)
  74. *retval = thread->retval;
  75. return 1;
  76. fail:
  77. ossl_crypto_mutex_lock(thread->statelock);
  78. CRYPTO_THREAD_SET_ERROR(thread, CRYPTO_THREAD_JOINED);
  79. /* Have another thread that's awaiting join retry to avoid that
  80. * thread deadlock. */
  81. CRYPTO_THREAD_UNSET_STATE(thread, CRYPTO_THREAD_JOIN_AWAIT);
  82. ossl_crypto_condvar_broadcast(thread->condvar);
  83. ossl_crypto_mutex_unlock(thread->statelock);
  84. return 0;
  85. }
  86. int ossl_crypto_thread_native_clean(CRYPTO_THREAD *handle)
  87. {
  88. uint64_t req_state_mask;
  89. if (handle == NULL)
  90. return 0;
  91. req_state_mask = 0;
  92. req_state_mask |= CRYPTO_THREAD_FINISHED;
  93. req_state_mask |= CRYPTO_THREAD_JOINED;
  94. ossl_crypto_mutex_lock(handle->statelock);
  95. if (CRYPTO_THREAD_GET_STATE(handle, req_state_mask) == 0) {
  96. ossl_crypto_mutex_unlock(handle->statelock);
  97. return 0;
  98. }
  99. ossl_crypto_mutex_unlock(handle->statelock);
  100. ossl_crypto_mutex_free(&handle->lock);
  101. ossl_crypto_mutex_free(&handle->statelock);
  102. ossl_crypto_condvar_free(&handle->condvar);
  103. OPENSSL_free(handle->handle);
  104. OPENSSL_free(handle);
  105. return 1;
  106. }