APU_DECLARE(apr_status_t) apr_reslist_acquire(apr_reslist_t *reslist, void **resource) { apr_status_t rv; apr_res_t *res; apr_thread_mutex_lock(reslist->listlock); /* If there are idle resources on the available list, use * them right away. */ if (reslist->nidle > 0) { /* Pop off the first resource */ res = pop_resource(reslist); *resource = res->opaque; free_container(reslist, res); apr_thread_mutex_unlock(reslist->listlock); return APR_SUCCESS; } /* If we've hit our max, block until we're allowed to create * a new one, or something becomes free. */ else while (reslist->ntotal >= reslist->hmax && reslist->nidle <= 0) { if (reslist->timeout) { if ((rv = apr_thread_cond_timedwait(reslist->avail, reslist->listlock, reslist->timeout)) != APR_SUCCESS) { apr_thread_mutex_unlock(reslist->listlock); return rv; } } else apr_thread_cond_wait(reslist->avail, reslist->listlock); } /* If we popped out of the loop, first try to see if there * are new resources available for immediate use. */ if (reslist->nidle > 0) { res = pop_resource(reslist); *resource = res->opaque; free_container(reslist, res); apr_thread_mutex_unlock(reslist->listlock); return APR_SUCCESS; } /* Otherwise the reason we dropped out of the loop * was because there is a new slot available, so create * a resource to fill the slot and use it. */ else { rv = create_resource(reslist, &res); if (rv == APR_SUCCESS) { reslist->ntotal++; *resource = res->opaque; } free_container(reslist, res); apr_thread_mutex_unlock(reslist->listlock); return rv; } }
static apr_status_t reslist_cleanup(void *data_) { apr_status_t rv; apr_reslist_t *rl = data_; apr_res_t *res; apr_thread_mutex_lock(rl->listlock); while (rl->nidle > 0) { res = pop_resource(rl); rl->ntotal--; rv = destroy_resource(rl, res); if (rv != APR_SUCCESS) { return rv; } free_container(rl, res); } assert(rl->nidle == 0); assert(rl->ntotal == 0); apr_thread_mutex_destroy(rl->listlock); apr_thread_cond_destroy(rl->avail); return APR_SUCCESS; }
/** * Perform routine maintenance on the resource list. This call * may instantiate new resources or expire old resources. */ static apr_status_t reslist_maint(apr_reslist_t *reslist) { apr_time_t now; apr_status_t rv; apr_res_t *res; int created_one = 0; apr_thread_mutex_lock(reslist->listlock); /* Check if we need to create more resources, and if we are allowed to. */ while (reslist->nidle < reslist->min && reslist->ntotal <= reslist->hmax) { /* Create the resource */ rv = create_resource(reslist, &res); if (rv != APR_SUCCESS) { free_container(reslist, res); apr_thread_mutex_unlock(reslist->listlock); return rv; } /* Add it to the list */ push_resource(reslist, res); /* Update our counters */ reslist->ntotal++; /* If someone is waiting on that guy, wake them up. */ rv = apr_thread_cond_signal(reslist->avail); if (rv != APR_SUCCESS) { apr_thread_mutex_unlock(reslist->listlock); return rv; } created_one++; } /* We don't need to see if we're over the max if we were under it before */ if (created_one) { apr_thread_mutex_unlock(reslist->listlock); return APR_SUCCESS; } /* Check if we need to expire old resources */ now = apr_time_now(); while (reslist->nidle > reslist->smax && reslist->nidle > 0) { /* Peak at the first resource in the list */ res = APR_RING_FIRST(&reslist->avail_list); /* See if the oldest entry should be expired */ if (now - res->freed < reslist->ttl) { /* If this entry is too young, none of the others * will be ready to be expired either, so we are done. */ break; } res = pop_resource(reslist); reslist->ntotal--; rv = destroy_resource(reslist, res); if (rv != APR_SUCCESS) { apr_thread_mutex_unlock(reslist->listlock); return rv; } free_container(reslist, res); } apr_thread_mutex_unlock(reslist->listlock); return APR_SUCCESS; }