source: eaccelerator/trunk/mm.c @ 197

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