root/eaccelerator/branches/new-cache/mm.c

Revision 335, 31.1 kB (checked in by bart, 1 year ago)

Branch trunk for new caching code

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