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_arch_shm.h"
18
19 #include "apr_general.h"
20 #include "apr_errno.h"
21 #include "apr_user.h"
22 #include "apr_strings.h"
23 #include "apr_hash.h"
24
25 #if APR_USE_SHMEM_MMAP_SHM
26 /*
27 * For portable use, a shared memory object should be identified by a name of
28 * the form /somename; that is, a null-terminated string of up to NAME_MAX
29 * (i.e., 255) characters consisting of an initial slash, followed by one or
30 * more characters, none of which are slashes.
31 */
32 #ifndef NAME_MAX
33 #define NAME_MAX 255
34 #endif
35
36 /* See proc_mutex.c and sem_open for the reason for all this! */
rshash(const char * p)37 static unsigned int rshash (const char *p) {
38 /* hash function from Robert Sedgwicks 'Algorithms in C' book */
39 unsigned int b = 378551;
40 unsigned int a = 63689;
41 unsigned int retval = 0;
42
43 for( ; *p; p++) {
44 retval = retval * a + (*p);
45 a *= b;
46 }
47
48 return retval;
49 }
50
make_shm_open_safe_name(const char * filename,apr_pool_t * pool)51 static const char *make_shm_open_safe_name(const char *filename,
52 apr_pool_t *pool)
53 {
54 apr_ssize_t flen;
55 unsigned int h1, h2;
56
57 if (filename == NULL) {
58 return NULL;
59 }
60
61 flen = strlen(filename);
62 h1 = (apr_hashfunc_default(filename, &flen) & 0xffffffff);
63 h2 = (rshash(filename) & 0xffffffff);
64 return apr_psprintf(pool, "/ShM.%xH%x", h1, h2);
65
66 }
67 #endif
68
69 #if APR_USE_SHMEM_SHMGET
our_ftok(const char * filename)70 static key_t our_ftok(const char *filename)
71 {
72 /* to help avoid collisions while still using
73 * an easily recreated proj_id */
74 apr_ssize_t slen = strlen(filename);
75 return ftok(filename,
76 (int)apr_hashfunc_default(filename, &slen));
77 }
78 #endif
79
shm_cleanup_owner(void * m_)80 static apr_status_t shm_cleanup_owner(void *m_)
81 {
82 apr_shm_t *m = (apr_shm_t *)m_;
83
84 /* anonymous shared memory */
85 if (m->filename == NULL) {
86 #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
87 if (munmap(m->base, m->realsize) == -1) {
88 return errno;
89 }
90 return APR_SUCCESS;
91 #elif APR_USE_SHMEM_SHMGET_ANON
92 if (shmdt(m->base) == -1) {
93 return errno;
94 }
95 /* This segment will automatically remove itself after all
96 * references have detached. */
97 return APR_SUCCESS;
98 #endif
99 }
100
101 /* name-based shared memory */
102 else {
103 #if APR_USE_SHMEM_MMAP_TMP
104 if (munmap(m->base, m->realsize) == -1) {
105 return errno;
106 }
107 if (access(m->filename, F_OK)) {
108 return APR_SUCCESS;
109 }
110 else {
111 return apr_file_remove(m->filename, m->pool);
112 }
113 #elif APR_USE_SHMEM_MMAP_SHM
114 if (munmap(m->base, m->realsize) == -1) {
115 return errno;
116 }
117 if (shm_unlink(make_shm_open_safe_name(m->filename, m->pool)) == -1 && errno != ENOENT) {
118 return errno;
119 }
120 return APR_SUCCESS;
121 #elif APR_USE_SHMEM_SHMGET
122 /* Indicate that the segment is to be destroyed as soon
123 * as all processes have detached. This also disallows any
124 * new attachments to the segment. */
125 if (shmctl(m->shmid, IPC_RMID, NULL) == -1 && errno != EINVAL) {
126 return errno;
127 }
128 if (shmdt(m->base) == -1) {
129 return errno;
130 }
131 if (access(m->filename, F_OK)) {
132 return APR_SUCCESS;
133 }
134 else {
135 return apr_file_remove(m->filename, m->pool);
136 }
137 #else
138 return APR_ENOTIMPL;
139 #endif
140 }
141 }
142
apr_shm_create(apr_shm_t ** m,apr_size_t reqsize,const char * filename,apr_pool_t * pool)143 APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m,
144 apr_size_t reqsize,
145 const char *filename,
146 apr_pool_t *pool)
147 {
148 apr_shm_t *new_m;
149 apr_status_t status;
150 #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON
151 struct shmid_ds shmbuf;
152 apr_uid_t uid;
153 apr_gid_t gid;
154 #endif
155 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \
156 APR_USE_SHMEM_MMAP_ZERO
157 int tmpfd;
158 #endif
159 #if APR_USE_SHMEM_SHMGET
160 apr_size_t nbytes;
161 key_t shmkey;
162 #endif
163 #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_SHMGET || \
164 APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
165 apr_file_t *file; /* file where metadata is stored */
166 #endif
167
168 /* Check if they want anonymous or name-based shared memory */
169 if (filename == NULL) {
170 #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
171 new_m = apr_palloc(pool, sizeof(apr_shm_t));
172 new_m->pool = pool;
173 new_m->reqsize = reqsize;
174 new_m->realsize = reqsize +
175 APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */
176 new_m->filename = NULL;
177
178 #if APR_USE_SHMEM_MMAP_ZERO
179 status = apr_file_open(&file, "/dev/zero", APR_READ | APR_WRITE,
180 APR_OS_DEFAULT, pool);
181 if (status != APR_SUCCESS) {
182 return status;
183 }
184 status = apr_os_file_get(&tmpfd, file);
185 if (status != APR_SUCCESS) {
186 return status;
187 }
188
189 new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE,
190 MAP_SHARED, tmpfd, 0);
191 if (new_m->base == (void *)MAP_FAILED) {
192 return errno;
193 }
194
195 status = apr_file_close(file);
196 if (status != APR_SUCCESS) {
197 return status;
198 }
199
200 /* store the real size in the metadata */
201 *(apr_size_t*)(new_m->base) = new_m->realsize;
202 /* metadata isn't usable */
203 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
204
205 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
206 apr_pool_cleanup_null);
207 *m = new_m;
208 return APR_SUCCESS;
209
210 #elif APR_USE_SHMEM_MMAP_ANON
211 new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE,
212 MAP_ANON|MAP_SHARED, -1, 0);
213 if (new_m->base == (void *)MAP_FAILED) {
214 return errno;
215 }
216
217 /* store the real size in the metadata */
218 *(apr_size_t*)(new_m->base) = new_m->realsize;
219 /* metadata isn't usable */
220 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
221
222 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
223 apr_pool_cleanup_null);
224 *m = new_m;
225 return APR_SUCCESS;
226
227 #endif /* APR_USE_SHMEM_MMAP_ZERO */
228 #elif APR_USE_SHMEM_SHMGET_ANON
229 new_m = apr_palloc(pool, sizeof(apr_shm_t));
230 new_m->pool = pool;
231 new_m->reqsize = reqsize;
232 new_m->realsize = reqsize;
233 new_m->filename = NULL;
234
235 if ((new_m->shmid = shmget(IPC_PRIVATE, new_m->realsize,
236 SHM_R | SHM_W | IPC_CREAT)) < 0) {
237 return errno;
238 }
239
240 if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
241 return errno;
242 }
243 new_m->usable = new_m->base;
244
245 if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) {
246 return errno;
247 }
248 apr_uid_current(&uid, &gid, pool);
249 shmbuf.shm_perm.uid = uid;
250 shmbuf.shm_perm.gid = gid;
251 if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) {
252 return errno;
253 }
254
255 /* Remove the segment once use count hits zero.
256 * We will not attach to this segment again, since it is
257 * anonymous memory, so it is ok to mark it for deletion.
258 */
259 if (shmctl(new_m->shmid, IPC_RMID, NULL) == -1) {
260 return errno;
261 }
262
263 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
264 apr_pool_cleanup_null);
265 *m = new_m;
266 return APR_SUCCESS;
267 #else
268 /* It is an error if they want anonymous memory but we don't have it. */
269 return APR_ENOTIMPL; /* requested anonymous but we don't have it */
270 #endif
271 }
272
273 /* Name-based shared memory */
274 else {
275 new_m = apr_palloc(pool, sizeof(apr_shm_t));
276 new_m->pool = pool;
277 new_m->reqsize = reqsize;
278 new_m->filename = apr_pstrdup(pool, filename);
279 #if APR_USE_SHMEM_MMAP_SHM
280 const char *shm_name = make_shm_open_safe_name(filename, pool);
281 #endif
282 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
283 new_m->realsize = reqsize +
284 APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */
285 /* FIXME: Ignore error for now. *
286 * status = apr_file_remove(file, pool);*/
287 status = APR_SUCCESS;
288
289 #if APR_USE_SHMEM_MMAP_TMP
290 /* FIXME: Is APR_OS_DEFAULT sufficient? */
291 status = apr_file_open(&file, filename,
292 APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
293 APR_OS_DEFAULT, pool);
294 if (status != APR_SUCCESS) {
295 return status;
296 }
297
298 status = apr_os_file_get(&tmpfd, file);
299 if (status != APR_SUCCESS) {
300 apr_file_close(file); /* ignore errors, we're failing */
301 apr_file_remove(new_m->filename, new_m->pool);
302 return status;
303 }
304
305 status = apr_file_trunc(file, new_m->realsize);
306 if (status != APR_SUCCESS && status != APR_ESPIPE) {
307 apr_file_close(file); /* ignore errors, we're failing */
308 apr_file_remove(new_m->filename, new_m->pool);
309 return status;
310 }
311
312 new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
313 MAP_SHARED, tmpfd, 0);
314 /* FIXME: check for errors */
315
316 status = apr_file_close(file);
317 if (status != APR_SUCCESS) {
318 return status;
319 }
320 #endif /* APR_USE_SHMEM_MMAP_TMP */
321 #if APR_USE_SHMEM_MMAP_SHM
322 /* FIXME: SysV uses 0600... should we? */
323 tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644);
324 if (tmpfd == -1) {
325 return errno;
326 }
327
328 status = apr_os_file_put(&file, &tmpfd,
329 APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
330 pool);
331 if (status != APR_SUCCESS) {
332 return status;
333 }
334
335 status = apr_file_trunc(file, new_m->realsize);
336 if (status != APR_SUCCESS && status != APR_ESPIPE) {
337 shm_unlink(shm_name); /* we're failing, remove the object */
338 return status;
339 }
340 new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
341 MAP_SHARED, tmpfd, 0);
342
343 /* FIXME: check for errors */
344
345 status = apr_file_close(file);
346 if (status != APR_SUCCESS) {
347 return status;
348 }
349 #endif /* APR_USE_SHMEM_MMAP_SHM */
350
351 /* store the real size in the metadata */
352 *(apr_size_t*)(new_m->base) = new_m->realsize;
353 /* metadata isn't usable */
354 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
355
356 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
357 apr_pool_cleanup_null);
358 *m = new_m;
359 return APR_SUCCESS;
360
361 #elif APR_USE_SHMEM_SHMGET
362 new_m->realsize = reqsize;
363
364 /* FIXME: APR_OS_DEFAULT is too permissive, switch to 600 I think. */
365 status = apr_file_open(&file, filename,
366 APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL,
367 APR_OS_DEFAULT, pool);
368 if (status != APR_SUCCESS) {
369 return status;
370 }
371
372 /* ftok() (on solaris at least) requires that the file actually
373 * exist before calling ftok(). */
374 shmkey = our_ftok(filename);
375 if (shmkey == (key_t)-1) {
376 apr_file_close(file);
377 return errno;
378 }
379
380 if ((new_m->shmid = shmget(shmkey, new_m->realsize,
381 SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) {
382 apr_file_close(file);
383 return errno;
384 }
385
386 if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
387 apr_file_close(file);
388 return errno;
389 }
390 new_m->usable = new_m->base;
391
392 if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) {
393 apr_file_close(file);
394 return errno;
395 }
396 apr_uid_current(&uid, &gid, pool);
397 shmbuf.shm_perm.uid = uid;
398 shmbuf.shm_perm.gid = gid;
399 if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) {
400 apr_file_close(file);
401 return errno;
402 }
403
404 nbytes = sizeof(reqsize);
405 status = apr_file_write(file, (const void *)&reqsize,
406 &nbytes);
407 if (status != APR_SUCCESS) {
408 apr_file_close(file);
409 return status;
410 }
411 status = apr_file_close(file);
412 if (status != APR_SUCCESS) {
413 return status;
414 }
415
416 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
417 apr_pool_cleanup_null);
418 *m = new_m;
419 return APR_SUCCESS;
420
421 #else
422 return APR_ENOTIMPL;
423 #endif
424 }
425 }
426
apr_shm_create_ex(apr_shm_t ** m,apr_size_t reqsize,const char * filename,apr_pool_t * p,apr_int32_t flags)427 APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m,
428 apr_size_t reqsize,
429 const char *filename,
430 apr_pool_t *p,
431 apr_int32_t flags)
432 {
433 return apr_shm_create(m, reqsize, filename, p);
434 }
435
apr_shm_remove(const char * filename,apr_pool_t * pool)436 APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename,
437 apr_pool_t *pool)
438 {
439 #if APR_USE_SHMEM_SHMGET
440 apr_status_t status;
441 apr_file_t *file;
442 key_t shmkey;
443 int shmid;
444 #endif
445
446 #if APR_USE_SHMEM_MMAP_TMP
447 return apr_file_remove(filename, pool);
448 #elif APR_USE_SHMEM_MMAP_SHM
449 const char *shm_name = make_shm_open_safe_name(filename, pool);
450 if (shm_unlink(shm_name) == -1) {
451 return errno;
452 }
453 return APR_SUCCESS;
454 #elif APR_USE_SHMEM_SHMGET
455 /* Presume that the file already exists; just open for writing */
456 status = apr_file_open(&file, filename, APR_FOPEN_WRITE,
457 APR_OS_DEFAULT, pool);
458 if (status) {
459 return status;
460 }
461
462 /* ftok() (on solaris at least) requires that the file actually
463 * exist before calling ftok(). */
464 shmkey = our_ftok(filename);
465 if (shmkey == (key_t)-1) {
466 goto shm_remove_failed;
467 }
468
469 apr_file_close(file);
470
471 if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) {
472 goto shm_remove_failed;
473 }
474
475 /* Indicate that the segment is to be destroyed as soon
476 * as all processes have detached. This also disallows any
477 * new attachments to the segment. */
478 if (shmctl(shmid, IPC_RMID, NULL) == -1) {
479 goto shm_remove_failed;
480 }
481 return apr_file_remove(filename, pool);
482
483 shm_remove_failed:
484 status = errno;
485 /* ensure the file has been removed anyway. */
486 apr_file_remove(filename, pool);
487 return status;
488 #else
489
490 /* No support for anonymous shm */
491 return APR_ENOTIMPL;
492 #endif
493 }
494
apr_shm_destroy(apr_shm_t * m)495 APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m)
496 {
497 return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner);
498 }
499
shm_cleanup_attach(void * m_)500 static apr_status_t shm_cleanup_attach(void *m_)
501 {
502 apr_shm_t *m = (apr_shm_t *)m_;
503
504 if (m->filename == NULL) {
505 /* It doesn't make sense to detach from an anonymous memory segment. */
506 return APR_EINVAL;
507 }
508 else {
509 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
510 if (munmap(m->base, m->realsize) == -1) {
511 return errno;
512 }
513 return APR_SUCCESS;
514 #elif APR_USE_SHMEM_SHMGET
515 if (shmdt(m->base) == -1) {
516 return errno;
517 }
518 return APR_SUCCESS;
519 #else
520 return APR_ENOTIMPL;
521 #endif
522 }
523 }
524
apr_shm_attach(apr_shm_t ** m,const char * filename,apr_pool_t * pool)525 APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m,
526 const char *filename,
527 apr_pool_t *pool)
528 {
529 if (filename == NULL) {
530 /* It doesn't make sense to attach to a segment if you don't know
531 * the filename. */
532 return APR_EINVAL;
533 }
534 else {
535 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
536 apr_shm_t *new_m;
537 apr_status_t status;
538 int tmpfd;
539 apr_file_t *file; /* file where metadata is stored */
540 apr_size_t nbytes;
541
542 new_m = apr_palloc(pool, sizeof(apr_shm_t));
543 new_m->pool = pool;
544 new_m->filename = apr_pstrdup(pool, filename);
545 #if APR_USE_SHMEM_MMAP_SHM
546 const char *shm_name = make_shm_open_safe_name(filename, pool);
547
548 /* FIXME: SysV uses 0600... should we? */
549 tmpfd = shm_open(shm_name, O_RDWR, 0644);
550 if (tmpfd == -1) {
551 return errno;
552 }
553
554 status = apr_os_file_put(&file, &tmpfd,
555 APR_READ | APR_WRITE,
556 pool);
557 if (status != APR_SUCCESS) {
558 return status;
559 }
560
561 #elif APR_USE_SHMEM_MMAP_TMP
562 status = apr_file_open(&file, filename,
563 APR_READ | APR_WRITE,
564 APR_OS_DEFAULT, pool);
565 if (status != APR_SUCCESS) {
566 return status;
567 }
568 status = apr_os_file_get(&tmpfd, file);
569 if (status != APR_SUCCESS) {
570 return status;
571 }
572 #else
573 return APR_ENOTIMPL;
574 #endif
575
576 nbytes = sizeof(new_m->realsize);
577 status = apr_file_read(file, (void *)&(new_m->realsize),
578 &nbytes);
579 if (status != APR_SUCCESS) {
580 return status;
581 }
582
583 status = apr_os_file_get(&tmpfd, file);
584 if (status != APR_SUCCESS) {
585 apr_file_close(file); /* ignore errors, we're failing */
586 apr_file_remove(new_m->filename, new_m->pool);
587 return status;
588 }
589
590 new_m->reqsize = new_m->realsize - sizeof(apr_size_t);
591
592 new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
593 MAP_SHARED, tmpfd, 0);
594 /* FIXME: check for errors */
595
596 status = apr_file_close(file);
597 if (status != APR_SUCCESS) {
598 return status;
599 }
600
601 /* metadata isn't part of the usable segment */
602 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
603
604 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
605 apr_pool_cleanup_null);
606 *m = new_m;
607 return APR_SUCCESS;
608
609 #elif APR_USE_SHMEM_SHMGET
610 apr_shm_t *new_m;
611 apr_status_t status;
612 apr_file_t *file; /* file where metadata is stored */
613 apr_size_t nbytes;
614 key_t shmkey;
615
616 new_m = apr_palloc(pool, sizeof(apr_shm_t));
617
618 status = apr_file_open(&file, filename,
619 APR_FOPEN_READ, APR_OS_DEFAULT, pool);
620 if (status != APR_SUCCESS) {
621 return status;
622 }
623
624 nbytes = sizeof(new_m->reqsize);
625 status = apr_file_read(file, (void *)&(new_m->reqsize),
626 &nbytes);
627 if (status != APR_SUCCESS) {
628 return status;
629 }
630 status = apr_file_close(file);
631 if (status != APR_SUCCESS) {
632 return status;
633 }
634
635 new_m->filename = apr_pstrdup(pool, filename);
636 new_m->pool = pool;
637 shmkey = our_ftok(filename);
638 if (shmkey == (key_t)-1) {
639 return errno;
640 }
641 if ((new_m->shmid = shmget(shmkey, 0, SHM_R | SHM_W)) == -1) {
642 return errno;
643 }
644 if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
645 return errno;
646 }
647 new_m->usable = new_m->base;
648 new_m->realsize = new_m->reqsize;
649
650 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
651 apr_pool_cleanup_null);
652 *m = new_m;
653 return APR_SUCCESS;
654
655 #else
656 return APR_ENOTIMPL;
657 #endif
658 }
659 }
660
apr_shm_attach_ex(apr_shm_t ** m,const char * filename,apr_pool_t * pool,apr_int32_t flags)661 APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m,
662 const char *filename,
663 apr_pool_t *pool,
664 apr_int32_t flags)
665 {
666 return apr_shm_attach(m, filename, pool);
667 }
668
apr_shm_detach(apr_shm_t * m)669 APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m)
670 {
671 apr_status_t rv = shm_cleanup_attach(m);
672 apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach);
673 return rv;
674 }
675
apr_shm_baseaddr_get(const apr_shm_t * m)676 APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m)
677 {
678 return m->usable;
679 }
680
apr_shm_size_get(const apr_shm_t * m)681 APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m)
682 {
683 return m->reqsize;
684 }
685
686 APR_POOL_IMPLEMENT_ACCESSOR(shm)
687
APR_DECLARE(apr_status_t)688 APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm,
689 apr_shm_t *shm)
690 {
691 return APR_ENOTIMPL;
692 }
693
apr_os_shm_put(apr_shm_t ** m,apr_os_shm_t * osshm,apr_pool_t * pool)694 APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m,
695 apr_os_shm_t *osshm,
696 apr_pool_t *pool)
697 {
698 return APR_ENOTIMPL;
699 }
700
701