root/eaccelerator/tags/0.9.3-rc2/mm.c

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

This patch fixes some stuff concerning configuration. With this patch some parts that are forgotten with the
code split are fixed. They are also needed to compile eA with VC.
The other stuff make it possible to compile eA as a static module for php.

  • 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_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.