]>
Commit | Line | Data |
---|---|---|
b0e82b74 CF |
1 | /* cygheap.cc: Cygwin heap manager. |
2 | ||
ca1cea7e | 3 | Copyright 2000, 2001 Red Hat, Inc. |
b0e82b74 CF |
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> | |
9fc09d00 | 15 | #include <stdlib.h> |
b0e82b74 CF |
16 | #include "cygheap.h" |
17 | #include "heap.h" | |
18 | #include "cygerrno.h" | |
9fc09d00 | 19 | #include "sync.h" |
2a6fc028 | 20 | #include "shared_info.h" |
b0e82b74 | 21 | |
a4785603 | 22 | init_cygheap NO_COPY *cygheap; |
1ec4f618 | 23 | void NO_COPY *cygheap_max = NULL; |
8d82847a | 24 | |
9fc09d00 CF |
25 | static NO_COPY muto *cygheap_protect = NULL; |
26 | ||
b0e82b74 CF |
27 | inline static void |
28 | init_cheap () | |
29 | { | |
6a4878cf | 30 | cygheap = (init_cygheap *) VirtualAlloc (NULL, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS); |
9149d76e CF |
31 | if (!cygheap) |
32 | api_fatal ("Couldn't reserve space for cygwin's heap, %E"); | |
a4785603 | 33 | cygheap_max = cygheap + 1; |
b0e82b74 CF |
34 | } |
35 | ||
36 | #define pagetrunc(x) ((void *) (((DWORD) (x)) & ~(4096 - 1))) | |
8d82847a | 37 | |
b0e82b74 CF |
38 | static void *__stdcall |
39 | _csbrk (int sbs) | |
40 | { | |
41 | void *lastheap; | |
8d82847a CF |
42 | bool needalloc; |
43 | ||
44 | if (cygheap) | |
45 | needalloc = 0; | |
46 | else | |
47 | { | |
48 | init_cheap (); | |
49 | needalloc = 1; | |
50 | } | |
51 | ||
b0e82b74 CF |
52 | lastheap = cygheap_max; |
53 | (char *) cygheap_max += sbs; | |
54 | void *heapalign = (void *) pagetrunc (lastheap); | |
8d82847a CF |
55 | |
56 | if (!needalloc) | |
57 | needalloc = sbs && ((heapalign == lastheap) || heapalign != pagetrunc (cygheap_max)); | |
a4785603 | 58 | if (needalloc && !VirtualAlloc (lastheap, (DWORD) sbs ?: 1, MEM_COMMIT, PAGE_READWRITE)) |
b0e82b74 CF |
59 | api_fatal ("couldn't commit memory for cygwin heap, %E"); |
60 | ||
61 | return lastheap; | |
62 | } | |
63 | ||
a4785603 CF |
64 | extern "C" void __stdcall |
65 | cygheap_init () | |
66 | { | |
67 | cygheap_protect = new_muto (FALSE, "cygheap_protect"); | |
68 | _csbrk (0); | |
69 | } | |
70 | ||
b0e82b74 CF |
71 | /* Copyright (C) 1997, 2000 DJ Delorie */ |
72 | ||
8d82847a CF |
73 | #define NBUCKETS 32 |
74 | char *buckets[NBUCKETS] = {0}; | |
b0e82b74 | 75 | |
8d82847a CF |
76 | #define N0 ((_cmalloc_entry *) NULL) |
77 | #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data))) | |
8d82847a | 78 | |
166b2571 CF |
79 | static void *_cmalloc (int size) __attribute ((regparm(1))); |
80 | static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2))); | |
81 | ||
b0e82b74 CF |
82 | static void *__stdcall |
83 | _cmalloc (int size) | |
84 | { | |
8d82847a | 85 | _cmalloc_entry *rvc; |
166b2571 | 86 | int b, sz; |
b0e82b74 | 87 | |
166b2571 CF |
88 | /* Calculate "bit bucket" and size as a power of two. */ |
89 | for (b = 3, sz = 8; sz && sz < (size + 4); b++, sz <<= 1) | |
90 | continue; | |
b0e82b74 | 91 | |
9fc09d00 | 92 | cygheap_protect->acquire (); |
b0e82b74 CF |
93 | if (buckets[b]) |
94 | { | |
8d82847a CF |
95 | rvc = (_cmalloc_entry *) buckets[b]; |
96 | buckets[b] = rvc->ptr; | |
97 | rvc->b = b; | |
b0e82b74 | 98 | } |
9fc09d00 CF |
99 | else |
100 | { | |
166b2571 | 101 | size = sz + sizeof (_cmalloc_entry); |
9fc09d00 | 102 | rvc = (_cmalloc_entry *) _csbrk (size); |
b0e82b74 | 103 | |
9fc09d00 | 104 | rvc->b = b; |
a4785603 CF |
105 | rvc->prev = cygheap->chain; |
106 | cygheap->chain = rvc; | |
9fc09d00 CF |
107 | } |
108 | cygheap_protect->release (); | |
8d82847a | 109 | return rvc->data; |
b0e82b74 CF |
110 | } |
111 | ||
112 | static void __stdcall | |
113 | _cfree (void *ptr) | |
114 | { | |
9fc09d00 | 115 | cygheap_protect->acquire (); |
8d82847a CF |
116 | _cmalloc_entry *rvc = to_cmalloc (ptr); |
117 | DWORD b = rvc->b; | |
118 | rvc->ptr = buckets[b]; | |
119 | buckets[b] = (char *) rvc; | |
9fc09d00 | 120 | cygheap_protect->release (); |
b0e82b74 CF |
121 | } |
122 | ||
123 | static void *__stdcall | |
124 | _crealloc (void *ptr, int size) | |
125 | { | |
7e24f1bf CF |
126 | void *newptr; |
127 | if (ptr == NULL) | |
128 | newptr = _cmalloc (size); | |
129 | else | |
130 | { | |
166b2571 | 131 | int oldsize = 1 << to_cmalloc (ptr)->b; |
7e24f1bf CF |
132 | if (size <= oldsize) |
133 | return ptr; | |
134 | newptr = _cmalloc (size); | |
135 | memcpy (newptr, ptr, oldsize); | |
136 | _cfree (ptr); | |
137 | } | |
b0e82b74 CF |
138 | return newptr; |
139 | } | |
140 | ||
141 | /* End Copyright (C) 1997 DJ Delorie */ | |
142 | ||
b0e82b74 CF |
143 | #define sizeof_cygheap(n) ((n) + sizeof(cygheap_entry)) |
144 | ||
145 | struct cygheap_entry | |
146 | { | |
8d82847a CF |
147 | int type; |
148 | struct cygheap_entry *next; | |
b0e82b74 CF |
149 | char data[0]; |
150 | }; | |
151 | ||
152 | #define N ((cygheap_entry *) NULL) | |
153 | #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data))) | |
154 | ||
8d82847a | 155 | /* Called by fork or spawn to reallocate cygwin heap */ |
b0e82b74 | 156 | extern "C" void __stdcall |
8d82847a | 157 | cygheap_fixup_in_child (HANDLE parent, bool execed) |
b0e82b74 CF |
158 | { |
159 | DWORD m, n; | |
160 | n = (DWORD) cygheap_max - (DWORD) cygheap; | |
8d82847a CF |
161 | |
162 | /* Reserve cygwin heap in same spot as parent */ | |
b0e82b74 | 163 | if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS)) |
a4785603 | 164 | api_fatal ("Couldn't reserve space for cygwin's heap (%p) in child, cygheap, %E", cygheap); |
b0e82b74 | 165 | |
8d82847a | 166 | /* Allocate same amount of memory as parent */ |
b0e82b74 CF |
167 | if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE)) |
168 | api_fatal ("Couldn't allocate space for child's heap %p, size %d, %E", | |
169 | cygheap, n); | |
8d82847a CF |
170 | |
171 | /* Copy memory from the parent */ | |
b0e82b74 | 172 | m = 0; |
aece55b9 | 173 | if (!ReadProcessMemory (parent, cygheap, cygheap, n, &m) || m != n) |
b0e82b74 CF |
174 | api_fatal ("Couldn't read parent's cygwin heap %d bytes != %d, %E", |
175 | n, m); | |
8d82847a | 176 | |
a4785603 | 177 | cygheap_init (); |
8d82847a | 178 | |
a4785603 | 179 | if (execed) |
8d82847a | 180 | { |
a4785603 CF |
181 | /* Walk the allocated memory chain looking for orphaned memory from |
182 | previous execs */ | |
183 | for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev) | |
184 | { | |
185 | cygheap_entry *ce = (cygheap_entry *) rvc->data; | |
186 | if (rvc->b >= NBUCKETS || ce->type <= HEAP_1_START) | |
187 | continue; | |
188 | else if (ce->type < HEAP_1_MAX) | |
189 | ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */ | |
190 | else | |
191 | _cfree (ce); /* Marked by parent for freeing in child */ | |
192 | } | |
8d82847a | 193 | } |
b0e82b74 CF |
194 | } |
195 | ||
166b2571 | 196 | inline static void * |
b0e82b74 CF |
197 | creturn (cygheap_types x, cygheap_entry * c, int len) |
198 | { | |
199 | if (!c) | |
200 | { | |
201 | __seterrno (); | |
202 | return NULL; | |
203 | } | |
204 | c->type = x; | |
47f81092 CF |
205 | char *cend = ((char *) c + sizeof (*c) + len); |
206 | if (cygheap_max < cend) | |
207 | cygheap_max = cend; | |
9fc09d00 | 208 | MALLOC_CHECK; |
b0e82b74 CF |
209 | return (void *) c->data; |
210 | } | |
211 | ||
212 | extern "C" void *__stdcall | |
213 | cmalloc (cygheap_types x, DWORD n) | |
214 | { | |
215 | cygheap_entry *c; | |
9fc09d00 | 216 | MALLOC_CHECK; |
b0e82b74 CF |
217 | c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n)); |
218 | if (!c) | |
219 | system_printf ("cmalloc returned NULL"); | |
220 | return creturn (x, c, n); | |
221 | } | |
222 | ||
223 | extern "C" void *__stdcall | |
224 | crealloc (void *s, DWORD n) | |
225 | { | |
9fc09d00 | 226 | MALLOC_CHECK; |
b0e82b74 CF |
227 | if (s == NULL) |
228 | return cmalloc (HEAP_STR, n); // kludge | |
229 | ||
230 | assert (!inheap (s)); | |
231 | cygheap_entry *c = tocygheap (s); | |
8d82847a | 232 | cygheap_types t = (cygheap_types) c->type; |
b0e82b74 CF |
233 | c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n)); |
234 | if (!c) | |
235 | system_printf ("crealloc returned NULL"); | |
236 | return creturn (t, c, n); | |
237 | } | |
238 | ||
239 | extern "C" void __stdcall | |
240 | cfree (void *s) | |
241 | { | |
9fc09d00 | 242 | MALLOC_CHECK; |
b0e82b74 CF |
243 | assert (!inheap (s)); |
244 | (void) _cfree (tocygheap (s)); | |
9fc09d00 | 245 | MALLOC_CHECK; |
b0e82b74 CF |
246 | } |
247 | ||
248 | extern "C" void *__stdcall | |
249 | ccalloc (cygheap_types x, DWORD n, DWORD size) | |
250 | { | |
251 | cygheap_entry *c; | |
9fc09d00 | 252 | MALLOC_CHECK; |
b0e82b74 CF |
253 | c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n * size)); |
254 | if (c) | |
bb5d559a | 255 | memset (c->data, 0, n * size); |
b0e82b74 CF |
256 | if (!c) |
257 | system_printf ("ccalloc returned NULL"); | |
258 | return creturn (x, c, n); | |
259 | } | |
260 | ||
261 | extern "C" char *__stdcall | |
262 | cstrdup (const char *s) | |
263 | { | |
9fc09d00 | 264 | MALLOC_CHECK; |
b0e82b74 CF |
265 | char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1); |
266 | if (!p) | |
267 | return NULL; | |
268 | strcpy (p, s); | |
9fc09d00 | 269 | MALLOC_CHECK; |
b0e82b74 CF |
270 | return p; |
271 | } | |
e5648465 CF |
272 | |
273 | extern "C" char *__stdcall | |
274 | cstrdup1 (const char *s) | |
275 | { | |
9fc09d00 | 276 | MALLOC_CHECK; |
e5648465 CF |
277 | char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1); |
278 | if (!p) | |
279 | return NULL; | |
280 | strcpy (p, s); | |
9fc09d00 | 281 | MALLOC_CHECK; |
e5648465 CF |
282 | return p; |
283 | } | |
1f0f8e12 CV |
284 | |
285 | cygheap_root::cygheap_root (cygheap_root &nroot) | |
286 | { | |
287 | rootlen = nroot.rootlen; | |
288 | root = nroot.root ? cstrdup (nroot.root) : NULL; | |
289 | } | |
290 | ||
291 | cygheap_root::~cygheap_root () | |
292 | { | |
293 | if (root) | |
294 | cfree (root); | |
295 | } | |
296 | ||
297 | char * | |
298 | cygheap_root::operator =(const char *new_root) | |
299 | { | |
300 | if (root) | |
301 | { | |
302 | cfree (root); | |
303 | root = NULL; | |
304 | } | |
305 | rootlen = 0; | |
306 | if (new_root && *new_root) | |
307 | { | |
308 | root = cstrdup (new_root); | |
309 | rootlen = strlen (root); | |
09872ef8 | 310 | if (rootlen >= 1 && root[rootlen - 1] == '/') |
1f0f8e12 CV |
311 | root[--rootlen] = '\0'; |
312 | if (!rootlen) | |
313 | { | |
314 | cfree (root); | |
315 | root = NULL; | |
316 | } | |
317 | } | |
318 | return root; | |
319 | } | |
320 | ||
321 | cygheap_user::~cygheap_user () | |
322 | { | |
cb503978 | 323 | #if 0 |
1f0f8e12 CV |
324 | if (pname) |
325 | cfree (pname); | |
326 | if (plogsrv) | |
327 | cfree (plogsrv); | |
328 | if (pdomain) | |
329 | cfree (pdomain); | |
330 | if (psid) | |
331 | cfree (psid); | |
cb503978 | 332 | #endif |
1f0f8e12 CV |
333 | } |
334 | ||
335 | void | |
336 | cygheap_user::set_name (const char *new_name) | |
337 | { | |
338 | if (pname) | |
339 | cfree (pname); | |
340 | pname = cstrdup (new_name ? new_name : ""); | |
341 | } | |
342 | ||
343 | void | |
344 | cygheap_user::set_logsrv (const char *new_logsrv) | |
345 | { | |
346 | if (plogsrv) | |
347 | cfree (plogsrv); | |
348 | plogsrv = (new_logsrv && *new_logsrv) ? cstrdup (new_logsrv) : NULL; | |
349 | } | |
350 | ||
351 | void | |
352 | cygheap_user::set_domain (const char *new_domain) | |
353 | { | |
354 | if (pdomain) | |
355 | cfree (pdomain); | |
356 | pdomain = (new_domain && *new_domain) ? cstrdup (new_domain) : NULL; | |
357 | } | |
358 | ||
359 | BOOL | |
360 | cygheap_user::set_sid (PSID new_sid) | |
361 | { | |
362 | if (!new_sid) | |
363 | { | |
364 | if (psid) | |
365 | cfree (psid); | |
366 | psid = NULL; | |
367 | return TRUE; | |
368 | } | |
369 | else | |
370 | { | |
371 | if (!psid) | |
372 | psid = cmalloc (HEAP_STR, MAX_SID_LEN); | |
373 | return CopySid (MAX_SID_LEN, psid, new_sid); | |
374 | } | |
375 | } |