1 | /*
|
---|
2 | * Copyright (c) 1995-2000, Index Data.
|
---|
3 | * See the file LICENSE for details.
|
---|
4 | * Sebastian Hammer, Adam Dickmeiss
|
---|
5 | *
|
---|
6 | * $Log$
|
---|
7 | * Revision 1.1 2000/08/03 03:12:08 johnmcp
|
---|
8 | * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
|
---|
9 | *
|
---|
10 | * Revision 1.21 2000/02/29 13:44:55 adam
|
---|
11 | * Check for config.h (currently not generated).
|
---|
12 | *
|
---|
13 | * Revision 1.20 2000/01/06 14:59:13 adam
|
---|
14 | * Added oid_init/oid_exit. Changed oid_exit.
|
---|
15 | *
|
---|
16 | * Revision 1.19 1999/11/30 13:47:12 adam
|
---|
17 | * Improved installation. Moved header files to include/yaz.
|
---|
18 | *
|
---|
19 | * Revision 1.18 1999/08/27 09:40:32 adam
|
---|
20 | * Renamed logf function to yaz_log. Removed VC++ project files.
|
---|
21 | *
|
---|
22 | * Revision 1.17 1999/07/13 13:28:25 adam
|
---|
23 | * Better debugging for NMEM routines.
|
---|
24 | *
|
---|
25 | * Revision 1.16 1999/03/31 11:18:25 adam
|
---|
26 | * Implemented odr_strdup. Added Reference ID to backend server API.
|
---|
27 | *
|
---|
28 | * Revision 1.15 1999/02/11 09:10:26 adam
|
---|
29 | * Function nmem_init only mandatory on Windows.
|
---|
30 | *
|
---|
31 | * Revision 1.14 1999/02/02 13:57:40 adam
|
---|
32 | * Uses preprocessor define WIN32 instead of WINDOWS to build code
|
---|
33 | * for Microsoft WIN32.
|
---|
34 | *
|
---|
35 | * Revision 1.13 1998/10/19 15:24:21 adam
|
---|
36 | * New nmem utility, nmem_transfer, that transfer blocks from one
|
---|
37 | * NMEM to another.
|
---|
38 | *
|
---|
39 | * Revision 1.12 1998/10/13 16:00:18 adam
|
---|
40 | * Implemented nmem_critical_{enter,leave}.
|
---|
41 | *
|
---|
42 | * Revision 1.11 1998/08/21 14:13:36 adam
|
---|
43 | * Added GNU Configure script to build Makefiles.
|
---|
44 | *
|
---|
45 | * Revision 1.10 1998/07/20 12:35:57 adam
|
---|
46 | * Added more memory diagnostics (when NMEM_DEBUG is 1).
|
---|
47 | *
|
---|
48 | * Revision 1.9 1998/07/07 15:49:01 adam
|
---|
49 | * Reduced chunk size.
|
---|
50 | *
|
---|
51 | * Revision 1.8 1998/07/03 14:21:27 adam
|
---|
52 | * Added critical sections for pthreads-library. Thanks to Ian Ibbotson,
|
---|
53 | * Fretwell Downing Informatics.
|
---|
54 | *
|
---|
55 | * Revision 1.7 1998/02/11 11:53:36 adam
|
---|
56 | * Changed code so that it compiles as C++.
|
---|
57 | *
|
---|
58 | * Revision 1.6 1997/10/31 12:20:09 adam
|
---|
59 | * Improved memory debugging for xmalloc/nmem.c. References to NMEM
|
---|
60 | * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
|
---|
61 | * Bug fix: missing fclose in data1_read_espec1.
|
---|
62 | *
|
---|
63 | * Revision 1.5 1997/10/06 09:09:52 adam
|
---|
64 | * Function mmem_exit releases memory used by the freelists.
|
---|
65 | *
|
---|
66 | * Revision 1.4 1997/09/29 07:12:50 adam
|
---|
67 | * NMEM thread safe. NMEM must be initialized before use (sigh) -
|
---|
68 | * routine nmem_init/nmem_exit implemented.
|
---|
69 | *
|
---|
70 | * Revision 1.3 1997/07/21 12:47:38 adam
|
---|
71 | * Moved definition of nmem_control and nmem_block.
|
---|
72 | *
|
---|
73 | * Revision 1.2 1995/12/13 13:44:37 quinn
|
---|
74 | * Modified Data1-system to use nmem
|
---|
75 | *
|
---|
76 | * Revision 1.1 1995/11/13 09:27:52 quinn
|
---|
77 | * Fiddling with the variant stuff.
|
---|
78 | *
|
---|
79 | *
|
---|
80 | */
|
---|
81 |
|
---|
82 | /*
|
---|
83 | * This is a simple and fairly wasteful little module for nibble memory
|
---|
84 | * allocation. Evemtually we'll put in something better.
|
---|
85 | */
|
---|
86 | #if HAVE_CONFIG_H
|
---|
87 | #include <config.h>
|
---|
88 | #endif
|
---|
89 |
|
---|
90 | #include <assert.h>
|
---|
91 | #include <string.h>
|
---|
92 | #include <yaz/xmalloc.h>
|
---|
93 | #include <yaz/nmem.h>
|
---|
94 | #include <yaz/log.h>
|
---|
95 | #ifdef WIN32
|
---|
96 | #include <windows.h>
|
---|
97 | #elif _REENTRANT
|
---|
98 |
|
---|
99 | #if HAVE_PTHREAD_H
|
---|
100 | #include <pthread.h>
|
---|
101 | #elif HAVE_THREAD_H
|
---|
102 | #include <thread.h>
|
---|
103 | #endif
|
---|
104 |
|
---|
105 | #endif
|
---|
106 |
|
---|
107 | #define NMEM_CHUNK (4*1024)
|
---|
108 |
|
---|
109 | #ifdef WIN32
|
---|
110 | static CRITICAL_SECTION critical_section;
|
---|
111 | #define NMEM_ENTER EnterCriticalSection(&critical_section)
|
---|
112 | #define NMEM_LEAVE LeaveCriticalSection(&critical_section)
|
---|
113 | #elif _REENTRANT
|
---|
114 | static pthread_mutex_t nmem_mutex = PTHREAD_MUTEX_INITIALIZER;
|
---|
115 | #define NMEM_ENTER pthread_mutex_lock(&nmem_mutex);
|
---|
116 | #define NMEM_LEAVE pthread_mutex_unlock(&nmem_mutex);
|
---|
117 | #else
|
---|
118 | #define NMEM_ENTER
|
---|
119 | #define NMEM_LEAVE
|
---|
120 | #endif
|
---|
121 |
|
---|
122 | static nmem_block *freelist = NULL; /* "global" freelists */
|
---|
123 | static nmem_control *cfreelist = NULL;
|
---|
124 | static int nmem_active_no = 0;
|
---|
125 | static int nmem_init_flag = 0;
|
---|
126 |
|
---|
127 | #if NMEM_DEBUG
|
---|
128 | struct nmem_debug {
|
---|
129 | void *p;
|
---|
130 | char file[40];
|
---|
131 | int line;
|
---|
132 | struct nmem_debug *next;
|
---|
133 | };
|
---|
134 |
|
---|
135 | struct nmem_debug *nmem_debug_list = 0;
|
---|
136 | #endif
|
---|
137 |
|
---|
138 | static void free_block(nmem_block *p)
|
---|
139 | {
|
---|
140 | p->next = freelist;
|
---|
141 | freelist = p;
|
---|
142 | #if NMEM_DEBUG
|
---|
143 | yaz_log (LOG_DEBUG, "nmem free_block p=%p", p);
|
---|
144 | #endif
|
---|
145 | }
|
---|
146 |
|
---|
147 | #if NMEM_DEBUG
|
---|
148 | void nmem_print_list (void)
|
---|
149 | {
|
---|
150 | struct nmem_debug *p;
|
---|
151 |
|
---|
152 | yaz_log (LOG_DEBUG, "nmem print list");
|
---|
153 | NMEM_ENTER;
|
---|
154 | for (p = nmem_debug_list; p; p = p->next)
|
---|
155 | yaz_log (LOG_DEBUG, " %s:%d p=%p", p->file, p->line, p->p);
|
---|
156 | NMEM_LEAVE;
|
---|
157 | }
|
---|
158 | #endif
|
---|
159 | /*
|
---|
160 | * acquire a block with a minimum of size free bytes.
|
---|
161 | */
|
---|
162 | static nmem_block *get_block(int size)
|
---|
163 | {
|
---|
164 | nmem_block *r, *l;
|
---|
165 |
|
---|
166 | #if NMEM_DEBUG
|
---|
167 | yaz_log (LOG_DEBUG, "nmem get_block size=%d", size);
|
---|
168 | #endif
|
---|
169 | for (r = freelist, l = 0; r; l = r, r = r->next)
|
---|
170 | if (r->size >= size)
|
---|
171 | break;
|
---|
172 | if (r)
|
---|
173 | {
|
---|
174 | #if NMEM_DEBUG
|
---|
175 | yaz_log (LOG_DEBUG, "nmem get_block found free block p=%p", r);
|
---|
176 | #endif
|
---|
177 | if (l)
|
---|
178 | l->next = r->next;
|
---|
179 | else
|
---|
180 | freelist = r->next;
|
---|
181 | }
|
---|
182 | else
|
---|
183 | {
|
---|
184 | int get = NMEM_CHUNK;
|
---|
185 |
|
---|
186 | if (get < size)
|
---|
187 | get = size;
|
---|
188 | #if NMEM_DEBUG
|
---|
189 | yaz_log (LOG_DEBUG, "nmem get_block alloc new block size=%d", get);
|
---|
190 | #endif
|
---|
191 | r = (nmem_block *)xmalloc(sizeof(*r));
|
---|
192 | r->buf = (char *)xmalloc(r->size = get);
|
---|
193 | }
|
---|
194 | r->top = 0;
|
---|
195 | return r;
|
---|
196 | }
|
---|
197 |
|
---|
198 | void nmem_reset(NMEM n)
|
---|
199 | {
|
---|
200 | nmem_block *t;
|
---|
201 |
|
---|
202 | #if NMEM_DEBUG
|
---|
203 | yaz_log (LOG_DEBUG, "nmem_reset p=%p", n);
|
---|
204 | #endif
|
---|
205 | if (!n)
|
---|
206 | return;
|
---|
207 | NMEM_ENTER;
|
---|
208 | while (n->blocks)
|
---|
209 | {
|
---|
210 | t = n->blocks;
|
---|
211 | n->blocks = n->blocks->next;
|
---|
212 | free_block(t);
|
---|
213 | }
|
---|
214 | n->total = 0;
|
---|
215 | NMEM_LEAVE;
|
---|
216 | }
|
---|
217 |
|
---|
218 | #if NMEM_DEBUG
|
---|
219 | void *nmem_malloc_f (const char *file, int line, NMEM n, int size)
|
---|
220 | #else
|
---|
221 | void *nmem_malloc(NMEM n, int size)
|
---|
222 | #endif
|
---|
223 | {
|
---|
224 | struct nmem_block *p;
|
---|
225 | char *r;
|
---|
226 |
|
---|
227 | #if NMEM_DEBUG
|
---|
228 | yaz_log (LOG_DEBUG, "%s:%d: nmem_malloc p=%p size=%d", file, line,
|
---|
229 | n, size);
|
---|
230 | #endif
|
---|
231 | if (!n)
|
---|
232 | {
|
---|
233 | abort ();
|
---|
234 | return xmalloc(size);
|
---|
235 | }
|
---|
236 | #ifdef WIN32
|
---|
237 | assert (nmem_init_flag);
|
---|
238 | #endif
|
---|
239 | NMEM_ENTER;
|
---|
240 | p = n->blocks;
|
---|
241 | if (!p || p->size - p->top < size)
|
---|
242 | {
|
---|
243 | p = get_block(size);
|
---|
244 | p->next = n->blocks;
|
---|
245 | n->blocks = p;
|
---|
246 | }
|
---|
247 | r = p->buf + p->top;
|
---|
248 | /* align size */
|
---|
249 | p->top += (size + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
|
---|
250 | n->total += size;
|
---|
251 | NMEM_LEAVE;
|
---|
252 | return r;
|
---|
253 | }
|
---|
254 |
|
---|
255 | int nmem_total(NMEM n)
|
---|
256 | {
|
---|
257 | return n->total;
|
---|
258 | }
|
---|
259 |
|
---|
260 | #if NMEM_DEBUG
|
---|
261 | NMEM nmem_create_f(const char *file, int line)
|
---|
262 | #else
|
---|
263 | NMEM nmem_create(void)
|
---|
264 | #endif
|
---|
265 | {
|
---|
266 | NMEM r;
|
---|
267 | #if NMEM_DEBUG
|
---|
268 | struct nmem_debug *debug_p;
|
---|
269 | #endif
|
---|
270 |
|
---|
271 | NMEM_ENTER;
|
---|
272 | nmem_active_no++;
|
---|
273 | r = cfreelist;
|
---|
274 | if (r)
|
---|
275 | cfreelist = cfreelist->next;
|
---|
276 | else
|
---|
277 | r = (nmem_control *)xmalloc(sizeof(*r));
|
---|
278 | NMEM_LEAVE;
|
---|
279 |
|
---|
280 | #if NMEM_DEBUG
|
---|
281 | yaz_log (LOG_DEBUG, "%s:%d: nmem_create %d p=%p", file, line,
|
---|
282 | nmem_active_no, r);
|
---|
283 | #endif
|
---|
284 | r->blocks = 0;
|
---|
285 | r->total = 0;
|
---|
286 | r->next = 0;
|
---|
287 |
|
---|
288 | #if NMEM_DEBUG
|
---|
289 | for (debug_p = nmem_debug_list; debug_p; debug_p = debug_p->next)
|
---|
290 | if (debug_p->p == r)
|
---|
291 | {
|
---|
292 | yaz_log (LOG_FATAL, "multi used block in nmem");
|
---|
293 | abort ();
|
---|
294 | }
|
---|
295 | debug_p = xmalloc (sizeof(*debug_p));
|
---|
296 | strncpy (debug_p->file, file, sizeof(debug_p->file)-1);
|
---|
297 | debug_p->file[sizeof(debug_p->file)-1] = '\0';
|
---|
298 | debug_p->line = line;
|
---|
299 | debug_p->p = r;
|
---|
300 | debug_p->next = nmem_debug_list;
|
---|
301 | nmem_debug_list = debug_p;
|
---|
302 |
|
---|
303 | nmem_print_list();
|
---|
304 | #endif
|
---|
305 | return r;
|
---|
306 | }
|
---|
307 |
|
---|
308 | #if NMEM_DEBUG
|
---|
309 | void nmem_destroy_f(const char *file, int line, NMEM n)
|
---|
310 | #else
|
---|
311 | void nmem_destroy(NMEM n)
|
---|
312 | #endif
|
---|
313 | {
|
---|
314 | #if NMEM_DEBUG
|
---|
315 | struct nmem_debug **debug_p;
|
---|
316 | int ok = 0;
|
---|
317 | #endif
|
---|
318 | if (!n)
|
---|
319 | return;
|
---|
320 |
|
---|
321 | #if NMEM_DEBUG
|
---|
322 | yaz_log (LOG_DEBUG, "%s:%d: nmem_destroy %d p=%p", file, line,
|
---|
323 | nmem_active_no-1, n);
|
---|
324 | NMEM_ENTER;
|
---|
325 | for (debug_p = &nmem_debug_list; *debug_p; debug_p = &(*debug_p)->next)
|
---|
326 | if ((*debug_p)->p == n)
|
---|
327 | {
|
---|
328 | struct nmem_debug *debug_save = *debug_p;
|
---|
329 | *debug_p = (*debug_p)->next;
|
---|
330 | xfree (debug_save);
|
---|
331 | ok = 1;
|
---|
332 | break;
|
---|
333 | }
|
---|
334 | NMEM_LEAVE;
|
---|
335 | nmem_print_list();
|
---|
336 | if (!ok)
|
---|
337 | {
|
---|
338 | yaz_log (LOG_WARN, "%s:%d destroying unallocated nmem block p=%p",
|
---|
339 | file, line, n);
|
---|
340 | return;
|
---|
341 | }
|
---|
342 | #endif
|
---|
343 | nmem_reset(n);
|
---|
344 | NMEM_ENTER;
|
---|
345 | nmem_active_no--;
|
---|
346 | n->next = cfreelist;
|
---|
347 | cfreelist = n;
|
---|
348 | NMEM_LEAVE;
|
---|
349 | }
|
---|
350 |
|
---|
351 | void nmem_transfer (NMEM dst, NMEM src)
|
---|
352 | {
|
---|
353 | nmem_block *t;
|
---|
354 | while ((t=src->blocks))
|
---|
355 | {
|
---|
356 | src->blocks = t->next;
|
---|
357 | t->next = dst->blocks;
|
---|
358 | dst->blocks = t;
|
---|
359 | }
|
---|
360 | dst->total += src->total;
|
---|
361 | src->total = 0;
|
---|
362 | }
|
---|
363 |
|
---|
364 | void nmem_critical_enter (void)
|
---|
365 | {
|
---|
366 | NMEM_ENTER;
|
---|
367 | }
|
---|
368 |
|
---|
369 | void nmem_critical_leave (void)
|
---|
370 | {
|
---|
371 | NMEM_LEAVE;
|
---|
372 | }
|
---|
373 |
|
---|
374 | void nmem_init (void)
|
---|
375 | {
|
---|
376 | nmem_init_flag = 1;
|
---|
377 | #ifdef WIN32
|
---|
378 | InitializeCriticalSection(&critical_section);
|
---|
379 | #endif
|
---|
380 | nmem_active_no = 0;
|
---|
381 | freelist = NULL;
|
---|
382 | cfreelist = NULL;
|
---|
383 | }
|
---|
384 |
|
---|
385 | void nmem_exit (void)
|
---|
386 | {
|
---|
387 | while (freelist)
|
---|
388 | {
|
---|
389 | struct nmem_block *fl = freelist;
|
---|
390 | freelist = freelist->next;
|
---|
391 | xfree (fl->buf);
|
---|
392 | xfree (fl);
|
---|
393 | }
|
---|
394 | while (cfreelist)
|
---|
395 | {
|
---|
396 | struct nmem_control *cfl = cfreelist;
|
---|
397 | cfreelist = cfreelist->next;
|
---|
398 | xfree (cfl);
|
---|
399 | }
|
---|
400 | nmem_init_flag = 0;
|
---|
401 | #ifdef WIN32
|
---|
402 | DeleteCriticalSection(&critical_section);
|
---|
403 | #endif
|
---|
404 | }
|
---|
405 |
|
---|