/** Libmm replacement used by cache design of FTPHP-searchd Some source codes cut from eAccelerator/PHP 共享内存管理, 改自 eAccelerator 中的 mm.c, 采用 sem 信号量加锁, 线程安全! 使用时包含 mm.h 这个头文件即可, 数据类型 MM 就是这块共享内存的操作句柄类型. 常用 API 介绍: 1. MM *mm_create(size_t size); 创建 size (单位bytes) 大小的共享内存空间(此为匿名mmap, 用于父子关系之间的进程) 成功返回 MM 指针, 失败返回 NULL 2. void mm_destroy(MM *mm); 销毁 mm, 它同时销毁所有的信号量锁, 多进程模型中只允许一次调用, 子进程退出时 不必调用该函数, 以免破解整个全局的 mm 结构. 3. mm_lock(MM *mm); mm_unlock(MM *mm); 对整个 mm 进行加锁或解锁. 注意: 在 mm_malloc 和 mm_free 内部隐蔽地调用了 mm_lock/mm_unlock, 所以务必 不能已加锁代码段里使用 mm_malloc/mm_free, 否则会造成死锁, 应当改用 mm_malloc_nolock/mm_free_nolock 4. mm_lock1(MM *mm); mm_unlock1(MM *mm); ... mm_lock4(MM *mm); mm_unlock4(MM *mm); ... 这 4 组加锁/解锁之间互不影响, 可用于各类区间操作需加锁时使用. 5. void *mm_malloc(MM *mm, size_t size); void mm_free(MM *mm, void *p); 申请和释放内存, 带全局锁 6. void *mm_malloc_nolock(MM *mm, size_t size); void mm_malloc_free(MM *mm, void *p); 同上, 但不上锁 罕用的 API: 1. size_t mm_size(MM *mm); 获取 mm 在创建时的 size. 2. int mm_protect(MM *mm, int mode); 保护 mm , 内部调用 mprotect() mode 值为 MM_PROT_NONE, MM_PROT_READ, MM_PROT_WRITE, MM_PROT_EXEC 的组合 3. size_t mm_maxsize(MM *mm); size_t mm_avaiable(MM *mm); 分别返回当前能申请到的最大内存长度和当前可用内存空间余额 4. size_t mm_sizeof(MM *mm, void *p); 如果 p 为 mm_malloc 申请的内存, 则该调用可以返回申请时的长度 $Id: mm.h,v 1.3 2009/05/12 16:01:25 hightman Exp $ */ #ifndef __FTPHP_MM_20090527_H__ #define __FTPHP_MM_20090527_H__ #include <sys/types.h> #ifdef __cplusplus extern "C" { #endif #ifndef MM #define MM void #endif #define MM_SEM_NUM 5 #define mm_lock(x) _mm_lock(x,0) #define mm_unlock(x) _mm_unlock(x,0) #define mm_lock1(x) _mm_lock(x,1) #define mm_unlock1(x) _mm_unlock(x,1) #define mm_lock2(x) _mm_lock(x,2) #define mm_unlock2(x) _mm_unlock(x,2) #define mm_lock3(x) _mm_lock(x,3) #define mm_unlock3(x) _mm_unlock(x,3) #define mm_lock4(x) _mm_lock(x,4) #define mm_unlock4(x) _mm_unlock(x,4) #define MM_PROT_NONE 1 #define MM_PROT_READ 2 #define MM_PROT_WRITE 4 #define MM_PROT_EXEC 8 MM *mm_create(size_t size); // create mm by mmap size_t mm_size(MM *mm); void mm_destroy(MM *mm); int _mm_lock(MM *mm, int num); // lock this mm int _mm_unlock(MM *mm, int num); int mm_protect(MM *mm, int mode); // protect the mm to avoid read|write? size_t mm_available(MM *mm); size_t mm_maxsize(MM *mm); void *mm_malloc(MM *mm, size_t size); void mm_free(MM *mm, void *p); void *mm_malloc_nolock(MM *mm, size_t size); void mm_free_nolock(MM *mm, void *p); size_t mm_sizeof(MM *mm, void *x); #ifdef __cplusplus } #endif #endif |
/** Libmm replacement used by cache design of FTPHP-searchd Some source codes cut from eAccelerator/PHP $Id: mm.c,v 1.3 2009/05/12 16:01:25 hightman Exp $ */ #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/sem.h> #include <sys/mman.h> #include <errno.h> typedef struct mm_mutex { int semid; } mm_mutex; typedef struct mm_free_bucket { size_t size; struct mm_free_bucket *next; } mm_free_bucket; typedef struct mm_core { size_t size; void *start; size_t available; mm_mutex *lock; mm_free_bucket *free_list; } mm_core; typedef union mm_mem_head { size_t size; double a1; int (*a2)(int); void *a3; } mm_mem_head; #define MM_SIZE(sz) (sizeof(mm_mem_head)+(sz)) #define PTR_TO_HEAD(p) (((mm_mem_head *)(p)) - 1) #define HEAD_TO_PTR(p) ((void *)(((mm_mem_head *)(p)) + 1)) #define MM mm_core #define MM_WORD mm_mem_head #if (defined (__GNUC__) && __GNUC__ >= 2) # define MM_PLATFORM_ALIGNMENT (__alignof__ (MM_WORD)) #else # define MM_PLATFORM_ALIGNMENT (sizeof(MM_WORD)) #endif #define MM_ALIGN(n) (void*)((((size_t)(n)-1) & ~(MM_PLATFORM_ALIGNMENT-1)) + MM_PLATFORM_ALIGNMENT) #include "mm.h" /* MM-lock implement */ static int mm_init_lock(mm_mutex *lock) { union semun arg; int n = MM_SEM_NUM; if ((lock->semid = semget(IPC_PRIVATE, n, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0) { return 0; } arg.val = 1; while (n--) { if (semctl(lock->semid, n, SETVAL, arg) < 0) { semctl(lock->semid, n, IPC_RMID, 0); } } return 1; } static int mm_do_lock(mm_mutex *lock, int num) { struct sembuf op; int rc; op.sem_num = (unsigned short)num; op.sem_op = -1; op.sem_flg = SEM_UNDO; do { rc = semop(lock->semid, &op, 1); } while (rc < 0 && errno == EINTR); return (rc == 0); } static int mm_do_unlock(mm_mutex *lock, int num) { struct sembuf op; op.sem_num = (unsigned short)num; op.sem_op = 1; op.sem_flg = SEM_UNDO; if (!semop(lock->semid, &op, 1)) return 1; return 0; } static void mm_destroy_lock(mm_mutex *lock) { int n = MM_SEM_NUM; while (n--) { semctl(lock->semid, n, IPC_RMID, 0); } } int _mm_lock(MM *mm, int num) { return mm_do_lock(mm->lock, num); } int _mm_unlock(MM *mm, int num) { return mm_do_unlock(mm->lock, num); } /* shared memory implement */ static MM *mm_create_shm(size_t size) { MM *p; p = (MM *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if (p != (MM *)-1) { p->size = size; p->start = (char *)p + sizeof(MM); } return p; } static void mm_destroy_shm(MM *mm) { if (mm != NULL && mm != (MM *)-1) { munmap(mm, mm->size); } } static void mm_init(MM *mm) { mm->start = MM_ALIGN(mm->start); mm->lock = mm->start; mm->start = MM_ALIGN((void *)(((char *)(mm->start)) + sizeof(mm_mutex))); mm->available = mm->size - (((char *)(mm->start))-(char *)mm); mm->free_list = (mm_free_bucket *)mm->start; mm->free_list->size = mm->available; mm->free_list->next = NULL; } void *mm_malloc_nolock(MM *mm, size_t size) { if (size > 0) { mm_mem_head *x = NULL; size_t realsize = (size_t) MM_ALIGN(MM_SIZE(size)); if (realsize <= mm->available) { /* Search for free bucket */ mm_free_bucket *p = mm->free_list; mm_free_bucket *q = NULL; mm_free_bucket *best = NULL; mm_free_bucket *best_prev = NULL; while (p != NULL) { if (p->size == realsize) { /* Found free bucket with the same size */ if (q == NULL) { mm->free_list = p->next; x = (mm_mem_head *)p; } else { q->next = p->next; x = (mm_mem_head *)p; } break; } else if (p->size > realsize && (best == NULL || best->size > p->size)) { /* Found best bucket (smallest bucket with the grater size) */ best = p; best_prev = q; } q = p; p = p->next; } if (x == NULL && best != NULL) { if (best->size-realsize < sizeof(mm_free_bucket)) { realsize = best->size; x = (mm_mem_head *)best; if (best_prev == NULL) { mm->free_list = best->next; } else { best_prev->next = best->next; } } else { if (best_prev == NULL) { mm->free_list = (mm_free_bucket *)((char *)best + realsize); mm->free_list->size = best->size-realsize; mm->free_list->next = best->next; } else { best_prev->next = (mm_free_bucket *)((char *)best + realsize); best_prev->next->size = best->size-realsize; best_prev->next->next = best->next; } best->size = realsize; x = (mm_mem_head *)best; } } if (x != NULL) { mm->available -= realsize; } } if (x != NULL) { return HEAD_TO_PTR(x); } } return NULL; } void mm_free_nolock(MM *mm, void *x) { if (x != NULL) { if (x >= mm->start && x < (void *)((char *)mm + mm->size)) { mm_mem_head *p = PTR_TO_HEAD(x); size_t size = p->size; if ((char *)p+size <= (char *)mm + mm->size) { mm_free_bucket *b = (mm_free_bucket *)p; b->next = NULL; if (mm->free_list == NULL) { mm->free_list = b; } else { mm_free_bucket *q = mm->free_list; mm_free_bucket *prev = NULL; mm_free_bucket *next = NULL; while (q != NULL) { if (b < q) { next = q; break; } prev = q; q = q->next; } if (prev != NULL && (char *)prev+prev->size == (char *)b) { if ((char *)next == (char *)b+size) { /* merging with prev and next */ prev->size += size + next->size; prev->next = next->next; } else { /* merging with prev */ prev->size += size; } } else { if ((char *)next == (char *)b+size) { /* merging with next */ b->size += next->size; b->next = next->next; } else { /* don't merge */ b->next = next; } if (prev != NULL) { prev->next = b; } else { mm->free_list = b; } } } mm->available += size; } } } } size_t mm_maxsize(MM *mm) { size_t ret = MM_SIZE(0); mm_free_bucket *p; if (!mm_lock(mm)) { return 0; } p = mm->free_list; while (p != NULL) { if (p->size > ret) { ret = p->size; } p = p->next; } mm_unlock(mm); return ret - MM_SIZE(0); } void *mm_malloc(MM *mm, size_t size) { void *ret; if (!mm_lock(mm)) { return NULL; } ret = mm_malloc_nolock(mm,size); mm_unlock(mm); return ret; } void mm_free(MM *mm, void *x) { mm_lock(mm); mm_free_nolock(mm, x); mm_unlock(mm); } MM *mm_create(size_t size) { MM *p; if (size == 0) { size = 32 * 1024 * 1024; } p = mm_create_shm(size); if (p == (MM *)-1) { return NULL; } mm_init(p); if (!mm_init_lock(p->lock)) { mm_destroy_shm(p); return NULL; } return p; } void mm_destroy(MM *mm) { if (mm != NULL) { mm_destroy_lock(mm->lock); mm_destroy_shm(mm); } } size_t mm_size(MM *mm) { if (mm != NULL) { return mm->size; } return 0; } size_t mm_sizeof(MM *mm, void *x) { mm_mem_head *p; size_t ret; if (mm == NULL || x == NULL || !mm_lock(mm)) { return 0; } p = PTR_TO_HEAD(x); ret = p->size; mm_unlock(mm); return ret; } size_t mm_available(MM *mm) { size_t available; if (mm != NULL && mm_lock(mm)) { available = mm->available; mm_unlock(mm); return available; } return 0; } |
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) | Powered by Discuz! X3.2 |