9df63472f545d8faf7ebe7a500e342fde097c419
[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.4  1997-09-29 07:12:50  adam
8  * NMEM thread safe. NMEM must be initialized before use (sigh) -
9  * routine nmem_init/nmem_exit implemented.
10  *
11  * Revision 1.3  1997/07/21 12:47:38  adam
12  * Moved definition of nmem_control and nmem_block.
13  *
14  * Revision 1.2  1995/12/13 13:44:37  quinn
15  * Modified Data1-system to use nmem
16  *
17  * Revision 1.1  1995/11/13  09:27:52  quinn
18  * Fiddling with the variant stuff.
19  *
20  *
21  */
22
23 /*
24  * This is a simple and fairly wasteful little module for nibble memory
25  * allocation. Evemtually we'll put in something better.
26  */
27
28 #include <xmalloc.h>
29 #include <nmem.h>
30 #ifdef WINDOWS
31 #include <windows.h>
32 #endif
33
34 #define NMEM_CHUNK (10*1024)
35
36 #ifdef WINDOWS
37 static CRITICAL_SECTION critical_section;
38 #define NMEM_ENTER EnterCriticalSection(&critical_section)
39 #define NMEM_LEAVE LeaveCriticalSection(&critical_section)
40 #else
41 #define NMEM_ENTER
42 #define NMEM_LEAVE
43 #endif
44
45 static nmem_block *freelist = NULL;        /* "global" freelists */
46 static nmem_control *cfreelist = NULL;
47
48 static void free_block(nmem_block *p)
49 {  
50     p->next = freelist;
51     freelist = p;
52 }
53
54 /*
55  * acquire a block with a minimum of size free bytes.
56  */
57 static nmem_block *get_block(int size)
58 {
59     nmem_block *r, *l;
60
61     for (r = freelist, l = 0; r; l = r, r = r->next)
62         if (r->size >= size)
63             break;
64     if (r)
65         if (l)
66             l->next = r->next;
67         else
68             freelist = r->next;
69     else
70     {
71         int get = NMEM_CHUNK;
72
73         if (get < size)
74             get = size;
75         r = xmalloc(sizeof(*r));
76         r->buf = xmalloc(r->size = get);
77     }
78     r->top = 0;
79     return r;
80 }
81
82 void nmem_reset(NMEM n)
83 {
84     nmem_block *t;
85
86     if (!n)
87         return;
88     NMEM_ENTER;
89     while (n->blocks)
90     {
91         t = n->blocks;
92         n->blocks = n->blocks->next;
93         free_block(t);
94     }
95     NMEM_LEAVE;
96     n->total = 0;
97 }
98
99 void *nmem_malloc(NMEM n, int size)
100 {
101     struct nmem_block *p;
102     char *r;
103
104     if (!n)
105         return xmalloc(size);
106     NMEM_ENTER;
107     p = n->blocks;
108     if (!p || p->size - p->top < size)
109     {
110         p = get_block(size);
111         p->next = n->blocks;
112         n->blocks = p;
113     }
114     r = p->buf + p->top;
115     /* align size */
116     p->top += (size + (sizeof(long) - 1)) & ~(sizeof(long) - 1);
117     n->total += size;
118     NMEM_LEAVE;
119     return r;
120 }
121
122 int nmem_total(NMEM n)
123 {
124     return n->total;
125 }
126
127 NMEM nmem_create(void)
128 {
129     NMEM r;
130     
131     NMEM_ENTER;
132     r = cfreelist;
133     if (r)
134         cfreelist = cfreelist->next;
135     else
136         r = xmalloc(sizeof(*r));
137     NMEM_LEAVE;
138     r->blocks = 0;
139     r->total = 0;
140     r->next = 0;
141     return r;
142 }
143
144 void nmem_destroy(NMEM n)
145 {
146     if (!n)
147         return;
148     nmem_reset(n);
149     NMEM_ENTER;
150     n->next = cfreelist;
151     cfreelist = n;
152     NMEM_LEAVE;
153 }
154
155 void nmem_init (void)
156 {
157 #ifdef WINDOWS
158     InitializeCriticalSection(&critical_section);
159 #endif
160     freelist = NULL;
161     cfreelist = NULL;
162 }
163
164 void nmem_exit (void)
165 {
166 #ifdef WINDOWS
167     DeleteCriticalSection(&critical_section);
168 #endif
169 }
170