test_pthread_rwlock.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: CC0
  5. *
  6. * This example code is in the Public Domain (or CC0 licensed, at your option.)
  7. *
  8. * Unless required by applicable law or agreed to in writing, this
  9. * software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  10. * CONDITIONS OF ANY KIND, either express or implied.
  11. */
  12. #include "sdkconfig.h"
  13. #include <errno.h>
  14. #include <stdatomic.h>
  15. #include "freertos/FreeRTOS.h"
  16. #include "freertos/task.h"
  17. #include "freertos/semphr.h"
  18. #include "esp_timer.h"
  19. #include "esp_pthread.h"
  20. #include <pthread.h>
  21. #include "unity.h"
  22. TEST_CASE("pthread_rwlock_init invalid arg", "[pthread][rwlock]")
  23. {
  24. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(NULL, NULL), EINVAL);
  25. }
  26. TEST_CASE("pthread_rwlock_destroy invalid arg", "[pthread][rwlock]")
  27. {
  28. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(NULL), EINVAL);
  29. pthread_rwlock_t rwlock = 0;
  30. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), EINVAL);
  31. }
  32. TEST_CASE("create and destroy rwlock", "[pthread][rwlock]")
  33. {
  34. pthread_rwlock_t rwlock;
  35. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  36. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  37. }
  38. TEST_CASE("pthread_rwlock_destroy encounters static initializer", "[pthread][rwlock]")
  39. {
  40. pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
  41. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  42. }
  43. TEST_CASE("rdlock invalid param", "[pthread][rwlock]")
  44. {
  45. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(NULL), EINVAL);
  46. pthread_rwlock_t rwlock = 0;
  47. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), EINVAL);
  48. }
  49. TEST_CASE("unlock invalid param", "[pthread][rwlock]")
  50. {
  51. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(NULL), EINVAL);
  52. pthread_rwlock_t rwlock = 0;
  53. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), EINVAL);
  54. }
  55. TEST_CASE("wrlock lock invalid param", "[pthread][rwlock]")
  56. {
  57. TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(NULL), EINVAL);
  58. pthread_rwlock_t rwlock = 0;
  59. TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(&rwlock), EINVAL);
  60. }
  61. TEST_CASE("rdlock lock statically initialized lock", "[pthread][rwlock]")
  62. {
  63. pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
  64. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), 0);
  65. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0);
  66. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  67. }
  68. TEST_CASE("rdlock unlock", "[pthread][rwlock]")
  69. {
  70. pthread_rwlock_t rwlock;
  71. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  72. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), 0);
  73. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0);
  74. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  75. }
  76. TEST_CASE("multiple read locks", "[pthread][rwlock]")
  77. {
  78. pthread_rwlock_t rwlock;
  79. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  80. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), 0);
  81. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(&rwlock), 0);
  82. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0);
  83. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0);
  84. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  85. }
  86. TEST_CASE("wrlock lock-unlock", "[pthread][rwlock]")
  87. {
  88. pthread_rwlock_t rwlock;
  89. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  90. TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(&rwlock), 0);
  91. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(&rwlock), 0);
  92. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  93. }
  94. struct ReaderWriterArgs {
  95. QueueHandle_t *wait_queue;
  96. size_t sem_wait_release_num;
  97. pthread_rwlock_t *rwlock;
  98. volatile bool reading;
  99. volatile bool writing;
  100. };
  101. static void *reader(void *arg)
  102. {
  103. uint8_t dummy_message;
  104. struct ReaderWriterArgs *rw_args = (struct ReaderWriterArgs*) arg;
  105. TEST_ASSERT_EQUAL(xQueueReceive(*(rw_args->wait_queue), &dummy_message, portMAX_DELAY), pdTRUE);
  106. TEST_ASSERT_EQUAL_INT(pthread_rwlock_rdlock(rw_args->rwlock), 0);
  107. rw_args->reading = true;
  108. TEST_ASSERT_FALSE(rw_args->writing);
  109. rw_args->reading = false;
  110. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(rw_args->rwlock), 0);
  111. return NULL;
  112. }
  113. static void *writer(void *arg)
  114. {
  115. uint8_t dummy_msg;
  116. struct ReaderWriterArgs *rw_args = (struct ReaderWriterArgs*) arg;
  117. TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(rw_args->rwlock), 0);
  118. rw_args->writing = true;
  119. for (size_t i = 0; i < rw_args->sem_wait_release_num; i++) {
  120. TEST_ASSERT_EQUAL(xQueueSendToBack(*(rw_args->wait_queue), &dummy_msg, portMAX_DELAY), pdTRUE);
  121. }
  122. TEST_ASSERT_FALSE(rw_args->reading);
  123. vTaskDelay(20 / portTICK_PERIOD_MS);
  124. TEST_ASSERT_FALSE(rw_args->reading);
  125. rw_args->writing = false;
  126. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(rw_args->rwlock), 0);
  127. return NULL;
  128. }
  129. TEST_CASE("wrlock reader waits", "[pthread][rwlock]")
  130. {
  131. QueueHandle_t wait_queue;
  132. pthread_rwlock_t rwlock;
  133. pthread_t reader_thread;
  134. pthread_t writer_thread;
  135. struct ReaderWriterArgs rw_args;
  136. wait_queue = xQueueCreate(1, 1);
  137. TEST_ASSERT(wait_queue);
  138. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  139. rw_args.wait_queue = &wait_queue;
  140. rw_args.sem_wait_release_num = 1;
  141. rw_args.rwlock = &rwlock;
  142. rw_args.writing = false;
  143. rw_args.reading = false;
  144. TEST_ASSERT_EQUAL(pthread_create(&reader_thread, NULL, reader, &rw_args), 0);
  145. TEST_ASSERT_EQUAL(pthread_create(&writer_thread, NULL, writer, &rw_args), 0);
  146. TEST_ASSERT_EQUAL(pthread_join(writer_thread, NULL), 0);
  147. TEST_ASSERT_EQUAL(pthread_join(reader_thread, NULL), 0);
  148. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  149. vQueueDelete(wait_queue);
  150. }
  151. TEST_CASE("wrlock multiple readers wait", "[pthread][rwlock]")
  152. {
  153. static const size_t THREAD_NUM = 4;
  154. QueueHandle_t wait_queue;
  155. pthread_rwlock_t rwlock;
  156. pthread_t reader_thread[THREAD_NUM];
  157. pthread_t writer_thread;
  158. struct ReaderWriterArgs rw_args;
  159. wait_queue = xQueueCreate(THREAD_NUM, 1);
  160. TEST_ASSERT(wait_queue);
  161. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  162. rw_args.wait_queue = &wait_queue;
  163. rw_args.sem_wait_release_num = THREAD_NUM;
  164. rw_args.rwlock = &rwlock;
  165. rw_args.writing = false;
  166. rw_args.reading = false;
  167. for (size_t i = 0; i < THREAD_NUM; i++) {
  168. TEST_ASSERT_EQUAL(pthread_create(&(reader_thread[i]), NULL, reader, &rw_args), 0);
  169. }
  170. TEST_ASSERT_EQUAL(pthread_create(&writer_thread, NULL, writer, &rw_args), 0);
  171. TEST_ASSERT_EQUAL(pthread_join(writer_thread, NULL), 0);
  172. for (size_t i = 0; i < THREAD_NUM; i++) {
  173. TEST_ASSERT_EQUAL(pthread_join(reader_thread[i], NULL), 0);
  174. }
  175. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  176. vQueueDelete(wait_queue);
  177. }
  178. static void *writer2(void *arg)
  179. {
  180. uint8_t dummy_msg;
  181. struct ReaderWriterArgs *rw_args = (struct ReaderWriterArgs*) arg;
  182. TEST_ASSERT_EQUAL(xQueueReceive(*(rw_args->wait_queue), &dummy_msg, portMAX_DELAY), pdTRUE);
  183. TEST_ASSERT_TRUE(rw_args->writing);
  184. TEST_ASSERT_EQUAL_INT(pthread_rwlock_wrlock(rw_args->rwlock), 0);
  185. TEST_ASSERT_FALSE(rw_args->writing);
  186. rw_args->writing = true;
  187. vTaskDelay(10 / portTICK_PERIOD_MS);
  188. rw_args->writing = false;
  189. TEST_ASSERT_EQUAL_INT(pthread_rwlock_unlock(rw_args->rwlock), 0);
  190. return NULL;
  191. }
  192. TEST_CASE("wrlock writer waits", "[pthread][rwlock]")
  193. {
  194. QueueHandle_t wait_queue;
  195. pthread_rwlock_t rwlock;
  196. pthread_t writer_thread;
  197. pthread_t writer_2_thread;
  198. struct ReaderWriterArgs rw_args;
  199. wait_queue = xQueueCreate(1, 1);
  200. TEST_ASSERT(wait_queue);
  201. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  202. rw_args.wait_queue = &wait_queue;
  203. rw_args.sem_wait_release_num = 1;
  204. rw_args.rwlock = &rwlock;
  205. rw_args.writing = false;
  206. rw_args.reading = false;
  207. TEST_ASSERT_EQUAL(pthread_create(&writer_2_thread, NULL, writer2, &rw_args), 0);
  208. TEST_ASSERT_EQUAL(pthread_create(&writer_thread, NULL, writer, &rw_args), 0);
  209. TEST_ASSERT_EQUAL(pthread_join(writer_thread, NULL), 0);
  210. TEST_ASSERT_EQUAL(pthread_join(writer_2_thread, NULL), 0);
  211. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  212. vQueueDelete(wait_queue);
  213. }
  214. TEST_CASE("wrlock multiple writers wait", "[pthread][rwlock]")
  215. {
  216. static const size_t THREAD_NUM = 4;
  217. QueueHandle_t wait_queue;
  218. pthread_rwlock_t rwlock;
  219. pthread_t writer_thread;
  220. pthread_t writer_2_thread[THREAD_NUM];
  221. struct ReaderWriterArgs rw_args;
  222. wait_queue = xQueueCreate(THREAD_NUM, 1);
  223. TEST_ASSERT(wait_queue);
  224. TEST_ASSERT_EQUAL_INT(pthread_rwlock_init(&rwlock, NULL), 0);
  225. rw_args.wait_queue = &wait_queue;
  226. rw_args.sem_wait_release_num = THREAD_NUM;
  227. rw_args.rwlock = &rwlock;
  228. rw_args.writing = false;
  229. rw_args.reading = false;
  230. for (size_t i = 0; i < THREAD_NUM; i++) {
  231. TEST_ASSERT_EQUAL(pthread_create(&writer_2_thread[i], NULL, writer2, &rw_args), 0);
  232. }
  233. TEST_ASSERT_EQUAL(pthread_create(&writer_thread, NULL, writer, &rw_args), 0);
  234. TEST_ASSERT_EQUAL(pthread_join(writer_thread, NULL), 0);
  235. for (size_t i = 0; i < THREAD_NUM; i++) {
  236. TEST_ASSERT_EQUAL(pthread_join(writer_2_thread[i], NULL), 0);
  237. }
  238. TEST_ASSERT_EQUAL_INT(pthread_rwlock_destroy(&rwlock), 0);
  239. vQueueDelete(wait_queue);
  240. }