d177c0745009dfb335b748c29593f8be6e280b97
[sip-router] / mem / shm_mem.c
1 /* $Id$
2  *
3  * Shared memory functions
4  *
5  * Copyright (C) 2001-2003 FhG Fokus
6  *
7  * This file is part of sip-router, a free SIP server.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 /*
22  * History:
23  * --------
24  *  2003-03-12  split shm_mem_init in shm_getmem & shm_mem_init_mallocs
25  *               (andrei)
26  *  2004-07-27  ANON mmap support, needed on darwin (andrei)
27  *  2004-09-19  shm_mem_destroy: destroy first the lock & then unmap (andrei)
28  *  2007-06-10   support for sfm_malloc & shm_malloc_destroy() (andrei)
29  */
30
31
32 #ifdef SHM_MEM
33
34 #include <stdlib.h>
35
36 #include "shm_mem.h"
37 #include "../config.h"
38 #include "../globals.h"
39 #include "memdbg.h"
40
41 #ifdef  SHM_MMAP
42
43 #include <unistd.h>
44 #include <sys/mman.h>
45 #include <sys/types.h> /*open*/
46 #include <sys/stat.h>
47 #include <fcntl.h>
48
49 #endif
50
51 #define _ROUND2TYPE(s, type) \
52         (((s)+(sizeof(type)-1))&(~(sizeof(type)-1)))
53 #define _ROUND_LONG(s) _ROUND2TYPE(s, long)
54
55
56 #ifndef SHM_MMAP
57 static int shm_shmid=-1; /*shared memory id*/
58 #endif
59
60 #ifndef SHM_SAFE_MALLOC
61 gen_lock_t* mem_lock=0;
62 #endif
63
64 static void* shm_mempool=(void*)-1;
65 #ifdef LL_MALLOC
66         struct sfm_block* shm_block;
67 #elif SF_MALLOC
68         struct sfm_block* shm_block;
69 #elif F_MALLOC
70         struct fm_block* shm_block;
71 #elif DL_MALLOC
72         mspace shm_block;
73 #else
74         struct qm_block* shm_block;
75 #endif
76
77
78 inline static void* sh_realloc(void* p, unsigned int size)
79 {
80         void *r;
81         shm_lock(); 
82         shm_free_unsafe(p);
83         r=shm_malloc_unsafe(size);
84         shm_unlock();
85         return r;
86 }
87
88 /* look at a buffer if there is perhaps enough space for the new size
89    (It is beneficial to do so because vq_malloc is pretty stateful
90     and if we ask for a new buffer size, we can still make it happy
91     with current buffer); if so, we return current buffer again;
92     otherwise, we free it, allocate a new one and return it; no
93     guarantee for buffer content; if allocation fails, we return
94     NULL
95 */
96
97 #ifdef DBG_QM_MALLOC
98 void* _shm_resize( void* p, unsigned int s, const char* file, const char* func,
99                                                         int line)
100 #else
101 void* _shm_resize( void* p , unsigned int s)
102 #endif
103 {
104         if (p==0) {
105                 DBG("WARNING:vqm_resize: resize(0) called\n");
106                 return shm_malloc( s );
107         }
108         return sh_realloc( p, s ); 
109 }
110
111
112
113
114
115 int shm_getmem()
116 {
117
118 #ifdef SHM_MMAP
119 #ifndef USE_ANON_MMAP
120         int fd;
121 #endif
122 #else
123         struct shmid_ds shm_info;
124 #endif
125
126 #ifdef SHM_MMAP
127         if (shm_mempool && (shm_mempool!=(void*)-1)){
128 #else
129         if ((shm_shmid!=-1)||(shm_mempool!=(void*)-1)){
130 #endif
131                 LOG(L_CRIT, "BUG: shm_mem_init: shm already initialized\n");
132                 return -1;
133         }
134         
135 #ifdef SHM_MMAP
136 #ifdef USE_ANON_MMAP
137         shm_mempool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE,
138                                          MAP_ANON|MAP_SHARED, -1 ,0);
139 #else
140         fd=open("/dev/zero", O_RDWR);
141         if (fd==-1){
142                 LOG(L_CRIT, "ERROR: shm_mem_init: could not open /dev/zero: %s\n",
143                                 strerror(errno));
144                 return -1;
145         }
146         shm_mempool=mmap(0, shm_mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd ,0);
147         /* close /dev/zero */
148         close(fd);
149 #endif /* USE_ANON_MMAP */
150 #else
151         
152         shm_shmid=shmget(IPC_PRIVATE, /* SHM_MEM_SIZE */ shm_mem_size , 0700);
153         if (shm_shmid==-1){
154                 LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate shared memory"
155                                 " segment: %s\n", strerror(errno));
156                 return -1;
157         }
158         shm_mempool=shmat(shm_shmid, 0, 0);
159 #endif
160         if (shm_mempool==(void*)-1){
161                 LOG(L_CRIT, "ERROR: shm_mem_init: could not attach shared memory"
162                                 " segment: %s\n", strerror(errno));
163                 /* destroy segment*/
164                 shm_mem_destroy();
165                 return -1;
166         }
167         return 0;
168 }
169
170
171
172 int shm_mem_init_mallocs(void* mempool, unsigned long pool_size)
173 {
174         /* init it for malloc*/
175         shm_block=shm_malloc_init(mempool, pool_size);
176         if (shm_block==0){
177                 LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize shared"
178                                 " malloc\n");
179                 shm_mem_destroy();
180                 return -1;
181         }
182 #ifndef SHM_SAFE_MALLOC
183         mem_lock=shm_malloc_unsafe(sizeof(gen_lock_t)); /* skip lock_alloc, 
184                                                                                                            race cond*/
185         if (mem_lock==0){
186                 LOG(L_CRIT, "ERROR: shm_mem_init: could not allocate lock\n");
187                 shm_mem_destroy();
188                 return -1;
189         }
190         if (lock_init(mem_lock)==0){
191                 LOG(L_CRIT, "ERROR: shm_mem_init: could not initialize lock\n");
192                 shm_mem_destroy();
193                 return -1;
194         }
195 #endif  /*SHM SAFE_MALLOC */
196         
197         DBG("shm_mem_init: success\n");
198         
199         return 0;
200 }
201
202
203 int shm_mem_init(int force_alloc)
204 {
205         int ret;
206         long sz;
207         long* p;
208         long* end;
209         
210         ret=shm_getmem();
211         if (ret<0) return ret;
212         if (force_alloc){
213                 sz=sysconf(_SC_PAGESIZE);
214                 DBG("shm_mem_init: %ld bytes/page\n", sz);
215                 if ((sz<sizeof(*p)) || (_ROUND_LONG(sz)!=sz)){
216                         LOG(L_WARN, "shm_mem_init: invalid page size %ld, using 4096\n",
217                                         sz);
218                         sz=4096; /* invalid page size, use 4096 */
219                 }
220                 end=shm_mempool+shm_mem_size-sizeof(*p);
221                 /* touch one word in every page */
222                 for(p=(long*)_ROUND_LONG((long)shm_mempool); p<=end;
223                                                                                 p=(long*)((char*)p+sz))
224                         *p=0; 
225         }
226         return shm_mem_init_mallocs(shm_mempool, shm_mem_size);
227 }
228
229
230 void shm_mem_destroy()
231 {
232 #ifndef SHM_MMAP
233         struct shmid_ds shm_info;
234 #endif
235         
236         DBG("shm_mem_destroy\n");
237 #ifndef SHM_SAFE_MALLOC
238         if (mem_lock){
239                 DBG("destroying the shared memory lock\n");
240                 lock_destroy(mem_lock); /* we don't need to dealloc it*/
241         }
242 #endif  /*SHM SAFE_MALLOC */
243         if (shm_block){
244                 shm_malloc_destroy(shm_block);
245                 shm_block=0;
246         }
247         if (shm_mempool && (shm_mempool!=(void*)-1)) {
248 #ifdef SHM_MMAP
249                 munmap(shm_mempool, /* SHM_MEM_SIZE */ shm_mem_size );
250 #else
251                 shmdt(shm_mempool);
252 #endif
253                 shm_mempool=(void*)-1;
254         }
255 #ifndef SHM_MMAP
256         if (shm_shmid!=-1) {
257                 shmctl(shm_shmid, IPC_RMID, &shm_info);
258                 shm_shmid=-1;
259         }
260 #endif
261 }
262
263
264 #endif