diff options
-rw-r--r-- | buckets/apr_buckets_mmap.c | 44 |
1 files changed, 23 insertions, 21 deletions
diff --git a/buckets/apr_buckets_mmap.c b/buckets/apr_buckets_mmap.c index 11d1b2c6..b9d68b05 100644 --- a/buckets/apr_buckets_mmap.c +++ b/buckets/apr_buckets_mmap.c @@ -62,9 +62,9 @@ static apr_status_t mmap_bucket_read(apr_bucket *b, const char **str, apr_bucket_mmap *m = b->data; apr_status_t ok; void *addr; - + if (!m->mmap) { - /* due to cleanup issues we have no choice but to check this */ + /* the apr_mmap_t was already cleaned up out from under us */ return APR_EINVAL; } @@ -79,10 +79,11 @@ static apr_status_t mmap_bucket_read(apr_bucket *b, const char **str, static apr_status_t mmap_bucket_cleanup(void *data) { - /* the mmap has disappeared out from under us. we have no choice - * but to invalidate this bucket. from now on, all you can do to this - * bucket is destroy it, not read from it. - */ + /* the apr_mmap_t is about to disappear out from under us, so we + * have no choice but to pretend it doesn't exist anymore. the + * refcount is now useless because there's nothing to refer to + * anymore. so the only valid action on any remaining referrer + * is to delete it. no more reads, no more anything. */ apr_bucket_mmap *m = data; m->mmap = NULL; @@ -94,7 +95,7 @@ static void mmap_bucket_destroy(void *data) apr_bucket_mmap *m = data; if (apr_bucket_shared_destroy(m)) { - if (m->mmap && m->mmap->is_owner) { + if (m->mmap) { apr_pool_cleanup_kill(m->mmap->cntxt, m, mmap_bucket_cleanup); apr_mmap_delete(m->mmap); } @@ -114,10 +115,8 @@ APU_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm, m = apr_bucket_alloc(sizeof(*m), b->list); m->mmap = mm; - if (mm->is_owner) { - apr_pool_cleanup_register(mm->cntxt, m, mmap_bucket_cleanup, - apr_pool_cleanup_null); - } + apr_pool_cleanup_register(mm->cntxt, m, mmap_bucket_cleanup, + apr_pool_cleanup_null); b = apr_bucket_shared_make(b, m, start, length); b->type = &apr_bucket_type_mmap; @@ -139,33 +138,36 @@ APU_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm, return apr_bucket_mmap_make(b, mm, start, length); } -static apr_status_t mmap_bucket_setaside(apr_bucket *data, apr_pool_t *p) +static apr_status_t mmap_bucket_setaside(apr_bucket *b, apr_pool_t *p) { - apr_bucket_mmap *m = data->data; + apr_bucket_mmap *m = b->data; apr_mmap_t *mm = m->mmap; apr_mmap_t *new_mm; apr_status_t ok; if (!mm) { - /* due to cleanup issues we have no choice but to check this */ + /* the apr_mmap_t was already cleaned up out from under us */ return APR_EINVAL; } + /* shortcut if possible */ if (apr_pool_is_ancestor(mm->cntxt, p)) { return APR_SUCCESS; } + /* duplicate apr_mmap_t into new pool */ + /* XXX: the transfer_ownership flag on this call + * will go away soon.. it's ignored right now. */ ok = apr_mmap_dup(&new_mm, mm, p, 1); if (ok != APR_SUCCESS) { return ok; } - - m->mmap = new_mm; - if (new_mm->is_owner) { - apr_pool_cleanup_kill(mm->cntxt, m, mmap_bucket_cleanup); - apr_pool_cleanup_register(new_mm->cntxt, m, mmap_bucket_cleanup, - apr_pool_cleanup_null); - } + + /* decrement refcount on old apr_bucket_mmap */ + mmap_bucket_destroy(mm); + + /* create new apr_bucket_mmap pointing to new apr_mmap_t */ + apr_bucket_mmap_make(b, new_mm, b->start, b->length); return APR_SUCCESS; } |