root/eaccelerator/tags/0.9.1/mm.c

Revision 22, 26.4 kB (checked in by anonymous, 4 years ago)

This commit was manufactured by cvs2svn to create tag
'release-0-9-1'.

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