1 /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
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
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.
19 #include "apr_reslist.h"
20 #include "apr_thread_proc.h"
24 #endif /* APR_HAVE_TIME_H */
30 fprintf(stderr
, "this program requires APR thread support\n");
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 */
47 apr_interval_time_t sleep_upon_construct
;
48 apr_interval_time_t sleep_upon_destruct
;
57 static apr_status_t
my_constructor(void **resource
, void *params
,
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 */
78 static apr_status_t
my_destructor(void *resource
, void *params
,
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
);
94 apr_reslist_t
*reslist
;
95 apr_interval_time_t work_delay_sleep
;
98 static void * APR_THREAD_FUNC
resource_consuming_thread(apr_thread_t
*thd
,
102 my_thread_info_t
*thread_info
= data
;
103 apr_reslist_t
*rl
= thread_info
->reslist
;
106 for (i
= 0; i
< CONSUMER_ITERATIONS
; i
++) {
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
);
116 printf(" [tid:%d,iter:%d] using resource id:%d\n", thread_info
->tid
,
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
);
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
);
141 static void test_timeout(apr_reslist_t
*rl
)
144 my_resource_t
*resources
[RESLIST_HMAX
];
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
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
);
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",
176 /* release the resources; otherwise the destroy operation
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
);
188 static apr_status_t
test_reslist(apr_pool_t
*parpool
)
193 my_parameters_t
*params
;
195 apr_thread_t
*my_threads
[CONSUMER_THREADS
];
196 my_thread_info_t my_thread_info
[CONSUMER_THREADS
];
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");
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
,
221 if (rv
!= APR_SUCCESS
) {
222 fprintf(stderr
, "Error allocating shared memory block\n");
225 fprintf(stdout
, "OK\n");
227 printf("Creating %d threads", CONSUMER_THREADS
);
228 for (i
= 0; i
< CONSUMER_THREADS
; i
++) {
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
],
236 if (rv
!= APR_SUCCESS
) {
237 fprintf(stderr
, "Failed to create thread %d\n", i
);
243 printf("Waiting for threads to finish");
244 for (i
= 0; i
< CONSUMER_THREADS
; i
++) {
245 apr_status_t thread_rv
;
247 apr_thread_join(&thread_rv
, my_threads
[i
]);
248 if (rv
!= APR_SUCCESS
) {
249 fprintf(stderr
, "Failed to join thread %d\n", i
);
257 printf("Destroying resource list.................");
258 rv
= apr_reslist_destroy(rl
);
259 if (rv
!= APR_SUCCESS
) {
265 apr_pool_destroy(pool
);
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");
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
)));
295 printf("Resource list test passed!\n");
300 #endif /* APR_HAS_THREADS */