source: eaccelerator/trunk/mm.c @ 375

Revision 375, 31.1 KB checked in by bart, 8 months ago (diff)

Update year in copyright

  • 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
100struct mm_mutex;
101
102typedef struct mm_free_bucket {
103  size_t                 size;
104  struct mm_free_bucket* next;
105} mm_free_bucket;
106
107typedef 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
116typedef 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
135typedef 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)
164static 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
193typedef 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
202static 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
210static 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
224static 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
233static 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
242typedef struct mm_mutex {
243  pthread_mutex_t mutex;
244} mm_mutex;
245
246static 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
262static 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
269static int mm_do_unlock(mm_mutex* lock) {
270  if (pthread_mutex_unlock(&lock->mutex) != 0) {
271    return 0;
272  }
273  return 1;
274}
275
276static 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
288typedef struct mm_mutex {
289  sem_t* sem;
290} mm_mutex;
291
292static 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
317static int mm_do_lock(mm_mutex* lock, int kind) {
318  return (sem_wait(lock->sem) == 0);
319}
320
321static int mm_do_unlock(mm_mutex* lock) {
322  return (sem_post(lock->sem) == 0);
323}
324
325static 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
336union semun {
337    int val;
338    struct semid_ds *buf;
339    unsigned short *array;
340    struct seminfo *__buf;
341};
342#endif
343
344typedef struct mm_mutex {
345  int semid;
346} mm_mutex;
347
348static 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
381static 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
394static 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
407static 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
418typedef struct mm_mutex {
419  int fd;
420} mm_mutex;
421
422static 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
434static 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
452static 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
466static 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
478static int   mm_flock_fd  = -1;
479static pid_t mm_flock_pid = -1;
480
481typedef struct mm_mutex {
482  char filename[MAXPATHLEN];
483} mm_mutex;
484
485static 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
499static 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
524static 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
538static 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
560typedef struct mm_mutex {
561  HANDLE hMutex;
562} mm_mutex;
563
564static mm_mutex g_lock;
565
566static 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
585static 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
602static void mm_destroy_lock(mm_mutex* lock) {
603  CloseHandle(g_lock.hMutex);
604}
605
606static 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
617static 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
635typedef struct mm_mutex {
636  int semid;
637} mm_mutex;
638
639static int mm_attach_lock(const char* key, mm_mutex* lock) {
640  return 1;
641}
642
643static int mm_init_lock(const char* key, mm_mutex* lock) {
644  return 1;
645}
646
647static void mm_destroy_lock(mm_mutex* lock) {
648}
649
650static int mm_do_lock(mm_mutex* lock, int kind) {
651  return 1;
652}
653
654static 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
662int 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
673int 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
699static 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
751static 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
772static 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
782static 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
792static 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
807static 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
819static 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
847static 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
857static 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
881static 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
906static 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
950static 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
982static 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
992static 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
1002static 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
1014static void mm_init(MM* mm) {
1015  mm->available = mm->size - sizeof(MM);
1016  mm->lock = malloc(sizeof(mm_mutex));
1017}
1018
1019void* 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
1036void 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
1045size_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
1056static 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
1067void* 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
1136void 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
1189size_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
1207void* 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
1217void 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
1223void mm_set_attach(MM* mm, void* attach_addr) {
1224  mm->attach_addr = attach_addr;
1225}
1226
1227void* 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
1245MM* 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
1266void mm_destroy(MM* mm) {
1267  if (mm != NULL) {
1268    mm_destroy_lock(mm->lock);
1269    mm_destroy_shm(mm);
1270  }
1271}
1272
1273size_t mm_size(MM* mm) {
1274  if (mm != NULL) {
1275    return mm->size;
1276  }
1277  return 0;
1278}
1279
1280size_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
1292size_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
1302const char* mm_shm_type() {
1303  return MM_SHM_TYPE;
1304}
1305
1306const char* mm_sem_type() {
1307  return MM_SEM_TYPE;
1308}
1309
1310int 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))
1331void 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
1338void mm_check_mem(void *x) {}
1339#endif
1340
1341#ifdef MM_TEST_SHM
1342int 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
1355int 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  if (mm == NULL) {
1361    return 1;
1362  }
1363  if (!mm_lock(mm, MM_LOCK_RW)) {
1364    ret = 1;
1365  }
1366  if (!mm_unlock(mm)) {
1367    ret = 1;
1368  }
1369  if (!mm_lock(mm, MM_LOCK_RD)) {
1370    ret = 1;
1371  }
1372  if (!mm_unlock(mm)) {
1373    ret = 1;
1374  }
1375  mm_destroy(mm);
1376  return ret;
1377}
1378#endif
Note: See TracBrowser for help on using the repository browser.