2 * Ethereal memory management and garbage collection functions
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 /* When required, allocate more memory from the OS in this size chunks */
38 #define EMEM_PACKET_CHUNK_SIZE 10485760
41 * Tools like Valgrind and ElectricFence don't work well with memchunks.
42 * Uncomment the defines below to make {ep|se}_alloc() allocate each
43 * object individually.
45 /* #define EP_DEBUG_FREE 1 */
46 /* #define SE_DEBUG_FREE 1 */
48 typedef struct _emem_chunk_t {
49 struct _emem_chunk_t *next;
50 unsigned int amount_free;
51 unsigned int free_offset;
55 typedef struct _emem_header_t {
56 emem_chunk_t *free_list;
57 emem_chunk_t *used_list;
60 static emem_header_t ep_packet_mem;
61 static emem_header_t se_packet_mem;
63 /* Initialize the packet-lifetime memory allocation pool.
64 * This function should be called only once when Etehreal or Tethereal starts
70 ep_packet_mem.free_list=NULL;
71 ep_packet_mem.used_list=NULL;
73 /* Initialize the capture-lifetime memory allocation pool.
74 * This function should be called only once when Etehreal or Tethereal starts
80 se_packet_mem.free_list=NULL;
81 se_packet_mem.used_list=NULL;
84 /* allocate 'size' amount of memory with an allocation lifetime until the
93 /* round up to 8 byte boundary */
95 size=(size+7)&0xfffffff8;
98 /* make sure we dont try to allocate too much (arbitrary limit) */
99 DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
101 /* we dont have any free data, so we must allocate a new one */
102 if(!ep_packet_mem.free_list){
104 npc=g_malloc(sizeof(emem_chunk_t));
106 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
108 npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE);
109 ep_packet_mem.free_list=npc;
112 /* oops, we need to allocate more memory to serve this request
113 * than we have free. move this node to the used list and try again
115 if(size>ep_packet_mem.free_list->amount_free){
117 npc=ep_packet_mem.free_list;
118 ep_packet_mem.free_list=ep_packet_mem.free_list->next;
119 npc->next=ep_packet_mem.used_list;
120 ep_packet_mem.used_list=npc;
123 /* we dont have any free data, so we must allocate a new one */
124 if(!ep_packet_mem.free_list){
126 npc=g_malloc(sizeof(emem_chunk_t));
128 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
130 npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE);
131 ep_packet_mem.free_list=npc;
135 buf=ep_packet_mem.free_list->buf+ep_packet_mem.free_list->free_offset;
137 ep_packet_mem.free_list->amount_free-=size;
138 ep_packet_mem.free_list->free_offset+=size;
140 #else /* EP_DEBUG_FREE */
143 npc=g_malloc(sizeof(emem_chunk_t));
144 npc->next=ep_packet_mem.used_list;
145 npc->amount_free=size;
147 npc->buf=g_malloc(size);
149 ep_packet_mem.used_list=npc;
150 #endif /* EP_DEBUG_FREE */
154 /* allocate 'size' amount of memory with an allocation lifetime until the
158 se_alloc(size_t size)
162 #ifndef SE_DEBUG_FREE
163 /* round up to 8 byte boundary */
165 size=(size+7)&0xfffffff8;
168 /* make sure we dont try to allocate too much (arbitrary limit) */
169 DISSECTOR_ASSERT(size<(EMEM_PACKET_CHUNK_SIZE>>2));
171 /* we dont have any free data, so we must allocate a new one */
172 if(!se_packet_mem.free_list){
174 npc=g_malloc(sizeof(emem_chunk_t));
176 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
178 npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE);
179 se_packet_mem.free_list=npc;
182 /* oops, we need to allocate more memory to serve this request
183 * than we have free. move this node to the used list and try again
185 if(size>se_packet_mem.free_list->amount_free){
187 npc=se_packet_mem.free_list;
188 se_packet_mem.free_list=se_packet_mem.free_list->next;
189 npc->next=se_packet_mem.used_list;
190 se_packet_mem.used_list=npc;
193 /* we dont have any free data, so we must allocate a new one */
194 if(!se_packet_mem.free_list){
196 npc=g_malloc(sizeof(emem_chunk_t));
198 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
200 npc->buf=g_malloc(EMEM_PACKET_CHUNK_SIZE);
201 se_packet_mem.free_list=npc;
205 buf=se_packet_mem.free_list->buf+se_packet_mem.free_list->free_offset;
207 se_packet_mem.free_list->amount_free-=size;
208 se_packet_mem.free_list->free_offset+=size;
210 #else /* SE_DEBUG_FREE */
213 npc=g_malloc(sizeof(emem_chunk_t));
214 npc->next=se_packet_mem_used_list;
215 npc->amount_free=size;
217 npc->buf=g_malloc(size);
219 se_packet_mem.used_list=npc;
220 #endif /* SE_DEBUG_FREE */
226 void* ep_alloc0(size_t size) {
227 return memset(ep_alloc(size),'\0',size);
230 gchar* ep_strdup(const gchar* src) {
231 guint len = strlen(src);
234 dst = strncpy(ep_alloc(len+1), src, len);
241 gchar* ep_strndup(const gchar* src, size_t len) {
242 guint actual_len = strlen(src);
245 if (len > actual_len)
248 dst = strncpy(ep_alloc(len+1), src, len);
255 guint8* ep_memdup(const guint8* src, size_t len) {
256 return memcpy(ep_alloc(len), src, len);
259 gchar* ep_strdup_printf(const gchar* fmt, ...) {
265 len = g_printf_string_upper_bound (fmt, ap);
267 dst = ep_alloc(len+1);
268 g_vsnprintf (dst, len, fmt, ap);
274 gchar** ep_strsplit(const gchar* string, const gchar* sep, int max_tokens) {
282 enum { AT_START, IN_PAD, IN_TOKEN } state;
290 s = splitted = ep_strdup(string);
291 str_len = strlen(splitted);
292 sep_len = strlen(sep);
294 if (max_tokens < 1) max_tokens = INT_MAX;
299 while (tokens <= (guint)max_tokens && ( s = strstr(s,sep) )) {
302 for(i=0; i < sep_len; i++ )
309 vec = ep_alloc_array(gchar*,tokens+1);
312 for (i=0; i< str_len; i++) {
315 switch(splitted[i]) {
320 vec[curr_tok] = &(splitted[i]);
326 switch(splitted[i]) {
333 switch(splitted[i]) {
335 vec[curr_tok] = &(splitted[i]);
344 vec[curr_tok] = NULL;
351 void* se_alloc0(size_t size) {
352 return memset(se_alloc(size),'\0',size);
355 gchar* se_strdup(const gchar* src) {
356 guint len = strlen(src);
359 dst = strncpy(se_alloc(len+1), src, len);
366 gchar* se_strndup(const gchar* src, size_t len) {
367 guint actual_len = strlen(src);
370 if (len > actual_len)
373 dst = strncpy(se_alloc(len+1), src, len);
380 guint8* se_memdup(const guint8* src, size_t len) {
381 return memcpy(se_alloc(len), src, len);
384 gchar* se_strdup_printf(const gchar* fmt, ...) {
390 len = g_printf_string_upper_bound (fmt, ap);
392 dst = se_alloc(len+1);
393 g_vsnprintf (dst, len, fmt, ap);
399 /* release all allocated memory back to the pool.
406 /* move all used chunks over to the free list */
407 while(ep_packet_mem.used_list){
408 npc=ep_packet_mem.used_list;
409 ep_packet_mem.used_list=ep_packet_mem.used_list->next;
410 npc->next=ep_packet_mem.free_list;
411 ep_packet_mem.free_list=npc;
414 /* clear them all out */
415 npc = ep_packet_mem.free_list;
416 while (npc != NULL) {
417 #ifndef EP_DEBUG_FREE
418 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
421 #else /* EP_DEBUG_FREE */
422 emem_chunk_t *next = npc->next;
427 #endif /* EP_DEBUG_FREE */
434 /* release all allocated memory back to the pool.
441 /* move all used chunks ove to the free list */
442 while(se_packet_mem.used_list){
443 npc=se_packet_mem.used_list;
444 se_packet_mem.used_list=se_packet_mem.used_list->next;
445 npc->next=se_packet_mem.free_list;
446 se_packet_mem.free_list=npc;
449 /* clear them all out */
450 npc = se_packet_mem.free_list;
451 while (npc != NULL) {
452 #ifndef SE_DEBUG_FREE
453 npc->amount_free=EMEM_PACKET_CHUNK_SIZE;
456 #else /* SE_DEBUG_FREE */
457 emem_chunk_t *next = npc->next;
462 #endif /* SE_DEBUG_FREE */