Revert change to testdate.c (commited by accident)
[apr-util.git] / test / testreslist.c
blobc227ff3468e9380e8d2ec8e58f7b49ad8f9e96c9
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>
20 #include "apu.h"
21 #include "apr_reslist.h"
22 #include "apr_thread_pool.h"
24 #if APR_HAVE_TIME_H
25 #include <time.h>
26 #endif /* APR_HAVE_TIME_H */
28 #include "abts.h"
29 #include "testutil.h"
31 #if APR_HAS_THREADS
33 #define RESLIST_MIN 3
34 #define RESLIST_SMAX 10
35 #define RESLIST_HMAX 20
36 #define RESLIST_TTL APR_TIME_C(350000) /* 35 ms */
37 #define CONSUMER_THREADS 25
38 #define CONSUMER_ITERATIONS 250
39 #define CONSTRUCT_SLEEP_TIME APR_TIME_C(250000) /* 25 ms */
40 #define DESTRUCT_SLEEP_TIME APR_TIME_C(100000) /* 10 ms */
41 #define WORK_DELAY_SLEEP_TIME APR_TIME_C(150000) /* 15 ms */
43 typedef struct {
44 apr_interval_time_t sleep_upon_construct;
45 apr_interval_time_t sleep_upon_destruct;
46 int c_count;
47 int d_count;
48 } my_parameters_t;
50 typedef struct {
51 int id;
52 } my_resource_t;
54 static apr_status_t my_constructor(void **resource, void *params,
55 apr_pool_t *pool)
57 my_resource_t *res;
58 my_parameters_t *my_params = params;
60 /* Create some resource */
61 res = apr_palloc(pool, sizeof(*res));
62 res->id = my_params->c_count++;
64 /* Sleep for awhile, to simulate construction overhead. */
65 apr_sleep(my_params->sleep_upon_construct);
67 /* Set the resource so it can be managed by the reslist */
68 *resource = res;
69 return APR_SUCCESS;
72 static apr_status_t my_destructor(void *resource, void *params,
73 apr_pool_t *pool)
75 my_resource_t *res = resource;
76 my_parameters_t *my_params = params;
77 res->id = my_params->d_count++;
79 apr_sleep(my_params->sleep_upon_destruct);
81 return APR_SUCCESS;
84 typedef struct {
85 int tid;
86 abts_case *tc;
87 apr_reslist_t *reslist;
88 apr_interval_time_t work_delay_sleep;
89 } my_thread_info_t;
91 static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd,
92 void *data)
94 int i;
95 void *vp;
96 apr_status_t rv;
97 my_resource_t *res;
98 my_thread_info_t *thread_info = data;
99 apr_reslist_t *rl = thread_info->reslist;
101 for (i = 0; i < CONSUMER_ITERATIONS; i++) {
102 rv = apr_reslist_acquire(rl, &vp);
103 ABTS_INT_EQUAL(thread_info->tc, rv, APR_SUCCESS);
104 res = vp;
105 apr_sleep(thread_info->work_delay_sleep);
107 /* simulate a 5% chance of the resource being bad */
108 if (drand48() < 0.95) {
109 rv = apr_reslist_release(rl, res);
110 ABTS_INT_EQUAL(thread_info->tc, rv, APR_SUCCESS);
111 } else {
112 rv = apr_reslist_invalidate(rl, res);
113 ABTS_INT_EQUAL(thread_info->tc, rv, APR_SUCCESS);
117 return APR_SUCCESS;
120 static void test_timeout(abts_case *tc, apr_reslist_t *rl)
122 apr_status_t rv;
123 my_resource_t *resources[RESLIST_HMAX];
124 my_resource_t *res;
125 void *vp;
126 int i;
128 apr_reslist_timeout_set(rl, 1000);
130 /* deplete all possible resources from the resource list
131 * so that the next call will block until timeout is reached
132 * (since there are no other threads to make a resource
133 * available)
136 for (i = 0; i < RESLIST_HMAX; i++) {
137 rv = apr_reslist_acquire(rl, (void**)&resources[i]);
138 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
141 /* next call will block until timeout is reached */
142 rv = apr_reslist_acquire(rl, &vp);
143 ABTS_TRUE(tc, APR_STATUS_IS_TIMEUP(rv));
145 res = vp;
147 /* release the resources; otherwise the destroy operation
148 * will blow
150 for (i = 0; i < RESLIST_HMAX; i++) {
151 rv = apr_reslist_release(rl, resources[i]);
152 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
156 static void test_shrinking(abts_case *tc, apr_reslist_t *rl)
158 apr_status_t rv;
159 my_resource_t *resources[RESLIST_HMAX];
160 my_resource_t *res;
161 void *vp;
162 int i;
163 int sleep_time = RESLIST_TTL / RESLIST_HMAX;
165 /* deplete all possible resources from the resource list */
166 for (i = 0; i < RESLIST_HMAX; i++) {
167 rv = apr_reslist_acquire(rl, (void**)&resources[i]);
168 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
171 /* Free all resources above RESLIST_SMAX - 1 */
172 for (i = RESLIST_SMAX - 1; i < RESLIST_HMAX; i++) {
173 rv = apr_reslist_release(rl, resources[i]);
174 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
177 for (i = 0; i < RESLIST_HMAX; i++) {
178 rv = apr_reslist_acquire(rl, &vp);
179 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
180 res = vp;
181 apr_sleep(sleep_time);
182 rv = apr_reslist_release(rl, res);
183 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
185 apr_sleep(sleep_time);
188 * Now free the remaining elements. This should trigger the shrinking of
189 * the list
191 for (i = 0; i < RESLIST_SMAX - 1; i++) {
192 rv = apr_reslist_release(rl, resources[i]);
193 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
197 static void test_reslist(abts_case *tc, void *data)
199 int i;
200 apr_status_t rv;
201 apr_reslist_t *rl;
202 my_parameters_t *params;
203 apr_thread_pool_t *thrp;
204 my_thread_info_t thread_info[CONSUMER_THREADS];
206 /* XXX: non-portable */
207 srand48(time(0));
209 rv = apr_thread_pool_create(&thrp, CONSUMER_THREADS/2, CONSUMER_THREADS, p);
210 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
212 /* Create some parameters that will be passed into each
213 * constructor and destructor call. */
214 params = apr_pcalloc(p, sizeof(*params));
215 params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME;
216 params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME;
218 /* We're going to want 10 blocks of data from our target rmm. */
219 rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX,
220 RESLIST_TTL, my_constructor, my_destructor,
221 params, p);
222 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
224 for (i = 0; i < CONSUMER_THREADS; i++) {
225 thread_info[i].tid = i;
226 thread_info[i].tc = tc;
227 thread_info[i].reslist = rl;
228 thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME;
229 rv = apr_thread_pool_push(thrp, resource_consuming_thread,
230 &thread_info[i], 0, NULL);
231 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
234 rv = apr_thread_pool_destroy(thrp);
235 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
237 test_timeout(tc, rl);
239 test_shrinking(tc, rl);
240 ABTS_INT_EQUAL(tc, RESLIST_SMAX, params->c_count - params->d_count);
242 rv = apr_reslist_destroy(rl);
243 ABTS_INT_EQUAL(tc, rv, APR_SUCCESS);
246 #endif /* APR_HAS_THREADS */
248 abts_suite *testreslist(abts_suite *suite)
250 suite = ADD_SUITE(suite);
252 #if APR_HAS_THREADS
253 abts_run_test(suite, test_reslist, NULL);
254 #endif
256 return suite;