Re-import of fprobe-ulog
[fprobe-ulog.git] / trunk / src / mem.c
1 /*
2         Copyright (C) Slava Astashonok <sla@0n.ru>
3
4         This program is free software; you can redistribute it and/or
5         modify it under the terms of the GNU General Public License.
6
7         $Id: mem.c,v 1.4.2.2.2.1 2005/01/29 19:30:41 sla Exp $
8 */
9
10 #include <common.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <my_log.h>
15 #include <errno.h>
16 #include <mem.h>
17
18 #ifdef MEM_THREADSAFE
19 #include <pthread.h>
20 #endif
21
22 #ifdef MEM_THREADSAFE
23 static pthread_mutex_t mem_mutex = PTHREAD_MUTEX_INITIALIZER;
24 #endif
25 static struct Mem *root;
26 unsigned int total_elements;
27 unsigned int free_elements;
28 static unsigned int element_size;
29 static unsigned int bulk_quantity;
30 static unsigned int limit_memory;
31 unsigned int total_memory;
32 static unsigned int mem_index_table_size;
33 static unsigned int element_table_size;
34 static unsigned int malloc_size;
35
36 void *mem_alloc()
37 {
38         unsigned int i;
39         struct Mem *mptr;
40         mem_index_t *iptr;
41 #if MEM_BITS == 0
42         void *eptr;
43 #endif
44
45 #ifdef MEM_THREADSAFE
46         pthread_mutex_lock(&mem_mutex);
47 #endif
48         if (!free_elements) {
49                 if (limit_memory && (total_memory + malloc_size) > limit_memory) {
50 #if ((DEBUG) & DEBUG_M)
51                         my_log(LOG_DEBUG, "M: limit exhausted");
52 #endif
53                         mptr = 0;
54                         errno = ENOMEM;
55                         goto done;
56                 }
57                 if (!(mptr = calloc(malloc_size, 1))) goto done;
58                 iptr = (void *) mptr + sizeof(struct Mem);
59 #if MEM_BITS == 0
60                 eptr = (void *) iptr + mem_index_table_size;
61 #endif
62                 for (i = 0; i < bulk_quantity; i++) {
63 #if MEM_BITS == 0
64                         *iptr++ = eptr;
65                         eptr += element_size;
66 #else
67                         *iptr++ = i;
68 #endif
69                 }
70                 mptr->free = bulk_quantity - 1;
71                 free_elements += mptr->free;
72                 total_elements += bulk_quantity;
73                 total_memory += malloc_size;
74                 mptr->first = iptr;
75                 mptr->last = (void *) iptr + element_table_size - element_size;
76                 mptr->next = root;
77                 root = mptr;
78 #if ((DEBUG) & DEBUG_M)
79                 my_log(LOG_DEBUG, "M: alloc bulk: base:%x first:%x last:%x",
80                         mptr, mptr->first, mptr->last);
81                 my_log(LOG_DEBUG, "M: mem: total: %d (%dKB), free: %d",
82                         total_elements, total_memory >> 10, free_elements);
83 #endif
84                 mptr = mptr->last;
85                 goto done;
86         }
87
88         mptr = root;
89         while (mptr->free == 0) mptr = mptr->next;
90         mptr->free--;
91         free_elements--;
92         iptr = (void *) mptr + sizeof(struct Mem);
93 #if MEM_BITS == 0
94         mptr = iptr[mptr->free];
95 #else
96         mptr = mptr->first + iptr[mptr->free] * element_size;
97 #endif
98
99 done:
100 #if ((DEBUG) & DEBUG_M)
101         my_log(LOG_DEBUG, "M: alloc: %x", mptr);
102 #endif
103 #ifdef MEM_THREADSAFE
104         pthread_mutex_unlock(&mem_mutex);
105 #endif
106         return mptr;
107 }
108
109 void mem_free(void *eptr)
110 {
111         mem_index_t *iptr;
112         struct Mem *mptr, **pptr;
113
114 #ifdef MEM_THREADSAFE
115         pthread_mutex_lock(&mem_mutex);
116 #endif
117 #if ((DEBUG) & DEBUG_M)
118         my_log(LOG_DEBUG, "M: free: %x", eptr);
119 #endif
120         mptr = root;
121         pptr = &root;
122         while (mptr->first > eptr || mptr->last < eptr) {
123                 pptr = &mptr->next;
124                 mptr = mptr->next;
125         }
126         iptr = (void *) mptr + sizeof(struct Mem);
127 #if MEM_BITS == 0
128         iptr[mptr->free] = eptr;
129 #else
130         iptr[mptr->free] = (eptr - mptr->first) / element_size;
131 #endif
132         mptr->free++;
133         free_elements++;
134         if (mptr->free == bulk_quantity) {
135 #if ((DEBUG) & DEBUG_M)
136                 my_log(LOG_DEBUG, "M: free bulk: base:%x first:%x last:%x",
137                         mptr, mptr->first, mptr->last);
138 #endif
139                 *pptr = mptr->next;
140                 free(mptr);
141                 total_elements -= bulk_quantity;
142                 free_elements -= bulk_quantity;
143                 total_memory -= malloc_size;
144 #if ((DEBUG) & DEBUG_M)
145                 my_log(LOG_DEBUG, "M: mem: total: %d (%dKB), free: %d",
146                         total_elements, total_memory >> 10, free_elements);
147 #endif
148         }
149 #ifdef MEM_THREADSAFE
150         pthread_mutex_unlock(&mem_mutex);
151 #endif
152 }
153
154 int mem_init(unsigned int element, unsigned int bulk, unsigned int limit)
155 {
156         bulk_quantity = (unsigned) (mem_index_t) bulk; /* for safety: movzbl, movzwl */
157         mem_index_table_size = sizeof(mem_index_t) * bulk_quantity;
158         element_size = element;
159         element_table_size = element_size * bulk_quantity;
160         malloc_size = sizeof(struct Mem) + mem_index_table_size + element_table_size;
161         limit_memory = limit;
162 #if ((DEBUG) & DEBUG_M)
163         my_log(LOG_DEBUG, "M: init: element size:%d quantity:%d bulk size:%d limit:%d",
164                 element_size, bulk_quantity, malloc_size, limit_memory);
165 #endif
166         return 0;
167 }