root/eaccelerator/tags/0.9.5-rc1/mm.c

Revision 230, 30.0 kB (checked in by bart, 2 years ago)

Removed the code from mm.c that tried to allocate more then one segment

because it didn't work, this part needs a redesign of the mm code to
allow this. It should allocate one to init the shared memory and add
the other to the free list.

  • Property svn:eol-style set to native
  • Property svn:keywords set to svn:eol-style
Line 
1 /*
2    +----------------------------------------------------------------------+
3    | eAccelerator project                                                 |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 2004 - 2006 eAccelerator                               |
6    | http://eaccelerator.net                                              |
7    +----------------------------------------------------------------------+
8    | This program is free software; you can redistribute it and/or        |
9    | modify it under the terms of the GNU General Public License          |
10    | as published by the Free Software Foundation; either version 2       |
11    | of the License, or (at your option) any later version.               |
12    |                                                                      |
13    | This program is distributed in the hope that it will be useful,      |
14    | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
15    | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
16    | GNU General Public License for more details.                         |
17    |                                                                      |
18    | You should have received a copy of the GNU General Public License    |
19    | along with this program; if not, write to the Free Software          |
20    | Foundation, Inc., 59 Temple Place - Suite 330, Boston,               |
21    | MA  02111-1307, USA.                                                 |
22    |                                                                      |
23    | A copy is availble at http://www.gnu.org/copyleft/gpl.txt            |
24    +----------------------------------------------------------------------+
25    $Id: mm.c 176 2006-03-05 12:18:54Z bart $
26 */
27
28 /* libmm replacement */
29
30 #if !defined(MM_TEST_SHM) && !defined(MM_TEST_SEM)
31 # ifdef HAVE_CONFIG_H
32 #  include "config.h"
33 # endif
34 # include "php.h"
35 #endif
36
37 #ifdef WIN32
38 #  if 1
39 #    define MM_SHM_WIN32
40 #    define MM_SEM_WIN32
41 #  else
42 #    define MM_SHM_MALLOC
43 #    define MM_SEM_NONE
44 #  endif
45 #endif
46
47 #if !defined(MM_TEST_SEM) && !defined(MM_TEST_SHM)
48 # include "debug.h"
49 #endif
50
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <errno.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <fcntl.h>
58
59 #ifdef WIN32
60 #  include <limits.h>
61 #else
62 #  ifdef HAVE_UNISTD_H
63 #    include <unistd.h>
64 #  endif
65 #  ifdef HAVE_SYS_PARAM_H
66 #    include <sys/param.h>
67 #  endif
68 #  ifdef HAVE_LIMITS_H
69 #    include <limits.h>
70 #  endif
71 #endif
72
73 #if defined(MM_SHM_MMAP_FILE) || defined(MM_SHM_MMAP_ZERO) || defined(MM_SHM_MMAP_ANON) || defined(MM_SHM_MMAP_POSIX) || defined(HAVE_MPROTECT)
74 #  include <sys/mman.h>
75 #endif
76 #if defined(MM_SHM_IPC) || defined(MM_SEM_IPC)
77 #  include <sys/ipc.h>
78 #endif
79 #ifdef MM_SHM_IPC
80 #  include <sys/shm.h>
81 #endif
82 #if defined(MM_SHM_WIN32) || defined(MM_SEM_WIN32)
83 #  include <windows.h>
84 #endif
85 #ifdef MM_SHM_MALLOC
86 #  include <malloc.h>
87 #endif
88 #ifdef MM_SEM_IPC
89 #  include <sys/sem.h>
90 #endif
91 #ifdef MM_SEM_FLOCK
92 #  include <sys/file.h>
93 #endif
94 #ifdef MM_SEM_POSIX
95 #  include <semaphore.h>
96 #endif
97 #ifdef MM_SEM_PTHREAD
98 #  include <pthread.h>
99 #endif
100
101 struct mm_mutex;
102
103 typedef struct mm_free_bucket {
104   size_t                 size;
105   struct mm_free_bucket* next;
106 } mm_free_bucket;
107
108 typedef struct mm_core {
109   size_t           size;
110   void*            start;
111   size_t           available;
112   void*            attach_addr;
113   struct mm_mutex* lock;
114   mm_free_bucket*  free_list;
115 } mm_core;
116
117 typedef union mm_mem_head {
118   size_t size;
119   double a1;
120   int (*a2)(int);
121   void *a3;
122 } mm_mem_head;
123
124 #define MM_SIZE(sz)       (sizeof(mm_mem_head)+(sz))
125 #define PTR_TO_HEAD(p)    (((mm_mem_head *)(p)) - 1)
126 #define HEAD_TO_PTR(p)    ((void *)(((mm_mem_head *)(p)) + 1))
127
128 #define MM mm_core
129 #define MM_PRIVATE
130 #include "mm.h"
131
132 typedef union mm_word {
133   size_t size;
134   void*  ptr;
135   double d;
136   int (*func)(int);
137 } mm_word;
138
139 #if (defined (__GNUC__) && __GNUC__ >= 2)
140 #define MM_PLATFORM_ALIGNMENT (__alignof__ (mm_word))
141 #else
142 #define MM_PLATFORM_ALIGNMENT (sizeof(mm_word))
143 #endif
144
145 #define MM_ALIGN(n) (void*)((((size_t)(n)-1) & ~(MM_PLATFORM_ALIGNMENT-1)) + MM_PLATFORM_ALIGNMENT)
146 /*#define MM_ALIGN(n) (void*)((1+(((size_t)(n)-1) / sizeof(mm_word))) * sizeof(mm_word))*/
147
148 #ifndef MAXPATHLEN
149 #  ifdef PATH_MAX
150 #    define MAXPATHLEN PATH_MAX
151 #  elif defined(_POSIX_PATH_MAX)
152 #    define MAXPATHLEN _POSIX_PATH_MAX
153 #  else
154 #    define MAXPATHLEN 256
155 #  endif
156 #endif
157
158 #undef MM_SHM_CAN_ATTACH
159
160 #if defined(MM_SEM_POSIX) || defined(MM_SEM_FCNTL) || defined(MM_SEM_FLOCK) || defined(MM_SEM_WIN32) || defined(MM_SHM_MMAP_POSIX) || defined(MM_SHM_MMAP_FILE)
161 static int strxcat(char* dst, const char* src, int size) {
162   int dst_len = strlen(dst);
163   int src_len = strlen(src);
164   if (dst_len + src_len < size) {
165     memcpy(dst+dst_len, src, src_len+1);
166     return 1;
167   } else {
168     memcpy(dst+dst_len, src, (size-1)-dst_len);
169     dst[size-1] = '\000';
170     return 0;
171   }
172 }
173 #endif
174
175 #if defined(MM_SEM_SPINLOCK)
176
177 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
178 #  include "x86_spinlocks.h"
179 #else
180 #  error "spinlocks are not implemented for your system"
181 #endif
182
183 /*********************************/
184 /* Semaphores                    */
185 /********************************/
186
187 /* ######################################################################### */
188
189 #define MM_SEM_TYPE "spinlock"
190 #define MM_SEM_CAN_ATTACH
191
192 typedef struct mm_mutex {
193   spinlock_t spinlock;
194 } mm_mutex;
195
196 /* not used
197 static int mm_attach_lock(const char* key, mm_mutex* lock) {
198   return 1;
199 }
200 */
201
202 static int mm_init_lock(const char* key, mm_mutex* lock) {
203   spinlock_init(&lock->spinlock);
204   return 1;
205 }
206
207 static int mm_do_lock(mm_mutex* lock, int kind) {
208   spinlock_lock(&lock->spinlock);
209   return 1;
210 }
211
212 static int mm_do_unlock(mm_mutex* lock) {
213   spinlock_unlock(&lock->spinlock);
214   return 1;
215 }
216
217 static void mm_destroy_lock(mm_mutex* lock) {
218 }
219
220 /* ######################################################################### */
221
222 #elif defined(MM_SEM_PTHREAD)
223
224 #define MM_SEM_TYPE "pthread"
225
226 typedef struct mm_mutex {
227   pthread_mutex_t mutex;
228 } mm_mutex;
229
230 static int mm_init_lock(const char* key, mm_mutex* lock) {
231   pthread_mutexattr_t mattr;
232
233   if (pthread_mutexattr_init(&mattr) != 0) {
234     return 0;
235   }
236   if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED) != 0) {
237     return 0;
238   }
239   if (pthread_mutex_init(&lock->mutex, &mattr) != 0) {
240     return 0;
241   }
242   pthread_mutexattr_destroy(&mattr);
243   return 1;
244 }
245
246 static int mm_do_lock(mm_mutex* lock, int kind) {
247   if (pthread_mutex_lock(&lock->mutex) != 0) {
248     return 0;
249   }
250   return 1;
251 }
252
253 static int mm_do_unlock(mm_mutex* lock) {
254   if (pthread_mutex_unlock(&lock->mutex) != 0) {
255     return 0;
256   }
257   return 1;
258 }
259
260 static void mm_destroy_lock(mm_mutex* lock) {
261   pthread_mutex_destroy(&lock->mutex);
262 }
263
264 /* ######################################################################### */
265
266 #elif defined(MM_SEM_POSIX)
267
268 /* not tested */
269
270 #define MM_SEM_TYPE "posix"
271
272 typedef struct mm_mutex {
273   sem_t* sem;
274 } mm_mutex;
275
276 static int mm_init_lock(const char* key, mm_mutex* lock) {
277 #ifdef SEM_NAME_LEN
278   char s[SEM_NAME_LEN];
279
280   strncpy(s,key,SEM_NAME_LEN-1);
281   strxcat(s,".sem.XXXXXX",SEM_NAME_LEN);
282 #else
283   char s[MAXPATHLEN];
284
285   strncpy(s,key,MAXPATHLEN-1);
286   strxcat(s,".sem.XXXXXX",MAXPATHLEN);
287 #endif
288   if (mktemp(s) == NULL) return 0;
289   if ((lock->sem = sem_open(s, O_CREAT, S_IRUSR | S_IWUSR, 1)) == (sem_t*)SEM_FAILED) {
290     return 0;
291   }
292   sem_unlink(s);
293   return 1;
294 }
295
296 static int mm_do_lock(mm_mutex* lock, int kind) {
297   return (sem_wait(lock->sem) == 0);
298 }
299
300 static int mm_do_unlock(mm_mutex* lock) {
301   return (sem_post(lock->sem) == 0);
302 }
303
304 static void mm_destroy_lock(mm_mutex* lock) {
305   sem_close(lock->sem);
306 }
307
308 /* ######################################################################### */
309
310 #elif defined(MM_SEM_IPC)
311
312 #define MM_SEM_TYPE "sysvipc"
313
314 #ifndef HAVE_UNION_SEMUN
315 union semun {
316     int val;
317     struct semid_ds *buf;
318     unsigned short *array;
319     struct seminfo *__buf;
320 };
321 #endif
322
323 typedef struct mm_mutex {
324   int semid;
325 } mm_mutex;
326
327 static int mm_init_lock(const char* key, mm_mutex* lock) {
328   int rc;
329   union semun arg;
330   struct semid_ds buf;
331
332   if ((lock->semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0) {
333     return 0;
334   }
335
336   arg.buf = &buf;
337   do {
338     rc = semctl(lock->semid, 0, IPC_STAT, arg);
339   } while (rc < 0 && errno == EINTR);
340
341   buf.sem_perm.uid = EA_USERID;
342
343   do {
344     rc = semctl(lock->semid, 0, IPC_SET, arg);
345   } while (rc < 0 && errno == EINTR);
346  
347   arg.val = 1;
348   do {
349     rc = semctl(lock->semid, 0, SETVAL, arg);
350   } while (rc < 0 && errno == EINTR);
351   if (rc < 0) {
352     do {
353       semctl(lock->semid, 0, IPC_RMID, 0);
354     } while (rc < 0 && errno == EINTR);
355     return 0;
356   }
357   return 1;
358 }
359
360 static int mm_do_lock(mm_mutex* lock, int kind) {
361   int rc;
362   struct sembuf op;
363
364   op.sem_num = 0;
365   op.sem_op  = -1;
366   op.sem_flg = SEM_UNDO;
367   do {
368     rc = semop(lock->semid, &op, 1);
369   } while (rc < 0 && errno == EINTR);
370   return (rc == 0);
371 }
372
373 static int mm_do_unlock(mm_mutex* lock) {
374   int rc;
375   struct sembuf op;
376
377   op.sem_num = 0;
378   op.sem_op  = 1;
379   op.sem_flg = SEM_UNDO;
380   do {
381     rc = semop(lock->semid, &op, 1);
382   } while (rc < 0 && errno == EINTR);
383   return (rc == 0);
384 }
385
386 static void mm_destroy_lock(mm_mutex* lock) {
387   int rc;
388   do {
389     rc = semctl(lock->semid, 0, IPC_RMID, 0);
390   } while (rc < 0 && errno == EINTR);
391 }
392
393 #elif defined(MM_SEM_FCNTL)
394
395 #define MM_SEM_TYPE "fcntl"
396
397 typedef struct mm_mutex {
398   int fd;
399 } mm_mutex;
400
401 static int mm_init_lock(const char* key, mm_mutex* lock) {
402   char s[MAXPATHLEN];
403
404   strncpy(s,key,MAXPATHLEN-1);
405   strxcat(s,".sem.XXXXXX",MAXPATHLEN);
406   lock->fd =mkstemp(s);
407   if (lock->fd != -1) {
408     unlink(s);
409   }
410   return (lock->fd != -1);
411 }
412
413 static int mm_do_lock(mm_mutex* lock, int kind) {
414   int rc;
415   struct flock l;
416   l.l_whence   = SEEK_SET;
417   l.l_start    = 0;
418   l.l_len      = 0;
419   l.l_pid      = 0;
420   if (kind == MM_LOCK_RD) {
421     l.l_type     = F_RDLCK;
422   } else {
423     l.l_type     = F_WRLCK;
424   }
425   do {
426     rc = fcntl(lock->fd, F_SETLKW, &l);
427   } while (rc < 0 && errno == EINTR);
428   return (rc == 0);
429 }
430
431 static int mm_do_unlock(mm_mutex* lock) {
432   int rc;
433   struct flock l;
434   l.l_whence   = SEEK_SET;
435   l.l_start    = 0;
436   l.l_len      = 0;
437   l.l_pid      = 0;
438   l.l_type     = F_UNLCK;
439   do {
440     rc = fcntl(lock->fd, F_SETLKW, &l);
441   } while (rc < 0 && errno == EINTR);
442   return (rc == 0);
443 }
444
445 static void mm_destroy_lock(mm_mutex* lock) {
446   close(lock->fd);
447 }
448
449 /* ######################################################################### */
450
451 #elif defined(MM_SEM_FLOCK)
452
453 /* this method is not thread safe */
454
455 #define MM_SEM_TYPE "flock"
456
457 static int   mm_flock_fd  = -1;
458 static pid_t mm_flock_pid = -1;
459
460 typedef struct mm_mutex {
461   char filename[MAXPATHLEN];
462 } mm_mutex;
463
464 static int mm_init_lock(const char* key, mm_mutex* lock) {
465   strncpy(lock->filename,key,MAXPATHLEN-1);
466   strxcat(lock->filename,".sem.XXXXXX",MAXPATHLEN);
467   mm_flock_fd =mkstemp(lock->filename);
468   if (mm_flock_fd != -1) {
469 #if defined(F_SETFD) && defined(FD_CLOEXEC)
470     fcntl(mm_flock_fd, F_SETFD, FD_CLOEXEC);
471 #endif
472     mm_flock_pid = getpid();
473     return 1;
474   }
475   return 0;
476 }
477
478 static int mm_do_lock(mm_mutex* lock, int kind) {
479   pid_t pid = getpid();
480   int rc;
481   if (kind == MM_LOCK_RD) {
482     kind = LOCK_SH;
483   } else {
484     kind = LOCK_EX;
485   }
486
487   if (mm_flock_fd == -1 || mm_flock_pid != pid) {
488     mm_flock_fd = open(lock->filename, O_RDWR, S_IRUSR | S_IWUSR);
489     if (mm_flock_fd == -1) {
490       return 0;
491     }
492 #if defined(F_SETFD) && defined(FD_CLOEXEC)
493     fcntl(mm_flock_fd, F_SETFD, FD_CLOEXEC);
494 #endif
495     mm_flock_pid = pid;
496   }
497   do {
498     rc = flock(mm_flock_fd, kind);
499   } while (rc < 0 && errno == EINTR);
500   return (rc == 0);
501 }
502
503 static int mm_do_unlock(mm_mutex* lock) {
504   int rc;
505   if (mm_flock_fd == -1) {
506     mm_flock_fd = open(lock->filename, O_RDWR, S_IRUSR | S_IWUSR);
507     if (mm_flock_fd == -1) {
508       return 0;
509     }
510   }
511   do {
512     rc = flock(mm_flock_fd, LOCK_UN);
513   } while (rc < 0 && errno == EINTR);
514   return (rc == 0);
515 }
516
517 static void mm_destroy_lock(mm_mutex* lock) {
518   close(mm_flock_fd);
519   unlink(lock->filename);
520 }
521
522 /* ######################################################################### */
523
524 #elif defined(MM_SEM_BEOS)
525
526 #define MM_SEM_TYPE "beos"
527 #error "Semophore type (MM_SEM_BEOS) is not implemented"
528
529 #elif defined(MM_SEM_OS2)
530
531 #define MM_SEM_TYPE "os2"
532 #error "Semophore type (MM_SEM_OS2) is not implemented"
533
534 #elif defined(MM_SEM_WIN32)
535
536 #define MM_SEM_TYPE "win32"
537 #define MM_SEM_CAN_ATTACH
538
539 typedef struct mm_mutex {
540   HANDLE hMutex;
541 } mm_mutex;
542
543 static mm_mutex g_lock;
544
545 static int mm_attach_lock(const char* key, mm_mutex* lock) {
546   char* ch;
547   char name[256];
548   HANDLE hMutex;
549
550   strncpy(name, key, 255);
551   strxcat(name, ".sem", 255);
552   for (ch = name; *ch; ++ch) {
553     if (*ch == ':' || *ch == '/' || *ch == '\\') {
554       *ch = '_';
555     }
556   }
557   g_lock.hMutex = hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, name);
558   if (!g_lock.hMutex) {
559     return 0;
560   }
561   return 1;
562 }
563
564 static int mm_init_lock(const char* key, mm_mutex* lock) {
565   char* ch;
566   char name[256];
567   strncpy(name, key, 255);
568   strxcat(name, ".sem", 255);
569   for (ch = name; *ch; ++ch) {
570     if (*ch == ':' || *ch == '/' || *ch == '\\') {
571       *ch = '_';
572     }
573   }
574   g_lock.hMutex = CreateMutex(NULL, FALSE, name);
575   if (!g_lock.hMutex) {
576     return 0;
577   }
578   return 1;
579 }
580
581 static void mm_destroy_lock(mm_mutex* lock) {
582   CloseHandle(g_lock.hMutex);
583 }
584
585 static int mm_do_lock(mm_mutex* lock, int kind) {
586   DWORD rv;
587
588   rv = WaitForSingleObject(g_lock.hMutex, INFINITE);
589
590   if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) {
591     return 1;
592   }
593   return 0;
594 }
595
596 static int mm_do_unlock(mm_mutex* lock) {
597   if (ReleaseMutex(g_lock.hMutex) == 0) {
598       // Releasing the mutex doesn't seem to work under windows. It gives some
599       // extremely obscure error code. Locking seems to work though. Because this
600       // flood the error log of the win32 users we are not going to return 0 here
601       // until a windows dev has found the problem.
602   }
603   return 1;
604 }
605
606 /* ######################################################################### */
607
608 #elif defined(MM_SEM_NONE)
609
610 #define MM_SEM_TYPE "none"
611 #define MM_SEM_CAN_ATTACH
612
613
614 typedef struct mm_mutex {
615   int semid;
616 } mm_mutex;
617
618 static int mm_attach_lock(const char* key, mm_mutex* lock) {
619   return 1;
620 }
621
622 static int mm_init_lock(const char* key, mm_mutex* lock) {
623   return 1;
624 }
625
626 static void mm_destroy_lock(mm_mutex* lock) {
627 }
628
629 static int mm_do_lock(mm_mutex* lock, int kind) {
630   return 1;
631 }
632
633 static int mm_do_unlock(mm_mutex* lock) {
634   return 1;
635 }
636
637 #else
638 #  error "Semaohore type is not selected. Define one of the following: MM_SEM_SPINLOCK, MM_SEM_PTHREAD, MM_SEM_POSIX, MM_SEM_IPC, MM_SEM_FCNTL, MM_SEM_FLOCK, MM_SEM_BEOS, MM_SEM_OS2, MM_SEM_WIN32"
639 #endif
640
641 int mm_lock(MM* mm, int kind) {
642   if (mm_do_lock(mm->lock, kind)) {
643     return 1;
644   } else {
645 #if !defined(MM_TEST_SEM) && !defined(MM_TEST_SHM)
646     ea_debug_error("eAccelerator: Could not lock!\n");
647 #endif
648     return 0;
649   }
650 }
651
652 int mm_unlock(MM* mm) {
653   if (mm_do_unlock(mm->lock)) {
654     return 1;
655   } else {
656 #if !defined(MM_TEST_SEM) && !defined(MM_TEST_SHM)
657     ea_debug_error("eAccelerator: Could not release lock!\n");
658 #endif
659     return 0;
660   }
661 }
662
663 /* Shared Memory Implementations */
664
665 /* ######################################################################### */
666
667 #if defined(MM_SHM_IPC)
668
669 #define MM_SHM_TYPE "sysvipc"
670
671 #ifndef SHM_R
672 # define SHM_R 0444 /* read permission */
673 #endif
674 #ifndef SHM_W
675 # define SHM_W 0222 /* write permission */
676 #endif
677
678 static MM* mm_create_shm(const char* key, size_t size) {
679   int fd;
680   void** segment = NULL;
681   if ((fd = shmget(IPC_PRIVATE, size, (IPC_CREAT | SHM_R | SHM_W))) >= 0) {
682     MM* p;
683     if ((p = (MM*)shmat(fd, NULL, 0)) != ((void *)-1)) {
684       struct shmid_ds shmbuf;
685       if (shmctl(fd, IPC_STAT, &shmbuf) == 0) {
686         shmbuf.shm_perm.uid = getuid();
687         shmbuf.shm_perm.gid = getgid();
688         if (shmctl(fd, IPC_SET, &shmbuf) == 0) {
689           shmctl(fd, IPC_RMID, NULL);
690           p->size = size;
691           segment = (void**)((char*)p+sizeof(MM));
692           *segment = (void*)-1;
693           segment++;
694           p->start = segment;
695           return p;
696         }
697       }
698       shmdt(p);
699     }
700     shmctl(fd, IPC_RMID, NULL);
701   } else {
702     size_t seg_size = 1024*1024;
703
704     while (seg_size <= size/2) {
705       seg_size *= 2;
706     }
707     while ((fd = shmget(IPC_PRIVATE, seg_size, (IPC_CREAT | SHM_R | SHM_W))) == -1) {
708       if (seg_size <= 1024*1024) {
709         ea_debug_error("eAccelerator: shmmax should be at least 2MB");
710         return (MM*)-1;
711       }
712       seg_size /= 2;
713     }
714     ea_debug_error("eAccelerator: Could not allocate %d bytes, the maximum size the kernel allows is %d bytes. "
715             "Lower the amount of memory request or increase the limit in /proc/sys/kernel/shmmax.\n", size, seg_size);
716
717     /* bart: Removed the code that tried to allocate more then one segment
718      * because it didn't work, this part needs a redesign of the mm code to
719      * allow this. It should allocate one to init the shared memory and add
720      * the other to the free list.
721      */
722   }
723   return (MM*)-1;
724 }
725
726 static void mm_destroy_shm(MM* mm) {
727   void** segment = (void**)((char*)mm+sizeof(MM));
728   while (*segment != (void*)-1) {
729     shmdt(*segment);
730     ++segment;
731   }
732   shmdt(mm);
733 }
734
735 /* ######################################################################### */
736
737 #elif defined(MM_SHM_MMAP_ANON)
738
739 #define MM_SHM_TYPE "mmap_anon"
740
741 #ifndef MAP_ANON
742 #  ifdef MAP_ANONYMOUS
743 #    define MAP_ANON MAP_ANONYMOUS
744 #  endif
745 #endif
746
747 static MM* mm_create_shm(const char* key, size_t size) {
748   MM* p;
749   p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
750   if (p != (MM*)-1) {
751     p->size = size;
752     p->start = (char*)p+sizeof(MM);
753   }
754   return p;
755 }
756
757 static void mm_destroy_shm(MM* mm) {
758   munmap(mm,mm->size);
759 }
760
761 /* ######################################################################### */
762
763 #elif defined(MM_SHM_MMAP_ZERO)
764
765 #define MM_SHM_TYPE "mmap_zero"
766
767 static MM* mm_create_shm(const char* key, size_t size) {
768   MM* p;
769   int fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
770   if (fd == -1) {
771     return (MM*)-1;
772   }
773   p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
774   close(fd);
775   if (p != (MM*)-1) {
776     p->size = size;
777     p->start = (char*)p+sizeof(MM);
778   }
779   return p;
780 }
781
782 static void mm_destroy_shm(MM* mm) {
783   munmap(mm,mm->size);
784 }
785
786 /* ######################################################################### */
787
788 #elif defined(MM_SHM_MMAP_POSIX)
789
790 #define MM_SHM_TYPE "mmap_posix"
791
792 /* Not Tested */
793
794 static MM* mm_create_shm(const char* key, size_t size) {
795   MM* p;
796   int fd;
797   char s[MAXPATHLEN];
798
799   strncpy(s,key,MAXPATHLEN-1);
800   strxcat(s,".shm.XXXXXX",MAXPATHLEN);
801   if (mktemp(s) == NULL) {
802     return (MM*)-1;
803   }
804   if ((fd = shm_open(s, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) == -1) {
805     return (MM*)-1;
806   }
807   if (ftruncate(fd, size) < 0) {
808     close(fd);
809     shm_unlink(s);
810     return (MM*)-1;
811   }
812   p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
813   shm_unlink(s);
814   close(fd);
815   if (p != (MM*)-1) {
816     p->size = size;
817     p->start = (char*)p+sizeof(MM);
818   }
819   return p;
820 }
821
822 static void mm_destroy_shm(MM* mm) {
823   munmap(mm,mm->size);
824 }
825
826 /* ######################################################################### */
827
828 #elif defined(MM_SHM_MMAP_FILE)
829
830 #define MM_SHM_TYPE "mmap_file"
831
832 static MM* mm_create_shm(const char* key, size_t size) {
833   MM* p;
834   int fd;
835   char s[MAXPATHLEN];
836
837   strncpy(s,key,MAXPATHLEN-1);
838   strxcat(s,".shm.XXXXXX",MAXPATHLEN);
839   fd = mkstemp(s);
840   if (fd < 0) {
841     return (MM*)-1;
842   }
843   if (ftruncate(fd, size) < 0) {
844     return (MM*)-1;
845   }
846   p = (MM*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
847   close(fd);
848   unlink(s);
849   if (p != (MM*)-1) {
850     p->size = size;
851     p->start = (char*)p+sizeof(MM);
852   }
853   return p;
854 }
855
856 static void mm_destroy_shm(MM* mm) {
857   munmap(mm,mm->size);
858 }
859
860 /* ######################################################################### */
861
862 #elif defined(MM_SHM_BEOS)
863
864 #define MM_SHM_TYPE "beos"
865 #error "Shared memeory type (MM_SHM_BEOS) is not implemented"
866
867 /* ######################################################################### */
868
869 #elif defined(MM_SHM_OS2)
870
871 #define MM_SHM_TYPE "os2"
872 #error "Shared memeory type (MM_SHM_OS2) is not implemented"
873
874 /* ######################################################################### */
875
876 #elif defined(MM_SHM_WIN32)
877
878 #define MM_SHM_TYPE "win32"
879 #define MM_SHM_CAN_ATTACH
880
881 static MM* mm_attach_shm(const char* key, size_t size) {
882   HANDLE  shm_handle;
883   MM*     mm;
884   MM*     addr;
885   MM**    addr_ptr;
886   char    s[MAXPATHLEN];
887   char*   ch;
888
889
890   strcpy(s,key);
891   for (ch = s; *ch; ++ch) {
892     if (*ch == ':' || *ch == '/' || *ch == '\\') {
893       *ch = '_';
894     }
895   }
896
897   shm_handle = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, s);
898   if (shm_handle) {
899     mm = (MM*)MapViewOfFile(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
900     if (mm == NULL) {
901       return (MM*)-1;
902     }
903 /*
904     if (mm->size != size) {
905       UnmapViewOfFile(mm);
906       CloseHandle(shm_handle);
907       return (MM*)-1;
908     }
909 */
910     addr_ptr = (MM**)(((char*)mm)+sizeof(MM));
911     addr = *addr_ptr;
912     if (addr != mm) {
913       UnmapViewOfFile(mm);
914       mm = (MM*)MapViewOfFileEx(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0, addr);
915       if (mm == NULL) {
916         return (MM*)-1;
917       }
918     }
919 /*  CloseHandle(shm_handle);*/
920     return mm;
921   }
922   return (MM*)-1;
923 }
924
925 static MM* mm_create_shm(const char* key, size_t size) {
926   HANDLE  shm_handle;
927   MM*     mm;
928   MM**    addr_ptr;
929   char    s[MAXPATHLEN];
930   char*   ch;
931
932
933   strcpy(s,key);
934   for (ch = s; *ch; ++ch) {
935     if (*ch == ':' || *ch == '/' || *ch == '\\') {
936       *ch = '_';
937     }
938   }
939
940   shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, s);
941   if (!shm_handle) {
942     return (MM*)-1;
943   }
944   mm = (MM*)MapViewOfFileEx(shm_handle, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
945   if (mm == NULL) {
946     return (MM*)-1;
947   }
948   addr_ptr = (MM**)(((char*)mm)+sizeof(MM));
949   *addr_ptr = mm;
950   mm->size = size;
951   mm->start = ((char*)mm)+sizeof(MM)+sizeof(void*);
952
953 /*  CloseHandle(shm_handle);*/
954   return mm;
955 }
956
957 static void mm_destroy_shm(MM* mm) {
958   UnmapViewOfFile(mm);
959 }
960
961 /* ######################################################################### */
962
963 #elif defined(MM_SHM_MALLOC)
964
965 #define MM_SHM_TYPE "malloc"
966
967 static void* mm_create_shm(const char* key, size_t size) {
968   MM* p = (MM*)malloc(sizeof(MM));
969   if (p == NULL) {
970     return (MM*)-1;
971   }
972   p->size  = size;
973   p->start = NULL;
974   return p;
975 }
976
977 static void mm_destroy_shm(MM* mm) {
978   free(mm);
979 }
980
981 /* ######################################################################### */
982
983 #else
984 #define MM_SHM_TYPE "none"
985 #  error "Shared memeory type is not selected. Define one of the following: MM_SHM_IPC, MM_SHM_MMAP_ANON, MM_SHM_MMAP_ZERO, MM_SHM_MMAP_FILE, MM_SHM_MALLOC, MM_SHM_BEOS, MM_SHM_OS2, MM_SHM_WIN32"
986 #endif
987
988 #ifdef MM_SHM_MALLOC
989 static void mm_init(MM* mm) {
990   mm->available = mm->size - sizeof(MM);
991   mm->lock = malloc(sizeof(mm_mutex));
992 }
993
994 void* mm_malloc_nolock(MM* mm, size_t size) {
995   if (size > 0) {
996     mm_mem_head *p = NULL;
997     if (mm->available >= MM_SIZE(size)) {
998       p = malloc(MM_SIZE(size));
999       if (p != NULL) {
1000         p->size = MM_SIZE(size);
1001         mm->available -= MM_SIZE(size);
1002       }
1003     }
1004     if (p != NULL) {
1005       return HEAD_TO_PTR(p);
1006     }
1007   }
1008   return NULL;
1009 }
1010
1011 void mm_free_nolock(MM* mm, void* x) {
1012   if (x != NULL) {
1013     mm_mem_head *p;
1014     p = PTR_TO_HEAD(x);
1015     mm->available += p->size;
1016     free(p);
1017   }
1018 }
1019
1020 size_t mm_maxsize(MM* mm) {
1021   size_t ret;
1022   if (!mm_lock(mm, MM_LOCK_RD)) {
1023     return 0;
1024   }
1025   ret = mm->available - MM_SIZE(0);
1026   mm_unlock(mm);
1027   return ret;
1028 }
1029
1030 #else
1031 static void mm_init(MM* mm) {
1032   mm->start = MM_ALIGN(mm->start);
1033   mm->attach_addr = (void*)mm;
1034   mm->lock = mm->start;
1035   mm->start = MM_ALIGN((void*)(((char*)(mm->start)) + sizeof(mm_mutex)));
1036   mm->available = mm->size - (((char*)(mm->start))-(char*)mm);
1037   mm->free_list = (mm_free_bucket*)mm->start;
1038   mm->free_list->size = mm->available;
1039   mm->free_list->next = NULL;
1040 }
1041
1042 void* mm_malloc_nolock(MM* mm, size_t size) {
1043   if (size > 0) {
1044     mm_mem_head* x = NULL;
1045     size_t realsize = (size_t)MM_ALIGN(MM_SIZE(size));
1046     if (realsize <= mm->available) {
1047       /* Search for free bucket */
1048       mm_free_bucket* p = mm->free_list;
1049       mm_free_bucket* q = NULL;
1050       mm_free_bucket* best = NULL;
1051       mm_free_bucket* best_prev = NULL;
1052       while (p != NULL) {
1053         if (p->size == realsize) {
1054           /* Found free bucket with the same size */
1055           if (q == NULL) {
1056             mm->free_list = p->next;
1057             x = (mm_mem_head*)p;
1058           } else {
1059             q->next = p->next;
1060             x = (mm_mem_head*)p;
1061           }
1062           break;
1063         } else if (p->size > realsize && (best == NULL || best->size > p->size)) {
1064           /* Found best bucket (smallest bucket with the grater size) */
1065           best = p;
1066           best_prev = q;
1067         }
1068         q = p;
1069         p = p->next;
1070       }
1071       if (x == NULL && best != NULL) {
1072         if (best->size-realsize < sizeof(mm_free_bucket)) {
1073           realsize = best->size;
1074           x = (mm_mem_head*)best;
1075           if (best_prev == NULL) {
1076             mm->free_list = best->next;
1077           } else {
1078             best_prev->next = best->next;
1079           }
1080         } else {
1081           if (best_prev == NULL) {
1082             mm->free_list = (mm_free_bucket*)((char*)best + realsize);
1083             mm->free_list->size = best->size-realsize;
1084             mm->free_list->next = best->next;
1085           } else {
1086             best_prev->next = (mm_free_bucket*)((char*)best + realsize);
1087             best_prev->next->size = best->size-realsize;
1088             best_prev->next->next = best->next;
1089           }
1090           best->size = realsize;
1091           x = (mm_mem_head*)best;
1092         }
1093       }
1094       if (x != NULL) {
1095         mm->available -= realsize;
1096       }
1097     }
1098     if (x != NULL) {
1099       return HEAD_TO_PTR(x);
1100     }
1101   }
1102   return NULL;
1103 }
1104
1105 void mm_free_nolock(MM* mm, void* x) {
1106   if (x != NULL) {
1107     if (x >= mm->start && x < (void*)((char*)mm + mm->size)) {
1108       mm_mem_head *p = PTR_TO_HEAD(x);
1109       size_t size = p->size;
1110       if ((char*)p+size <= (char*)mm + mm->size) {
1111         mm_free_bucket* b = (mm_free_bucket*)p;
1112         b->next = NULL;
1113         if (mm->free_list == NULL) {
1114           mm->free_list = b;
1115         } else {
1116           mm_free_bucket* q = mm->free_list;
1117           mm_free_bucket* prev = NULL;
1118           mm_free_bucket* next = NULL;
1119           while (q != NULL) {
1120             if (b < q) {
1121               next = q;
1122               break;
1123             }
1124             prev = q;
1125             q = q->next;
1126           }
1127           if (prev != NULL && (char*)prev+prev->size == (char*)b) {
1128             if ((char*)next == (char*)b+size) {
1129               /* merging with prev and next */
1130               prev->size += size + next->size;
1131               prev->next = next->next;
1132             } else {
1133               /* merging with prev */
1134               prev->size += size;
1135             }
1136           } else {
1137             if ((char*)next == (char*)b+size) {
1138               /* merging with next */
1139               b->size += next->size;
1140               b->next = next->next;
1141             } else {
1142               /* don't merge */
1143               b->next = next;
1144             }
1145             if (prev != NULL) {
1146               prev->next = b;
1147             } else {
1148               mm->free_list = b;
1149             }
1150           }
1151         }
1152         mm->available += size;
1153       }
1154     }
1155   }
1156 }
1157
1158 size_t mm_maxsize(MM* mm) {
1159   size_t ret = MM_SIZE(0);
1160   mm_free_bucket* p;
1161   if (!mm_lock(mm, MM_LOCK_RD)) {
1162     return 0;
1163   }
1164   p = mm->free_list;
1165   while (p != NULL) {
1166     if (p->size > ret) {
1167       ret = p->size;
1168     }
1169     p = p->next;
1170   }
1171   mm_unlock(mm);
1172   return ret - MM_SIZE(0);
1173 }
1174 #endif
1175
1176 void* mm_malloc_lock(MM* mm, size_t size) {
1177   void *ret;
1178   if (!mm_lock(mm, MM_LOCK_RW)) {
1179     return NULL;
1180   }
1181   ret = mm_malloc_nolock(mm,size);
1182   mm_unlock(mm);
1183   return ret;
1184 }
1185
1186 void mm_free_lock(MM* mm, void* x) {
1187   mm_lock(mm, MM_LOCK_RW);
1188   mm_free_nolock(mm,x);
1189   mm_unlock(mm);
1190 }
1191
1192 void mm_set_attach(MM* mm, void* attach_addr) {
1193   mm->attach_addr = attach_addr;
1194 }
1195
1196 void* mm_attach(size_t size, const char* key) {
1197 #ifdef MM_SHM_CAN_ATTACH
1198   MM* mm = mm_attach_shm(key, size);
1199   if (mm == (MM*)-1) {
1200     return NULL;
1201   }
1202 #ifdef MM_SEM_CAN_ATTACH
1203   if (!mm_attach_lock(key, mm->lock)) {
1204     mm_destroy_shm(mm);
1205     return NULL;
1206   }
1207 #endif
1208   return mm->attach_addr;
1209 #else
1210   return NULL;
1211 #endif
1212 }
1213
1214 MM* mm_create(size_t size, const char* key) {
1215   MM* p;
1216   if (size == 0) {
1217     size = 32 * 1024 * 1024;
1218   }
1219   p = mm_create_shm(key, size);
1220   if (p == (MM*)-1) {
1221     return NULL;
1222   }
1223   mm_init(p);
1224   if (p->lock == NULL) {
1225     mm_destroy_shm(p);
1226     return NULL;
1227   }
1228   if (!mm_init_lock(key, p->lock)) {
1229     mm_destroy_shm(p);
1230     return NULL;
1231   }
1232   return p;
1233 }
1234
1235 void mm_destroy(MM* mm) {
1236   if (mm != NULL) {
1237     mm_destroy_lock(mm->lock);
1238     mm_destroy_shm(mm);
1239   }
1240 }
1241
1242 size_t mm_size(MM* mm) {
1243   if (mm != NULL) {
1244     return mm->size;
1245   }
1246   return 0;
1247 }
1248
1249 size_t mm_sizeof(MM* mm, void* x) {
1250   mm_mem_head *p;
1251   size_t ret;
1252   if (mm == NULL || x == NULL || !mm_lock(mm, MM_LOCK_RD)) {
1253     return 0;
1254   }
1255   p = PTR_TO_HEAD(x);
1256   ret = p->size;
1257   mm_unlock(mm);
1258   return ret;
1259 }
1260
1261 size_t mm_available(MM* mm) {
1262   size_t available;
1263   if (mm != NULL && mm_lock(mm, MM_LOCK_RD)) {
1264     available = mm->available;
1265     mm_unlock(mm);
1266     return available;
1267   }
1268   return 0;
1269 }
1270
1271 const char* mm_shm_type() {
1272   return MM_SHM_TYPE;
1273 }
1274
1275 const char* mm_sem_type() {
1276   return MM_SEM_TYPE;
1277 }
1278
1279 int mm_protect(MM* mm, int mode) {
1280 #ifdef HAVE_MPROTECT
1281   int pmode = 0;
1282   if (mode & MM_PROT_NONE) {
1283     pmode |= PROT_NONE;
1284   }
1285   if (mode & MM_PROT_READ) {
1286     pmode |= PROT_READ;
1287   }
1288   if (mode & MM_PROT_WRITE) {
1289     pmode |= PROT_WRITE;
1290   }
1291   if (mode & MM_PROT_EXEC) {
1292     pmode |= PROT_EXEC;
1293   }
1294   return (mprotect(mm, mm->size, pmode) == 0);
1295 #endif
1296   return 0;
1297 }
1298
1299 #ifdef MM_TEST_SHM
1300 int main() {
1301   char key[] = "/tmp/mm";
1302   size_t size = 32*1024*1024;
1303   MM *mm = mm_create(size, key);
1304   if (mm == NULL) {
1305     return 1;
1306   }
1307   mm_destroy(mm);
1308   return 0;
1309 }
1310 #endif
1311
1312 #ifdef MM_TEST_SEM
1313 int main() {
1314   int ret = 0;
1315   char key[] = "/tmp/mm";
1316   size_t size = 1*1024*1024;
1317   MM *mm = mm_create(size, key);
1318   if (mm == NULL) {
1319     return 1;
1320   }
1321   if (!mm_lock(mm, MM_LOCK_RW)) {
1322     ret = 1;
1323   }
1324   if (!mm_unlock(mm)) {
1325     ret = 1;
1326   }
1327   if (!mm_lock(mm, MM_LOCK_RD)) {
1328     ret = 1;
1329   }
1330   if (!mm_unlock(mm)) {
1331     ret = 1;
1332   }
1333   mm_destroy(mm);
1334   return ret;
1335 }
1336 #endif
Note: See TracBrowser for help on using the browser.