]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/cygheap.cc
* child_info: Bump child_info "version".
[newlib-cygwin.git] / winsup / cygwin / cygheap.cc
1 /* cygheap.cc: Cygwin heap manager.
2
3 Copyright 2000 Cygnus Solutions.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <errno.h>
13 #include <fhandler.h>
14 #include <assert.h>
15 #include <stdlib.h>
16 #include "cygheap.h"
17 #include "heap.h"
18 #include "cygerrno.h"
19 #include "sync.h"
20
21 void NO_COPY *cygheap = NULL;
22 void NO_COPY *cygheap_max = NULL;
23
24 static NO_COPY muto *cygheap_protect = NULL;
25
26 extern "C" void __stdcall
27 cygheap_init ()
28 {
29 cygheap_protect = new_muto (FALSE, "cygheap_protect");
30 }
31
32 inline static void
33 init_cheap ()
34 {
35 cygheap = VirtualAlloc (NULL, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS);
36 if (!cygheap)
37 api_fatal ("Couldn't reserve space for cygwin's heap, %E");
38 cygheap_max = (((char **) cygheap) + 1);
39 }
40
41 #define pagetrunc(x) ((void *) (((DWORD) (x)) & ~(4096 - 1)))
42
43 static void *__stdcall
44 _csbrk (int sbs)
45 {
46 void *lastheap;
47 bool needalloc;
48
49 if (cygheap)
50 needalloc = 0;
51 else
52 {
53 init_cheap ();
54 needalloc = 1;
55 }
56
57 lastheap = cygheap_max;
58 (char *) cygheap_max += sbs;
59 void *heapalign = (void *) pagetrunc (lastheap);
60
61 if (!needalloc)
62 needalloc = sbs && ((heapalign == lastheap) || heapalign != pagetrunc (cygheap_max));
63 if (needalloc && !VirtualAlloc (lastheap, (DWORD) sbs, MEM_COMMIT, PAGE_READWRITE))
64 api_fatal ("couldn't commit memory for cygwin heap, %E");
65
66 return lastheap;
67 }
68
69 /* Copyright (C) 1997, 2000 DJ Delorie */
70
71 #define NBUCKETS 32
72 char *buckets[NBUCKETS] = {0};
73 int bucket2size[NBUCKETS] = {0};
74
75 static inline int
76 size2bucket (int size)
77 {
78 int rv = 0x1f;
79 int bit = ~0x10;
80 int i;
81
82 if (size < 4)
83 size = 4;
84 size = (size + 3) & ~3;
85
86 for (i = 0; i < 5; i++)
87 {
88 if (bucket2size[rv & bit] >= size)
89 rv &= bit;
90 bit >>= 1;
91 }
92 return rv;
93 }
94
95 static inline void
96 init_buckets ()
97 {
98 unsigned b;
99 for (b = 0; b < NBUCKETS; b++)
100 bucket2size[b] = (1 << b);
101 }
102
103 struct _cmalloc_entry
104 {
105 union
106 {
107 DWORD b;
108 char *ptr;
109 };
110 struct _cmalloc_entry *prev;
111 char data[0];
112 };
113
114
115 #define N0 ((_cmalloc_entry *) NULL)
116 #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data)))
117 #define cygheap_chain ((_cmalloc_entry **)cygheap)
118
119 static void *__stdcall
120 _cmalloc (int size)
121 {
122 _cmalloc_entry *rvc;
123 int b;
124
125 if (bucket2size[0] == 0)
126 init_buckets ();
127
128 b = size2bucket (size);
129 cygheap_protect->acquire ();
130 if (buckets[b])
131 {
132 rvc = (_cmalloc_entry *) buckets[b];
133 buckets[b] = rvc->ptr;
134 rvc->b = b;
135 }
136 else
137 {
138 size = bucket2size[b] + sizeof (_cmalloc_entry);
139 rvc = (_cmalloc_entry *) _csbrk (size);
140
141 rvc->b = b;
142 rvc->prev = *cygheap_chain;
143 *cygheap_chain = rvc;
144 }
145 cygheap_protect->release ();
146 return rvc->data;
147 }
148
149 static void __stdcall
150 _cfree (void *ptr)
151 {
152 cygheap_protect->acquire ();
153 _cmalloc_entry *rvc = to_cmalloc (ptr);
154 DWORD b = rvc->b;
155 rvc->ptr = buckets[b];
156 buckets[b] = (char *) rvc;
157 cygheap_protect->release ();
158 }
159
160 static void *__stdcall
161 _crealloc (void *ptr, int size)
162 {
163 void *newptr;
164 if (ptr == NULL)
165 newptr = _cmalloc (size);
166 else
167 {
168 int oldsize = bucket2size[to_cmalloc (ptr)->b];
169 if (size <= oldsize)
170 return ptr;
171 newptr = _cmalloc (size);
172 memcpy (newptr, ptr, oldsize);
173 _cfree (ptr);
174 }
175 return newptr;
176 }
177
178 /* End Copyright (C) 1997 DJ Delorie */
179
180 #define sizeof_cygheap(n) ((n) + sizeof(cygheap_entry))
181
182 struct cygheap_entry
183 {
184 int type;
185 struct cygheap_entry *next;
186 char data[0];
187 };
188
189 #define N ((cygheap_entry *) NULL)
190 #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data)))
191
192 /* Called by fork or spawn to reallocate cygwin heap */
193 extern "C" void __stdcall
194 cygheap_fixup_in_child (HANDLE parent, bool execed)
195 {
196 DWORD m, n;
197 n = (DWORD) cygheap_max - (DWORD) cygheap;
198
199 /* Reserve cygwin heap in same spot as parent */
200 if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS))
201 api_fatal ("Couldn't reserve space for cygwin's heap in child, %E");
202
203 /* Allocate same amount of memory as parent */
204 if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE))
205 api_fatal ("Couldn't allocate space for child's heap %p, size %d, %E",
206 cygheap, n);
207
208 /* Copy memory from the parent */
209 m = 0;
210 n = (DWORD) pagetrunc (n + 4095);
211 if (!ReadProcessMemory (parent, cygheap, cygheap, n, &m) ||
212 m != n)
213 api_fatal ("Couldn't read parent's cygwin heap %d bytes != %d, %E",
214 n, m);
215
216 if (!execed)
217 return; /* Forked. Nothing extra to do. */
218
219 /* Walk the allocated memory chain looking for orphaned memory from
220 previous execs */
221 for (_cmalloc_entry *rvc = *cygheap_chain; rvc; rvc = rvc->prev)
222 {
223 cygheap_entry *ce = (cygheap_entry *) rvc->data;
224 if (rvc->b >= NBUCKETS || ce->type <= HEAP_1_START)
225 continue;
226 else if (ce->type < HEAP_1_MAX)
227 ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */
228 else
229 _cfree (ce); /* Marked by parent for freeing in child */
230 }
231 }
232
233 static void *__stdcall
234 creturn (cygheap_types x, cygheap_entry * c, int len)
235 {
236 if (!c)
237 {
238 __seterrno ();
239 return NULL;
240 }
241 c->type = x;
242 if (cygheap_max < ((char *) c + len))
243 cygheap_max = (char *) c + len;
244 MALLOC_CHECK;
245 return (void *) c->data;
246 }
247
248 extern "C" void *__stdcall
249 cmalloc (cygheap_types x, DWORD n)
250 {
251 cygheap_entry *c;
252 MALLOC_CHECK;
253 c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
254 if (!c)
255 system_printf ("cmalloc returned NULL");
256 return creturn (x, c, n);
257 }
258
259 extern "C" void *__stdcall
260 crealloc (void *s, DWORD n)
261 {
262 MALLOC_CHECK;
263 if (s == NULL)
264 return cmalloc (HEAP_STR, n); // kludge
265
266 assert (!inheap (s));
267 cygheap_entry *c = tocygheap (s);
268 cygheap_types t = (cygheap_types) c->type;
269 c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n));
270 if (!c)
271 system_printf ("crealloc returned NULL");
272 return creturn (t, c, n);
273 }
274
275 extern "C" void __stdcall
276 cfree (void *s)
277 {
278 MALLOC_CHECK;
279 assert (!inheap (s));
280 (void) _cfree (tocygheap (s));
281 MALLOC_CHECK;
282 }
283
284 extern "C" void *__stdcall
285 ccalloc (cygheap_types x, DWORD n, DWORD size)
286 {
287 cygheap_entry *c;
288 MALLOC_CHECK;
289 c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n * size));
290 if (c)
291 memset (c->data, 0, size);
292 if (!c)
293 system_printf ("ccalloc returned NULL");
294 return creturn (x, c, n);
295 }
296
297 extern "C" char *__stdcall
298 cstrdup (const char *s)
299 {
300 MALLOC_CHECK;
301 char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1);
302 if (!p)
303 return NULL;
304 strcpy (p, s);
305 MALLOC_CHECK;
306 return p;
307 }
308
309 extern "C" char *__stdcall
310 cstrdup1 (const char *s)
311 {
312 MALLOC_CHECK;
313 char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1);
314 if (!p)
315 return NULL;
316 strcpy (p, s);
317 MALLOC_CHECK;
318 return p;
319 }
This page took 0.051693 seconds and 6 git commands to generate.