You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/mem/shm.c

279 lines
5.9 KiB

/*
* Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com)
*
* This file is part of Kamailio, a free SIP server.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include "../config.h"
#include "../globals.h"
#include "memdbg.h"
#include "shm.h"
#ifdef SHM_MMAP
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h> /*open*/
#include <sys/stat.h>
#include <fcntl.h>
#endif
#include "memcore.h"
#define _ROUND2TYPE(s, type) \
(((s)+(sizeof(type)-1))&(~(sizeof(type)-1)))
#define _ROUND_LONG(s) _ROUND2TYPE(s, long)
void shm_core_destroy(void);
#ifndef SHM_MMAP
static int _shm_core_shmid = -1; /*shared memory id*/
#endif
gen_lock_t* _shm_lock=0;
static void* _shm_core_pool = (void*)-1;
sr_shm_api_t _shm_root = {0};
/**
*
*/
int shm_getmem(void)
{
#ifdef SHM_MMAP
#ifndef USE_ANON_MMAP
int fd;
#endif
#else
struct shmid_ds shm_info;
#endif
#ifdef SHM_MMAP
if (_shm_core_pool && (_shm_core_pool!=(void*)-1)){
#else
if ((_shm_core_shmid!=-1)||(_shm_core_pool!=(void*)-1)){
#endif
LOG(L_CRIT, "shm already initialized\n");
return -1;
}
#ifdef SHM_MMAP
#ifdef USE_ANON_MMAP
_shm_core_pool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_SHARED, -1 ,0);
#else
fd=open("/dev/zero", O_RDWR);
if (fd==-1){
LOG(L_CRIT, "could not open /dev/zero: %s\n",
strerror(errno));
return -1;
}
_shm_core_pool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd ,0);
/* close /dev/zero */
close(fd);
#endif /* USE_ANON_MMAP */
#else
_shm_core_shmid=shmget(IPC_PRIVATE, shm_mem_size , 0700);
if (_shm_core_shmid==-1){
LOG(L_CRIT, "could not allocate shared memory"
" segment: %s\n", strerror(errno));
return -1;
}
_shm_core_pool=shmat(_shm_core_shmid, 0, 0);
#endif
if (_shm_core_pool==(void*)-1){
LOG(L_CRIT, "could not attach shared memory"
" segment: %s\n", strerror(errno));
/* destroy segment*/
shm_core_destroy();
return -1;
}
return 0;
}
/**
*
*/
void* shm_core_get_pool(void)
{
int ret;
long sz;
long* p;
long* end;
ret=shm_getmem();
if (ret<0)
return NULL;
if (shm_force_alloc){
sz=sysconf(_SC_PAGESIZE);
DBG("%ld bytes/page\n", sz);
if ((sz<sizeof(*p)) || (_ROUND_LONG(sz)!=sz)){
LOG(L_WARN, "invalid page size %ld, using 4096\n",
sz);
sz=4096; /* invalid page size, use 4096 */
}
end=_shm_core_pool+shm_mem_size-sizeof(*p);
/* touch one word in every page */
for(p=(long*)_ROUND_LONG((long)_shm_core_pool); p<=end;
p=(long*)((char*)p+sz))
*p=0;
}
return _shm_core_pool;
}
/**
* init the core lock
*/
int shm_core_lock_init(void)
{
if (_shm_lock) {
LM_DBG("shared memory lock initialized\n");
return 0;
}
_shm_lock=shm_malloc_unsafe(sizeof(gen_lock_t)); /* skip lock_alloc,
race cond*/
if (_shm_lock==0){
LOG(L_CRIT, "could not allocate lock\n");
shm_core_destroy();
return -1;
}
if (lock_init(_shm_lock)==0){
LOG(L_CRIT, "could not initialize lock\n");
shm_core_destroy();
return -1;
}
return 0;
}
/**
*
*/
void shm_core_lock_destroy(void)
{
if (_shm_lock){
DBG("destroying the shared memory lock\n");
lock_destroy(_shm_lock); /* we don't need to dealloc it*/
}
}
/**
*
*/
void shm_core_destroy(void)
{
#ifndef SHM_MMAP
struct shmid_ds shm_info;
#endif
if (_shm_core_pool && (_shm_core_pool!=(void*)-1)) {
#ifdef SHM_MMAP
munmap(_shm_core_pool, /* SHM_MEM_SIZE */ shm_mem_size );
#else
shmdt(_shm_core_pool);
#endif
_shm_core_pool=(void*)-1;
}
#ifndef SHM_MMAP
if (shm_shmid!=-1) {
shmctl(shm_shmid, IPC_RMID, &shm_info);
shm_shmid=-1;
}
#endif
}
/**
*
*/
int shm_init_api(sr_shm_api_t *ap)
{
memset(&_shm_root, 0, sizeof(sr_shm_api_t));
_shm_root.mname = ap->mname;
_shm_root.mem_pool = ap->mem_pool;
_shm_root.mem_block = ap->mem_block;
_shm_root.xmalloc = ap->xmalloc;
_shm_root.xmalloc_unsafe = ap->xmalloc_unsafe;
_shm_root.xfree = ap->xfree;
_shm_root.xfree_unsafe = ap->xfree_unsafe;
_shm_root.xrealloc = ap->xrealloc;
_shm_root.xresize = ap->xresize;
_shm_root.xstatus = ap->xstatus;
_shm_root.xinfo = ap->xinfo;
_shm_root.xavailable = ap->xavailable;
_shm_root.xsums = ap->xsums;
_shm_root.xdestroy = ap->xdestroy;
_shm_root.xmodstats = ap->xmodstats;
_shm_root.xfmodstats = ap->xfmodstats;
return 0;
}
/**
*
*/
int shm_init_manager(char *name)
{
if(strcmp(name, "fm")==0
|| strcmp(name, "f_malloc")==0
|| strcmp(name, "fmalloc")==0) {
/*fast malloc*/
return fm_malloc_init_shm_manager();
} else if(strcmp(name, "qm")==0
|| strcmp(name, "q_malloc")==0
|| strcmp(name, "qmalloc")==0) {
/*quick malloc*/
return qm_malloc_init_shm_manager();
} else if(strcmp(name, "tlsf")==0
|| strcmp(name, "tlsf_malloc")==0) {
/*tlsf malloc*/
return tlsf_malloc_init_shm_manager();
} else if(strcmp(name, "sm")==0) {
/*system malloc*/
} else {
/*custom malloc - module*/
}
return -1;
}
/**
*
*/
void shm_destroy_manager(void)
{
shm_core_lock_destroy();
if(_shm_root.xdestroy) {
_shm_root.xdestroy();
LM_DBG("destroying memory manager: %s\n",
(_shm_root.mname)?_shm_root.mname:"unknown");
}
shm_core_destroy();
}
/**
*
*/
void shm_print_manager(void)
{
LM_DBG("shm - using memory manager: %s\n",
(_pkg_root.mname)?_pkg_root.mname:"unknown");
}