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