root/eaccelerator/branches/0.9.6/mm.c

Revision 401, 31.3 kB (checked in by bart, 6 months ago)

Now really add the sched_yield command and not only in commented out

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