root/eaccelerator/tags/0.9.3/mm.c

Revision 100, 26.6 kB (checked in by zoeloelip, 3 years ago)

Compile fix for bug 1201564. Seems like a type because HAVE_UNION_SEMUN is
defined in config.m4 and not HAVE_SEMUN. This bug only can only apear on
systems using sysvipc for shared memory type.

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