testlock.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "fspr_thread_proc.h"
  17. #include "fspr_file_io.h"
  18. #include "fspr_thread_mutex.h"
  19. #include "fspr_thread_rwlock.h"
  20. #include "fspr_thread_cond.h"
  21. #include "fspr_errno.h"
  22. #include "fspr_general.h"
  23. #include "fspr_getopt.h"
  24. #include "testutil.h"
  25. #if APR_HAS_THREADS
  26. #define MAX_ITER 40000
  27. #define MAX_COUNTER 100000
  28. #define MAX_RETRY 5
  29. static void *APR_THREAD_FUNC thread_rwlock_func(fspr_thread_t *thd, void *data);
  30. static void *APR_THREAD_FUNC thread_mutex_function(fspr_thread_t *thd, void *data);
  31. static void *APR_THREAD_FUNC thread_cond_producer(fspr_thread_t *thd, void *data);
  32. static void *APR_THREAD_FUNC thread_cond_consumer(fspr_thread_t *thd, void *data);
  33. static fspr_thread_mutex_t *thread_mutex;
  34. static fspr_thread_rwlock_t *rwlock;
  35. static int i = 0, x = 0;
  36. static int buff[MAX_COUNTER];
  37. struct {
  38. fspr_thread_mutex_t *mutex;
  39. int nput;
  40. int nval;
  41. } put;
  42. struct {
  43. fspr_thread_mutex_t *mutex;
  44. fspr_thread_cond_t *cond;
  45. int nready;
  46. } nready;
  47. static fspr_thread_mutex_t *timeout_mutex;
  48. static fspr_thread_cond_t *timeout_cond;
  49. static void *APR_THREAD_FUNC thread_rwlock_func(fspr_thread_t *thd, void *data)
  50. {
  51. int exitLoop = 1;
  52. while (1)
  53. {
  54. fspr_thread_rwlock_rdlock(rwlock);
  55. if (i == MAX_ITER)
  56. exitLoop = 0;
  57. fspr_thread_rwlock_unlock(rwlock);
  58. if (!exitLoop)
  59. break;
  60. fspr_thread_rwlock_wrlock(rwlock);
  61. if (i != MAX_ITER)
  62. {
  63. i++;
  64. x++;
  65. }
  66. fspr_thread_rwlock_unlock(rwlock);
  67. }
  68. return NULL;
  69. }
  70. static void *APR_THREAD_FUNC thread_mutex_function(fspr_thread_t *thd, void *data)
  71. {
  72. int exitLoop = 1;
  73. /* slight delay to allow things to settle */
  74. fspr_sleep (1);
  75. while (1)
  76. {
  77. fspr_thread_mutex_lock(thread_mutex);
  78. if (i == MAX_ITER)
  79. exitLoop = 0;
  80. else
  81. {
  82. i++;
  83. x++;
  84. }
  85. fspr_thread_mutex_unlock(thread_mutex);
  86. if (!exitLoop)
  87. break;
  88. }
  89. return NULL;
  90. }
  91. static void *APR_THREAD_FUNC thread_cond_producer(fspr_thread_t *thd, void *data)
  92. {
  93. for (;;) {
  94. fspr_thread_mutex_lock(put.mutex);
  95. if (put.nput >= MAX_COUNTER) {
  96. fspr_thread_mutex_unlock(put.mutex);
  97. return NULL;
  98. }
  99. buff[put.nput] = put.nval;
  100. put.nput++;
  101. put.nval++;
  102. fspr_thread_mutex_unlock(put.mutex);
  103. fspr_thread_mutex_lock(nready.mutex);
  104. if (nready.nready == 0)
  105. fspr_thread_cond_signal(nready.cond);
  106. nready.nready++;
  107. fspr_thread_mutex_unlock(nready.mutex);
  108. *((int *) data) += 1;
  109. }
  110. return NULL;
  111. }
  112. static void *APR_THREAD_FUNC thread_cond_consumer(fspr_thread_t *thd, void *data)
  113. {
  114. int i;
  115. for (i = 0; i < MAX_COUNTER; i++) {
  116. fspr_thread_mutex_lock(nready.mutex);
  117. while (nready.nready == 0)
  118. fspr_thread_cond_wait(nready.cond, nready.mutex);
  119. nready.nready--;
  120. fspr_thread_mutex_unlock(nready.mutex);
  121. if (buff[i] != i)
  122. printf("buff[%d] = %d\n", i, buff[i]);
  123. }
  124. return NULL;
  125. }
  126. static void test_thread_mutex(abts_case *tc, void *data)
  127. {
  128. fspr_thread_t *t1, *t2, *t3, *t4;
  129. fspr_status_t s1, s2, s3, s4;
  130. s1 = fspr_thread_mutex_create(&thread_mutex, APR_THREAD_MUTEX_DEFAULT, p);
  131. ABTS_INT_EQUAL(tc, APR_SUCCESS, s1);
  132. ABTS_PTR_NOTNULL(tc, thread_mutex);
  133. i = 0;
  134. x = 0;
  135. s1 = fspr_thread_create(&t1, NULL, thread_mutex_function, NULL, p);
  136. ABTS_INT_EQUAL(tc, APR_SUCCESS, s1);
  137. s2 = fspr_thread_create(&t2, NULL, thread_mutex_function, NULL, p);
  138. ABTS_INT_EQUAL(tc, APR_SUCCESS, s2);
  139. s3 = fspr_thread_create(&t3, NULL, thread_mutex_function, NULL, p);
  140. ABTS_INT_EQUAL(tc, APR_SUCCESS, s3);
  141. s4 = fspr_thread_create(&t4, NULL, thread_mutex_function, NULL, p);
  142. ABTS_INT_EQUAL(tc, APR_SUCCESS, s4);
  143. fspr_thread_join(&s1, t1);
  144. fspr_thread_join(&s2, t2);
  145. fspr_thread_join(&s3, t3);
  146. fspr_thread_join(&s4, t4);
  147. ABTS_INT_EQUAL(tc, MAX_ITER, x);
  148. }
  149. static void test_thread_rwlock(abts_case *tc, void *data)
  150. {
  151. fspr_thread_t *t1, *t2, *t3, *t4;
  152. fspr_status_t s1, s2, s3, s4;
  153. s1 = fspr_thread_rwlock_create(&rwlock, p);
  154. if (s1 == APR_ENOTIMPL) {
  155. ABTS_NOT_IMPL(tc, "rwlocks not implemented");
  156. return;
  157. }
  158. APR_ASSERT_SUCCESS(tc, "rwlock_create", s1);
  159. ABTS_PTR_NOTNULL(tc, rwlock);
  160. i = 0;
  161. x = 0;
  162. s1 = fspr_thread_create(&t1, NULL, thread_rwlock_func, NULL, p);
  163. APR_ASSERT_SUCCESS(tc, "create thread 1", s1);
  164. s2 = fspr_thread_create(&t2, NULL, thread_rwlock_func, NULL, p);
  165. APR_ASSERT_SUCCESS(tc, "create thread 2", s2);
  166. s3 = fspr_thread_create(&t3, NULL, thread_rwlock_func, NULL, p);
  167. APR_ASSERT_SUCCESS(tc, "create thread 3", s3);
  168. s4 = fspr_thread_create(&t4, NULL, thread_rwlock_func, NULL, p);
  169. APR_ASSERT_SUCCESS(tc, "create thread 4", s4);
  170. fspr_thread_join(&s1, t1);
  171. fspr_thread_join(&s2, t2);
  172. fspr_thread_join(&s3, t3);
  173. fspr_thread_join(&s4, t4);
  174. ABTS_INT_EQUAL(tc, MAX_ITER, x);
  175. fspr_thread_rwlock_destroy(rwlock);
  176. }
  177. static void test_cond(abts_case *tc, void *data)
  178. {
  179. fspr_thread_t *p1, *p2, *p3, *p4, *c1;
  180. fspr_status_t s0, s1, s2, s3, s4;
  181. int count1, count2, count3, count4;
  182. int sum;
  183. APR_ASSERT_SUCCESS(tc, "create put mutex",
  184. fspr_thread_mutex_create(&put.mutex,
  185. APR_THREAD_MUTEX_DEFAULT, p));
  186. ABTS_PTR_NOTNULL(tc, put.mutex);
  187. APR_ASSERT_SUCCESS(tc, "create nready mutex",
  188. fspr_thread_mutex_create(&nready.mutex,
  189. APR_THREAD_MUTEX_DEFAULT, p));
  190. ABTS_PTR_NOTNULL(tc, nready.mutex);
  191. APR_ASSERT_SUCCESS(tc, "create condvar",
  192. fspr_thread_cond_create(&nready.cond, p));
  193. ABTS_PTR_NOTNULL(tc, nready.cond);
  194. count1 = count2 = count3 = count4 = 0;
  195. put.nput = put.nval = 0;
  196. nready.nready = 0;
  197. i = 0;
  198. x = 0;
  199. s0 = fspr_thread_create(&p1, NULL, thread_cond_producer, &count1, p);
  200. ABTS_INT_EQUAL(tc, APR_SUCCESS, s0);
  201. s1 = fspr_thread_create(&p2, NULL, thread_cond_producer, &count2, p);
  202. ABTS_INT_EQUAL(tc, APR_SUCCESS, s1);
  203. s2 = fspr_thread_create(&p3, NULL, thread_cond_producer, &count3, p);
  204. ABTS_INT_EQUAL(tc, APR_SUCCESS, s2);
  205. s3 = fspr_thread_create(&p4, NULL, thread_cond_producer, &count4, p);
  206. ABTS_INT_EQUAL(tc, APR_SUCCESS, s3);
  207. s4 = fspr_thread_create(&c1, NULL, thread_cond_consumer, NULL, p);
  208. ABTS_INT_EQUAL(tc, APR_SUCCESS, s4);
  209. fspr_thread_join(&s0, p1);
  210. fspr_thread_join(&s1, p2);
  211. fspr_thread_join(&s2, p3);
  212. fspr_thread_join(&s3, p4);
  213. fspr_thread_join(&s4, c1);
  214. APR_ASSERT_SUCCESS(tc, "destroy condvar",
  215. fspr_thread_cond_destroy(nready.cond));
  216. sum = count1 + count2 + count3 + count4;
  217. /*
  218. printf("count1 = %d count2 = %d count3 = %d count4 = %d\n",
  219. count1, count2, count3, count4);
  220. */
  221. ABTS_INT_EQUAL(tc, MAX_COUNTER, sum);
  222. }
  223. static void test_timeoutcond(abts_case *tc, void *data)
  224. {
  225. fspr_status_t s;
  226. fspr_interval_time_t timeout;
  227. fspr_time_t begin, end;
  228. int i;
  229. s = fspr_thread_mutex_create(&timeout_mutex, APR_THREAD_MUTEX_DEFAULT, p);
  230. ABTS_INT_EQUAL(tc, APR_SUCCESS, s);
  231. ABTS_PTR_NOTNULL(tc, timeout_mutex);
  232. s = fspr_thread_cond_create(&timeout_cond, p);
  233. ABTS_INT_EQUAL(tc, APR_SUCCESS, s);
  234. ABTS_PTR_NOTNULL(tc, timeout_cond);
  235. timeout = fspr_time_from_sec(5);
  236. for (i = 0; i < MAX_RETRY; i++) {
  237. fspr_thread_mutex_lock(timeout_mutex);
  238. begin = fspr_time_now();
  239. s = fspr_thread_cond_timedwait(timeout_cond, timeout_mutex, timeout);
  240. end = fspr_time_now();
  241. fspr_thread_mutex_unlock(timeout_mutex);
  242. if (s != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(s)) {
  243. continue;
  244. }
  245. ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(s));
  246. ABTS_ASSERT(tc, "Timer returned too late", end - begin - timeout < 100000);
  247. break;
  248. }
  249. ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY);
  250. APR_ASSERT_SUCCESS(tc, "Unable to destroy the conditional",
  251. fspr_thread_cond_destroy(timeout_cond));
  252. }
  253. #endif /* !APR_HAS_THREADS */
  254. #if !APR_HAS_THREADS
  255. static void threads_not_impl(abts_case *tc, void *data)
  256. {
  257. ABTS_NOT_IMPL(tc, "Threads not implemented on this platform");
  258. }
  259. #endif
  260. abts_suite *testlock(abts_suite *suite)
  261. {
  262. suite = ADD_SUITE(suite)
  263. #if !APR_HAS_THREADS
  264. abts_run_test(suite, threads_not_impl, NULL);
  265. #else
  266. abts_run_test(suite, test_thread_mutex, NULL);
  267. abts_run_test(suite, test_thread_rwlock, NULL);
  268. abts_run_test(suite, test_cond, NULL);
  269. abts_run_test(suite, test_timeoutcond, NULL);
  270. #endif
  271. return suite;
  272. }