mem/shm_mem.c
47f59303
 /*
 
7dd0b342
  *
84d8e165
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
e4f42ce1
  * This file is part of sip-router, a free SIP server.
7dd0b342
  *
e4f42ce1
  * 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.
7dd0b342
  *
e4f42ce1
  * 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.
628e3a5a
  */
47f59303
 
fd92af47
 /*
  * History:
  * --------
84d8e165
  *  2003-03-12  split shm_mem_init in shm_getmem & shm_mem_init_mallocs
fd92af47
  *               (andrei)
194b6a35
  *  2004-07-27  ANON mmap support, needed on darwin (andrei)
dd0e65a8
  *  2004-09-19  shm_mem_destroy: destroy first the lock & then unmap (andrei)
fbe11914
  *  2007-06-10   support for sfm_malloc & shm_malloc_destroy() (andrei)
fd92af47
  */
628e3a5a
 
47f59303
 /**
  * \file
  * \brief  Shared memory functions
  * \ingroup mem
  */
 
7dd0b342
 
628e3a5a
 #ifdef SHM_MEM
 
caf80ae6
 #include <stdlib.h>
 
628e3a5a
 #include "shm_mem.h"
dda9dab1
 #include "../config.h"
4e2fdd79
 #include "../globals.h"
58d0d1b5
 #include "memdbg.h"
628e3a5a
 
dcb5f364
 #ifdef  SHM_MMAP
 
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/types.h> /*open*/
 #include <sys/stat.h>
 #include <fcntl.h>
 
 #endif
 
11c0a282
 #define _ROUND2TYPE(s, type) \
 	(((s)+(sizeof(type)-1))&(~(sizeof(type)-1)))
 #define _ROUND_LONG(s) _ROUND2TYPE(s, long)
628e3a5a
 
 
dcb5f364
 #ifndef SHM_MMAP
628e3a5a
 static int shm_shmid=-1; /*shared memory id*/
dcb5f364
 #endif
dda9dab1
 
fbe11914
 #ifndef SHM_SAFE_MALLOC
0bd53297
 gen_lock_t* mem_lock=0;
fbe11914
 #endif
eca7f442
 
628e3a5a
 static void* shm_mempool=(void*)-1;
fbe11914
 #ifdef LL_MALLOC
 	struct sfm_block* shm_block;
 #elif SF_MALLOC
 	struct sfm_block* shm_block;
b2dec9c6
 #elif F_MALLOC
 	struct fm_block* shm_block;
51ea5ec2
 #elif DL_MALLOC
 	mspace shm_block;
dda9dab1
 #else
 	struct qm_block* shm_block;
 #endif
628e3a5a
 
51eadd0c
 
 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;
 }
ea6721d7
 
 /* look at a buffer if there is perhaps enough space for the new size
84d8e165
    (It is beneficial to do so because vq_malloc is pretty stateful
ea6721d7
     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
 */
caf80ae6
 
 #ifdef DBG_QM_MALLOC
4168f707
 void* _shm_resize( void* p, unsigned int s, const char* file, const char* func,
 							int line)
caf80ae6
 #else
 void* _shm_resize( void* p , unsigned int s)
 #endif
 {
 	if (p==0) {
 		DBG("WARNING:vqm_resize: resize(0) called\n");
 		return shm_malloc( s );
 	}
 	return sh_realloc( p, s ); 
 }
 
628e3a5a
 
ea6721d7
 
fd92af47
 
 
9f8a2ff6
 int shm_getmem(void)
628e3a5a
 {
 
dcb5f364
 #ifdef SHM_MMAP
6c006f79
 #ifndef USE_ANON_MMAP
dcb5f364
 	int fd;
6c006f79
 #endif
dcb5f364
 #else
 	struct shmid_ds shm_info;
 #endif
628e3a5a
 
dcb5f364
 #ifdef SHM_MMAP
 	if (shm_mempool && (shm_mempool!=(void*)-1)){
 #else
a7ce1229
 	if ((shm_shmid!=-1)||(shm_mempool!=(void*)-1)){
dcb5f364
 #endif
628e3a5a
 		LOG(L_CRIT, "BUG: shm_mem_init: shm already initialized\n");
 		return -1;
 	}
 	
dcb5f364
 #ifdef SHM_MMAP
194b6a35
 #ifdef USE_ANON_MMAP
 	shm_mempool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE,
 					 MAP_ANON|MAP_SHARED, -1 ,0);
 #else
454ef89a
 	fd=open("/dev/zero", O_RDWR);
dcb5f364
 	if (fd==-1){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not open /dev/zero: %s\n",
 				strerror(errno));
 		return -1;
 	}
