]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr-util/buckets/apr_buckets_pool.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr-util / buckets / apr_buckets_pool.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_buckets.h"
18 #define APR_WANT_MEMFUNC
19 #include "apr_want.h"
20
21 static apr_status_t pool_bucket_cleanup(void *data)
22 {
23     apr_bucket_pool *p = data;
24
25     /*
26      * If the pool gets cleaned up, we have to copy the data out
27      * of the pool and onto the heap.  But the apr_buckets out there
28      * that point to this pool bucket need to be notified such that
29      * they can morph themselves into a regular heap bucket the next
30      * time they try to read.  To avoid having to manipulate
31      * reference counts and b->data pointers, the apr_bucket_pool
32      * actually _contains_ an apr_bucket_heap as its first element,
33      * so the two share their apr_bucket_refcount member, and you
34      * can typecast a pool bucket struct to make it look like a
35      * regular old heap bucket struct.
36      */
37     p->heap.base = apr_bucket_alloc(p->heap.alloc_len, p->list);
38     memcpy(p->heap.base, p->base, p->heap.alloc_len);
39     p->base = NULL;
40     p->pool = NULL;
41
42     return APR_SUCCESS;
43 }
44
45 static apr_status_t pool_bucket_read(apr_bucket *b, const char **str, 
46                                      apr_size_t *len, apr_read_type_e block)
47 {
48     apr_bucket_pool *p = b->data;
49     const char *base = p->base;
50
51     if (p->pool == NULL) {
52         /*
53          * pool has been cleaned up... masquerade as a heap bucket from now
54          * on. subsequent bucket operations will use the heap bucket code.
55          */
56         b->type = &apr_bucket_type_heap;
57         base = p->heap.base;
58     }
59     *str = base + b->start;
60     *len = b->length;
61     return APR_SUCCESS;
62 }
63
64 static void pool_bucket_destroy(void *data)
65 {
66     apr_bucket_pool *p = data;
67
68     /* If the pool is cleaned up before the last reference goes
69      * away, the data is really now on the heap; heap_destroy() takes
70      * over.  free() in heap_destroy() thinks it's freeing
71      * an apr_bucket_heap, when in reality it's freeing the whole
72      * apr_bucket_pool for us.
73      */
74     if (p->pool) {
75         /* the shared resource is still in the pool
76          * because the pool has not been cleaned up yet
77          */
78         if (apr_bucket_shared_destroy(p)) {
79             apr_pool_cleanup_kill(p->pool, p, pool_bucket_cleanup);
80             apr_bucket_free(p);
81         }
82     }
83     else {
84         /* the shared resource is no longer in the pool, it's
85          * on the heap, but this reference still thinks it's a pool
86          * bucket.  we should just go ahead and pass control to
87          * heap_destroy() for it since it doesn't know any better.
88          */
89         apr_bucket_type_heap.destroy(p);
90     }
91 }
92
93 APU_DECLARE(apr_bucket *) apr_bucket_pool_make(apr_bucket *b,
94                       const char *buf, apr_size_t length, apr_pool_t *pool)
95 {
96     apr_bucket_pool *p;
97
98     p = apr_bucket_alloc(sizeof(*p), b->list);
99
100     /* XXX: we lose the const qualifier here which indicates
101      * there's something screwy with the API...
102      */
103     /* XXX: why is this?  buf is const, p->base is const... what's
104      * the problem?  --jcw */
105     p->base = (char *) buf;
106     p->pool = pool;
107     p->list = b->list;
108
109     b = apr_bucket_shared_make(b, p, 0, length);
110     b->type = &apr_bucket_type_pool;
111
112     /* pre-initialize heap bucket member */
113     p->heap.alloc_len = length;
114     p->heap.base      = NULL;
115     p->heap.free_func = apr_bucket_free;
116
117     apr_pool_cleanup_register(p->pool, p, pool_bucket_cleanup,
118                               apr_pool_cleanup_null);
119     return b;
120 }
121
122 APU_DECLARE(apr_bucket *) apr_bucket_pool_create(const char *buf,
123                                                  apr_size_t length,
124                                                  apr_pool_t *pool,
125                                                  apr_bucket_alloc_t *list)
126 {
127     apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
128
129     APR_BUCKET_INIT(b);
130     b->free = apr_bucket_free;
131     b->list = list;
132     return apr_bucket_pool_make(b, buf, length, pool);
133 }
134
135 APU_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_pool = {
136     "POOL", 5, APR_BUCKET_DATA,
137     pool_bucket_destroy,
138     pool_bucket_read,
139     apr_bucket_setaside_noop, /* don't need to setaside thanks to the cleanup*/
140     apr_bucket_shared_split,
141     apr_bucket_shared_copy
142 };