Added GNU Configure script to build Makefiles.
[yaz-moved-to-github.git] / util / nmem.c
1 /*
2  * Copyright (c) 1995-1998, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: nmem.c,v $
7  * Revision 1.11  1998-08-21 14:13:36  adam
8  * Added GNU Configure script to build Makefiles.
9  *
10  * Revision 1.10  1998/07/20 12:35:57  adam
11  * Added more memory diagnostics (when NMEM_DEBUG is 1).
12  *
13  * Revision 1.9  1998/07/07 15:49:01  adam
14  * Reduced chunk size.
15  *
16  * Revision 1.8  1998/07/03 14:21:27  adam
17  * Added critical sections for pthreads-library. Thanks to Ian Ibbotson,
18  * Fretwell Downing Informatics.
19  *
20  * Revision 1.7  1998/02/11 11:53:36  adam
21  * Changed code so that it compiles as C++.
22  *
23  * Revision 1.6  1997/10/31 12:20:09  adam
24  * Improved memory debugging for xmalloc/nmem.c. References to NMEM
25  * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
26  * Bug fix: missing fclose in data1_read_espec1.
27  *
28  * Revision 1.5  1997/10/06 09:09:52  adam
29  * Function mmem_exit releases memory used by the freelists.
30  *
31  * Revision 1.4  1997/09/29 07:12:50  adam
32  * NMEM thread safe. NMEM must be initialized before use (sigh) -
33  * routine nmem_init/nmem_exit implemented.
34  *
35  * Revision 1.3  1997/07/21 12:47:38  adam
36  * Moved definition of nmem_control and nmem_block.
37  *
38  * Revision 1.2  1995/12/13 13:44:37  quinn
39  * Modified Data1-system to use nmem
40  *
41  * Revision 1.1  1995/11/13  09:27:52  quinn
42  * Fiddling with the variant stuff.
43  *
44  *
45  */
46
47 /*
48  * This is a simple and fairly wasteful little module for nibble memory
49  * allocation. Evemtually we'll put in something better.
50  */
51
52 #include <xmalloc.h>
53 #include <nmem.h>
54 #include <log.h>
55 #ifdef WINDOWS
56 #include <windows.h>
57 #elif _REENTRANT
58
59 #if HAVE_PTHREAD_H
60 #include <pthread.h>
61 #elif HAVE_THREAD_H
62 #include <thread.h>
63 #endif
64
65 #endif
66
67 #define NMEM_CHUNK (4*1024)
68
69 #ifdef WINDOWS
70 static CRITICAL_SECTION critical_section;
71 #define NMEM_ENTER EnterCriticalSection(&critical_section)
72 #define NMEM_LEAVE LeaveCriticalSection(&critical_section)
73 #elif _REENTRANT
74 static pthread_mutex_t nmem_mutex = PTHREAD_MUTEX_INITIALIZER;
75 #define NMEM_ENTER pthread_mutex_lock(&nmem_mutex);
76 #define NMEM_LEAVE pthread_mutex_unlock(&nmem_mutex);
77 #else
78 #define NMEM_ENTER
79 #define NMEM_LEAVE
80 #endif
81
82 static nmem_block *freelist = NULL;        /* "global" freelists */
83 static nmem_control *cfreelist = NULL;
84 static int nmem_active_no = 0;
85
86 static void free_block(nmem_block *p)
87 {  
88     p->next = freelist;
89     freelist = p;
90 #if NMEM_DEBUG
91     logf (LOG_DEBUG, "nmem free_block p=%p", p);
92 #endif
93 }
94
95 /*
96  * acquire a block with a minimum of size free bytes.
97  */
98 static nmem_block *get_block(int size)
99 {
100     nmem_block *r, *l;
101
102 #if NMEM_DEBUG
103     logf (LOG_DEBUG, "nmem get_block size=%d", size);
104 #endif
105     for (r = freelist, l = 0; r; l = r, r = r->next)
106         if (r->size >= size)
107             break;
108     if (r)
109     {
110 #if NMEM_DEBUG
111         logf (LOG_DEBUG, "nmem get_block found free block p=%p", r);
112 #endif
113         if (l)
114             l->next = r->next;
115         else
116             freelist = r->next;
117     }
118     else
119     {
120         int get = NMEM_CHUNK;
121
122         if (get < size)
123             get = size;
124 #if NMEM_DEBUG
125         logf (LOG_DEBUG, "nmem get_block alloc new block size=%d", get);
126 #endif
127         r = (nmem_block *)xmalloc(sizeof(*r));
128         r->buf = (char *)xmalloc(r->size = get);
129     }
130     r->top = 0;
131     return r;
132 }
133
134 void nmem_reset(NMEM n)
135 {
136     nmem_block *t;
137
138 #if NMEM_DEBUG
139     logf (LOG_DEBUG, "nmem_reset p=%p", n);
140 #endif
141     if (!n)
142         return;
143     NMEM_ENTER;
144     while (n->blocks)
145     {
146         t = n->blocks;
147         n->blocks = n->blocks->next;
148         free_block(t);
149     }
150     NMEM_LEAVE;
151     n->total = 0;
152 }
153
154 #if NMEM_DEBUG
155 void *nmem_malloc_f (const char *file, int line, NMEM n, int size)
156 #else
157 void *nmem_malloc(NMEM n, int size)
158 #endif
159 {
160     struct nmem_block *p;
161     char *r;
162
163 #if NMEM_DEBUG
164     logf (LOG_DEBUG, "%s:%d: nmem_malloc p=%p size=%d", file, line,
165                      n, size);
166 #endif
167     if (!n)
168         return xmalloc(size);
169     NMEM_ENTER;
170     p = n->blocks;
171     if (!p || p->size - p->top < size)
172     {
173         p = get_block(size);
174         p->next = n->blocks;
175         n->blocks = p;
176     }
177     r = p->buf + p->top;
178     /* align size */
179     p->top += (size + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
180     n->total += size;
181     NMEM_LEAVE;
182     return r;
183 }
184
185 int nmem_total(NMEM n)
186 {
187     return n->total;
188 }
189
190 #if NMEM_DEBUG
191 NMEM nmem_create_f(const char *file, int line)
192 #else
193 NMEM nmem_create(void)
194 #endif
195 {
196     NMEM r;
197     
198     NMEM_ENTER;
199     nmem_active_no++;
200     r = cfreelist;
201     if (r)
202         cfreelist = cfreelist->next;
203     else
204         r = (nmem_control *)xmalloc(sizeof(*r));
205     NMEM_LEAVE;
206
207 #if NMEM_DEBUG
208     logf (LOG_DEBUG, "%s:%d: nmem_create %d p=%p", file, line,
209                      nmem_active_no-1, r);
210 #endif
211     r->blocks = 0;
212     r->total = 0;
213     r->next = 0;
214     return r;
215 }
216
217 #if NMEM_DEBUG
218 void nmem_destroy_f(const char *file, int line, NMEM n)
219 #else
220 void nmem_destroy(NMEM n)
221 #endif
222 {
223     if (!n)
224         return;
225     nmem_reset(n);
226     NMEM_ENTER;
227     nmem_active_no--;
228     n->next = cfreelist;
229     cfreelist = n;
230     NMEM_LEAVE;
231 #if NMEM_DEBUG
232     logf (LOG_DEBUG, "%s:%d: nmem_destroy %d p=%p", file, line,
233                      nmem_active_no, n);
234 #endif
235 }
236
237 void nmem_init (void)
238 {
239 #ifdef WINDOWS
240     InitializeCriticalSection(&critical_section);
241 #endif
242     nmem_active_no = 0;
243     freelist = NULL;
244     cfreelist = NULL;
245 }
246
247 void nmem_exit (void)
248 {
249     while (freelist)
250     {
251         struct nmem_block *fl = freelist;
252         freelist = freelist->next;
253         xfree (fl->buf);
254         xfree (fl);
255     }
256     while (cfreelist)
257     {
258         struct nmem_control *cfl = cfreelist;
259         cfreelist = cfreelist->next;
260         xfree (cfl);
261     }
262 #ifdef WINDOWS
263     DeleteCriticalSection(&critical_section);
264 #endif
265 }
266