/* Licensed to the Apache Software Foundation (ASF) under one or more *contributorlicenseagreements.SeetheNOTICEfiledistributedwith *thisworkforadditionalinformationregardingcopyrightownership. *TheASFlicensesthisfiletoYouundertheApacheLicense,Version2.0 *(the"License");youmaynotusethisfileexceptincompliancewith *theLicense.YoumayobtainacopyoftheLicenseat * *http://www.apache.org/licenses/LICENSE-2.0 * *Unlessrequiredbyapplicablelaworagreedtoinwriting,software *distributedundertheLicenseisdistributedonan"ASIS"BASIS, *WITHOUTWARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied. *SeetheLicenseforthespecificlanguagegoverningpermissionsand *limitationsundertheLicense.
*/
staticint bucket_is_mmap(apr_bucket *b)
{ #if APR_HAS_MMAP return APR_BUCKET_IS_MMAP(b); #else /* if it is not defined as enabled, it should always be no */ return0; #endif
}
static apr_off_t bucket_mem_used(apr_bucket *b)
{ if (APR_BUCKET_IS_FILE(b) || bucket_is_mmap(b)) { return0;
} else { /* should all have determinate length */ return (apr_off_t)b->length;
}
}
staticint report_consumption(h2_bucket_beam *beam, int locked)
{ int rv = 0;
apr_off_t len = beam->recv_bytes - beam->recv_bytes_reported;
h2_beam_io_callback *cb = beam->cons_io_cb;
if (len > 0) { if (cb) { void *ctx = beam->cons_ctx;
if (locked) apr_thread_mutex_unlock(beam->lock);
cb(ctx, beam, len); if (locked) apr_thread_mutex_lock(beam->lock);
rv = 1;
}
beam->recv_bytes_reported += len;
} return rv;
}
static apr_size_t calc_buffered(h2_bucket_beam *beam)
{
apr_size_t len = 0;
apr_bucket *b; for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
b = APR_BUCKET_NEXT(b)) { if (b->length == ((apr_size_t)-1)) { /* do not count */
} elseif (APR_BUCKET_IS_FILE(b) || bucket_is_mmap(b)) { /* if unread, has no real mem footprint. */
} else {
len += b->length;
}
} return len;
}
staticvoid purge_consumed_buckets(h2_bucket_beam *beam)
{
apr_bucket *b; /* delete all sender buckets in purge brigade, needs to be called
* from sender thread only */ while (!H2_BLIST_EMPTY(&beam->buckets_consumed)) {
b = H2_BLIST_FIRST(&beam->buckets_consumed); if(AP_BUCKET_IS_EOR(b)) {
APR_BUCKET_REMOVE(b);
H2_BLIST_INSERT_TAIL(&beam->buckets_eor, b);
} else {
apr_bucket_delete(b);
}
}
}
staticvoid purge_eor_buckets(h2_bucket_beam *beam)
{
apr_bucket *b; /* delete all sender buckets in purge brigade, needs to be called
* from sender thread only */ while (!H2_BLIST_EMPTY(&beam->buckets_eor)) {
b = H2_BLIST_FIRST(&beam->buckets_eor);
apr_bucket_delete(b);
}
}
(void)block; if (beam->aborted) {
rv = APR_ECONNABORTED; goto cleanup;
}
ap_assert(beam->pool);
b = APR_BRIGADE_FIRST(bb); if (APR_BUCKET_IS_METADATA(b)) {
APR_BUCKET_REMOVE(b);
apr_bucket_setaside(b, beam->pool);
H2_BLIST_INSERT_TAIL(&beam->buckets_to_send, b); goto cleanup;
} /* non meta bucket */
/* in case of indeterminate length, we need to read the bucket,
* so that it transforms itself into something stable. */ if (b->length == ((apr_size_t)-1)) {
rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) goto cleanup;
}
if (APR_BUCKET_IS_FILE(b)) { /* For file buckets the problem is their internal readpool that *isusedonthefirstreadtoallocatebuffer/mmap. *Sincesettingasideafilebucketwillde-registerthe *filecleanupfunctionfromthepreviouspool,weneedto *callthatonlyfromthesenderthread. * *Currently,wedonothandlefilebucketwithrefcount>1as *thebeamisthennotincompletecontrolofthefile'slifetime. *Whichresultsinthebugthatafilegetclosedbythereceiver *whilethesenderorthebeamstillhavebucketsusingit. * *Additionally,weallowcallbackstopreventbeamingfile *handlesacross.Theusecaseforthisistolimitthenumber *ofopenfilehandlesandratherusealessefficientbeam
* transport. */
apr_bucket_file *bf = b->data;
can_beam = !beam->copy_files && (bf->refcount.refcount == 1);
} elseif (bucket_is_mmap(b)) {
can_beam = !beam->copy_files;
}
if (!*pspace_left) {
rv = APR_EAGAIN; goto cleanup;
}
/* bucket is accepted and added to beam->buckets_to_send */ if (APR_BUCKET_IS_HEAP(b)) { /* For heap buckets, a read from a receiver thread is fine. The *datawillbethereandliveuntilthebucketitselfis
* destroyed. */
rv = apr_bucket_setaside(b, beam->pool); if (rv != APR_SUCCESS) goto cleanup;
} elseif (can_beam && (APR_BUCKET_IS_FILE(b) || bucket_is_mmap(b))) {
rv = apr_bucket_setaside(b, beam->pool); if (rv != APR_SUCCESS) goto cleanup;
} else { /* we know of no special shortcut to transfer the bucket to
* another pool without copying. So we make it a heap bucket. */
apr_bucket *b2;
rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); if (rv != APR_SUCCESS) goto cleanup; /* this allocates and copies data */
b2 = apr_bucket_heap_create(data, len, NULL, bb->bucket_alloc);
apr_bucket_delete(b);
b = b2;
APR_BRIGADE_INSERT_HEAD(bb, b);
}
/* transfer from our sender brigade, transforming sender buckets to
* receiver ones until we have enough */ while (remain >= 0 && !H2_BLIST_EMPTY(&beam->buckets_to_send)) {
if (APR_BUCKET_IS_METADATA(bsender)) { /* we need a real copy into the receivers bucket_alloc */ if (APR_BUCKET_IS_EOS(bsender)) { /* this closes the beam */
beam->closed = 1;
brecv = apr_bucket_eos_create(bb->bucket_alloc);
} elseif (APR_BUCKET_IS_FLUSH(bsender)) {
brecv = apr_bucket_flush_create(bb->bucket_alloc);
} #if AP_HAS_RESPONSE_BUCKETS elseif (AP_BUCKET_IS_RESPONSE(bsender)) {
brecv = ap_bucket_response_clone(bsender, bb->p, bb->bucket_alloc);
} elseif (AP_BUCKET_IS_REQUEST(bsender)) {
brecv = ap_bucket_request_clone(bsender, bb->p, bb->bucket_alloc);
} elseif (AP_BUCKET_IS_HEADERS(bsender)) {
brecv = ap_bucket_headers_clone(bsender, bb->p, bb->bucket_alloc);
} #else elseif (H2_BUCKET_IS_HEADERS(bsender)) {
brecv = h2_bucket_headers_clone(bsender, bb->p, bb->bucket_alloc);
} #endif/* AP_HAS_RESPONSE_BUCKETS */ elseif (AP_BUCKET_IS_ERROR(bsender)) {
ap_bucket_error *eb = bsender->data;
brecv = ap_bucket_error_create(eb->status, eb->data,
bb->p, bb->bucket_alloc);
}
} elseif (bsender->length == 0) { /* nop */
} #if APR_HAS_MMAP elseif (APR_BUCKET_IS_MMAP(bsender)) {
apr_bucket_mmap *bmmap = bsender->data;
apr_mmap_t *mmap;
rv = apr_mmap_dup(&mmap, bmmap->mmap, bb->p); if (rv != APR_SUCCESS) goto leave;
brecv = apr_bucket_mmap_create(mmap, bsender->start, bsender->length, bb->bucket_alloc);
} #endif elseif (APR_BUCKET_IS_FILE(bsender)) { /* This is setaside into the target brigade pool so that *anyreadoperationmesseswiththatpoolandnot
* the sender one. */
apr_bucket_file *f = (apr_bucket_file *)bsender->data;
apr_file_t *fd = f->fd; int setaside = (f->readpool != bb->p);
if (setaside) {
rv = apr_file_setaside(&fd, fd, bb->p); if (rv != APR_SUCCESS) goto leave;
}
ng = apr_brigade_insert_file(bb, fd, bsender->start, (apr_off_t)bsender->length,
bb->p); #if APR_HAS_MMAP /* disable mmap handling as this leads to segfaults when *theunderlyingfileischangedwhilememorypointerhas
* been handed out. See also PR 59348 */
apr_bucket_file_enable_mmap(ng, 0); #endif
remain -= bsender->length;
++transferred;
} else { constchar *data;
apr_size_t dlen; /* we did that when the bucket was added, so this should *giveusthesamedataasbeforewithoutchangingthebucket
* or anything (pool) connected to it. */
rv = apr_bucket_read(bsender, &data, &dlen, APR_BLOCK_READ); if (rv != APR_SUCCESS) goto leave;
rv = apr_brigade_write(bb, NULL, NULL, data, dlen); if (rv != APR_SUCCESS) goto leave;
remain -= dlen;
++transferred;
}
if (brecv) { /* we have a proxy that we can give the receiver */
APR_BRIGADE_INSERT_TAIL(bb, brecv);
remain -= brecv->length;
++transferred;
}
APR_BUCKET_REMOVE(bsender);
H2_BLIST_INSERT_TAIL(&beam->buckets_consumed, bsender);
beam->recv_bytes += bsender->length;
++consumed_buckets;
}
if (beam->recv_cb && consumed_buckets > 0) {
beam->recv_cb(beam->recv_ctx, beam);
}
for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
b = APR_BUCKET_NEXT(b)) { /* should all have determinate length */
l += b->length;
} return l;
}
apr_off_t h2_beam_get_buffered(h2_bucket_beam *beam)
{
apr_off_t l = 0;
apr_thread_mutex_lock(beam->lock);
l = get_buffered_data_len(beam);
apr_thread_mutex_unlock(beam->lock); return l;
}
apr_off_t h2_beam_get_mem_used(h2_bucket_beam *beam)
{
apr_bucket *b;
apr_off_t l = 0;
apr_thread_mutex_lock(beam->lock); for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
b = APR_BUCKET_NEXT(b)) {
l += bucket_mem_used(b);
}
apr_thread_mutex_unlock(beam->lock); return l;
}
int h2_beam_empty(h2_bucket_beam *beam)
{ int empty = 1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.