threadpool_test.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Copyright 2022 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 <string.h>
  10. #include <internal/cryptlib.h>
  11. #include <internal/thread_arch.h>
  12. #include <internal/thread.h>
  13. #include <openssl/thread.h>
  14. #include "testutil.h"
  15. static int test_thread_reported_flags(void)
  16. {
  17. uint32_t flags = OSSL_get_thread_support_flags();
  18. #if !defined(OPENSSL_THREADS)
  19. if (!TEST_int_eq(flags, 0))
  20. return 0;
  21. #endif
  22. #if defined(OPENSSL_NO_THREAD_POOL)
  23. if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL, 0))
  24. return 0;
  25. #else
  26. if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL,
  27. OSSL_THREAD_SUPPORT_FLAG_THREAD_POOL))
  28. return 0;
  29. #endif
  30. #if defined(OPENSSL_NO_DEFAULT_THREAD_POOL)
  31. if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN, 0))
  32. return 0;
  33. #else
  34. if (!TEST_int_eq(flags & OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN,
  35. OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN))
  36. return 0;
  37. #endif
  38. return 1;
  39. }
  40. #ifndef OPENSSL_NO_THREAD_POOL
  41. # define TEST_THREAD_NATIVE_FN_SET_VALUE 1
  42. static uint32_t test_thread_native_fn(void *data)
  43. {
  44. uint32_t *ldata = (uint32_t*) data;
  45. *ldata = *ldata + 1;
  46. return *ldata - 1;
  47. }
  48. /* Tests of native threads */
  49. static int test_thread_native(void)
  50. {
  51. uint32_t retval;
  52. uint32_t local;
  53. CRYPTO_THREAD *t;
  54. /* thread spawn, join */
  55. local = 1;
  56. t = ossl_crypto_thread_native_start(test_thread_native_fn, &local, 1);
  57. if (!TEST_ptr(t))
  58. return 0;
  59. /*
  60. * pthread_join results in undefined behaviour if called on a joined
  61. * thread. We do not impose such restrictions, so it's up to us to
  62. * ensure that this does not happen (thread sanitizer will warn us
  63. * if we do).
  64. */
  65. if (!TEST_int_eq(ossl_crypto_thread_native_join(t, &retval), 1))
  66. return 0;
  67. if (!TEST_int_eq(ossl_crypto_thread_native_join(t, &retval), 1))
  68. return 0;
  69. if (!TEST_int_eq(retval, 1) || !TEST_int_eq(local, 2))
  70. return 0;
  71. if (!TEST_int_eq(ossl_crypto_thread_native_clean(t), 1))
  72. return 0;
  73. t = NULL;
  74. if (!TEST_int_eq(ossl_crypto_thread_native_clean(t), 0))
  75. return 0;
  76. return 1;
  77. }
  78. # if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL)
  79. static int test_thread_internal(void)
  80. {
  81. uint32_t retval[3];
  82. uint32_t local[3] = { 0 };
  83. uint32_t threads_supported;
  84. size_t i;
  85. void *t[3];
  86. int status = 0;
  87. OSSL_LIB_CTX *cust_ctx = OSSL_LIB_CTX_new();
  88. threads_supported = OSSL_get_thread_support_flags();
  89. threads_supported &= OSSL_THREAD_SUPPORT_FLAG_DEFAULT_SPAWN;
  90. if (threads_supported == 0) {
  91. if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0))
  92. goto cleanup;
  93. if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0))
  94. goto cleanup;
  95. if (!TEST_int_eq(OSSL_set_max_threads(NULL, 1), 0))
  96. goto cleanup;
  97. if (!TEST_int_eq(OSSL_set_max_threads(cust_ctx, 1), 0))
  98. goto cleanup;
  99. if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0))
  100. goto cleanup;
  101. if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0))
  102. goto cleanup;
  103. t[0] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]);
  104. if (!TEST_ptr_null(t[0]))
  105. goto cleanup;
  106. status = 1;
  107. goto cleanup;
  108. }
  109. /* fail when not allowed to use threads */
  110. if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0))
  111. goto cleanup;
  112. t[0] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]);
  113. if (!TEST_ptr_null(t[0]))
  114. goto cleanup;
  115. /* fail when enabled on a different context */
  116. if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0))
  117. goto cleanup;
  118. if (!TEST_int_eq(OSSL_set_max_threads(cust_ctx, 1), 1))
  119. goto cleanup;
  120. if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 0))
  121. goto cleanup;
  122. if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 1))
  123. goto cleanup;
  124. t[0] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]);
  125. if (!TEST_ptr_null(t[0]))
  126. goto cleanup;
  127. if (!TEST_int_eq(OSSL_set_max_threads(cust_ctx, 0), 1))
  128. goto cleanup;
  129. /* sequential startup */
  130. if (!TEST_int_eq(OSSL_set_max_threads(NULL, 1), 1))
  131. goto cleanup;
  132. if (!TEST_uint64_t_eq(OSSL_get_max_threads(NULL), 1))
  133. goto cleanup;
  134. if (!TEST_uint64_t_eq(OSSL_get_max_threads(cust_ctx), 0))
  135. goto cleanup;
  136. for (i = 0; i < OSSL_NELEM(t); ++i) {
  137. local[0] = i + 1;
  138. t[i] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[0]);
  139. if (!TEST_ptr(t[i]))
  140. goto cleanup;
  141. /*
  142. * pthread_join results in undefined behaviour if called on a joined
  143. * thread. We do not impose such restrictions, so it's up to us to
  144. * ensure that this does not happen (thread sanitizer will warn us
  145. * if we do).
  146. */
  147. if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[0]), 1))
  148. goto cleanup;
  149. if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[0]), 1))
  150. goto cleanup;
  151. if (!TEST_int_eq(retval[0], i + 1) || !TEST_int_eq(local[0], i + 2))
  152. goto cleanup;
  153. if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 1))
  154. goto cleanup;
  155. t[i] = NULL;
  156. if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 0))
  157. goto cleanup;
  158. }
  159. /* parallel startup */
  160. if (!TEST_int_eq(OSSL_set_max_threads(NULL, OSSL_NELEM(t)), 1))
  161. goto cleanup;
  162. for (i = 0; i < OSSL_NELEM(t); ++i) {
  163. local[i] = i + 1;
  164. t[i] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[i]);
  165. if (!TEST_ptr(t[i]))
  166. goto cleanup;
  167. }
  168. for (i = 0; i < OSSL_NELEM(t); ++i) {
  169. if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[i]), 1))
  170. goto cleanup;
  171. }
  172. for (i = 0; i < OSSL_NELEM(t); ++i) {
  173. if (!TEST_int_eq(retval[i], i + 1) || !TEST_int_eq(local[i], i + 2))
  174. goto cleanup;
  175. if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 1))
  176. goto cleanup;
  177. }
  178. /* parallel startup, bottleneck */
  179. if (!TEST_int_eq(OSSL_set_max_threads(NULL, OSSL_NELEM(t) - 1), 1))
  180. goto cleanup;
  181. for (i = 0; i < OSSL_NELEM(t); ++i) {
  182. local[i] = i + 1;
  183. t[i] = ossl_crypto_thread_start(NULL, test_thread_native_fn, &local[i]);
  184. if (!TEST_ptr(t[i]))
  185. goto cleanup;
  186. }
  187. for (i = 0; i < OSSL_NELEM(t); ++i) {
  188. if (!TEST_int_eq(ossl_crypto_thread_join(t[i], &retval[i]), 1))
  189. goto cleanup;
  190. }
  191. for (i = 0; i < OSSL_NELEM(t); ++i) {
  192. if (!TEST_int_eq(retval[i], i + 1) || !TEST_int_eq(local[i], i + 2))
  193. goto cleanup;
  194. if (!TEST_int_eq(ossl_crypto_thread_clean(t[i]), 1))
  195. goto cleanup;
  196. }
  197. if (!TEST_int_eq(OSSL_set_max_threads(NULL, 0), 1))
  198. goto cleanup;
  199. status = 1;
  200. cleanup:
  201. OSSL_LIB_CTX_free(cust_ctx);
  202. return status;
  203. }
  204. # endif
  205. static uint32_t test_thread_native_multiple_joins_fn1(void *data)
  206. {
  207. return 0;
  208. }
  209. static uint32_t test_thread_native_multiple_joins_fn2(void *data)
  210. {
  211. ossl_crypto_thread_native_join((CRYPTO_THREAD *)data, NULL);
  212. return 0;
  213. }
  214. static uint32_t test_thread_native_multiple_joins_fn3(void *data)
  215. {
  216. ossl_crypto_thread_native_join((CRYPTO_THREAD *)data, NULL);
  217. return 0;
  218. }
  219. static int test_thread_native_multiple_joins(void)
  220. {
  221. CRYPTO_THREAD *t, *t1, *t2;
  222. t = ossl_crypto_thread_native_start(test_thread_native_multiple_joins_fn1, NULL, 1);
  223. t1 = ossl_crypto_thread_native_start(test_thread_native_multiple_joins_fn2, t, 1);
  224. t2 = ossl_crypto_thread_native_start(test_thread_native_multiple_joins_fn3, t, 1);
  225. if (!TEST_ptr(t) || !TEST_ptr(t1) || !TEST_ptr(t2))
  226. return 0;
  227. if (!TEST_int_eq(ossl_crypto_thread_native_join(t2, NULL), 1))
  228. return 0;
  229. if (!TEST_int_eq(ossl_crypto_thread_native_join(t1, NULL), 1))
  230. return 0;
  231. if (!TEST_int_eq(ossl_crypto_thread_native_clean(t2), 1))
  232. return 0;
  233. if (!TEST_int_eq(ossl_crypto_thread_native_clean(t1), 1))
  234. return 0;
  235. if (!TEST_int_eq(ossl_crypto_thread_native_clean(t), 1))
  236. return 0;
  237. return 1;
  238. }
  239. #endif
  240. int setup_tests(void)
  241. {
  242. ADD_TEST(test_thread_reported_flags);
  243. #if !defined(OPENSSL_NO_THREAD_POOL)
  244. ADD_TEST(test_thread_native);
  245. ADD_TEST(test_thread_native_multiple_joins);
  246. # if !defined(OPENSSL_NO_DEFAULT_THREAD_POOL)
  247. ADD_TEST(test_thread_internal);
  248. # endif
  249. #endif
  250. return 1;
  251. }