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