]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/cygheap.cc
* pinfo.cc (pinfo::init): Reverse order of setting status and pid info in an
[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
74 struct _cmalloc_entry
75 {
76 union
77 {
78 DWORD b;
79 char *ptr;
80 };
81 struct _cmalloc_entry *prev;
82 char data[0];
83 };
84
85
86 #define N0 ((_cmalloc_entry *) NULL)
87 #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data)))
88 #define cygheap_chain ((_cmalloc_entry **)cygheap)
89
90 static void *_cmalloc (int size) __attribute ((regparm(1)));
91 static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2)));
92
93 static void *__stdcall
94 _cmalloc (int size)
95 {
96 _cmalloc_entry *rvc;
97 int b, sz;
98
99 /* Calculate "bit bucket" and size as a power of two. */
100 for (b = 3, sz = 8; sz && sz < (size + 4); b++, sz <<= 1)
101 continue;
102
103 cygheap_protect->acquire ();
104 if (buckets[b])
105 {
106 rvc = (_cmalloc_entry *) buckets[b];
107 buckets[b] = rvc->ptr;
108 rvc->b = b;
109 }
110 else
111 {
112 size = sz + sizeof (_cmalloc_entry);
113 rvc = (_cmalloc_entry *) _csbrk (size);
114
115 rvc->b = b;
116 rvc->prev = *cygheap_chain;
117 *cygheap_chain = rvc;
118 }
119 cygheap_protect->release ();
120 return rvc->data;
121 }
122
123 static void __stdcall
124 _cfree (void *ptr)
125 {
126 cygheap_protect->acquire ();
127 _cmalloc_entry *rvc = to_cmalloc (ptr);
128 DWORD b = rvc->b;
129 rvc->ptr = buckets[b];
130 buckets[b] = (char *) rvc;
131 cygheap_protect->release ();
132 }
133
134 static void *__stdcall
135 _crealloc (void *ptr, int size)
136 {
137 void *newptr;
138 if (ptr == NULL)
139 newptr = _cmalloc (size);
140 else
141 {
142 int oldsize = 1 << to_cmalloc (ptr)->b;
143 if (size <= oldsize)
144 return ptr;
145 newptr = _cmalloc (size);
146 memcpy (newptr, ptr, oldsize);
147 _cfree (ptr);
148 }
149 return newptr;
150 }
151
152 /* End Copyright (C) 1997 DJ Delorie */
153
154 #define sizeof_cygheap(n) ((n) + sizeof(cygheap_entry))
155
156 struct cygheap_entry
157 {
158 int type;
159 struct cygheap_entry *next;
160 char data[0];
161 };
162
163 #define N ((cygheap_entry *) NULL)
164 #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data)))
165
166 /* Called by fork or spawn to reallocate cygwin heap */
167 extern "C" void __stdcall
168 cygheap_fixup_in_child (HANDLE parent, bool execed)
169 {
170 DWORD m, n;
171 n = (DWORD) cygheap_max - (DWORD) cygheap;
172
173 /* Reserve cygwin heap in same spot as parent */
174 if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS))
175 api_fatal ("Couldn't reserve space for cygwin's heap in child, %E");
176
177 /* Allocate same amount of memory as parent */
178 if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE))
179 api_fatal ("Couldn't allocate space for child's heap %p, size %d, %E",
180 cygheap, n);
181
182 /* Copy memory from the parent */
183 m = 0;
184 if (!ReadProcessMemory (parent, cygheap, cygheap, n, &m) || m != n)
185 api_fatal ("Couldn't read parent's cygwin heap %d bytes != %d, %E",
186 n, m);
187
188 if (!execed)
189 return; /* Forked. Nothing extra to do. */
190
191 /* Walk the allocated memory chain looking for orphaned memory from
192 previous execs */
193 for (_cmalloc_entry *rvc = *cygheap_chain; rvc; rvc = rvc->prev)
194 {
195 cygheap_entry *ce = (cygheap_entry *) rvc->data;
196 if (rvc->b >= NBUCKETS || ce->type <= HEAP_1_START)
197 continue;
198 else if (ce->type < HEAP_1_MAX)
199 ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */
200 else
201 _cfree (ce); /* Marked by parent for freeing in child */
202 }
203 }
204
205 inline static void *
206 creturn (cygheap_types x, cygheap_entry * c, int len)
207 {
208 if (!c)
209 {
210 __seterrno ();
211 return NULL;
212 }
213 c->type = x;
214 if (cygheap_max < ((char *) c + len))
215 cygheap_max = (char *) c + len;
216 MALLOC_CHECK;
217 return (void *) c->data;
218 }
219
220 extern "C" void *__stdcall
221 cmalloc (cygheap_types x, DWORD n)
222 {
223 cygheap_entry *c;
224 MALLOC_CHECK;
225 c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
226 if (!c)
227 system_printf ("cmalloc returned NULL");
228 return creturn (x, c, n);
229 }
230
231 extern "C" void *__stdcall
232 crealloc (void *s, DWORD n)
233 {
234 MALLOC_CHECK;
235 if (s == NULL)
236 return cmalloc (HEAP_STR, n); // kludge
237
238 assert (!inheap (s));
239 cygheap_entry *c = tocygheap (s);
240 cygheap_types t = (cygheap_types) c->type;
241 c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n));
242 if (!c)
243 system_printf ("crealloc returned NULL");
244 return creturn (t, c, n);
245 }
246
247 extern "C" void __stdcall
248 cfree (void *s)
249 {
250 MALLOC_CHECK;
251 assert (!inheap (s));
252 (void) _cfree (tocygheap (s));
253 MALLOC_CHECK;
254 }
255
256 extern "C" void *__stdcall
257 ccalloc (cygheap_types x, DWORD n, DWORD size)
258 {
259 cygheap_entry *c;
260 MALLOC_CHECK;
261 c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n * size));
262 if (c)
263 memset (c->data, 0, n * size);
264 if (!c)
265 system_printf ("ccalloc returned NULL");
266 return creturn (x, c, n);
267 }
268
269 extern "C" char *__stdcall
270 cstrdup (const char *s)
271 {
272 MALLOC_CHECK;
273 char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1);
274 if (!p)
275 return NULL;
276 strcpy (p, s);
277 MALLOC_CHECK;
278 return p;
279 }
280
281 extern "C" char *__stdcall
282 cstrdup1 (const char *s)
283 {
284 MALLOC_CHECK;
285 char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1);
286 if (!p)
287 return NULL;
288 strcpy (p, s);
289 MALLOC_CHECK;
290 return p;
291 }
This page took 0.051195 seconds and 6 git commands to generate.