test_pthread.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5. */
  6. #include <errno.h>
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "esp_pthread.h"
  10. #include <pthread.h>
  11. #include "unity.h"
  12. static void *compute_square(void *arg)
  13. {
  14. int *num = (int *) arg;
  15. *num = (*num) * (*num);
  16. vTaskDelay(2); // ensure the test task has time to continue execution
  17. pthread_exit((void *) num);
  18. return NULL;
  19. }
  20. TEST_CASE("pthread create join", "[pthread]")
  21. {
  22. int res = 0;
  23. volatile int num = 7;
  24. volatile bool attr_init = false;
  25. void *thread_rval = NULL;
  26. pthread_t new_thread = (pthread_t)NULL;
  27. pthread_attr_t attr;
  28. if (TEST_PROTECT()) {
  29. res = pthread_attr_init(&attr);
  30. TEST_ASSERT_EQUAL_INT(0, res);
  31. attr_init = true;
  32. res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  33. TEST_ASSERT_EQUAL_INT(0, res);
  34. res = pthread_create(&new_thread, &attr, compute_square, (void *) &num);
  35. TEST_ASSERT_EQUAL_INT(0, res);
  36. res = pthread_join(new_thread, &thread_rval);
  37. TEST_ASSERT_EQUAL_INT(EDEADLK, res);
  38. vTaskDelay(100 / portTICK_PERIOD_MS);
  39. TEST_ASSERT_EQUAL_INT(49, num);
  40. res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  41. TEST_ASSERT_EQUAL_INT(0, res);
  42. res = pthread_create(&new_thread, &attr, compute_square, (void *) &num);
  43. TEST_ASSERT_EQUAL_INT(0, res);
  44. res = pthread_join(new_thread, &thread_rval);
  45. TEST_ASSERT_EQUAL_INT(0, res);
  46. TEST_ASSERT_EQUAL_INT(2401, num);
  47. TEST_ASSERT_EQUAL_PTR(&num, thread_rval);
  48. }
  49. if (attr_init) {
  50. pthread_attr_destroy(&attr);
  51. }
  52. }
  53. static void *waiting_thread(void *arg)
  54. {
  55. TaskHandle_t *task_handle = (TaskHandle_t *)arg;
  56. TaskHandle_t parent_task = *task_handle;
  57. *task_handle = xTaskGetCurrentTaskHandle();
  58. xTaskNotify(parent_task, 0, eNoAction);
  59. xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
  60. return NULL;
  61. }
  62. TEST_CASE("pthread detach", "[pthread]")
  63. {
  64. int res = 0;
  65. pthread_t new_thread = (pthread_t)NULL;
  66. TaskHandle_t task_handle = NULL;
  67. const int task_count = uxTaskGetNumberOfTasks();
  68. bool detach_works = false;
  69. if (TEST_PROTECT()) {
  70. task_handle = xTaskGetCurrentTaskHandle();
  71. res = pthread_create(&new_thread, NULL, waiting_thread, (void *)&task_handle);
  72. TEST_ASSERT_EQUAL_INT(0, res);
  73. res = xTaskNotifyWait(0, 0, NULL, 100 / portTICK_PERIOD_MS);
  74. TEST_ASSERT_EQUAL_INT(pdTRUE, res);
  75. xTaskNotify(task_handle, 0, eNoAction);
  76. vTaskDelay(100 / portTICK_PERIOD_MS);
  77. res = pthread_detach(new_thread);
  78. TEST_ASSERT_EQUAL_INT(0, res);
  79. res = uxTaskGetNumberOfTasks();
  80. TEST_ASSERT_EQUAL_INT(task_count, res);
  81. detach_works = true;
  82. }
  83. if (!detach_works) {
  84. vTaskDelete(task_handle);
  85. } else {
  86. detach_works = false;
  87. }
  88. if (TEST_PROTECT()) {
  89. task_handle = xTaskGetCurrentTaskHandle();
  90. res = pthread_create(&new_thread, NULL, waiting_thread, (void *)&task_handle);
  91. TEST_ASSERT_EQUAL_INT(0, res);
  92. res = xTaskNotifyWait(0, 0, NULL, 100 / portTICK_PERIOD_MS);
  93. TEST_ASSERT_EQUAL_INT(pdTRUE, res);
  94. res = pthread_detach(new_thread);
  95. TEST_ASSERT_EQUAL_INT(0, res);
  96. xTaskNotify(task_handle, 0, eNoAction);
  97. vTaskDelay(100 / portTICK_PERIOD_MS);
  98. res = uxTaskGetNumberOfTasks();
  99. TEST_ASSERT_EQUAL_INT(task_count, res);
  100. detach_works = true;
  101. }
  102. if (!detach_works) {
  103. vTaskDelete(task_handle);
  104. }
  105. }
  106. TEST_CASE("pthread attr init destroy", "[pthread]")
  107. {
  108. int res = 0;
  109. size_t stack_size_1 = 0, stack_size_2 = 0;
  110. volatile bool attr_init = pdFALSE;
  111. pthread_attr_t attr;
  112. if (TEST_PROTECT()) {
  113. res = pthread_attr_init(&attr);
  114. TEST_ASSERT_EQUAL_INT(0, res);
  115. attr_init = true;
  116. res = pthread_attr_getstacksize(&attr, &stack_size_1);
  117. TEST_ASSERT_EQUAL_INT(0, res);
  118. res = pthread_attr_setstacksize(&attr, stack_size_1);
  119. TEST_ASSERT_EQUAL_INT(0, res);
  120. res = pthread_attr_getstacksize(&attr, &stack_size_2);
  121. TEST_ASSERT_EQUAL_INT(0, res);
  122. TEST_ASSERT_EQUAL_INT(stack_size_2, stack_size_1);
  123. stack_size_1 = PTHREAD_STACK_MIN - 1;
  124. res = pthread_attr_setstacksize(&attr, stack_size_1);
  125. TEST_ASSERT_EQUAL_INT(EINVAL, res);
  126. }
  127. if (attr_init) {
  128. TEST_ASSERT_EQUAL_INT(0, pthread_attr_destroy(&attr));
  129. }
  130. }
  131. static void *unlock_mutex(void *arg)
  132. {
  133. pthread_mutex_t *mutex = (pthread_mutex_t *) arg;
  134. intptr_t res = (intptr_t) pthread_mutex_unlock(mutex);
  135. pthread_exit((void *) res);
  136. return NULL;
  137. }
  138. static void test_mutex_lock_unlock(int mutex_type)
  139. {
  140. int res = 0;
  141. int set_type = -1;
  142. volatile bool attr_created = false;
  143. volatile bool mutex_created = false;
  144. volatile intptr_t thread_rval = 0;
  145. pthread_mutex_t mutex;
  146. pthread_mutexattr_t attr;
  147. pthread_t new_thread;
  148. if (TEST_PROTECT()) {
  149. res = pthread_mutexattr_init(&attr);
  150. TEST_ASSERT_EQUAL_INT(0, res);
  151. attr_created = true;
  152. res = pthread_mutexattr_settype(&attr, mutex_type);
  153. TEST_ASSERT_EQUAL_INT(0, res);
  154. res = pthread_mutexattr_gettype(&attr, &set_type);
  155. TEST_ASSERT_EQUAL_INT(0, res);
  156. TEST_ASSERT_EQUAL_INT(mutex_type, set_type);
  157. res = pthread_mutex_init(&mutex, &attr);
  158. TEST_ASSERT_EQUAL_INT(0, res);
  159. mutex_created = true;
  160. res = pthread_mutex_lock(&mutex);
  161. TEST_ASSERT_EQUAL_INT(0, res);
  162. res = pthread_mutex_lock(&mutex);
  163. if(mutex_type == PTHREAD_MUTEX_ERRORCHECK) {
  164. TEST_ASSERT_EQUAL_INT(EDEADLK, res);
  165. } else {
  166. TEST_ASSERT_EQUAL_INT(0, res);
  167. res = pthread_mutex_unlock(&mutex);
  168. TEST_ASSERT_EQUAL_INT(0, res);
  169. }
  170. pthread_create(&new_thread, NULL, unlock_mutex, &mutex);
  171. pthread_join(new_thread, (void **) &thread_rval);
  172. TEST_ASSERT_EQUAL_INT(EPERM, (int) thread_rval);
  173. res = pthread_mutex_unlock(&mutex);
  174. TEST_ASSERT_EQUAL_INT(0, res);
  175. }
  176. if (attr_created) {
  177. pthread_mutexattr_destroy(&attr);
  178. }
  179. if (mutex_created) {
  180. pthread_mutex_destroy(&mutex);
  181. }
  182. }
  183. TEST_CASE("pthread mutex lock unlock", "[pthread]")
  184. {
  185. int res = 0;
  186. /* Present behavior of mutex initializer is unlike what is
  187. * defined in Posix standard, ie. calling pthread_mutex_lock
  188. * on such a mutex would internally cause dynamic allocation.
  189. * Therefore pthread_mutex_destroy needs to be called in
  190. * order to avoid memory leak. */
  191. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  192. res = pthread_mutex_lock(&mutex);
  193. TEST_ASSERT_EQUAL_INT(0, res);
  194. res = pthread_mutex_unlock(&mutex);
  195. TEST_ASSERT_EQUAL_INT(0, res);
  196. /* This deviates from the Posix standard static mutex behavior.
  197. * This needs to be removed in the future when standard mutex
  198. * initializer is supported */
  199. pthread_mutex_destroy(&mutex);
  200. test_mutex_lock_unlock(PTHREAD_MUTEX_ERRORCHECK);
  201. test_mutex_lock_unlock(PTHREAD_MUTEX_RECURSIVE);
  202. }
  203. static void timespec_add_nano(struct timespec * out, struct timespec * in, long val)
  204. {
  205. out->tv_nsec = val + in->tv_nsec;
  206. if (out->tv_nsec < (in->tv_nsec)) {
  207. out->tv_sec += 1;
  208. }
  209. }
  210. TEST_CASE("pthread mutex trylock timedlock", "[pthread]")
  211. {
  212. int res = 0;
  213. volatile bool mutex_created = false;
  214. pthread_mutex_t mutex;
  215. struct timespec abs_timeout;
  216. if (TEST_PROTECT()) {
  217. res = pthread_mutex_init(&mutex, NULL);
  218. TEST_ASSERT_EQUAL_INT(0, res);
  219. mutex_created = true;
  220. res = pthread_mutex_trylock(&mutex);
  221. TEST_ASSERT_EQUAL_INT(0, res);
  222. res = pthread_mutex_trylock(&mutex);
  223. TEST_ASSERT_EQUAL_INT(EBUSY, res);
  224. clock_gettime(CLOCK_REALTIME, &abs_timeout);
  225. timespec_add_nano(&abs_timeout, &abs_timeout, 100000000LL);
  226. res = pthread_mutex_timedlock(&mutex, &abs_timeout);
  227. TEST_ASSERT_EQUAL_INT(ETIMEDOUT, res);
  228. res = pthread_mutex_unlock(&mutex);
  229. TEST_ASSERT_EQUAL_INT(0, res);
  230. }
  231. if (mutex_created) {
  232. pthread_mutex_destroy(&mutex);
  233. }
  234. }