e3fc93f4
 	shm_mempool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd ,0);
dcb5f364
 	/* close /dev/zero */
 	close(fd);
194b6a35
 #endif /* USE_ANON_MMAP */
dcb5f364
 #else
 	
40a8d9dd
 	shm_shmid=shmget(IPC_PRIVATE, /* SHM_MEM_SIZE */ shm_mem_size , 0700);
628e3a5a
 	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);
dcb5f364
 #endif
628e3a5a
 	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;
 	}
fd92af47
 	return 0;
 }
 
eca7f442
 
fd92af47
 
c082177a
 int shm_mem_init_mallocs(void* mempool, unsigned long pool_size)
fd92af47
 {
628e3a5a
 	/* init it for malloc*/
c996d5dd
 	shm_block=shm_malloc_init(mempool, pool_size, MEM_TYPE_SHM);
628e3a5a
 	if (shm_block==0){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
 				" malloc\n");
 		shm_mem_destroy();
 		return -1;
 	}
fbe11914
 #ifndef SHM_SAFE_MALLOC
0bd53297
 	mem_lock=shm_malloc_unsafe(sizeof(gen_lock_t)); /* skip lock_alloc, 
 													   race cond*/
e0135488
 	if (mem_lock==0){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate lock\n");
 		shm_mem_destroy();
 		return -1;
 	}
 	if (lock_init(mem_lock)==0){
 		LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize lock\n");
 		shm_mem_destroy();
 		return -1;
 	}
fbe11914
 #endif  /*SHM SAFE_MALLOC */
eca7f442
 	
628e3a5a
 	DBG("shm_mem_init: success\n");
 	
 	return 0;
 }
 
 
7c855aa0
 int shm_mem_init(int force_alloc)
fd92af47
 {
 	int ret;
11c0a282
 	long sz;
 	long* p;
 	long* end;
fd92af47
 	
 	ret=shm_getmem();
 	if (ret<0) return ret;
11c0a282
 	if (force_alloc){
 		sz=sysconf(_SC_PAGESIZE);
 		DBG("shm_mem_init: %ld bytes/page\n", sz);
 		if ((sz<sizeof(*p)) || (_ROUND_LONG(sz)!=sz)){
 			LOG(L_WARN, "shm_mem_init: invalid page size %ld, using 4096\n",
 					sz);
 			sz=4096; /* invalid page size, use 4096 */
 		}
 		end=shm_mempool+shm_mem_size-sizeof(*p);
 		/* touch one word in every page */
 		for(p=(long*)_ROUND_LONG((long)shm_mempool); p<=end;
 										p=(long*)((char*)p+sz))
 			*p=0; 
 	}
fd92af47
 	return shm_mem_init_mallocs(shm_mempool, shm_mem_size);
 }
 
628e3a5a
 
9f8a2ff6
 void shm_mem_destroy(void)
628e3a5a
 {
dcb5f364
 #ifndef SHM_MMAP
628e3a5a
 	struct shmid_ds shm_info;
dcb5f364
 #endif
628e3a5a
 	
 	DBG("shm_mem_destroy\n");
fbe11914
 #ifndef SHM_SAFE_MALLOC
dd0e65a8
 	if (mem_lock){
 		DBG("destroying the shared memory lock\n");
 		lock_destroy(mem_lock); /* we don't need to dealloc it*/
 	}
fbe11914
 #endif  /*SHM SAFE_MALLOC */
 	if (shm_block){
 		shm_malloc_destroy(shm_block);
 		shm_block=0;
 	}
628e3a5a
 	if (shm_mempool && (shm_mempool!=(void*)-1)) {
dcb5f364
 #ifdef SHM_MMAP
40a8d9dd
 		munmap(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
dcb5f364
 #else
628e3a5a
 		shmdt(shm_mempool);
dcb5f364
 #endif
628e3a5a
 		shm_mempool=(void*)-1;
 	}
dcb5f364
 #ifndef SHM_MMAP
628e3a5a
 	if (shm_shmid!=-1) {
 		shmctl(shm_shmid, IPC_RMID, &shm_info);
 		shm_shmid=-1;
 	}
dcb5f364
 #endif
628e3a5a
 }
 
 
 #endif