1 /* ====================================================================
2  * Copyright (c) 1999-2000 Ralf S. Engelschall. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by
19  *     Ralf S. Engelschall <rse@engelschall.com>."
20  *
21  * 4. Redistributions of any form whatsoever must retain the following
22  *    acknowledgment:
23  *    "This product includes software developed by
24  *     Ralf S. Engelschall <rse@engelschall.com>."
25  *
26  * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
27  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL RALF S. ENGELSCHALL OR
30  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37  * OF THE POSSIBILITY OF SUCH DAMAGE.
38  * ====================================================================
39  */
40 
41 /*
42 **
43 **  mm_core.c -- Low-level Shared Memory API
44 **
45 */
46 
47 #define MM_PRIVATE
48 #include "mm.h"
49 
50 /*
51  * Some global variables
52  */
53 
54 #if defined(MM_SEMT_FCNTL)
55 /* lock/unlock structures for fcntl() */
56 static struct flock mm_core_dolock_rd;
57 static struct flock mm_core_dolock_rw;
58 static struct flock mm_core_dounlock;
59 #endif
60 
61 #if defined(MM_SEMT_IPCSEM)
62 /* lock/unlock structures for semop() */
63 static union  semun  mm_core_semctlarg;
64 static struct sembuf mm_core_dolock[2];
65 static struct sembuf mm_core_dounlock[1];
66 #endif
67 
68 #if defined(MM_SHMT_MMFILE) || defined(MM_SHMT_MMPOSX)
69 static size_t mm_core_mapoffset = 0;           /* we use own file */
70 #elif defined(MM_SHMT_MMZERO)
71 static size_t mm_core_mapoffset = 1024*1024*1; /* we share with other apps */
72 #endif
73 
mm_core_init(void)74 static void mm_core_init(void)
75 {
76     static int initialized = FALSE;
77     if (!initialized) {
78 #if defined(MM_SEMT_FCNTL)
79         mm_core_dolock_rd.l_whence   = SEEK_SET; /* from current point */
80         mm_core_dolock_rd.l_start    = 0;        /* -"- */
81         mm_core_dolock_rd.l_len      = 0;        /* until end of file */
82         mm_core_dolock_rd.l_type     = F_RDLCK;  /* set shard/read lock */
83         mm_core_dolock_rd.l_pid      = 0;        /* pid not actually interesting */
84         mm_core_dolock_rw.l_whence   = SEEK_SET; /* from current point */
85         mm_core_dolock_rw.l_start    = 0;        /* -"- */
86         mm_core_dolock_rw.l_len      = 0;        /* until end of file */
87         mm_core_dolock_rw.l_type     = F_WRLCK;  /* set exclusive/read-write lock */
88         mm_core_dolock_rw.l_pid      = 0;        /* pid not actually interesting */
89         mm_core_dounlock.l_whence    = SEEK_SET; /* from current point */
90         mm_core_dounlock.l_start     = 0;        /* -"- */
91         mm_core_dounlock.l_len       = 0;        /* until end of file */
92         mm_core_dounlock.l_type      = F_UNLCK;  /* unlock */
93         mm_core_dounlock.l_pid       = 0;        /* pid not actually interesting */
94 #endif
95 #if defined(MM_SEMT_IPCSEM)
96         mm_core_dolock[0].sem_num   = 0;
97         mm_core_dolock[0].sem_op    = 0;
98         mm_core_dolock[0].sem_flg   = 0;
99         mm_core_dolock[1].sem_num   = 0;
100         mm_core_dolock[1].sem_op    = 1;
101         mm_core_dolock[1].sem_flg   = SEM_UNDO;
102         mm_core_dounlock[0].sem_num = 0;
103         mm_core_dounlock[0].sem_op  = -1;
104         mm_core_dounlock[0].sem_flg = SEM_UNDO;
105 #endif
106         initialized = TRUE;
107     }
108     return;
109 }
110 
111 #if defined(MM_SEMT_FLOCK)
112 /*
113  * Determine per-process fd for semaphore
114  * (needed only for flock() based semaphore)
115  */
mm_core_getfdsem(mem_core * mc)116 static int mm_core_getfdsem(mem_core *mc)
117 {
118     int fd = -1;
119     pid_t pid;
120     int i;
121 
122     pid = getpid();
123     for (i = 0; i < MM_MAXCHILD &&
124                 mc->mc_fdsem[i].pid != 0 &&
125                 mc->mc_fdsem[i].fd != -1; i++) {
126         if (mc->mc_fdsem[i].pid == pid) {
127             fd = mc->mc_fdsem[i].fd;
128             break;
129         }
130     }
131     if (fd == -1 && i < MM_MAXCHILD) {
132         fd = open(mc->mc_fnsem, O_WRONLY, MM_CORE_FILEMODE);
133         mc->mc_fdsem[i].pid = getpid();
134         mc->mc_fdsem[i].fd  = fd;
135     }
136     return fd;
137 }
138 #endif /* MM_SEMT_FLOCK */
139 
140 /*
141  * Determine memory page size of OS
142  */
143 
mm_core_pagesize(void)144 static size_t mm_core_pagesize(void)
145 {
146     static int pagesize = 0;
147     if (pagesize == 0)
148 #if defined(MM_VMPS_GETPAGESIZE)
149         pagesize = getpagesize();
150 #elif defined(MM_VMPS_SYSCONF)
151         pagesize = sysconf(_SC_PAGESIZE);
152 #elif defined(MM_VMPS_BEOS)
153         pagesize = B_PAGE_SIZE;
154 #else
155         pagesize = MM_CORE_DEFAULT_PAGESIZE;
156 #endif
157     return pagesize;
158 }
159 
160 /*
161  * Align a size to the next page or word boundary
162  */
163 
mm_core_align2page(size_t size)164 size_t mm_core_align2page(size_t size)
165 {
166     int psize = mm_core_pagesize();
167     return ((size)%(psize) > 0 ? ((size)/(psize)+1)*(psize) : (size));
168 }
169 
mm_core_align2word(size_t size)170 size_t mm_core_align2word(size_t size)
171 {
172     return ((1+((size-1) / SIZEOF_mem_word)) * SIZEOF_mem_word);
173 }
174 
mm_core_maxsegsize(void)175 size_t mm_core_maxsegsize(void)
176 {
177     return mm_core_align2page((MM_SHM_MAXSEGSIZE-SIZEOF_mem_core)-mm_core_pagesize());
178 }
179 
180 #if defined(MM_SHMT_IPCSHM) || defined(MM_SEMT_IPCSEM)
181 /*
182  * will return either a normal key value or IPC_PRIVATE
183  * used for attaching to existing shared memorys
184  */
__mm_get_key_value(const char * file,char suffix)185 static key_t __mm_get_key_value ( const char *file, char suffix )
186 {
187     key_t key;
188     key = ftok(file, suffix);
189 
190     if ( key < 0 ) return IPC_PRIVATE;
191     else return key;
192 }
193 #endif
194 
195 /*
196  * Create a shared memory area
197  *
198  * *initialize = 1 - the allocated memory will be initialized on ANY case
199  * *initialize = 0 - the allocated memory will NOT be initialized
200  */
201 
mm_core_create(size_t usersize,const char * file,int * initialize)202 void *mm_core_create(size_t usersize, const char *file, int *initialize)
203 {
204     mem_core *mc;
205     void *area = ((void *)-1);
206     int fdmem = 0;
207     int fdsem = 0;
208 #if defined(MM_SEMT_IPCSEM)
209     int fdsem_rd = 0;
210 #endif
211 #if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
212     char *fnmem;
213 #endif
214 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
215     char *fnsem;
216 #endif
217     size_t size;
218 #if defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
219     int zero = 0;
220 #endif
221 #if defined(MM_SHMT_IPCSHM)
222     struct shmid_ds shmbuf;
223     key_t key = -1;
224 #endif
225 #if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
226     char shmfilename[MM_MAXPATH];
227 #endif
228 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
229     char semfilename[MM_MAXPATH];
230 #endif
231 #if defined(MM_SHMT_BEOS)
232     area_id temparea;
233 #endif
234     char filename[MM_MAXPATH];
235 
236     if ( initialize != NULL )
237         *initialize = 1;
238 
239     if (usersize <= 0 || usersize > mm_core_maxsegsize()) {
240         errno = EINVAL;
241         return NULL;
242     }
243     if (file == NULL) {
244         sprintf(filename, MM_CORE_DEFAULT_FILE, (int)getpid());
245         file = filename;
246     }
247 
248     mm_core_init();
249     size = mm_core_align2page(usersize+SIZEOF_mem_core);
250 
251 #if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
252     sprintf(shmfilename, "%s.mem", file);
253     fnmem = shmfilename;
254 #endif
255 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
256     sprintf(semfilename, "%s.sem", file);
257     fnsem = semfilename;
258 #endif
259 
260 #if defined(MM_SHMT_MMANON)
261     if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
262                              MAP_ANON|MAP_SHARED, -1, 0)) == (void *)MAP_FAILED)
263         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map anonymous area");
264 #endif /* MM_SHMT_MMANON */
265 
266 #if defined(MM_SHMT_BEOS)
267     if ((temparea = create_area("mm", (void*)&area, B_ANY_ADDRESS,
268                                 size, B_LAZY_LOCK, B_READ_AREA|B_WRITE_AREA)) < 0)
269         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to create the memory area");
270 #endif /* MM_SHMT_BEOS */
271 
272 #if defined(MM_SHMT_MMPOSX)
273     shm_unlink(fnmem); /* Ok when it fails */
274     if ((fdmem = shm_open(fnmem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1)
275         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open tempfile");
276     if (ftruncate(fdmem, mm_core_mapoffset+size) == -1)
277         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to truncate tempfile");
278     write(fdmem, &zero, sizeof(zero));
279     if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
280                              MAP_SHARED, fdmem, mm_core_mapoffset)) == (void *)MAP_FAILED)
281         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map tempfile");
282     shm_unlink(fnmem);
283     mm_core_mapoffset += size;
284 #endif /* MM_SHMT_MMPOSX */
285 
286 #if defined(MM_SHMT_MMZERO)
287     if ((fdmem = open("/dev/zero", O_RDWR, MM_CORE_FILEMODE)) == -1)
288         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open /dev/zero");
289     if (lseek(fdmem, mm_core_mapoffset+size, SEEK_SET) == -1)
290         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to seek in /dev/zero");
291     write(fdmem, &zero, sizeof(zero));
292     if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
293                              MAP_SHARED, fdmem, mm_core_mapoffset)) == (void *)MAP_FAILED)
294         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map /dev/zero");
295     mm_core_mapoffset += size;
296 #endif /* MM_SHMT_MMZERO */
297 
298 #if defined(MM_SHMT_MMFILE)
299     unlink(fnmem);
300     if ((fdmem = open(fnmem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1)
301         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open memory file");
302     if (ftruncate(fdmem, mm_core_mapoffset+size) == -1)
303         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to truncate memory file");
304     write(fdmem, &zero, sizeof(zero));
305     if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
306                              MAP_SHARED, fdmem, mm_core_mapoffset)) == (void *)MAP_FAILED)
307         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to memory map memory file");
308     mm_core_mapoffset += size;
309 #endif /* MM_SHMT_MMFILE */
310 
311 #if defined(MM_SHMT_IPCSHM)
312     key = __mm_get_key_value(file, 'm');
313     if ((fdmem = shmget(key, size, (SHM_R|SHM_W|IPC_CREAT|IPC_EXCL))) == -1)
314     {
315         *initialize = 0;
316         if ((fdmem = shmget(key, size, (SHM_R|SHM_W|IPC_CREAT))) == -1)
317             FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to acquire shared memory segment");
318     }
319     if ((area = (void *)shmat(fdmem, NULL, 0)) == ((void *)-1))
320         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to attach shared memory");
321     if (shmctl(fdmem, IPC_STAT, &shmbuf) == -1)
322         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to get status of shared memory");
323     shmbuf.shm_perm.uid = getuid();
324     shmbuf.shm_perm.gid = getgid();
325     if (shmctl(fdmem, IPC_SET, &shmbuf) == -1)
326         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to set status of shared memory");
327     if (key==IPC_PRIVATE && shmctl(fdmem, IPC_RMID, NULL) == -1)
328         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to remove shared memory in advance");
329 #endif /* MM_SHMT_IPCSHM */
330 
331 #if defined(MM_SEMT_FLOCK)
332     unlink(fnsem);
333     if ((fdsem = open(fnsem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1)
334         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open semaphore file");
335 #endif /* MM_SEMT_FLOCK */
336 
337 #if defined(MM_SEMT_FCNTL)
338     unlink(fnsem);
339     if ((fdsem = open(fnsem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1)
340         FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to open semaphore file");
341 #endif /* MM_SEMT_FCNTL */
342 
343 #if defined(MM_SEMT_IPCSEM)
344     key = __mm_get_key_value(file, 'w');
345     fdsem = semget(key, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
346     if (fdsem == -1 && errno == EEXIST)
347         fdsem = semget(key, 1, IPC_EXCL|S_IRUSR|S_IWUSR);
348         if (fdsem == -1)
349             FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to acquire semaphore");
350     mm_core_semctlarg.val = 0;
351     semctl(fdsem, 0, SETVAL, mm_core_semctlarg);
352     key = __mm_get_key_value(file, 'r');
353     fdsem_rd = semget(key, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
354     if (fdsem_rd == -1 && errno == EEXIST)
355         fdsem_rd = semget(key, 1, IPC_EXCL|S_IRUSR|S_IWUSR);
356         if (fdsem_rd == -1)
357             FAIL(MM_ERR_CORE|MM_ERR_SYSTEM, "failed to acquire semaphore");
358     mm_core_semctlarg.val = 0;
359     semctl(fdsem_rd, 0, SETVAL, mm_core_semctlarg);
360 #endif /* MM_SEMT_IPCSEM */
361 
362     /*
363      * Configure the memory core parameters
364      */
365     mc = (mem_core *)area;
366     if ( !*initialize && !getenv("MM_INIT_MEMORY") )
367         goto return_success;
368     mc->mc_size     = size;
369     mc->mc_usize    = usersize;
370     mc->mc_pid      = getpid();
371     mc->mc_fdmem    = fdmem;
372     mc->mc_mapcount = 0;
373 #if defined(MM_SEMT_FLOCK)
374     mc->mc_fdsem[0].pid = getpid();
375     mc->mc_fdsem[0].fd  = fdsem;
376     mc->mc_fdsem[1].pid = 0;
377     mc->mc_fdsem[1].fd  = -1;
378 #else
379     mc->mc_fdsem = fdsem;
380 #endif
381 #if defined(MM_SEMT_BEOS)
382     mc->mc_semid = create_sem(0, "mm_semid");
383     mc->mc_ben = 0;
384 #endif
385 #if defined(MM_SHMT_BEOS)
386     mc->mc_areaid = temparea;
387 #endif
388 #if defined(MM_SEMT_IPCSEM)
389     mc->mc_fdsem_rd = fdsem_rd;
390     mc->mc_readers = 0;
391 #endif
392 #if defined(MM_SHMT_MMFILE)
393     memcpy(mc->mc_fnmem, fnmem, MM_MAXPATH);
394 #endif
395 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
396     memcpy(mc->mc_fnsem, fnsem, MM_MAXPATH);
397 #endif
398 
399     /*
400      * Return successfully established core
401      */
402     return_success:
403     return ((void *)&(mc->mc_base.mw_cp));
404 
405     /*
406      * clean-up sequence (CUS) for error situation
407      */
408     BEGIN_FAILURE
409 #if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
410     if (area != ((void *)-1))
411         munmap((caddr_t)area, size);
412 #endif
413 #if defined(MM_SHMT_IPCSHM)
414     if (area != ((void *)-1))
415         shmdt(area);
416 #endif
417 #if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
418     if (fdmem != -1)
419         close(fdmem);
420 #endif
421 #if defined(MM_SEMT_BEOS)
422     delete_sem(mc->mc_semid);
423 #endif
424 #if defined(MM_SHMT_BEOS)
425     delete_area(mc->mc_areaid);
426 #endif
427 #if defined(MM_SHMT_IPCSHM)
428     if (fdmem != -1)
429         shmctl(fdmem, IPC_RMID, NULL);
430 #endif
431 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
432     if (fdsem != -1)
433         close(fdsem);
434 #endif
435 #if defined(MM_SEMT_IPCSEM)
436     if (fdsem != -1)
437         semctl(fdsem, 0, IPC_RMID, 0);
438     if (fdsem_rd != -1)
439         semctl(fdsem_rd, 0, IPC_RMID, 0);
440 #endif
441 #if defined(MM_SHMT_MMFILE)
442     unlink(fnmem);
443 #endif
444 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
445     unlink(fnsem);
446 #endif
447     return NULL;
448     END_FAILURE
449 }
450 
mm_core_permission(void * core,mode_t mode,uid_t owner,gid_t group)451 int mm_core_permission(void *core, mode_t mode, uid_t owner, gid_t group)
452 {
453     int rc;
454     mem_core *mc;
455 
456     if (core == NULL)
457         return -1;
458     mc = (mem_core *)((char *)core-SIZEOF_mem_core);
459     rc = 0;
460 #if defined(MM_SHMT_MMFILE)
461     if (rc == 0 && chmod(mc->mc_fnmem, mode) < 0)
462         rc = -1;
463     if (rc == 0 && chown(mc->mc_fnmem, owner, group) < 0)
464         rc = -1;
465 #endif
466 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
467     if (rc == 0 && chmod(mc->mc_fnsem, mode) < 0)
468         rc = -1;
469     if (rc == 0 && chown(mc->mc_fnsem, owner, group) < 0)
470         rc = -1;
471 #endif
472     return rc;
473 }
474 
mm_core_delete(void * core,int destroy)475 void mm_core_delete(void *core, int destroy)
476 {
477     mem_core *mc;
478     int fdmem;
479     int fdsem;
480 #if defined(MM_SEMT_IPCSEM)
481     int fdsem_rd;
482 #endif
483     size_t size;
484 #if defined(MM_SHMT_MMFILE)
485     char fnmem[MM_MAXPATH];
486 #endif
487 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
488     char fnsem[MM_MAXPATH];
489 #endif
490 
491     if (core == NULL)
492         return;
493     mc = (mem_core *)((char *)core-SIZEOF_mem_core);
494     size  = mc->mc_size;
495     fdmem = mc->mc_fdmem;
496 #if !defined(MM_SEMT_FLOCK)
497     fdsem = mc->mc_fdsem;
498 #endif
499 #if defined(MM_SEMT_IPCSEM)
500     fdsem_rd = mc->mc_fdsem_rd;
501 #endif
502 #if defined(MM_SEMT_FLOCK)
503     fdsem = mm_core_getfdsem(mc);
504 #endif
505 #if defined(MM_SHMT_MMFILE)
506     memcpy(fnmem, mc->mc_fnmem, MM_MAXPATH);
507 #endif
508 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
509     memcpy(fnsem, mc->mc_fnsem, MM_MAXPATH);
510 #endif
511 
512 #if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
513     munmap((caddr_t)mc, size);
514 #endif
515 #if defined(MM_SHMT_IPCSHM)
516     shmdt((void *)mc);
517     if ( destroy )
518         shmctl(fdmem, IPC_RMID, NULL);
519 #endif
520 #if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
521     close(fdmem);
522 #endif
523 #if defined(MM_SHMT_MMFILE)
524     if ( destroy )
525         unlink(fnmem);
526 #endif
527 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
528     close(fdsem);
529 #endif
530 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
531     unlink(fnsem);
532 #endif
533 #if defined(MM_SEMT_IPCSEM)
534     if ( destroy )
535     {
536         semctl(fdsem, 0, IPC_RMID, 0);
537         semctl(fdsem_rd, 0, IPC_RMID, 0);
538     }
539 #endif
540     return;
541 }
542 
mm_core_detach(const void * core)543 void mm_core_detach (const void *core)
544 {
545     mem_core *mc;
546     int fdmem;
547     int fdsem;
548     size_t size;
549 
550     if (core == NULL)
551         return;
552     mc = (mem_core *)((char *)core-SIZEOF_mem_core);
553     size  = mc->mc_size;
554     fdmem = mc->mc_fdmem;
555 #if !defined(MM_SEMT_FLOCK)
556     fdsem = mc->mc_fdsem;
557 #endif
558 #if defined(MM_SEMT_FLOCK)
559     fdsem = mm_core_getfdsem(mc);
560 #endif
561 
562 #if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
563     munmap((caddr_t)mc, size);
564 #endif
565 #if defined(MM_SHMT_IPCSHM)
566     shmdt((void *)mc);
567 #endif
568 #if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
569     close(fdmem);
570 #endif
571 #if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
572     close(fdsem);
573 #endif
574     return;
575 }
576 
mm_core_size(const void * core)577 size_t mm_core_size(const void *core)
578 {
579     mem_core *mc;
580 
581     if (core == NULL)
582         return 0;
583     mc = (mem_core *)((char *)core-SIZEOF_mem_core);
584     return (mc->mc_usize);
585 }
586 
mm_core_lock(const void * core,mm_lock_mode mode)587 int mm_core_lock(const void *core, mm_lock_mode mode)
588 {
589     mem_core *mc;
590     int rc;
591     int fdsem;
592 
593     if (core == NULL)
594         return FALSE;
595     mc = (mem_core *)((char *)core-SIZEOF_mem_core);
596 #if !defined(MM_SEMT_FLOCK)
597     fdsem = mc->mc_fdsem;
598 #endif
599 #if defined(MM_SEMT_FLOCK)
600     fdsem = mm_core_getfdsem(mc);
601 #endif
602 
603 #if defined(MM_SEMT_FCNTL)
604     if (mode == MM_LOCK_RD)
605         while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dolock_rd)) < 0) && (errno == EINTR)) ;
606     else
607         while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dolock_rw)) < 0) && (errno == EINTR)) ;
608 #endif
609 #if defined(MM_SEMT_FLOCK)
610     if (mode == MM_LOCK_RD)
611         while (((rc = flock(fdsem, LOCK_SH)) < 0) && (errno == EINTR)) ;
612     else
613         while (((rc = flock(fdsem, LOCK_EX)) < 0) && (errno == EINTR)) ;
614 #endif
615 #if defined(MM_SEMT_IPCSEM)
616     if (mode == MM_LOCK_RD) {
617         while (((rc = semop(mc->mc_fdsem_rd, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ;
618         mc->mc_readers++;
619         if (mc->mc_readers == 1)
620             while (((rc = semop(fdsem, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ;
621         while (((rc = semop(mc->mc_fdsem_rd, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ;
622     }
623     else {
624         while (((rc = semop(fdsem, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ;
625     }
626     mc->mc_lockmode = mode;
627 #endif
628 #if defined(MM_SEMT_BEOS)
629     rc = 0;
630     if (atomic_add(&mc->mc_ben, 1) > 0) {
631         /* someone already in lock... acquire sem and wait */
632         if (acquire_sem(mc->mc_semid) != B_NO_ERROR) {
633             atomic_add(&mc->mc_ben, -1);
634             rc = -1;
635         }
636     }
637 #endif
638 
639     if (rc < 0) {
640         ERR(MM_ERR_CORE|MM_ERR_SYSTEM, "Failed to lock");
641         rc = FALSE;
642     }
643     else
644         rc = TRUE;
645     return rc;
646 }
647 
mm_core_unlock(const void * core)648 int mm_core_unlock(const void *core)
649 {
650     mem_core *mc;
651     int rc;
652     int fdsem;
653 
654     if (core == NULL)
655         return FALSE;
656     mc = (mem_core *)((char *)core-SIZEOF_mem_core);
657 #if !defined(MM_SEMT_FLOCK)
658     fdsem = mc->mc_fdsem;
659 #endif
660 #if defined(MM_SEMT_FLOCK)
661     fdsem = mm_core_getfdsem(mc);
662 #endif
663 
664 #if defined(MM_SEMT_FCNTL)
665     while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dounlock)) < 0) && (errno == EINTR)) ;
666 #endif
667 #if defined(MM_SEMT_FLOCK)
668     while (((rc = flock(fdsem, LOCK_UN)) < 0) && (errno == EINTR)) ;
669 #endif
670 #if defined(MM_SEMT_IPCSEM)
671     if (mc->mc_lockmode == MM_LOCK_RD) {
672         while (((rc = semop(mc->mc_fdsem_rd, mm_core_dolock, 2)) < 0) && (errno == EINTR)) ;
673         mc->mc_readers--;
674         if (mc->mc_readers == 0)
675             while (((rc = semop(fdsem, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ;
676         while (((rc = semop(mc->mc_fdsem_rd, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ;
677     }
678     else {
679         while (((rc = semop(fdsem, mm_core_dounlock, 1)) < 0) && (errno == EINTR)) ;
680     }
681 #endif
682 #if defined(MM_SEMT_BEOS)
683     rc = 0;
684     if (atomic_add(&mc->mc_ben, -1) > 1)
685         release_sem(mc->mc_semid);
686 #endif
687 
688     if (rc < 0) {
689         ERR(MM_ERR_CORE|MM_ERR_SYSTEM, "Failed to unlock");
690         rc = FALSE;
691     }
692     else
693         rc = TRUE;
694     return rc;
695 }
696 
697 /*
698     returns the ID (file descriptior, ipc id ... etc) of the shared memory segment
699 */
mm_core_shmid(const void * core)700 int mm_core_shmid (const void *core)
701 {
702     mem_core *mc = (mem_core *)((char *)core-SIZEOF_mem_core);
703 
704     return mc->mc_fdmem;
705 }
706 
707 /*
708     returns the amount of maps located in this shared memory segment
709 */
mm_core_mapcount(const void * core)710 int mm_core_mapcount(const void *core)
711 {
712     mem_core *mc = (mem_core *)((char *)core-SIZEOF_mem_core);
713 
714     return mc->mc_mapcount;
715 }
716 
717 /*
718     increases the map count on this shared memory
719     segment and returns the new count
720 */
mm_core_addmap(const void * core)721 int mm_core_addmap(const void *core)
722 {
723     mem_core *mc = (mem_core *)((char *)core-SIZEOF_mem_core);
724 
725     return ++mc->mc_mapcount;
726 }
727 
728 /*
729     decreases the map count on this shared
730     memory segment and returns the new count
731 */
mm_core_remmap(const void * core)732 int mm_core_remmap(const void *core)
733 {
734     mem_core *mc = (mem_core *)((char *)core-SIZEOF_mem_core);
735 
736     return --mc->mc_mapcount;
737 }
738 
mm_core_stat(const void * core,int * uid,int * gid,int * mode)739 int mm_core_stat(const void *core, int *uid, int *gid, int *mode)
740 {
741     struct shmid_ds buf;
742     mem_core *mc = (mem_core *)((char *)core-SIZEOF_mem_core);
743 
744     if ( shmctl(mc->mc_fdmem, IPC_STAT, &buf) != 0 )
745         return -1;
746 
747     if(uid)
748         *uid = buf.shm_perm.uid;
749 
750     if(gid)
751         *gid = buf.shm_perm.gid;
752 
753     if(mode)
754         *mode = buf.shm_perm.mode;
755 
756     return 0;
757 }
758 
759 /*EOF*/
760