Improved memory debugging for xmalloc/nmem.c. References to NMEM
[yaz-moved-to-github.git] / util / nmem.c
1 /*
2  * Copyright (c) 1995-1997, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: nmem.c,v $
7  * Revision 1.6  1997-10-31 12:20:09  adam
8  * Improved memory debugging for xmalloc/nmem.c. References to NMEM
9  * instead of ODR in n ESPEC-1 handling in source d1_espec.c.
10  * Bug fix: missing fclose in data1_read_espec1.
11  *
12  * Revision 1.5  1997/10/06 09:09:52  adam
13  * Function mmem_exit releases memory used by the freelists.
14  *
15  * Revision 1.4  1997/09/29 07:12:50  adam
16  * NMEM thread safe. NMEM must be initialized before use (sigh) -
17  * routine nmem_init/nmem_exit implemented.
18  *
19  * Revision 1.3  1997/07/21 12:47:38  adam
20  * Moved definition of nmem_control and nmem_block.
21  *
22  * Revision 1.2  1995/12/13 13:44:37  quinn
23  * Modified Data1-system to use nmem
24  *
25  * Revision 1.1  1995/11/13  09:27:52  quinn
26  * Fiddling with the variant stuff.
27  *
28  *
29  */
30
31 /*
32  * This is a simple and fairly wasteful little module for nibble memory
33  * allocation. Evemtually we'll put in something better.
34  */
35
36 #include <xmalloc.h>
37 #include <nmem.h>
38 #include <log.h>
39 #ifdef WINDOWS
40 #include <windows.h>
41 #endif
42
43 #define NMEM_CHUNK (10*1024)
44
45 #ifdef WINDOWS
46 static CRITICAL_SECTION critical_section;
47 #define NMEM_ENTER EnterCriticalSection(&critical_section)
48 #define NMEM_LEAVE LeaveCriticalSection(&critical_section)
49 #else
50 #define NMEM_ENTER
51 #define NMEM_LEAVE
52 #endif
53
54 static nmem_block *freelist = NULL;        /* "global" freelists */
55 static nmem_control *cfreelist = NULL;
56 static int nmem_active_no = 0;
57
58 static void free_block(nmem_block *p)
59 {  
60     p->next = freelist;
61     freelist = p;
62 }
63
64 /*
65  * acquire a block with a minimum of size free bytes.
66  */
67 static nmem_block *get_block(int size)
68 {
69     nmem_block *r, *l;
70
71     for (r = freelist, l = 0; r; l = r, r = r->next)
72         if (r->size >= size)
73             break;
74     if (r)
75         if (l)
76             l->next = r->next;
77         else
78             freelist = r->next;
79     else
80     {
81         int get = NMEM_CHUNK;
82
83         if (get < size)
84             get = size;
85         r = xmalloc(sizeof(*r));
86         r->buf = xmalloc(r->size = get);
87     }
88     r->top = 0;
89     return r;
90 }
91
92 void nmem_reset(NMEM n)
93 {
94     nmem_block *t;
95
96     if (!n)
97         return;
98     NMEM_ENTER;
99     while (n->blocks)
100     {
101         t = n->blocks;
102         n->blocks = n->blocks->next;
103         free_block(t);
104     }
105     NMEM_LEAVE;
106     n->total = 0;
107 }
108
109 void *nmem_malloc(NMEM n, int size)
110 {
111     struct nmem_block *p;
112     char *r;
113
114     if (!n)
115         return xmalloc(size);
116     NMEM_ENTER;
117     p = n->blocks;
118     if (!p || p->size - p->top < size)
119     {
120         p = get_block(size);
121         p->next = n->blocks;
122         n->blocks = p;
123     }
124     r = p->buf + p->top;
125     /* align size */
126     p->top += (size + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
127     n->total += size;
128     NMEM_LEAVE;
129     return r;
130 }
131
132 int nmem_total(NMEM n)
133 {
134     return n->total;
135 }
136
137 #if NMEM_DEBUG
138 NMEM nmem_create_f(const char *file, int line)
139 #else
140 NMEM nmem_create(void)
141 #endif
142 {
143     NMEM r;
144     
145     NMEM_ENTER;
146     nmem_active_no++;
147     r = cfreelist;
148     if (r)
149         cfreelist = cfreelist->next;
150     else
151         r = xmalloc(sizeof(*r));
152     NMEM_LEAVE;
153
154 #if NMEM_DEBUG
155     logf (LOG_DEBUG, "%s:%d: nmem_create %d p=%p", file, line,
156                      nmem_active_no-1, r);
157 #endif
158     r->blocks = 0;
159     r->total = 0;
160     r->next = 0;
161     return r;
162 }
163
164 #if NMEM_DEBUG
165 void nmem_destroy_f(const char *file, int line, NMEM n)
166 #else
167 void nmem_destroy(NMEM n)
168 #endif
169 {
170     if (!n)
171         return;
172     nmem_reset(n);
173     NMEM_ENTER;
174     nmem_active_no--;
175     n->next = cfreelist;
176     cfreelist = n;
177     NMEM_LEAVE;
178 #if NMEM_DEBUG
179     logf (LOG_DEBUG, "%s:%d: nmem_destroy %d p=%p", file, line,
180                      nmem_active_no, n);
181 #endif
182 }
183
184 void nmem_init (void)
185 {
186 #ifdef WINDOWS
187     InitializeCriticalSection(&critical_section);
188 #endif
189     nmem_active_no = 0;
190     freelist = NULL;
191     cfreelist = NULL;
192 }
193
194 void nmem_exit (void)
195 {
196     while (freelist)
197     {
198         struct nmem_block *fl = freelist;
199         freelist = freelist->next;
200         xfree (fl->buf);
201         xfree (fl);
202     }
203     while (cfreelist)
204     {
205         struct nmem_control *cfl = cfreelist;
206         cfreelist = cfreelist->next;
207         xfree (cfl);
208     }
209 #ifdef WINDOWS
210     DeleteCriticalSection(&critical_section);
211 #endif
212 }
213