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 "mod_perl.h"
18
19 /*
20 * modperl_svptr_table api is an add-on to the Perl ptr_table_ api.
21 * we use a PTR_TBL_t to map config structures (e.g. from parsed
22 * httpd.conf or .htaccess), where each interpreter needs to have its
23 * own copy of the Perl SV object. we do not use an HV* for this, because
24 * the HV keys must be SVs with a string value, too much overhead.
25 * we do not use an apr_hash_t because they only have the lifetime of
26 * the pool used to create them. which may or may not be the same lifetime
27 * of the objects we need to lookup.
28 */
29
30 #ifdef USE_ITHREADS
31
32 #if MP_PERL_BRANCH(5, 6)
33 # define my_sv_dup(s, p) SvREFCNT_inc(sv_dup(s))
34
35 typedef struct {
36 AV *stashes;
37 UV flags;
38 PerlInterpreter *proto_perl;
39 } CLONE_PARAMS;
40
41 #else
42 # ifdef sv_dup_inc
43 # define my_sv_dup(s, p) sv_dup_inc(s, p)
44 # else
45 # define my_sv_dup(s, p) SvREFCNT_inc(sv_dup(s, p))
46 # endif
47 #endif
48
49 /*
50 * copy a PTR_TBL_t whos PTR_TBL_ENT_t values are SVs.
51 * the SVs are dup-ed so each interpreter has its own copy.
52 */
modperl_svptr_table_clone(pTHX_ PerlInterpreter * proto_perl,PTR_TBL_t * source)53 PTR_TBL_t *modperl_svptr_table_clone(pTHX_ PerlInterpreter *proto_perl,
54 PTR_TBL_t *source)
55 {
56 UV i;
57 PTR_TBL_t *tbl;
58 PTR_TBL_ENT_t **src_ary, **dst_ary;
59 CLONE_PARAMS parms;
60
61 Newxz(tbl, 1, PTR_TBL_t);
62 tbl->tbl_max = source->tbl_max;
63 tbl->tbl_items = source->tbl_items;
64 Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t *);
65
66 dst_ary = tbl->tbl_ary;
67 src_ary = source->tbl_ary;
68
69 Zero(&parms, 1, CLONE_PARAMS);
70 parms.flags = 0;
71 parms.stashes = newAV();
72
73 for (i=0; i < source->tbl_max; i++, dst_ary++, src_ary++) {
74 PTR_TBL_ENT_t *src_ent, *dst_ent=NULL;
75
76 if (!*src_ary) {
77 continue;
78 }
79
80 for (src_ent = *src_ary;
81 src_ent;
82 src_ent = src_ent->next)
83 {
84 if (dst_ent == NULL) {
85 Newxz(dst_ent, 1, PTR_TBL_ENT_t);
86 *dst_ary = dst_ent;
87 }
88 else {
89 Newxz(dst_ent->next, 1, PTR_TBL_ENT_t);
90 dst_ent = dst_ent->next;
91 }
92
93 /* key is just a pointer we do not modify, no need to copy */
94 dst_ent->oldval = src_ent->oldval;
95
96 dst_ent->newval = my_sv_dup((SV*)src_ent->newval, &parms);
97 }
98 }
99
100 SvREFCNT_dec(parms.stashes);
101
102 return tbl;
103 }
104
105 #endif
106
107 /*
108 * need to free the SV values in addition to ptr_table_free
109 */
modperl_svptr_table_destroy(pTHX_ PTR_TBL_t * tbl)110 void modperl_svptr_table_destroy(pTHX_ PTR_TBL_t *tbl)
111 {
112 UV i;
113 PTR_TBL_ENT_t **ary = tbl->tbl_ary;
114
115 for (i=0; i < tbl->tbl_max; i++, ary++) {
116 PTR_TBL_ENT_t *ent;
117
118 if (!*ary) {
119 continue;
120 }
121
122 for (ent = *ary; ent; ent = ent->next) {
123 if (!ent->newval) {
124 continue;
125 }
126
127 SvREFCNT_dec((SV*)ent->newval);
128 ent->newval = NULL;
129 }
130 }
131
132 modperl_svptr_table_free(aTHX_ tbl);
133 }
134
135 /*
136 * the Perl ptr_table_ api does not provide a function to remove
137 * an entry from the table. we need to SvREFCNT_dec the SV value
138 * anyhow.
139 */
modperl_svptr_table_delete(pTHX_ PTR_TBL_t * tbl,void * key)140 void modperl_svptr_table_delete(pTHX_ PTR_TBL_t *tbl, void *key)
141 {
142 PTR_TBL_ENT_t *entry, **oentry;
143 UV hash = PTR2UV(key);
144
145 oentry = &tbl->tbl_ary[hash & tbl->tbl_max];
146 entry = *oentry;
147
148 for (; entry; oentry = &entry->next, entry = *oentry) {
149 if (entry->oldval == key) {
150 *oentry = entry->next;
151 SvREFCNT_dec((SV*)entry->newval);
152 Safefree(entry);
153 tbl->tbl_items--;
154 return;
155 }
156 }
157 }
158
159 /*
160 * XXX: the following are a copy of the Perl 5.8.0 Perl_ptr_table api
161 * renamed s/Perl_ptr/modperl_svptr/g;
162 * two reasons:
163 * these functions do not exist without -DUSE_ITHREADS
164 * the clear/free functions do not exist in 5.6.x
165 */
166
167 /* create a new pointer-mapping table */
168
169 PTR_TBL_t *
modperl_svptr_table_new(pTHX)170 modperl_svptr_table_new(pTHX)
171 {
172 PTR_TBL_t *tbl;
173 Newxz(tbl, 1, PTR_TBL_t);
174 tbl->tbl_max = 511;
175 tbl->tbl_items = 0;
176 Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
177 return tbl;
178 }
179
180 /* map an existing pointer using a table */
181
182 void *
modperl_svptr_table_fetch(pTHX_ PTR_TBL_t * tbl,void * sv)183 modperl_svptr_table_fetch(pTHX_ PTR_TBL_t *tbl, void *sv)
184 {
185 PTR_TBL_ENT_t *tblent;
186 UV hash = PTR2UV(sv);
187 MP_ASSERT(tbl);
188 tblent = tbl->tbl_ary[hash & tbl->tbl_max];
189 for (; tblent; tblent = tblent->next) {
190 if (tblent->oldval == sv)
191 return tblent->newval;
192 }
193 return (void*)NULL;
194 }
195
196 /* add a new entry to a pointer-mapping table */
197
198 void
modperl_svptr_table_store(pTHX_ PTR_TBL_t * tbl,void * oldv,void * newv)199 modperl_svptr_table_store(pTHX_ PTR_TBL_t *tbl, void *oldv, void *newv)
200 {
201 PTR_TBL_ENT_t *tblent, **otblent;
202 /* XXX this may be pessimal on platforms where pointers aren't good
203 * hash values e.g. if they grow faster in the most significant
204 * bits */
205 UV hash = PTR2UV(oldv);
206 bool i = 1;
207
208 MP_ASSERT(tbl);
209 otblent = &tbl->tbl_ary[hash & tbl->tbl_max];
210 for (tblent = *otblent; tblent; i=0, tblent = tblent->next) {
211 if (tblent->oldval == oldv) {
212 tblent->newval = newv;
213 return;
214 }
215 }
216 Newxz(tblent, 1, PTR_TBL_ENT_t);
217 tblent->oldval = oldv;
218 tblent->newval = newv;
219 tblent->next = *otblent;
220 *otblent = tblent;
221 tbl->tbl_items++;
222 if (i && tbl->tbl_items > tbl->tbl_max)
223 modperl_svptr_table_split(aTHX_ tbl);
224 }
225
226 /* double the hash bucket size of an existing ptr table */
227
228 void
modperl_svptr_table_split(pTHX_ PTR_TBL_t * tbl)229 modperl_svptr_table_split(pTHX_ PTR_TBL_t *tbl)
230 {
231 PTR_TBL_ENT_t **ary = tbl->tbl_ary;
232 UV oldsize = tbl->tbl_max + 1;
233 UV newsize = oldsize * 2;
234 UV i;
235
236 Renew(ary, newsize, PTR_TBL_ENT_t*);
237 Zero(&ary[oldsize], newsize-oldsize, PTR_TBL_ENT_t*);
238 tbl->tbl_max = --newsize;
239 tbl->tbl_ary = ary;
240 for (i=0; i < oldsize; i++, ary++) {
241 PTR_TBL_ENT_t **curentp, **entp, *ent;
242 if (!*ary)
243 continue;
244 curentp = ary + oldsize;
245 for (entp = ary, ent = *ary; ent; ent = *entp) {
246 if ((newsize & PTR2UV(ent->oldval)) != i) {
247 *entp = ent->next;
248 ent->next = *curentp;
249 *curentp = ent;
250 continue;
251 }
252 else
253 entp = &ent->next;
254 }
255 }
256 }
257
258 /* remove all the entries from a ptr table */
259
260 void
modperl_svptr_table_clear(pTHX_ PTR_TBL_t * tbl)261 modperl_svptr_table_clear(pTHX_ PTR_TBL_t *tbl)
262 {
263 register PTR_TBL_ENT_t **array;
264 register PTR_TBL_ENT_t *entry;
265 register PTR_TBL_ENT_t *oentry = (PTR_TBL_ENT_t *)NULL;
266 UV riter = 0;
267 UV max;
268
269 if (!tbl || !tbl->tbl_items) {
270 return;
271 }
272
273 array = tbl->tbl_ary;
274 entry = array[0];
275 max = tbl->tbl_max;
276
277 for (;;) {
278 if (entry) {
279 oentry = entry;
280 entry = entry->next;
281 Safefree(oentry);
282 }
283 if (!entry) {
284 if (++riter > max) {
285 break;
286 }
287 entry = array[riter];
288 }
289 }
290
291 tbl->tbl_items = 0;
292 }
293
294 /* clear and free a ptr table */
295
296 void
modperl_svptr_table_free(pTHX_ PTR_TBL_t * tbl)297 modperl_svptr_table_free(pTHX_ PTR_TBL_t *tbl)
298 {
299 if (!tbl) {
300 return;
301 }
302 modperl_svptr_table_clear(aTHX_ tbl);
303 Safefree(tbl->tbl_ary);
304 Safefree(tbl);
305 }
306
307 /*
308 * Local Variables:
309 * c-basic-offset: 4
310 * indent-tabs-mode: nil
311 * End:
312 */
313