test_pthread.c 8.1 KB

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