testreslist.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
  2. * applicable.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * 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 <stdio.h>
  17. #include <stdlib.h>
  18. #include "apr_reslist.h"
  19. #include "apr_thread_proc.h"
  20. #if APR_HAVE_TIME_H
  21. #include <time.h>
  22. #endif /* APR_HAVE_TIME_H */
  23. #if !APR_HAS_THREADS
  24. int main(void)
  25. {
  26. fprintf(stderr, "this program requires APR thread support\n");
  27. return 0;
  28. }
  29. #else
  30. #define RESLIST_MIN 3
  31. #define RESLIST_SMAX 10
  32. #define RESLIST_HMAX 20
  33. #define RESLIST_TTL APR_TIME_C(350000) /* 35 ms */
  34. #define CONSUMER_THREADS 25
  35. #define CONSUMER_ITERATIONS 250
  36. #define CONSTRUCT_SLEEP_TIME APR_TIME_C(250000) /* 25 ms */
  37. #define DESTRUCT_SLEEP_TIME APR_TIME_C(100000) /* 10 ms */
  38. #define WORK_DELAY_SLEEP_TIME APR_TIME_C(150000) /* 15 ms */
  39. typedef struct {
  40. apr_interval_time_t sleep_upon_construct;
  41. apr_interval_time_t sleep_upon_destruct;
  42. int c_count;
  43. int d_count;
  44. } my_parameters_t;
  45. typedef struct {
  46. int id;
  47. } my_resource_t;
  48. static apr_status_t my_constructor(void **resource, void *params,
  49. apr_pool_t *pool)
  50. {
  51. my_resource_t *res;
  52. my_parameters_t *my_params = params;
  53. /* Create some resource */
  54. res = apr_palloc(pool, sizeof(*res));
  55. res->id = my_params->c_count++;
  56. printf("++ constructing new resource [id:%d, #%d/%d]\n", res->id,
  57. my_params->c_count, my_params->d_count);
  58. /* Sleep for awhile, to simulate construction overhead. */
  59. apr_sleep(my_params->sleep_upon_construct);
  60. /* Set the resource so it can be managed by the reslist */
  61. *resource = res;
  62. return APR_SUCCESS;
  63. }
  64. static apr_status_t my_destructor(void *resource, void *params,
  65. apr_pool_t *pool)
  66. {
  67. my_resource_t *res = resource;
  68. my_parameters_t *my_params = params;
  69. printf("-- destructing old resource [id:%d, #%d/%d]\n", res->id,
  70. my_params->c_count, ++my_params->d_count);
  71. apr_sleep(my_params->sleep_upon_destruct);
  72. return APR_SUCCESS;
  73. }
  74. typedef struct {
  75. int tid;
  76. apr_reslist_t *reslist;
  77. apr_interval_time_t work_delay_sleep;
  78. } my_thread_info_t;
  79. static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd,
  80. void *data)
  81. {
  82. apr_status_t rv;
  83. my_thread_info_t *thread_info = data;
  84. apr_reslist_t *rl = thread_info->reslist;
  85. int i;
  86. for (i = 0; i < CONSUMER_ITERATIONS; i++) {
  87. my_resource_t *res;
  88. void *vp;
  89. rv = apr_reslist_acquire(rl, &vp);
  90. if (rv != APR_SUCCESS) {
  91. fprintf(stderr, "Failed to retrieve resource from reslist\n");
  92. apr_thread_exit(thd, rv);
  93. return NULL;
  94. }
  95. res = vp;
  96. printf(" [tid:%d,iter:%d] using resource id:%d\n", thread_info->tid,
  97. i, res->id);
  98. apr_sleep(thread_info->work_delay_sleep);
  99. /* simulate a 5% chance of the resource being bad */
  100. if ( drand48() < 0.95 ) {
  101. rv = apr_reslist_release(rl, res);
  102. if (rv != APR_SUCCESS) {
  103. fprintf(stderr, "Failed to return resource to reslist\n");
  104. apr_thread_exit(thd, rv);
  105. return NULL;
  106. }
  107. } else {
  108. printf("invalidating resource id:%d\n", res->id) ;
  109. rv = apr_reslist_invalidate(rl, res);
  110. if (rv != APR_SUCCESS) {
  111. fprintf(stderr, "Failed to invalidate resource\n");
  112. apr_thread_exit(thd, rv);
  113. return NULL;
  114. }
  115. }
  116. }
  117. return APR_SUCCESS;
  118. }
  119. static void test_timeout(apr_reslist_t *rl)
  120. {
  121. apr_status_t rv;
  122. my_resource_t *resources[RESLIST_HMAX];
  123. my_resource_t *res;
  124. void *vp;
  125. int i;
  126. printf("Setting timeout to 1000us: ");
  127. apr_reslist_timeout_set(rl, 1000);
  128. fprintf(stdout, "OK\n");
  129. /* deplete all possible resources from the resource list
  130. * so that the next call will block until timeout is reached
  131. * (since there are no other threads to make a resource
  132. * available)
  133. */
  134. for (i = 0; i < RESLIST_HMAX; i++) {
  135. rv = apr_reslist_acquire(rl, (void**)&resources[i]);
  136. if (rv != APR_SUCCESS) {
  137. fprintf(stderr, "couldn't acquire resource: %d\n", rv);
  138. exit(1);
  139. }
  140. }
  141. /* next call will block until timeout is reached */
  142. rv = apr_reslist_acquire(rl, &vp);
  143. if (!APR_STATUS_IS_TIMEUP(rv)) {
  144. fprintf(stderr, "apr_reslist_acquire()->%d instead of TIMEUP\n",
  145. rv);
  146. exit(1);
  147. }
  148. res = vp;
  149. /* release the resources; otherwise the destroy operation
  150. * will blow
  151. */
  152. for (i = 0; i < RESLIST_HMAX; i++) {
  153. rv = apr_reslist_release(rl, &resources[i]);
  154. if (rv != APR_SUCCESS) {
  155. fprintf(stderr, "couldn't release resource: %d\n", rv);
  156. exit(1);
  157. }
  158. }
  159. }
  160. static apr_status_t test_reslist(apr_pool_t *parpool)
  161. {
  162. apr_status_t rv;
  163. apr_pool_t *pool;
  164. apr_reslist_t *rl;
  165. my_parameters_t *params;
  166. int i;
  167. apr_thread_t *my_threads[CONSUMER_THREADS];
  168. my_thread_info_t my_thread_info[CONSUMER_THREADS];
  169. srand48(time(0)) ;
  170. printf("Creating child pool.......................");
  171. rv = apr_pool_create(&pool, parpool);
  172. if (rv != APR_SUCCESS) {
  173. fprintf(stderr, "Error creating child pool\n");
  174. return rv;
  175. }
  176. printf("OK\n");
  177. /* Create some parameters that will be passed into each
  178. * constructor and destructor call. */
  179. params = apr_pcalloc(pool, sizeof(*params));
  180. params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME;
  181. params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME;
  182. /* We're going to want 10 blocks of data from our target rmm. */
  183. printf("Creating resource list:\n"
  184. " min/smax/hmax: %d/%d/%d\n"
  185. " ttl: %" APR_TIME_T_FMT "\n", RESLIST_MIN, RESLIST_SMAX,
  186. RESLIST_HMAX, RESLIST_TTL);
  187. rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX,
  188. RESLIST_TTL, my_constructor, my_destructor,
  189. params, pool);
  190. if (rv != APR_SUCCESS) {
  191. fprintf(stderr, "Error allocating shared memory block\n");
  192. return rv;
  193. }
  194. fprintf(stdout, "OK\n");
  195. printf("Creating %d threads", CONSUMER_THREADS);
  196. for (i = 0; i < CONSUMER_THREADS; i++) {
  197. putchar('.');
  198. my_thread_info[i].tid = i;
  199. my_thread_info[i].reslist = rl;
  200. my_thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME;
  201. rv = apr_thread_create(&my_threads[i], NULL,
  202. resource_consuming_thread, &my_thread_info[i],
  203. pool);
  204. if (rv != APR_SUCCESS) {
  205. fprintf(stderr, "Failed to create thread %d\n", i);
  206. return rv;
  207. }
  208. }
  209. printf("\nDone!\n");
  210. printf("Waiting for threads to finish");
  211. for (i = 0; i < CONSUMER_THREADS; i++) {
  212. apr_status_t thread_rv;
  213. putchar('.');
  214. apr_thread_join(&thread_rv, my_threads[i]);
  215. if (rv != APR_SUCCESS) {
  216. fprintf(stderr, "Failed to join thread %d\n", i);
  217. return rv;
  218. }
  219. }
  220. printf("\nDone!\n");
  221. test_timeout(rl);
  222. printf("Destroying resource list.................");
  223. rv = apr_reslist_destroy(rl);
  224. if (rv != APR_SUCCESS) {
  225. printf("FAILED\n");
  226. return rv;
  227. }
  228. printf("OK\n");
  229. apr_pool_destroy(pool);
  230. return APR_SUCCESS;
  231. }
  232. int main(void)
  233. {
  234. apr_status_t rv;
  235. apr_pool_t *pool;
  236. char errmsg[200];
  237. apr_initialize();
  238. printf("APR Resource List Test\n");
  239. printf("======================\n\n");
  240. printf("Initializing the pool............................");
  241. if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
  242. printf("could not initialize pool\n");
  243. exit(-1);
  244. }
  245. printf("OK\n");
  246. rv = test_reslist(pool);
  247. if (rv != APR_SUCCESS) {
  248. printf("Resource list test FAILED: [%d] %s\n",
  249. rv, apr_strerror(rv, errmsg, sizeof(errmsg)));
  250. exit(-2);
  251. }
  252. printf("Resource list test passed!\n");
  253. return 0;
  254. }
  255. #endif /* APR_HAS_THREADS */