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 /* Memory handler for a plain memory divided in slot.
18 * This one uses plain memory.
19 */
20
21 #include "ap_slotmem.h"
22
23 #define AP_SLOTMEM_IS_PREGRAB(t) (t->type & AP_SLOTMEM_TYPE_PREGRAB)
24
25 struct ap_slotmem_instance_t {
26 char *name; /* per segment name */
27 void *base; /* data set start */
28 apr_size_t size; /* size of each memory slot */
29 unsigned int num; /* number of mem slots */
30 apr_pool_t *gpool; /* per segment global pool */
31 char *inuse; /* in-use flag table*/
32 ap_slotmem_type_t type; /* type-specific flags */
33 struct ap_slotmem_instance_t *next; /* location of next allocated segment */
34 };
35
36
37 /* global pool and list of slotmem we are handling */
38 static struct ap_slotmem_instance_t *globallistmem = NULL;
39 static apr_pool_t *gpool = NULL;
40
slotmem_do(ap_slotmem_instance_t * mem,ap_slotmem_callback_fn_t * func,void * data,apr_pool_t * pool)41 static apr_status_t slotmem_do(ap_slotmem_instance_t *mem, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool)
42 {
43 unsigned int i;
44 char *ptr;
45 char *inuse;
46 apr_status_t retval = APR_SUCCESS;
47
48
49 if (!mem)
50 return APR_ENOSHMAVAIL;
51
52 ptr = (char *)mem->base;
53 inuse = mem->inuse;
54 for (i = 0; i < mem->num; i++, inuse++) {
55 if (!AP_SLOTMEM_IS_PREGRAB(mem) ||
56 (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) {
57 retval = func((void *) ptr, data, pool);
58 if (retval != APR_SUCCESS)
59 break;
60 }
61 ptr += mem->size;
62 }
63 return retval;
64 }
65
slotmem_create(ap_slotmem_instance_t ** new,const char * name,apr_size_t item_size,unsigned int item_num,ap_slotmem_type_t type,apr_pool_t * pool)66 static apr_status_t slotmem_create(ap_slotmem_instance_t **new, const char *name, apr_size_t item_size, unsigned int item_num, ap_slotmem_type_t type, apr_pool_t *pool)
67 {
68 ap_slotmem_instance_t *res;
69 ap_slotmem_instance_t *next = globallistmem;
70 apr_size_t basesize = (item_size * item_num);
71
72 const char *fname;
73
74 if (name) {
75 if (name[0] == ':')
76 fname = name;
77 else
78 fname = ap_runtime_dir_relative(pool, name);
79
80 /* first try to attach to existing slotmem */
81 if (next) {
82 for (;;) {
83 if (strcmp(next->name, fname) == 0) {
84 /* we already have it */
85 *new = next;
86 return APR_SUCCESS;
87 }
88 if (!next->next) {
89 break;
90 }
91 next = next->next;
92 }
93 }
94 }
95 else
96 fname = "anonymous";
97
98 /* create the memory using the gpool */
99 res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, sizeof(ap_slotmem_instance_t));
100 res->base = apr_pcalloc(gpool, basesize + (item_num * sizeof(char)));
101 if (!res->base)
102 return APR_ENOSHMAVAIL;
103
104 /* For the chained slotmem stuff */
105 res->name = apr_pstrdup(gpool, fname);
106 res->size = item_size;
107 res->num = item_num;
108 res->next = NULL;
109 res->type = type;
110 res->inuse = (char *)res->base + basesize;
111 if (globallistmem == NULL)
112 globallistmem = res;
113 else
114 next->next = res;
115
116 *new = res;
117 return APR_SUCCESS;
118 }
119
slotmem_attach(ap_slotmem_instance_t ** new,const char * name,apr_size_t * item_size,unsigned int * item_num,apr_pool_t * pool)120 static apr_status_t slotmem_attach(ap_slotmem_instance_t **new, const char *name, apr_size_t *item_size, unsigned int *item_num, apr_pool_t *pool)
121 {
122 ap_slotmem_instance_t *next = globallistmem;
123 const char *fname;
124
125 if (name) {
126 if (name[0] == ':')
127 fname = name;
128 else
129 fname = ap_runtime_dir_relative(pool, name);
130 }
131 else
132 return APR_ENOSHMAVAIL;
133
134 /* first try to attach to existing slotmem */
135 while (next) {
136 if (strcmp(next->name, fname) == 0) {
137 /* we already have it */
138 *new = next;
139 *item_size = next->size;
140 *item_num = next->num;
141 return APR_SUCCESS;
142 }
143 next = next->next;
144 }
145
146 return APR_ENOSHMAVAIL;
147 }
148
slotmem_dptr(ap_slotmem_instance_t * score,unsigned int id,void ** mem)149 static apr_status_t slotmem_dptr(ap_slotmem_instance_t *score, unsigned int id, void **mem)
150 {
151
152 char *ptr;
153
154 if (!score)
155 return APR_ENOSHMAVAIL;
156 if (id >= score->num)
157 return APR_EINVAL;
158
159 ptr = (char *)score->base + score->size * id;
160 if (!ptr)
161 return APR_ENOSHMAVAIL;
162 *mem = ptr;
163 return APR_SUCCESS;
164 }
165
slotmem_get(ap_slotmem_instance_t * slot,unsigned int id,unsigned char * dest,apr_size_t dest_len)166 static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *dest, apr_size_t dest_len)
167 {
168 void *ptr;
169 char *inuse;
170 apr_status_t ret;
171
172 if (!slot) {
173 return APR_ENOSHMAVAIL;
174 }
175
176 inuse = slot->inuse + id;
177 if (id >= slot->num) {
178 return APR_EINVAL;
179 }
180 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
181 return APR_NOTFOUND;
182 }
183 ret = slotmem_dptr(slot, id, &ptr);
184 if (ret != APR_SUCCESS) {
185 return ret;
186 }
187 *inuse=1;
188 memcpy(dest, ptr, dest_len); /* bounds check? */
189 return APR_SUCCESS;
190 }
191
slotmem_put(ap_slotmem_instance_t * slot,unsigned int id,unsigned char * src,apr_size_t src_len)192 static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *src, apr_size_t src_len)
193 {
194 void *ptr;
195 char *inuse;
196 apr_status_t ret;
197
198 if (!slot) {
199 return APR_ENOSHMAVAIL;
200 }
201
202 inuse = slot->inuse + id;
203 if (id >= slot->num) {
204 return APR_EINVAL;
205 }
206 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
207 return APR_NOTFOUND;
208 }
209 ret = slotmem_dptr(slot, id, &ptr);
210 if (ret != APR_SUCCESS) {
211 return ret;
212 }
213 *inuse=1;
214 memcpy(ptr, src, src_len); /* bounds check? */
215 return APR_SUCCESS;
216 }
217
slotmem_num_slots(ap_slotmem_instance_t * slot)218 static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot)
219 {
220 return slot->num;
221 }
222
slotmem_num_free_slots(ap_slotmem_instance_t * slot)223 static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot)
224 {
225 unsigned int i, counter=0;
226 char *inuse = slot->inuse;
227 for (i = 0; i < slot->num; i++, inuse++) {
228 if (!*inuse)
229 counter++;
230 }
231 return counter;
232 }
233
slotmem_slot_size(ap_slotmem_instance_t * slot)234 static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot)
235 {
236 return slot->size;
237 }
238
239 /*
240 * XXXX: if !AP_SLOTMEM_IS_PREGRAB, then still worry about
241 * inuse for grab and return?
242 */
slotmem_grab(ap_slotmem_instance_t * slot,unsigned int * id)243 static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id)
244 {
245 unsigned int i;
246 char *inuse;
247
248 if (!slot) {
249 return APR_ENOSHMAVAIL;
250 }
251
252 inuse = slot->inuse;
253
254 for (i = 0; i < slot->num; i++, inuse++) {
255 if (!*inuse) {
256 break;
257 }
258 }
259 if (i >= slot->num) {
260 return APR_EINVAL;
261 }
262 *inuse = 1;
263 *id = i;
264 return APR_SUCCESS;
265 }
266
slotmem_fgrab(ap_slotmem_instance_t * slot,unsigned int id)267 static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id)
268 {
269 char *inuse;
270
271 if (!slot) {
272 return APR_ENOSHMAVAIL;
273 }
274
275 if (id >= slot->num) {
276 return APR_EINVAL;
277 }
278 inuse = slot->inuse + id;
279 *inuse = 1;
280 return APR_SUCCESS;
281 }
282
slotmem_release(ap_slotmem_instance_t * slot,unsigned int id)283 static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, unsigned int id)
284 {
285 char *inuse;
286
287 if (!slot) {
288 return APR_ENOSHMAVAIL;
289 }
290
291 inuse = slot->inuse;
292
293 if (id >= slot->num) {
294 return APR_EINVAL;
295 }
296 if (!inuse[id] ) {
297 return APR_NOTFOUND;
298 }
299 inuse[id] = 0;
300 return APR_SUCCESS;
301 }
302
303 static const ap_slotmem_provider_t storage = {
304 "plainmem",
305 &slotmem_do,
306 &slotmem_create,
307 &slotmem_attach,
308 &slotmem_dptr,
309 &slotmem_get,
310 &slotmem_put,
311 &slotmem_num_slots,
312 &slotmem_num_free_slots,
313 &slotmem_slot_size,
314 &slotmem_grab,
315 &slotmem_release,
316 &slotmem_fgrab
317 };
318
pre_config(apr_pool_t * p,apr_pool_t * plog,apr_pool_t * ptemp)319 static int pre_config(apr_pool_t *p, apr_pool_t *plog,
320 apr_pool_t *ptemp)
321 {
322 gpool = p;
323 return OK;
324 }
325
ap_slotmem_plain_register_hook(apr_pool_t * p)326 static void ap_slotmem_plain_register_hook(apr_pool_t *p)
327 {
328 /* XXX: static const char * const prePos[] = { "mod_slotmem.c", NULL }; */
329 ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "plain",
330 AP_SLOTMEM_PROVIDER_VERSION, &storage);
331 ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE);
332 }
333
334 AP_DECLARE_MODULE(slotmem_plain) = {
335 STANDARD20_MODULE_STUFF,
336 NULL, /* create per-directory config structure */
337 NULL, /* merge per-directory config structures */
338 NULL, /* create per-server config structure */
339 NULL, /* merge per-server config structures */
340 NULL, /* command apr_table_t */
341 ap_slotmem_plain_register_hook /* register hooks */
342 };
343
344