/* * 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.xstats = ap->xstats; _shm_root.xfstats = ap->xfstats; 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"); }