/* $Id$ * * Shared memory functions * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef SHM_MEM #include <stdlib.h> #include "shm_mem.h" #include "../config.h" #include "../globals.h" #ifdef SHM_MMAP #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> /*open*/ #include <sys/stat.h> #include <fcntl.h> #endif #ifdef FAST_LOCK #include "../fastlock.h" #endif /* define semun */ #if defined(HAVE_UNION_SEMUN) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including <sys/sem.h> */ #else /* according to X/OPEN we have to define it ourselves */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ }; #endif #ifndef SHM_MMAP static int shm_shmid=-1; /*shared memory id*/ #endif #ifdef FAST_LOCK fl_lock_t* mem_lock=0; #else int shm_semid=-1; /*semaphore id*/ #endif static void* shm_mempool=(void*)-1; #ifdef VQ_MALLOC struct vqm_block* shm_block; #elif F_MALLOC struct fm_block* shm_block; #else struct qm_block* shm_block; #endif inline static void* sh_realloc(void* p, unsigned int size) { void *r; shm_lock(); shm_free_unsafe(p); r=shm_malloc_unsafe(size); shm_unlock(); return r; } /* look at a buffer if there is perhaps enough space for the new size (It is benefitial to do so because vq_malloc is pretty stateful and if we ask for a new buffer size, we can still make it happy with current buffer); if so, we return current buffer again; otherwise, we free it, allocate a new one and return it; no guarantee for buffer content; if allocation fails, we return NULL */ #ifdef DBG_QM_MALLOC void* _shm_resize( void* p, unsigned int s, char* file, char* func, unsigned int line) #else void* _shm_resize( void* p , unsigned int s) #endif { #ifdef VQ_MALLOC struct vqm_frag *f; #endif if (p==0) { DBG("WARNING:vqm_resize: resize(0) called\n"); return shm_malloc( s ); } # ifdef DBG_QM_MALLOC # ifdef VQ_MALLOC f=(struct vqm_frag*) ((char*)p-sizeof(struct vqm_frag)); DBG("_shm_resize(%p, %d), called from %s: %s(%d)\n", p, s, file, func, line); VQM_DEBUG_FRAG(shm_block, f); if (p>(void *)shm_block->core_end || p<(void*)shm_block->init_core){ LOG(L_CRIT, "BUG: vqm_free: bad pointer %p (out of memory block!) - " "aborting\n", p); abort(); } #endif # endif return sh_realloc( p, s ); } #ifdef _OBSOLETED #ifdef DBG_QM_MALLOC void* _shm_resize( void* p, unsigned int s, char* file, char* func, unsigned int line) #else void* _shm_resize( void* p , unsigned int s) #endif { #ifdef VQ_MALLOC struct vqm_frag *f; #else #ifdef __SUNPRO_C /*no warning support on Sun cc */ #else #ifdef _NO_NO_NO #warning shm_resize performs suboptimally without VQ_MALLOC! #endif #endif #endif if (p==0) { DBG("WARNING:vqm_resize: resize(0) called\n"); return shm_malloc( s ); } # ifdef VQ_MALLOC f=(struct vqm_frag*) ((char*)p-sizeof(struct vqm_frag)); # ifdef DBG_QM_MALLOC DBG("_shm_resize(%p, %d), called from %s: %s(%d)\n", p, s, file, func, line); VQM_DEBUG_FRAG(shm_block, f); if (p>(void *)shm_block->core_end || p<(void*)shm_block->init_core){ LOG(L_CRIT, "BUG: vqm_free: bad pointer %p (out of memory block!) - " "aborting\n", p); abort(); } # endif if (s <= f->size-VQM_OVERHEAD) { # ifdef DBG_QM_MALLOC DBG("DEBUG: happy guy -- you reused a memory fragment!\n"); # endif return p; }; #endif /* we can't make the request happy with current size */ return sh_realloc( p, s ); } #endif int shm_mem_init() { #ifndef FAST_LOCK union semun su; int ret; #endif #ifdef SHM_MMAP int fd; #else struct shmid_ds shm_info; #endif #ifdef SHM_MMAP if (shm_mempool && (shm_mempool!=(void*)-1)){ #else if ((shm_shmid!=-1)||(shm_semid!=-1)||(shm_mempool!=(void*)-1)){ #endif LOG(L_CRIT, "BUG: shm_mem_init: shm already initialized\n"); return -1; } #ifdef SHM_MMAP fd=open("/dev/zero", O_RDWR); if (fd==-1){ LOG(L_CRIT, "ERROR: shm_mem_init: could not open /dev/zero: %s\n", strerror(errno)); return -1; } shm_mempool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd ,0); /* close /dev/zero */ close(fd); #else shm_shmid=shmget(IPC_PRIVATE, /* SHM_MEM_SIZE */ shm_mem_size , 0700); if (shm_shmid==-1){ LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate shared memory" " segment: %s\n", strerror(errno)); return -1; } shm_mempool=shmat(shm_shmid, 0, 0); #endif if (shm_mempool==(void*)-1){ LOG(L_CRIT, "ERROR: shm_mem_init: could not attach shared memory" " segment: %s\n", strerror(errno)); /* destroy segment*/ shm_mem_destroy(); return -1; } #ifndef FAST_LOCK /* alloc a semaphore (for malloc)*/ shm_semid=semget(IPC_PRIVATE, 1, 0700); if (shm_semid==-1){ LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate semaphore: %s\n", strerror(errno)); shm_mem_destroy(); return -1; } /* set its value to 1 (mutex)*/ su.val=1; ret=semctl(shm_semid, 0, SETVAL, su); if (ret==-1){ LOG(L_CRIT, "ERROR: shm_mem_init: could not set initial semaphore" " value: %s\n", strerror(errno)); shm_mem_destroy(); return -1; } #endif /* init it for malloc*/ # ifdef VQ_MALLOC shm_block=vqm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size ); #elif defined F_MALLOC shm_block=fm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size ); # else shm_block=qm_malloc_init(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size ); # endif if (shm_block==0){ LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared" " malloc\n"); shm_mem_destroy(); return -1; } #ifdef FAST_LOCK mem_lock=shm_malloc_unsafe(sizeof(fl_lock_t)); init_lock(*mem_lock); #endif DBG("shm_mem_init: success\n"); return 0; } void shm_mem_destroy() { #ifndef SHM_MMAP struct shmid_ds shm_info; #endif #ifndef FAST_LOCK union semun zero_un; #endif DBG("shm_mem_destroy\n"); if (shm_mempool && (shm_mempool!=(void*)-1)) { #ifdef SHM_MMAP munmap(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size ); #else shmdt(shm_mempool); #endif shm_mempool=(void*)-1; } #ifndef SHM_MMAP if (shm_shmid!=-1) { shmctl(shm_shmid, IPC_RMID, &shm_info); shm_shmid=-1; } #endif #ifndef FAST_LOCK if (shm_semid!=-1) { zero_un.val=0; semctl(shm_semid, 0, IPC_RMID, zero_un); shm_semid=-1; } #endif } #endif