Apache HTTPD
apr_reslist.c
Go to the documentation of this file.
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
17#include <assert.h>
18
19#include "apu.h"
20#include "apr_reslist.h"
21#include "apr_errno.h"
22#include "apr_strings.h"
23#include "apr_thread_mutex.h"
24#include "apr_thread_cond.h"
25#include "apr_ring.h"
26
35typedef struct apr_res_t apr_res_t;
36
42
44 apr_pool_t *pool; /* the pool used in constructor and destructor calls */
45 int ntotal; /* total number of resources managed by this list */
46 int nidle; /* number of available resources */
47 int min; /* desired minimum number of available resources */
48 int smax; /* soft maximum on the total number of resources */
49 int hmax; /* hard maximum on the total number of resources */
50 apr_interval_time_t ttl; /* TTL when we have too many resources */
51 apr_interval_time_t timeout; /* Timeout for waiting on resource */
54 void *params; /* opaque data passed to constructor and destructor calls */
57#if APR_HAS_THREADS
59 apr_thread_cond_t *avail;
60#endif
61};
62
68{
70 res = APR_RING_FIRST(&reslist->avail_list);
71 APR_RING_REMOVE(res, link);
72 reslist->nidle--;
73 return res;
74}
75
82{
83 APR_RING_INSERT_HEAD(&reslist->avail_list, resource, apr_res_t, link);
84 if (reslist->ttl) {
85 resource->freed = apr_time_now();
86 }
87 reslist->nidle++;
88}
89
94{
96
97 if (!APR_RING_EMPTY(&reslist->free_list, apr_res_t, link)) {
98 res = APR_RING_FIRST(&reslist->free_list);
99 APR_RING_REMOVE(res, link);
100 }
101 else
102 res = apr_pcalloc(reslist->pool, sizeof(*res));
103 return res;
104}
105
113
119{
120 apr_status_t rv;
121 apr_res_t *res;
122
124
125 rv = reslist->constructor(&res->opaque, reslist->params, reslist->pool);
126
127 *ret_res = res;
128 return rv;
129}
130
136{
137 return reslist->destructor(res->opaque, reslist->params, reslist->pool);
138}
139
141{
144 apr_res_t *res;
145
146#if APR_HAS_THREADS
147 apr_thread_mutex_lock(rl->listlock);
148#endif
149
150 while (rl->nidle > 0) {
153 rl->ntotal--;
155 if (rv1 != APR_SUCCESS) {
156 rv = rv1; /* loses info in the unlikely event of
157 * multiple *different* failures */
158 }
160 }
161
162 assert(rl->nidle == 0);
163 assert(rl->ntotal == 0);
164
165#if APR_HAS_THREADS
166 apr_thread_mutex_unlock(rl->listlock);
167 apr_thread_mutex_destroy(rl->listlock);
169#endif
170
171 return rv;
172}
173
179{
181 apr_status_t rv;
182 apr_res_t *res;
183 int created_one = 0;
184
185#if APR_HAS_THREADS
187#endif
188
189 /* Check if we need to create more resources, and if we are allowed to. */
190 while (reslist->nidle < reslist->min && reslist->ntotal < reslist->hmax) {
191 /* Create the resource */
193 if (rv != APR_SUCCESS) {
195#if APR_HAS_THREADS
197#endif
198 return rv;
199 }
200 /* Add it to the list */
202 /* Update our counters */
203 reslist->ntotal++;
204 /* If someone is waiting on that guy, wake them up. */
205#if APR_HAS_THREADS
206 rv = apr_thread_cond_signal(reslist->avail);
207 if (rv != APR_SUCCESS) {
209 return rv;
210 }
211#endif
212 created_one++;
213 }
214
215 /* We don't need to see if we're over the max if we were under it before,
216 * nor need we check for expiry if no ttl is configure.
217 */
218 if (created_one || !reslist->ttl) {
219#if APR_HAS_THREADS
221#endif
222 return APR_SUCCESS;
223 }
224
225 /* Check if we need to expire old resources */
226 now = apr_time_now();
227 while (reslist->nidle > reslist->smax && reslist->nidle > 0) {
228 /* Peak at the last resource in the list */
229 res = APR_RING_LAST(&reslist->avail_list);
230 /* See if the oldest entry should be expired */
231 if (now - res->freed < reslist->ttl) {
232 /* If this entry is too young, none of the others
233 * will be ready to be expired either, so we are done. */
234 break;
235 }
236 APR_RING_REMOVE(res, link);
237 reslist->nidle--;
238 reslist->ntotal--;
241 if (rv != APR_SUCCESS) {
242#if APR_HAS_THREADS
244#endif
245 return rv;
246 }
247 }
248
249#if APR_HAS_THREADS
251#endif
252 return APR_SUCCESS;
253}
254
256 int min, int smax, int hmax,
260 void *params,
262{
263 apr_status_t rv;
265
266 /* Do some sanity checks so we don't thrash around in the
267 * maintenance routine later. */
268 if (min < 0 || min > smax || min > hmax || smax > hmax || hmax == 0 ||
269 ttl < 0) {
270 return APR_EINVAL;
271 }
272
273#if !APR_HAS_THREADS
274 /* There can be only one resource when we have no threads. */
275 if (min > 0) {
276 min = 1;
277 }
278 if (smax > 0) {
279 smax = 1;
280 }
281 hmax = 1;
282#endif
283
284 rl = apr_pcalloc(pool, sizeof(*rl));
285 rl->pool = pool;
286 rl->min = min;
287 rl->smax = smax;
288 rl->hmax = hmax;
289 rl->ttl = ttl;
290 rl->constructor = con;
291 rl->destructor = de;
292 rl->params = params;
293
294 APR_RING_INIT(&rl->avail_list, apr_res_t, link);
295 APR_RING_INIT(&rl->free_list, apr_res_t, link);
296
297#if APR_HAS_THREADS
299 pool);
300 if (rv != APR_SUCCESS) {
301 return rv;
302 }
303 rv = apr_thread_cond_create(&rl->avail, pool);
304 if (rv != APR_SUCCESS) {
305 return rv;
306 }
307#endif
308
310 if (rv != APR_SUCCESS) {
311 /* Destroy what we've created so far.
312 */
314 return rv;
315 }
316
319
320 *reslist = rl;
321
322 return APR_SUCCESS;
323}
324
326{
328}
329
331 void **resource)
332{
333 apr_status_t rv;
334 apr_res_t *res;
335 apr_time_t now = 0;
336
337#if APR_HAS_THREADS
339#endif
340 /* If there are idle resources on the available list, use
341 * them right away. */
342 if (reslist->ttl) {
343 now = apr_time_now();
344 }
345 while (reslist->nidle > 0) {
346 /* Pop off the first resource */
348 if (reslist->ttl && (now - res->freed >= reslist->ttl)) {
349 /* this res is expired - kill it */
350 reslist->ntotal--;
353 if (rv != APR_SUCCESS) {
354#if APR_HAS_THREADS
356#endif
357 return rv; /* FIXME: this might cause unnecessary fails */
358 }
359 continue;
360 }
361 *resource = res->opaque;
363#if APR_HAS_THREADS
365#endif
366 return APR_SUCCESS;
367 }
368 /* If we've hit our max, block until we're allowed to create
369 * a new one, or something becomes free. */
370 while (reslist->ntotal >= reslist->hmax && reslist->nidle <= 0) {
371#if APR_HAS_THREADS
372 if (reslist->timeout) {
373 if ((rv = apr_thread_cond_timedwait(reslist->avail,
374 reslist->listlock, reslist->timeout)) != APR_SUCCESS) {
376 return rv;
377 }
378 }
379 else {
380 apr_thread_cond_wait(reslist->avail, reslist->listlock);
381 }
382#else
383 return APR_EAGAIN;
384#endif
385 }
386 /* If we popped out of the loop, first try to see if there
387 * are new resources available for immediate use. */
388 if (reslist->nidle > 0) {
390 *resource = res->opaque;
392#if APR_HAS_THREADS
394#endif
395 return APR_SUCCESS;
396 }
397 /* Otherwise the reason we dropped out of the loop
398 * was because there is a new slot available, so create
399 * a resource to fill the slot and use it. */
400 else {
402 if (rv == APR_SUCCESS) {
403 reslist->ntotal++;
404 *resource = res->opaque;
405 }
407#if APR_HAS_THREADS
409#endif
410 return rv;
411 }
412}
413
415 void *resource)
416{
417 apr_res_t *res;
418
419#if APR_HAS_THREADS
421#endif
423 res->opaque = resource;
425#if APR_HAS_THREADS
428#endif
429
431}
432
438
440{
442
443#if APR_HAS_THREADS
445#endif
446 count = reslist->ntotal - reslist->nidle;
447#if APR_HAS_THREADS
449#endif
450
451 return count;
452}
453
455 void *resource)
456{
458#if APR_HAS_THREADS
460#endif
461 ret = reslist->destructor(resource, reslist->params, reslist->pool);
462 reslist->ntotal--;
463#if APR_HAS_THREADS
466#endif
467 return ret;
468}
469
472{
476 else
479}
APR Error Codes.
#define min(a, b)
Definition apr_random.c:32
static apr_status_t destroy_resource(apr_reslist_t *reslist, apr_res_t *res)
static apr_status_t create_resource(apr_reslist_t *reslist, apr_res_t **ret_res)
static apr_status_t reslist_cleanup(void *data_)
static void free_container(apr_reslist_t *reslist, apr_res_t *container)
static void push_resource(apr_reslist_t *reslist, apr_res_t *resource)
Definition apr_reslist.c:81
static apr_res_t * get_container(apr_reslist_t *reslist)
Definition apr_reslist.c:93
static apr_res_t * pop_resource(apr_reslist_t *reslist)
Definition apr_reslist.c:67
APR-UTIL Resource List Routines.
APR Rings.
APR Strings library.
APR Condition Variable Routines.
APR Thread Mutex Routines.
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EINVAL
Definition apr_errno.h:711
unsigned int count
Definition apr_md5.h:152
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
apr_pool_t const char * params
Definition apr_dbd.h:141
APU_DECLARE(void)
Computes SipHash-2-4, producing a 64bit (APR_SIPHASH_DSIZE) hash from a message and a 128bit (APR_SIP...
const char apr_port_t apr_uint32_t apr_uint32_t smax
apr_status_t(* apr_reslist_constructor)(void **resource, void *params, apr_pool_t *pool)
Definition apr_reslist.h:50
int int int apr_interval_time_t apr_reslist_constructor con
Definition apr_reslist.h:92
int int int apr_interval_time_t apr_reslist_constructor apr_reslist_destructor de
Definition apr_reslist.h:93
apr_status_t(* apr_reslist_destructor)(void *resource, void *params, apr_pool_t *pool)
Definition apr_reslist.h:59
void ** resource
#define APR_RESLIST_CLEANUP_FIRST
Definition apr_reslist.h:64
int int int hmax
Definition apr_reslist.h:90
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_byte_t ttl
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
#define APR_RING_ENTRY(elem)
Definition apr_ring.h:70
#define APR_RING_INSERT_TAIL(hp, nep, elem, link)
Definition apr_ring.h:328
#define APR_RING_INIT(hp, elem, link)
Definition apr_ring.h:192
#define APR_RING_HEAD(head, elem)
Definition apr_ring.h:91
#define APR_RING_LAST(hp)
Definition apr_ring.h:171
#define APR_RING_EMPTY(hp, elem, link)
Definition apr_ring.h:204
#define APR_RING_REMOVE(ep, link)
Definition apr_ring.h:381
#define APR_RING_FIRST(hp)
Definition apr_ring.h:166
#define APR_RING_INSERT_HEAD(hp, nep, elem, link)
Definition apr_ring.h:317
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
struct apr_res_t::@68 link
apr_time_t freed
Definition apr_reslist.c:31
void * opaque
Definition apr_reslist.c:32
apr_reslist_constructor constructor
Definition apr_reslist.c:52
apr_interval_time_t timeout
Definition apr_reslist.c:51
apr_resring_t avail_list
Definition apr_reslist.c:55
apr_pool_t * pool
Definition apr_reslist.c:44
apr_reslist_destructor destructor
Definition apr_reslist.c:53
apr_resring_t free_list
Definition apr_reslist.c:56
apr_interval_time_t ttl
Definition apr_reslist.c:50
static apr_time_t now
Definition testtime.c:33
IN ULONG IN INT timeout