]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr/shmem/unix/shm.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / apr / shmem / unix / shm.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_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! */
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
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
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
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
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
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
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
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
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
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
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
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
676 APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m)
677 {
678     return m->usable;
679 }
680
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
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
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