- 論壇徽章:
- 1
|
通常情況類似于內(nèi)存池的資料比較多, 但之前開(kāi)發(fā)東西在多進(jìn)程/多線程混合的情況下尋求緩存解決方案時(shí), 采用了共享內(nèi)存.
而能對(duì)共享內(nèi)存進(jìn)行動(dòng)態(tài)再分配的庫(kù)有一個(gè)稱之為 libmm 的模塊, 但資料很少, 沒(méi)有采用它. 后來(lái)我自己從 eAccelerator
(php的一個(gè)緩存擴(kuò)展) 中找到一個(gè) mm.c , 對(duì)它進(jìn)行了簡(jiǎn)化和修改, 生成了一個(gè)我自己在用的 mm.c/mm.h 現(xiàn)在發(fā)布如下,
供有需要的參考, 但應(yīng)該特別注意的是, 我這里申請(qǐng)的共享內(nèi)存是一個(gè)匿名的內(nèi)存映射, 只能共享于有親屬關(guān)系的進(jìn)程中, 因
而可以在內(nèi)存中再直接存放指針數(shù)據(jù), 這一點(diǎn)比較方便.
而如果想用在無(wú)關(guān)系的進(jìn)程之間, 那必須對(duì)代碼進(jìn)行修改, 支持有名的 mmap 或 IPC-shm 以及 IPC-sem 的, 并且在
mmap() 時(shí)指定同主進(jìn)程相當(dāng)?shù)钠鹗嫉刂? 這個(gè)做法非常不值得推薦, mmap() 的起始捆綁地址一般應(yīng)當(dāng)由系統(tǒng)進(jìn)行分配比較好.
好了, 代碼如下, 供有需要或有興趣的參考, 內(nèi)存申請(qǐng)是由一個(gè)線性鏈表來(lái)管理的, 應(yīng)當(dāng)能滿足大部分應(yīng)用了 
1. mm.h
/**
Libmm replacement used by cache design of FTPHP-searchd
Some source codes cut from eAccelerator/PHP
共享內(nèi)存管理, 改自 eAccelerator 中的 mm.c, 采用 sem 信號(hào)量加鎖, 線程安全!
使用時(shí)包含 mm.h 這個(gè)頭文件即可, 數(shù)據(jù)類型 MM 就是這塊共享內(nèi)存的操作句柄類型.
常用 API 介紹:
1. MM *mm_create(size_t size);
創(chuàng)建 size (單位bytes) 大小的共享內(nèi)存空間(此為匿名mmap, 用于父子關(guān)系之間的進(jìn)程)
成功返回 MM 指針, 失敗返回 NULL
2. void mm_destroy(MM *mm);
銷毀 mm, 它同時(shí)銷毀所有的信號(hào)量鎖, 多進(jìn)程模型中只允許一次調(diào)用, 子進(jìn)程退出時(shí)
不必調(diào)用該函數(shù), 以免破解整個(gè)全局的 mm 結(jié)構(gòu).
3. mm_lock(MM *mm); mm_unlock(MM *mm);
對(duì)整個(gè) mm 進(jìn)行加鎖或解鎖.
注意: 在 mm_malloc 和 mm_free 內(nèi)部隱蔽地調(diào)用了 mm_lock/mm_unlock, 所以務(wù)必
不能已加鎖代碼段里使用 mm_malloc/mm_free, 否則會(huì)造成死鎖, 應(yīng)當(dāng)改用
mm_malloc_nolock/mm_free_nolock
4. mm_lock1(MM *mm); mm_unlock1(MM *mm); ... mm_lock4(MM *mm); mm_unlock4(MM *mm);
... 這 4 組加鎖/解鎖之間互不影響, 可用于各類區(qū)間操作需加鎖時(shí)使用.
5. void *mm_malloc(MM *mm, size_t size);
void mm_free(MM *mm, void *p);
申請(qǐng)和釋放內(nèi)存, 帶全局鎖
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 在創(chuàng)建時(shí)的 size.
2. int mm_protect(MM *mm, int mode);
保護(hù) mm , 內(nèi)部調(diào)用 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);
分別返回當(dāng)前能申請(qǐng)到的最大內(nèi)存長(zhǎng)度和當(dāng)前可用內(nèi)存空間余額
4. size_t mm_sizeof(MM *mm, void *p);
如果 p 為 mm_malloc 申請(qǐng)的內(nèi)存, 則該調(diào)用可以返回申請(qǐng)時(shí)的長(zhǎng)度
$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;
}
|
|
|