fdqueue.c revision 43c3e6a4b559b76b750c245ee95e2782c15b4296
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * Licensed under the Apache License, Version 2.0 (the "License");
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * you may not use this file except in compliance with the License.
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * You may obtain a copy of the License at
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * http://www.apache.org/licenses/LICENSE-2.0
7520452bb30b5abbd471f82352fc4c1c937e02c5Till Mossakowski * Unless required by applicable law or agreed to in writing, software
7520452bb30b5abbd471f82352fc4c1c937e02c5Till Mossakowski * distributed under the License is distributed on an "AS IS" BASIS,
7520452bb30b5abbd471f82352fc4c1c937e02c5Till Mossakowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * See the License for the specific language governing permissions and
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * limitations under the License.
83263d411f611d9902ef4d98c93be6ad9361c833Christian Maeder * 0 or positive: number of idle worker threads
521045d36343cd17dd217a81d4b9422ad6ab6a07Christian Maeder * negative: number of threads blocked waiting
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * for an idle worker
7ae38566aaf40710cd83ffa3ba25655c4ad22741Thiemo Wiedemeyerstatic apr_status_t queue_info_cleanup(void *data_)
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer apr_thread_cond_destroy(qi->wait_for_idler);
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer /* Clean up any pools in the recycled list */
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer struct recycled_pool *first_pool = qi->recycled_pools;
8a1077f446e5a0e127e0805e2c1efe6bf5eeb0d8Christian Maeder ((volatile void **) &(qi->recycled_pools), first_pool->next,
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyerapr_status_t ap_queue_info_create(fd_queue_info_t ** queue_info,
f9e0b18852b238ddb649d341194e05d7200d1bbeChristian Maeder rv = apr_thread_mutex_create(&qi->idlers_mutex, APR_THREAD_MUTEX_DEFAULT,
f456529a89bfb620d39e5fd5b0a53b24643db96dDominik Luecke rv = apr_thread_cond_create(&qi->wait_for_idler, pool);
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer apr_pool_cleanup_register(pool, qi, queue_info_cleanup,
40b73e7d13a858afeac95321fcdb9ac216bfbf01Thiemo Wiedemeyerapr_status_t ap_queue_info_set_idle(fd_queue_info_t * queue_info,
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer /* Atomically increment the count of idle workers */
331603b37dec12e37e2e1df9634ef0f2c5c73ddfThiemo Wiedemeyer prev_idlers = apr_atomic_inc32(&(queue_info->idlers));
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer /* If other threads are waiting on a worker, wake one up */
331603b37dec12e37e2e1df9634ef0f2c5c73ddfThiemo Wiedemeyer rv = apr_thread_mutex_lock(queue_info->idlers_mutex);
03bbcb1fefdbd8bc4e8329ca2688809d84aff0a9Christian Maeder rv = apr_thread_cond_signal(queue_info->wait_for_idler);
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer apr_thread_mutex_unlock(queue_info->idlers_mutex);
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer rv = apr_thread_mutex_unlock(queue_info->idlers_mutex);
71654489020a03cf6ce9f2947f3da26a996f9c32Razvan Pascanuapr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t * queue_info)
0b8b26a22f136a9b2a8e99d655f6fe6b0b96008cThiemo Wiedemeyer /* Atomically decrement the idle worker count, saving the old value */
0b8b26a22f136a9b2a8e99d655f6fe6b0b96008cThiemo Wiedemeyer prev_idlers = apr_atomic_add32(&(queue_info->idlers), -1);
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer /* Block if there weren't any idle workers */
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer rv = apr_thread_mutex_lock(queue_info->idlers_mutex);
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer apr_atomic_inc32(&(queue_info->idlers)); /* back out dec */
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer /* Re-check the idle worker count to guard against a
aa07f9c4585a94514dcff2979d853d6e04c12fb9Thiemo Wiedemeyer * race condition. Now that we're in the mutex-protected
5044e8de9e6fde7a139a5e34324c92a4d08a6e73Thiemo Wiedemeyer * region, one of two things may have happened:
aa07f9c4585a94514dcff2979d853d6e04c12fb9Thiemo Wiedemeyer * - If the idle worker count is still negative, the
8836fa284a241af325aa6f41234b5130b26ec4f9Thiemo Wiedemeyer * workers are all still busy, so it's safe to
aa07f9c4585a94514dcff2979d853d6e04c12fb9Thiemo Wiedemeyer * block on a condition variable.
8836fa284a241af325aa6f41234b5130b26ec4f9Thiemo Wiedemeyer * - If the idle worker count is non-negative, then a
8836fa284a241af325aa6f41234b5130b26ec4f9Thiemo Wiedemeyer * worker has become idle since the first check
8836fa284a241af325aa6f41234b5130b26ec4f9Thiemo Wiedemeyer * of queue_info->idlers above. It's possible
86b2d79be961f0247a2eed10ed4f86d8d6a7639dChristian Maeder * that the worker has also signaled the condition
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer * variable--and if so, the listener missed it
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * because it wasn't yet blocked on the condition
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * variable. But if the idle worker count is
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * now non-negative, it's safe for this function to
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * return immediately.
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * A negative value in queue_info->idlers tells how many
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * threads are waiting on an idle worker.
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer rv = apr_thread_cond_wait(queue_info->wait_for_idler,
d71a37fb09bce02af6c98e7a5ab0aa5639058e4fThiemo Wiedemeyer rv2 = apr_thread_mutex_unlock(queue_info->idlers_mutex);
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer rv = apr_thread_mutex_unlock(queue_info->idlers_mutex);
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyervoid ap_push_pool(fd_queue_info_t * queue_info,
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer /* If we have been given a pool to recycle, atomically link
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer * it into the queue_info's list of recycled pools
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer new_recycle = (struct recycled_pool *) apr_palloc(pool_to_recycle,
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer new_recycle->next = queue_info->recycled_pools;
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer ((volatile void **) &(queue_info->recycled_pools),
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer new_recycle, new_recycle->next) == new_recycle->next) {
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyervoid ap_pop_pool(apr_pool_t ** recycled_pool, fd_queue_info_t * queue_info)
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer /* Atomically pop a pool from the recycled list */
aa21e7aa42fef563dea0cc77edbde76f66cdbe88Thiemo Wiedemeyer /* This function is safe only as long as it is single threaded because
d9f20cf968e246ec283f0c09f60af4b47b174398Thiemo Wiedemeyer * it reaches into the queue and accesses "next" which can change.
d9f20cf968e246ec283f0c09f60af4b47b174398Thiemo Wiedemeyer * We are OK today because it is only called from the listener thread.
d9f20cf968e246ec283f0c09f60af4b47b174398Thiemo Wiedemeyer * cas-based pushes do not have the same limitation - any number can
d9f20cf968e246ec283f0c09f60af4b47b174398Thiemo Wiedemeyer * happen concurrently with a single cas-based pop.
84ba39232a012abf2085c8a421ebce6abc52d56eThiemo Wiedemeyer /* Atomically pop a pool from the recycled list */
d71a37fb09bce02af6c98e7a5ab0aa5639058e4fThiemo Wiedemeyer struct recycled_pool *first_pool = queue_info->recycled_pools;
3e3efd4ce838940032e875e6d08712a177c9c1d0Thiemo Wiedemeyer ((volatile void **) &(queue_info->recycled_pools),
3e3efd4ce838940032e875e6d08712a177c9c1d0Thiemo Wiedemeyer first_pool->next, first_pool) == first_pool) {
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyerapr_status_t ap_queue_info_term(fd_queue_info_t * queue_info)
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer rv = apr_thread_mutex_lock(queue_info->idlers_mutex);
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer apr_thread_cond_broadcast(queue_info->wait_for_idler);
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer return apr_thread_mutex_unlock(queue_info->idlers_mutex);
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer * Detects when the fd_queue_t is full. This utility function is expected
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer * to be called from within critical sections, and is not threadsafe.
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer#define ap_queue_full(queue) ((queue)->nelts == (queue)->bounds)
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer * Detects when the fd_queue_t is empty. This utility function is expected
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer * to be called from within critical sections, and is not threadsafe.
1ac36418f204bbe56f4cd951a979180721758999Christian Maeder#define ap_queue_empty(queue) ((queue)->nelts == 0)
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer * Callback routine that is called to destroy this
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyer * fd_queue_t when its pool is destroyed.
66fd8f017efdb8a6c862c3f1856dfaef90865dd5Thiemo Wiedemeyerstatic apr_status_t ap_queue_destroy(void *data)
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer /* Ignore errors here, we can't do anything about them anyway.
84ba39232a012abf2085c8a421ebce6abc52d56eThiemo Wiedemeyer * XXX: We should at least try to signal an error here, it is
1ac36418f204bbe56f4cd951a979180721758999Christian Maeder * indicative of a programmer error. -aaron */
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer apr_thread_cond_destroy(queue->not_empty);
84ba39232a012abf2085c8a421ebce6abc52d56eThiemo Wiedemeyer apr_thread_mutex_destroy(queue->one_big_mutex);
1a389234e68da7c3d087b038307ed8c66fc6dc32Thiemo Wiedemeyer * Initialize the fd_queue_t.
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyerapr_status_t ap_queue_init(fd_queue_t * queue, int queue_capacity,
71654489020a03cf6ce9f2947f3da26a996f9c32Razvan Pascanu if ((rv = apr_thread_mutex_create(&queue->one_big_mutex,
71654489020a03cf6ce9f2947f3da26a996f9c32Razvan Pascanu if ((rv = apr_thread_cond_create(&queue->not_empty, a)) != APR_SUCCESS) {
8836fa284a241af325aa6f41234b5130b26ec4f9Thiemo Wiedemeyer queue->data = apr_palloc(a, queue_capacity * sizeof(fd_queue_elem_t));
8836fa284a241af325aa6f41234b5130b26ec4f9Thiemo Wiedemeyer /* Set all the sockets in the queue to NULL */
37e30366abd83c00a5d5447b45694627fd783de8Cui Jian for (i = 0; i < queue_capacity; ++i)
37e30366abd83c00a5d5447b45694627fd783de8Cui Jian apr_pool_cleanup_register(a, queue, ap_queue_destroy,
370e81d7af7821f0ac6ee0643613e87a727841e7Thiemo Wiedemeyer * Push a new socket onto the queue.
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * precondition: ap_queue_info_wait_for_idler has already been called
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer * to reserve an idle worker thread
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyerapr_status_t ap_queue_push(fd_queue_t * queue, apr_socket_t * sd,
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) {
d1066b8fb69179973dcab47154858d77e72760a7Thiemo Wiedemeyer if ((rv = apr_thread_mutex_unlock(queue->one_big_mutex)) != APR_SUCCESS) {
53e76316f409f6b1b57ed3d2e5cb9cfe1cb511e5Thiemo Wiedemeyer * Retrieves the next available socket from the queue. If there are no
d1066b8fb69179973dcab47154858d77e72760a7Thiemo Wiedemeyer * sockets available, it will block until one becomes available.
d1066b8fb69179973dcab47154858d77e72760a7Thiemo Wiedemeyer * Once retrieved, the socket is placed into the address specified by
71654489020a03cf6ce9f2947f3da26a996f9c32Razvan Pascanuapr_status_t ap_queue_pop(fd_queue_t * queue, apr_socket_t ** sd,
966a6c024c828387023fccb0cd0049f78687e5dcThiemo Wiedemeyer if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) {
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer /* Keep waiting until we wake up and find that the queue is not empty. */
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer apr_thread_cond_wait(queue->not_empty, queue->one_big_mutex);
a4e6fb26100f53e3b1e9f5b97c2e0a0c129294e5Christian Maeder /* If we wake up and it's still empty, then we were interrupted */
28ca54b0d63d1d26a991711c8c7e85c474994715Christian Maeder rv = apr_thread_mutex_unlock(queue->one_big_mutex);
44c1fff98bd6c54db237bef5030657d3f47058a5Thiemo Wiedemeyer return APR_EOF; /* no more elements ever again */
c40b7badd217089d8a256dabdf8f7d4e219ca215Thiemo Wiedemeyer#endif /* AP_DEBUG */
71654489020a03cf6ce9f2947f3da26a996f9c32Razvan Pascanu rv = apr_thread_mutex_unlock(queue->one_big_mutex);
c40b7badd217089d8a256dabdf8f7d4e219ca215Thiemo Wiedemeyerapr_status_t ap_queue_interrupt_all(fd_queue_t * queue)
c40b7badd217089d8a256dabdf8f7d4e219ca215Thiemo Wiedemeyer if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) {
83263d411f611d9902ef4d98c93be6ad9361c833Christian Maeder apr_thread_cond_broadcast(queue->not_empty);
71654489020a03cf6ce9f2947f3da26a996f9c32Razvan Pascanu return apr_thread_mutex_unlock(queue->one_big_mutex);
83263d411f611d9902ef4d98c93be6ad9361c833Christian Maederapr_status_t ap_queue_term(fd_queue_t * queue)
d71a37fb09bce02af6c98e7a5ab0aa5639058e4fThiemo Wiedemeyer if ((rv = apr_thread_mutex_lock(queue->one_big_mutex)) != APR_SUCCESS) {
1ac36418f204bbe56f4cd951a979180721758999Christian Maeder /* we must hold one_big_mutex when setting this... otherwise,
c40b7badd217089d8a256dabdf8f7d4e219ca215Thiemo Wiedemeyer * we could end up setting it and waking everybody up just after a
c40b7badd217089d8a256dabdf8f7d4e219ca215Thiemo Wiedemeyer * would-be popper checks it but right before they block