APT_DECLARE(apt_list_elem_t*) apt_list_last_elem_get(const apt_obj_list_t *list) { if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { return NULL; } return APR_RING_LAST(&list->head); }
APT_DECLARE(void*) apt_obj_list_tail(apt_obj_list_t *list) { apt_list_elem_t *elem; if(APR_RING_EMPTY(&list->head,apt_list_elem_t,link)) { return NULL; } elem = APR_RING_LAST(&list->head); return elem->obj; }
static void mpf_timers_reschedule(mpf_timer_manager_t *manager) { mpf_timer_t *it; for(it = APR_RING_LAST(&manager->head); it != APR_RING_SENTINEL(&manager->head, mpf_timer_t, link); it = APR_RING_PREV(it, link)) { it->scheduled_time -= manager->elapsed_time; } manager->elapsed_time = 0; }
static void apt_timers_reschedule(apt_timer_queue_t *queue) { apt_timer_t *it; for(it = APR_RING_LAST(&queue->head); it != APR_RING_SENTINEL(&queue->head, apt_timer_t, link); it = APR_RING_PREV(it, link)) { it->scheduled_time -= queue->elapsed_time; } queue->elapsed_time = 0; }
/** * Split the contents of a brigade after bucket 'e' to an existing brigade * * XXXX: Should this function be added to APR-Util? */ static void brigade_move(apr_bucket_brigade *b, apr_bucket_brigade *a, apr_bucket *e) { apr_bucket *f; if (e != APR_BRIGADE_SENTINEL(b)) { f = APR_RING_LAST(&b->list); APR_RING_UNSPLICE(e, f, link); APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link); } APR_BRIGADE_CHECK_CONSISTENCY(a); APR_BRIGADE_CHECK_CONSISTENCY(b); }
/* * This function stop extra idle threads to the cnt. * @return the number of threads stopped * NOTE: There could be busy threads become idle during this function */ static struct apr_thread_list_elt *trim_threads(apr_thread_pool_t *me, apr_size_t *cnt, int idle) { struct apr_thread_list *thds; apr_size_t n, n_dbg, i; struct apr_thread_list_elt *head, *tail, *elt; apr_thread_mutex_lock(me->lock); if (idle) { thds = me->idle_thds; n = me->idle_cnt; } else { thds = me->busy_thds; n = me->thd_cnt - me->idle_cnt; } if (n <= *cnt) { apr_thread_mutex_unlock(me->lock); *cnt = 0; return NULL; } n -= *cnt; head = APR_RING_FIRST(thds); for (i = 0; i < *cnt; i++) { head = APR_RING_NEXT(head, link); } tail = APR_RING_LAST(thds); if (idle) { APR_RING_UNSPLICE(head, tail, link); me->idle_cnt = *cnt; } n_dbg = 0; for (elt = head; elt != tail; elt = APR_RING_NEXT(elt, link)) { elt->state = TH_STOP; n_dbg++; } elt->state = TH_STOP; n_dbg++; assert(n == n_dbg); *cnt = n; apr_thread_mutex_unlock(me->lock); APR_RING_PREV(head, link) = NULL; APR_RING_NEXT(tail, link) = NULL; return head; }
static APR_INLINE apt_bool_t mpf_timer_insert(mpf_timer_manager_t *manager, mpf_timer_t *timer) { mpf_timer_t *it; for(it = APR_RING_LAST(&manager->head); it != APR_RING_SENTINEL(&manager->head, mpf_timer_t, link); it = APR_RING_PREV(it, link)) { if(it->scheduled_time <= timer->scheduled_time) { APR_RING_INSERT_AFTER(it,timer,link); return TRUE; } } APR_RING_INSERT_HEAD(&manager->head,timer,mpf_timer_t,link); return TRUE; }
static APR_INLINE apt_bool_t apt_timer_insert(apt_timer_queue_t *timer_queue, apt_timer_t *timer) { apt_timer_t *it; for(it = APR_RING_LAST(&timer_queue->head); it != APR_RING_SENTINEL(&timer_queue->head, apt_timer_t, link); it = APR_RING_PREV(it, link)) { if(it->scheduled_time <= timer->scheduled_time) { APR_RING_INSERT_AFTER(it,timer,link); return TRUE; } } APR_RING_INSERT_HEAD(&timer_queue->head,timer,apt_timer_t,link); return TRUE; }
APU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b, apr_bucket *e) { apr_bucket_brigade *a; apr_bucket *f; a = apr_brigade_create(b->p, b->bucket_alloc); /* Return an empty brigade if there is nothing left in * the first brigade to split off */ if (e != APR_BRIGADE_SENTINEL(b)) { f = APR_RING_LAST(&b->list); APR_RING_UNSPLICE(e, f, link); APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link); } APR_BRIGADE_CHECK_CONSISTENCY(a); APR_BRIGADE_CHECK_CONSISTENCY(b); return a; }
static apr_status_t rate_limit_filter(ap_filter_t *f, apr_bucket_brigade *input_bb) { apr_status_t rv = APR_SUCCESS; rl_ctx_t *ctx = f->ctx; apr_bucket *fb; int do_sleep = 0; apr_bucket_alloc_t *ba = f->r->connection->bucket_alloc; apr_bucket_brigade *bb = input_bb; if (f->c->aborted) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, APLOGNO(01454) "rl: conn aborted"); apr_brigade_cleanup(bb); return APR_ECONNABORTED; } if (ctx == NULL) { const char *rl = NULL; int ratelimit; /* no subrequests. */ if (f->r->main != NULL) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } rl = apr_table_get(f->r->subprocess_env, "rate-limit"); if (rl == NULL) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* rl is in kilo bytes / second */ ratelimit = atoi(rl) * 1024; if (ratelimit <= 0) { /* remove ourselves */ ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } /* first run, init stuff */ ctx = apr_palloc(f->r->pool, sizeof(rl_ctx_t)); f->ctx = ctx; ctx->state = RATE_LIMIT; ctx->speed = ratelimit; /* calculate how many bytes / interval we want to send */ /* speed is bytes / second, so, how many (speed / 1000 % interval) */ ctx->chunk_size = (ctx->speed / (1000 / RATE_INTERVAL_MS)); ctx->tmpbb = apr_brigade_create(f->r->pool, ba); ctx->holdingbb = apr_brigade_create(f->r->pool, ba); } while (ctx->state != RATE_ERROR && (!APR_BRIGADE_EMPTY(bb) || !APR_BRIGADE_EMPTY(ctx->holdingbb))) { apr_bucket *e; if (!APR_BRIGADE_EMPTY(ctx->holdingbb)) { APR_BRIGADE_CONCAT(bb, ctx->holdingbb); } while (ctx->state == RATE_FULLSPEED && !APR_BRIGADE_EMPTY(bb)) { /* Find where we 'stop' going full speed. */ for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (AP_RL_BUCKET_IS_END(e)) { apr_bucket *f; f = APR_RING_LAST(&bb->list); APR_RING_UNSPLICE(e, f, link); APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f, apr_bucket, link); ctx->state = RATE_LIMIT; break; } } if (f->c->aborted) { apr_brigade_cleanup(bb); ctx->state = RATE_ERROR; break; } fb = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(bb, fb); rv = ap_pass_brigade(f->next, bb); if (rv != APR_SUCCESS) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01455) "rl: full speed brigade pass failed."); } } while (ctx->state == RATE_LIMIT && !APR_BRIGADE_EMPTY(bb)) { for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); e = APR_BUCKET_NEXT(e)) { if (AP_RL_BUCKET_IS_START(e)) { apr_bucket *f; f = APR_RING_LAST(&bb->list); APR_RING_UNSPLICE(e, f, link); APR_RING_SPLICE_TAIL(&ctx->holdingbb->list, e, f, apr_bucket, link); ctx->state = RATE_FULLSPEED; break; } } while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *stop_point; apr_off_t len = 0; if (f->c->aborted) { apr_brigade_cleanup(bb); ctx->state = RATE_ERROR; break; } if (do_sleep) { apr_sleep(RATE_INTERVAL_MS * 1000); } else { do_sleep = 1; } apr_brigade_length(bb, 1, &len); rv = apr_brigade_partition(bb, ctx->chunk_size, &stop_point); if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, APLOGNO(01456) "rl: partition failed."); break; } if (stop_point != APR_BRIGADE_SENTINEL(bb)) { apr_bucket *f; apr_bucket *e = APR_BUCKET_PREV(stop_point); f = APR_RING_FIRST(&bb->list); APR_RING_UNSPLICE(f, e, link); APR_RING_SPLICE_HEAD(&ctx->tmpbb->list, f, e, apr_bucket, link); } else { APR_BRIGADE_CONCAT(ctx->tmpbb, bb); } fb = apr_bucket_flush_create(ba); APR_BRIGADE_INSERT_TAIL(ctx->tmpbb, fb); #if 0 brigade_dump(f->r, ctx->tmpbb); brigade_dump(f->r, bb); #endif rv = ap_pass_brigade(f->next, ctx->tmpbb); apr_brigade_cleanup(ctx->tmpbb); if (rv != APR_SUCCESS) { ctx->state = RATE_ERROR; ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, f->r, APLOGNO(01457) "rl: brigade pass failed."); break; } } } } return rv; }
/** * 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 last resource in the list */ res = APR_RING_LAST(&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; } APR_RING_REMOVE(res, link); reslist->nidle--; reslist->ntotal--; rv = destroy_resource(reslist, res); free_container(reslist, res); if (rv != APR_SUCCESS) { apr_thread_mutex_unlock(reslist->listlock); return rv; } } apr_thread_mutex_unlock(reslist->listlock); return APR_SUCCESS; }