Fix bug #42294
[apr-util.git] / test / testreslist.c
blob2d3865fb1952fd0e8ac62b59b5a602df4972c931
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include "apr_reslist.h"
20 #include "apr_thread_proc.h"
22 #if APR_HAVE_TIME_H
23 #include <time.h>
24 #endif /* APR_HAVE_TIME_H */
26 #if !APR_HAS_THREADS
28 int main(void)
30 fprintf(stderr, "this program requires APR thread support\n");
31 return 0;
34 #else
36 #define RESLIST_MIN 3
37 #define RESLIST_SMAX 10
38 #define RESLIST_HMAX 20
39 #define RESLIST_TTL APR_TIME_C(350000) /* 35 ms */
40 #define CONSUMER_THREADS 25
41 #define CONSUMER_ITERATIONS 250
42 #define CONSTRUCT_SLEEP_TIME APR_TIME_C(250000) /* 25 ms */
43 #define DESTRUCT_SLEEP_TIME APR_TIME_C(100000) /* 10 ms */
44 #define WORK_DELAY_SLEEP_TIME APR_TIME_C(150000) /* 15 ms */
46 typedef struct {
47 apr_interval_time_t sleep_upon_construct;
48 apr_interval_time_t sleep_upon_destruct;
49 int c_count;
50 int d_count;
51 } my_parameters_t;
53 typedef struct {
54 int id;
55 } my_resource_t;
57 static apr_status_t my_constructor(void **resource, void *params,
58 apr_pool_t *pool)
60 my_resource_t *res;
61 my_parameters_t *my_params = params;
63 /* Create some resource */
64 res = apr_palloc(pool, sizeof(*res));
65 res->id = my_params->c_count++;
67 printf("++ constructing new resource [id:%d, #%d/%d]\n", res->id,
68 my_params->c_count, my_params->d_count);
70 /* Sleep for awhile, to simulate construction overhead. */
71 apr_sleep(my_params->sleep_upon_construct);
73 /* Set the resource so it can be managed by the reslist */
74 *resource = res;
75 return APR_SUCCESS;
78 static apr_status_t my_destructor(void *resource, void *params,
79 apr_pool_t *pool)
81 my_resource_t *res = resource;
82 my_parameters_t *my_params = params;
84 printf("-- destructing old resource [id:%d, #%d/%d]\n", res->id,
85 my_params->c_count, ++my_params->d_count);
87 apr_sleep(my_params->sleep_upon_destruct);
89 return APR_SUCCESS;
92 typedef struct {
93 int tid;
94 apr_reslist_t *reslist;
95 apr_interval_time_t work_delay_sleep;
96 } my_thread_info_t;
98 static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd,
99 void *data)
101 apr_status_t rv;
102 my_thread_info_t *thread_info = data;
103 apr_reslist_t *rl = thread_info->reslist;
104 int i;
106 for (i = 0; i < CONSUMER_ITERATIONS; i++) {
107 my_resource_t *res;
108 void *vp;
109 rv = apr_reslist_acquire(rl, &vp);
110 if (rv != APR_SUCCESS) {
111 fprintf(stderr, "Failed to retrieve resource from reslist\n");
112 apr_thread_exit(thd, rv);
113 return NULL;
115 res = vp;
116 printf(" [tid:%d,iter:%d] using resource id:%d\n", thread_info->tid,
117 i, res->id);
118 apr_sleep(thread_info->work_delay_sleep);
119 /* simulate a 5% chance of the resource being bad */
120 if ( drand48() < 0.95 ) {
121 rv = apr_reslist_release(rl, res);
122 if (rv != APR_SUCCESS) {
123 fprintf(stderr, "Failed to return resource to reslist\n");
124 apr_thread_exit(thd, rv);
125 return NULL;
127 } else {
128 printf("invalidating resource id:%d\n", res->id) ;
129 rv = apr_reslist_invalidate(rl, res);
130 if (rv != APR_SUCCESS) {
131 fprintf(stderr, "Failed to invalidate resource\n");
132 apr_thread_exit(thd, rv);
133 return NULL;
138 return APR_SUCCESS;
141 static void test_timeout(apr_reslist_t *rl)
143 apr_status_t rv;
144 my_resource_t *resources[RESLIST_HMAX];
145 my_resource_t *res;
146 void *vp;
147 int i;
149 printf("Setting timeout to 1000us: ");
150 apr_reslist_timeout_set(rl, 1000);
151 fprintf(stdout, "OK\n");
153 /* deplete all possible resources from the resource list
154 * so that the next call will block until timeout is reached
155 * (since there are no other threads to make a resource
156 * available)
159 for (i = 0; i < RESLIST_HMAX; i++) {
160 rv = apr_reslist_acquire(rl, (void**)&resources[i]);
161 if (rv != APR_SUCCESS) {
162 fprintf(stderr, "couldn't acquire resource: %d\n", rv);
163 exit(1);
167 /* next call will block until timeout is reached */
168 rv = apr_reslist_acquire(rl, &vp);
169 if (!APR_STATUS_IS_TIMEUP(rv)) {
170 fprintf(stderr, "apr_reslist_acquire()->%d instead of TIMEUP\n",
171 rv);
172 exit(1);
174 res = vp;
176 /* release the resources; otherwise the destroy operation
177 * will blow
179 for (i = 0; i < RESLIST_HMAX; i++) {
180 rv = apr_reslist_release(rl, &resources[i]);
181 if (rv != APR_SUCCESS) {
182 fprintf(stderr, "couldn't release resource: %d\n", rv);
183 exit(1);
188 static apr_status_t test_reslist(apr_pool_t *parpool)
190 apr_status_t rv;
191 apr_pool_t *pool;
192 apr_reslist_t *rl;
193 my_parameters_t *params;
194 int i;
195 apr_thread_t *my_threads[CONSUMER_THREADS];
196 my_thread_info_t my_thread_info[CONSUMER_THREADS];
197 srand48(time(0)) ;
199 printf("Creating child pool.......................");
200 rv = apr_pool_create(&pool, parpool);
201 if (rv != APR_SUCCESS) {
202 fprintf(stderr, "Error creating child pool\n");
203 return rv;
205 printf("OK\n");
207 /* Create some parameters that will be passed into each
208 * constructor and destructor call. */
209 params = apr_pcalloc(pool, sizeof(*params));
210 params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME;
211 params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME;
213 /* We're going to want 10 blocks of data from our target rmm. */
214 printf("Creating resource list:\n"
215 " min/smax/hmax: %d/%d/%d\n"
216 " ttl: %" APR_TIME_T_FMT "\n", RESLIST_MIN, RESLIST_SMAX,
217 RESLIST_HMAX, RESLIST_TTL);
218 rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX,
219 RESLIST_TTL, my_constructor, my_destructor,
220 params, pool);
221 if (rv != APR_SUCCESS) {
222 fprintf(stderr, "Error allocating shared memory block\n");
223 return rv;
225 fprintf(stdout, "OK\n");
227 printf("Creating %d threads", CONSUMER_THREADS);
228 for (i = 0; i < CONSUMER_THREADS; i++) {
229 putchar('.');
230 my_thread_info[i].tid = i;
231 my_thread_info[i].reslist = rl;
232 my_thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME;
233 rv = apr_thread_create(&my_threads[i], NULL,
234 resource_consuming_thread, &my_thread_info[i],
235 pool);
236 if (rv != APR_SUCCESS) {
237 fprintf(stderr, "Failed to create thread %d\n", i);
238 return rv;
241 printf("\nDone!\n");
243 printf("Waiting for threads to finish");
244 for (i = 0; i < CONSUMER_THREADS; i++) {
245 apr_status_t thread_rv;
246 putchar('.');
247 apr_thread_join(&thread_rv, my_threads[i]);
248 if (rv != APR_SUCCESS) {
249 fprintf(stderr, "Failed to join thread %d\n", i);
250 return rv;
253 printf("\nDone!\n");
255 test_timeout(rl);
257 printf("Destroying resource list.................");
258 rv = apr_reslist_destroy(rl);
259 if (rv != APR_SUCCESS) {
260 printf("FAILED\n");
261 return rv;
263 printf("OK\n");
265 apr_pool_destroy(pool);
267 return APR_SUCCESS;
271 int main(void)
273 apr_status_t rv;
274 apr_pool_t *pool;
275 char errmsg[200];
277 apr_initialize();
279 printf("APR Resource List Test\n");
280 printf("======================\n\n");
282 printf("Initializing the pool............................");
283 if (apr_pool_create(&pool, NULL) != APR_SUCCESS) {
284 printf("could not initialize pool\n");
285 exit(-1);
287 printf("OK\n");
289 rv = test_reslist(pool);
290 if (rv != APR_SUCCESS) {
291 printf("Resource list test FAILED: [%d] %s\n",
292 rv, apr_strerror(rv, errmsg, sizeof(errmsg)));
293 exit(-2);
295 printf("Resource list test passed!\n");
297 return 0;
300 #endif /* APR_HAS_THREADS */