aboutsummaryrefslogtreecommitdiffstats
path: root/mem_pool.c
blob: 56fc0ef78e04d0a6f284a89bbfcf588c4edba8d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include <sys/types.h>
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include "mem_pool.h"

#ifdef _THREAD_SAFE
pthread_mutex_t stat_mtx = PTHREAD_MUTEX_INITIALIZER;
#define STAT_LOCK() do { pthread_mutex_lock (&stat_mtx); } while (0)
#define STAT_UNLOCK() do { pthread_mutex_unlock (&stat_mtx); } while (0)
#else
#define STAT_LOCK() do {} while (0)
#define STAT_UNLOCK() do {} while (0)
#endif

/* Internal statistic */
static size_t bytes_allocated = 0;
static size_t chunks_allocated = 0;
static size_t chunks_freed = 0;

static struct _pool_chain *
pool_chain_new (size_t size) 
{
	struct _pool_chain *chain;
	chain = g_malloc (sizeof (struct _pool_chain));
	chain->begin = g_malloc (size);
	chain->len = size;
	chain->pos = chain->begin;
	chain->next = NULL;
	STAT_LOCK ();
	chunks_allocated ++;
	STAT_UNLOCK ();
	
	return chain;
}

memory_pool_t* 
memory_pool_new (size_t size)
{
	memory_pool_t *new;

	new = g_malloc (sizeof (memory_pool_t));
	new->cur_pool = pool_chain_new (size);
	new->first_pool = new->cur_pool;
	new->destructors = NULL;

	return new;
}

void *
memory_pool_alloc (memory_pool_t *pool, size_t size)
{
	u_char *tmp;
	struct _pool_chain *new, *cur;

	if (pool) {
		cur = pool->cur_pool;
		/* Find free space in pool chain */
		while (memory_pool_free (cur) < size && cur->next) {
			cur = cur->next;
		}
		if (cur->next == NULL && memory_pool_free (cur) < size) {
			/* Allocate new pool */
			if (cur->len >= size) {
				new = pool_chain_new (cur->len);
			}
			else {
				new = pool_chain_new (size + cur->len);
			}
			/* Attach new pool to chain */
			cur->next = new;
			pool->cur_pool = new;
			new->pos += size;
			STAT_LOCK ();
			bytes_allocated += size;
			STAT_UNLOCK ();
			return new->begin;
		}	
		tmp = cur->pos;
		cur->pos += size;
		STAT_LOCK ();
		bytes_allocated += size;
		STAT_UNLOCK ();
		return tmp;
	}
	return NULL;
}

void *
memory_pool_alloc0 (memory_pool_t *pool, size_t size)
{
	void *pointer = memory_pool_alloc (pool, size);
	if (pointer) {
		bzero (pointer, size);
	}
	return pointer;
}

char *
memory_pool_strdup (memory_pool_t *pool, const char *src)
{
	size_t len;
	char *newstr;

	if (src == NULL) {
		return NULL;
	}

	len = strlen (src);
	newstr = memory_pool_alloc (pool, len + 1);
	memcpy (newstr, src, len + 1);
	return newstr;
}

void
memory_pool_add_destructor (memory_pool_t *pool, pool_destruct_func func, void *data)
{
	struct _pool_destructors *cur;

	cur = memory_pool_alloc (pool, sizeof (struct _pool_destructors));
	if (cur) {
		cur->func = func;
		cur->data = data;
		cur->prev = pool->destructors;
		pool->destructors = cur;
	}
}

void
memory_pool_delete (memory_pool_t *pool)
{
	struct _pool_chain *cur = pool->first_pool, *tmp;
	struct _pool_destructors *destructor = pool->destructors;
	
	/* Call all pool destructors */
	while (destructor) {
		destructor->func (destructor->data);
		destructor = destructor->prev;
	}

	while (cur) {
		tmp = cur;
		cur = cur->next;
		g_free (tmp->begin);
		g_free (tmp);
		STAT_LOCK ();
		chunks_freed ++;
		STAT_UNLOCK ();
	}
	g_free (pool);
}

void
memory_pool_stat (memory_pool_stat_t *st)
{
	st->bytes_allocated = bytes_allocated;
	st->chunks_allocated = chunks_allocated;
	st->chunks_freed = chunks_freed;
}

/*
 * vi:ts=4
 */