]>
Commit | Line | Data |
---|---|---|
b0e82b74 CF |
1 | /* cygheap.cc: Cygwin heap manager. |
2 | ||
a7d2cc16 | 3 | Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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" | |
b0e82b74 | 12 | #include <assert.h> |
9fc09d00 | 13 | #include <stdlib.h> |
169c465a | 14 | #include "cygerrno.h" |
6b91b8d5 | 15 | #include "security.h" |
49eef6d5 | 16 | #include "path.h" |
7ac61736 | 17 | #include "fhandler.h" |
47063f00 | 18 | #include "dtable.h" |
b0e82b74 | 19 | #include "cygheap.h" |
5457dfcb | 20 | #include "child_info.h" |
b0e82b74 | 21 | #include "heap.h" |
c0a9bffd | 22 | #include "sigproc.h" |
ce95c640 CF |
23 | #include "pinfo.h" |
24 | #include <unistd.h> | |
7b4b41ab | 25 | #include <wchar.h> |
b0e82b74 | 26 | |
a4785603 | 27 | init_cygheap NO_COPY *cygheap; |
54030e21 | 28 | void NO_COPY *cygheap_max; |
8d82847a | 29 | |
ce95c640 | 30 | extern "C" char _cygheap_mid[] __attribute__((section(".cygheap"))); |
5d4a6721 | 31 | extern "C" char _cygheap_end[]; |
ce95c640 | 32 | |
322c131f | 33 | static NO_COPY muto cygheap_protect; |
9fc09d00 | 34 | |
5457dfcb CF |
35 | struct cygheap_entry |
36 | { | |
37 | int type; | |
38 | struct cygheap_entry *next; | |
39 | char data[0]; | |
40 | }; | |
41 | ||
4ce15a49 | 42 | #define NBUCKETS (sizeof (cygheap->buckets) / sizeof (cygheap->buckets[0])) |
5457dfcb | 43 | #define N0 ((_cmalloc_entry *) NULL) |
4c6a3e50 | 44 | #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (unsigned) (N0->data))) |
5457dfcb | 45 | |
e5ba4c06 CF |
46 | #define CFMAP_OPTIONS (SEC_RESERVE | PAGE_READWRITE) |
47 | #define MVMAP_OPTIONS (FILE_MAP_WRITE) | |
48 | ||
5457dfcb | 49 | extern "C" { |
ce95c640 CF |
50 | static void __stdcall _cfree (void *) __attribute__((regparm(1))); |
51 | static void *__stdcall _csbrk (int); | |
e5ba4c06 | 52 | } |
1cd06583 | 53 | |
5457dfcb CF |
54 | /* Called by fork or spawn to reallocate cygwin heap */ |
55 | void __stdcall | |
6ea3e429 | 56 | cygheap_fixup_in_child (bool execed) |
5457dfcb | 57 | { |
ce95c640 CF |
58 | cygheap_max = child_proc_info->cygheap; |
59 | cygheap = (init_cygheap *) cygheap_max; | |
60 | _csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap); | |
ad02bb70 | 61 | child_copy (child_proc_info->parent, false, "cygheap", cygheap, cygheap_max, NULL); |
e8454a34 CF |
62 | cygheap_init (); |
63 | debug_fixup_after_fork_exec (); | |
5457dfcb CF |
64 | if (execed) |
65 | { | |
b1d9a0bd | 66 | cygheap->hooks.next = NULL; |
1cc651ec | 67 | cygheap->user_heap.base = NULL; /* We can allocate the heap anywhere */ |
5457dfcb CF |
68 | /* Walk the allocated memory chain looking for orphaned memory from |
69 | previous execs */ | |
70 | for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev) | |
71 | { | |
72 | cygheap_entry *ce = (cygheap_entry *) rvc->data; | |
b2bfade3 | 73 | if (!rvc->ptr || rvc->b >= NBUCKETS || ce->type <= HEAP_1_START) |
5457dfcb CF |
74 | continue; |
75 | else if (ce->type < HEAP_1_MAX) | |
76 | ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */ | |
77 | else | |
78 | _cfree (ce); /* Marked by parent for freeing in child */ | |
79 | } | |
80 | } | |
81 | } | |
82 | ||
59297e04 CF |
83 | int |
84 | init_cygheap::manage_console_count (const char *something, int amount, bool avoid_freeing_console) | |
85 | { | |
974f27a5 CF |
86 | if (console_count == 0 && amount > 0) |
87 | init_console_handler (true); | |
59297e04 CF |
88 | console_count += amount; |
89 | debug_printf ("%s: console_count %d, amount %d, %s, avoid_freeing_console %d", | |
90 | something, console_count, amount, myctty (), avoid_freeing_console); | |
247ac234 | 91 | if (!avoid_freeing_console && amount <= 0 && !console_count && myself->ctty == -1) |
59297e04 | 92 | { |
974f27a5 CF |
93 | BOOL res = FreeConsole (); |
94 | debug_printf ("freed console, res %d", res); | |
95 | init_console_handler (false); | |
59297e04 CF |
96 | } |
97 | return console_count; | |
98 | } | |
09b01096 | 99 | |
2d1d1eb1 CF |
100 | void |
101 | init_cygheap::close_ctty () | |
102 | { | |
103 | debug_printf ("closing cygheap->ctty %p", cygheap->ctty); | |
104 | cygheap->ctty->close (); | |
f7239090 | 105 | cygheap->ctty = NULL; |
2d1d1eb1 CF |
106 | } |
107 | ||
ce95c640 CF |
108 | #define nextpage(x) ((char *) (((DWORD) ((char *) x + granmask)) & ~granmask)) |
109 | #define allocsize(x) ((DWORD) nextpage (x)) | |
110 | #ifdef DEBUGGING | |
111 | #define somekinda_printf debug_printf | |
112 | #else | |
113 | #define somekinda_printf malloc_printf | |
114 | #endif | |
8d82847a | 115 | |
b0e82b74 CF |
116 | static void *__stdcall |
117 | _csbrk (int sbs) | |
118 | { | |
772f6c3e | 119 | void *prebrk = cygheap_max; |
f90e23f2 | 120 | size_t granmask = getpagesize () - 1; |
ce95c640 | 121 | char *newbase = nextpage (prebrk); |
bd893898 | 122 | cygheap_max = (char *) cygheap_max + sbs; |
f51b3965 | 123 | if (!sbs || (newbase >= cygheap_max) || (cygheap_max <= _cygheap_end)) |
772f6c3e | 124 | /* nothing to do */; |
ce95c640 | 125 | else |
7da53596 | 126 | { |
ce95c640 CF |
127 | if (prebrk <= _cygheap_end) |
128 | newbase = _cygheap_end; | |
129 | ||
130 | DWORD adjsbs = allocsize ((char *) cygheap_max - newbase); | |
3623cfa3 | 131 | if (adjsbs && !VirtualAlloc (newbase, adjsbs, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)) |
ce95c640 CF |
132 | { |
133 | MEMORY_BASIC_INFORMATION m; | |
134 | if (!VirtualQuery (newbase, &m, sizeof m)) | |
135 | system_printf ("couldn't get memory info, %E"); | |
136 | somekinda_printf ("Couldn't reserve/commit %d bytes of space for cygwin's heap, %E", | |
137 | adjsbs); | |
138 | somekinda_printf ("AllocationBase %p, BaseAddress %p, RegionSize %p, State %p\n", | |
139 | m.AllocationBase, m.BaseAddress, m.RegionSize, m.State); | |
140 | __seterrno (); | |
141 | cygheap_max = (char *) cygheap_max - sbs; | |
142 | return NULL; | |
143 | } | |
7da53596 | 144 | } |
8d82847a | 145 | |
0301bfd0 | 146 | return prebrk; |
b0e82b74 CF |
147 | } |
148 | ||
a4785603 CF |
149 | extern "C" void __stdcall |
150 | cygheap_init () | |
151 | { | |
322c131f | 152 | cygheap_protect.init ("cygheap_protect"); |
772f6c3e CF |
153 | if (!cygheap) |
154 | { | |
e6fbf13e CV |
155 | cygheap = (init_cygheap *) memset (_cygheap_start, 0, |
156 | _cygheap_mid - _cygheap_start); | |
ce95c640 | 157 | cygheap_max = cygheap; |
0c55f6ed | 158 | _csbrk (sizeof (*cygheap)); |
772f6c3e | 159 | } |
0381fec6 CF |
160 | if (!cygheap->fdtab) |
161 | cygheap->fdtab.init (); | |
c0a9bffd CF |
162 | if (!cygheap->sigs) |
163 | sigalloc (); | |
a4785603 CF |
164 | } |
165 | ||
b0e82b74 CF |
166 | /* Copyright (C) 1997, 2000 DJ Delorie */ |
167 | ||
4c6a3e50 CF |
168 | static void *_cmalloc (unsigned size) __attribute ((regparm(1))); |
169 | static void *__stdcall _crealloc (void *ptr, unsigned size) __attribute ((regparm(2))); | |
166b2571 | 170 | |
b0e82b74 | 171 | static void *__stdcall |
4c6a3e50 | 172 | _cmalloc (unsigned size) |
b0e82b74 | 173 | { |
8d82847a | 174 | _cmalloc_entry *rvc; |
16828fc5 | 175 | unsigned b, sz; |
b0e82b74 | 176 | |
166b2571 | 177 | /* Calculate "bit bucket" and size as a power of two. */ |
4c6a3e50 | 178 | for (b = 3, sz = 8; sz && sz < size; b++, sz <<= 1) |
166b2571 | 179 | continue; |
b0e82b74 | 180 | |
322c131f | 181 | cygheap_protect.acquire (); |
4ce15a49 | 182 | if (cygheap->buckets[b]) |
b0e82b74 | 183 | { |
4ce15a49 CF |
184 | rvc = (_cmalloc_entry *) cygheap->buckets[b]; |
185 | cygheap->buckets[b] = rvc->ptr; | |
8d82847a | 186 | rvc->b = b; |
b0e82b74 | 187 | } |
9fc09d00 CF |
188 | else |
189 | { | |
4c6a3e50 | 190 | rvc = (_cmalloc_entry *) _csbrk (sz + sizeof (_cmalloc_entry)); |
7da53596 CF |
191 | if (!rvc) |
192 | { | |
322c131f | 193 | cygheap_protect.release (); |
7da53596 CF |
194 | return NULL; |
195 | } | |
b0e82b74 | 196 | |
9fc09d00 | 197 | rvc->b = b; |
a4785603 CF |
198 | rvc->prev = cygheap->chain; |
199 | cygheap->chain = rvc; | |
9fc09d00 | 200 | } |
322c131f | 201 | cygheap_protect.release (); |
8d82847a | 202 | return rvc->data; |
b0e82b74 CF |
203 | } |
204 | ||
205 | static void __stdcall | |
206 | _cfree (void *ptr) | |
207 | { | |
322c131f | 208 | cygheap_protect.acquire (); |
8d82847a CF |
209 | _cmalloc_entry *rvc = to_cmalloc (ptr); |
210 | DWORD b = rvc->b; | |
4ce15a49 CF |
211 | rvc->ptr = cygheap->buckets[b]; |
212 | cygheap->buckets[b] = (char *) rvc; | |
322c131f | 213 | cygheap_protect.release (); |
b0e82b74 CF |
214 | } |
215 | ||
216 | static void *__stdcall | |
4c6a3e50 | 217 | _crealloc (void *ptr, unsigned size) |
b0e82b74 | 218 | { |
7e24f1bf CF |
219 | void *newptr; |
220 | if (ptr == NULL) | |
221 | newptr = _cmalloc (size); | |
222 | else | |
223 | { | |
4c6a3e50 | 224 | unsigned oldsize = 1 << to_cmalloc (ptr)->b; |
7e24f1bf CF |
225 | if (size <= oldsize) |
226 | return ptr; | |
227 | newptr = _cmalloc (size); | |
32cba6cb CF |
228 | if (newptr) |
229 | { | |
230 | memcpy (newptr, ptr, oldsize); | |
231 | _cfree (ptr); | |
232 | } | |
7e24f1bf | 233 | } |
b0e82b74 CF |
234 | return newptr; |
235 | } | |
236 | ||
237 | /* End Copyright (C) 1997 DJ Delorie */ | |
238 | ||
f0227ea3 | 239 | #define sizeof_cygheap(n) ((n) + sizeof (cygheap_entry)) |
b0e82b74 | 240 | |
b0e82b74 CF |
241 | #define N ((cygheap_entry *) NULL) |
242 | #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data))) | |
243 | ||
166b2571 | 244 | inline static void * |
ee4388c4 | 245 | creturn (cygheap_types x, cygheap_entry * c, unsigned len, const char *fn = NULL) |
b0e82b74 CF |
246 | { |
247 | if (!c) | |
ee4388c4 CF |
248 | if (fn) |
249 | api_fatal ("%s would have returned NULL", fn); | |
250 | else | |
251 | { | |
252 | set_errno (ENOMEM); | |
253 | return NULL; | |
254 | } | |
b0e82b74 | 255 | c->type = x; |
47f81092 CF |
256 | char *cend = ((char *) c + sizeof (*c) + len); |
257 | if (cygheap_max < cend) | |
258 | cygheap_max = cend; | |
9fc09d00 | 259 | MALLOC_CHECK; |
b0e82b74 CF |
260 | return (void *) c->data; |
261 | } | |
262 | ||
ee4388c4 CF |
263 | inline static void * |
264 | cmalloc (cygheap_types x, DWORD n, const char *fn) | |
b0e82b74 CF |
265 | { |
266 | cygheap_entry *c; | |
9fc09d00 | 267 | MALLOC_CHECK; |
b0e82b74 | 268 | c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n)); |
ee4388c4 | 269 | return creturn (x, c, n, fn); |
b0e82b74 CF |
270 | } |
271 | ||
ee4388c4 CF |
272 | extern "C" void * |
273 | cmalloc (cygheap_types x, DWORD n) | |
274 | { | |
275 | return cmalloc (x, n, NULL); | |
276 | } | |
277 | ||
278 | extern "C" void * | |
279 | cmalloc_abort (cygheap_types x, DWORD n) | |
280 | { | |
281 | return cmalloc (x, n, "cmalloc"); | |
282 | } | |
283 | ||
284 | inline static void * | |
285 | crealloc (void *s, DWORD n, const char *fn) | |
b0e82b74 | 286 | { |
9fc09d00 | 287 | MALLOC_CHECK; |
b0e82b74 CF |
288 | if (s == NULL) |
289 | return cmalloc (HEAP_STR, n); // kludge | |
290 | ||
291 | assert (!inheap (s)); | |
292 | cygheap_entry *c = tocygheap (s); | |
8d82847a | 293 | cygheap_types t = (cygheap_types) c->type; |
b0e82b74 | 294 | c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n)); |
ee4388c4 CF |
295 | return creturn (t, c, n, fn); |
296 | } | |
297 | ||
298 | extern "C" void *__stdcall | |
299 | crealloc (void *s, DWORD n) | |
300 | { | |
301 | return crealloc (s, n, NULL); | |
302 | } | |
303 | ||
304 | extern "C" void *__stdcall | |
305 | crealloc_abort (void *s, DWORD n) | |
306 | { | |
307 | return crealloc (s, n, "crealloc"); | |
b0e82b74 CF |
308 | } |
309 | ||
310 | extern "C" void __stdcall | |
311 | cfree (void *s) | |
312 | { | |
313 | assert (!inheap (s)); | |
0c55f6ed | 314 | _cfree (tocygheap (s)); |
9fc09d00 | 315 | MALLOC_CHECK; |
b0e82b74 CF |
316 | } |
317 | ||
179cae11 CF |
318 | extern "C" void __stdcall |
319 | cfree_and_set (char *&s, char *what) | |
320 | { | |
321 | if (s && s != almost_null) | |
322 | cfree (s); | |
323 | s = what; | |
324 | } | |
325 | ||
ee4388c4 CF |
326 | inline static void * |
327 | ccalloc (cygheap_types x, DWORD n, DWORD size, const char *fn) | |
b0e82b74 CF |
328 | { |
329 | cygheap_entry *c; | |
9fc09d00 | 330 | MALLOC_CHECK; |
3e2d8af0 CF |
331 | n *= size; |
332 | c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n)); | |
b0e82b74 | 333 | if (c) |
3e2d8af0 | 334 | memset (c->data, 0, n); |
ee4388c4 CF |
335 | return creturn (x, c, n, fn); |
336 | } | |
337 | ||
338 | extern "C" void *__stdcall | |
339 | ccalloc (cygheap_types x, DWORD n, DWORD size) | |
340 | { | |
341 | return ccalloc (x, n, size, NULL); | |
342 | } | |
343 | ||
344 | extern "C" void *__stdcall | |
345 | ccalloc_abort (cygheap_types x, DWORD n, DWORD size) | |
346 | { | |
347 | return ccalloc (x, n, size, "ccalloc"); | |
b0e82b74 CF |
348 | } |
349 | ||
7b4b41ab CV |
350 | extern "C" PWCHAR __stdcall |
351 | cwcsdup (const PWCHAR s) | |
352 | { | |
353 | MALLOC_CHECK; | |
354 | PWCHAR p = (PWCHAR) cmalloc (HEAP_STR, wcslen (s) + 1); | |
355 | if (!p) | |
356 | return NULL; | |
357 | wcpcpy (p, s); | |
358 | MALLOC_CHECK; | |
359 | return p; | |
360 | } | |
361 | ||
362 | extern "C" PWCHAR __stdcall | |
363 | cwcsdup1 (const PWCHAR s) | |
364 | { | |
365 | MALLOC_CHECK; | |
366 | PWCHAR p = (PWCHAR) cmalloc (HEAP_1_STR, wcslen (s) + 1); | |
367 | if (!p) | |
368 | return NULL; | |
369 | wcpcpy (p, s); | |
370 | MALLOC_CHECK; | |
371 | return p; | |
372 | } | |
373 | ||
b0e82b74 CF |
374 | extern "C" char *__stdcall |
375 | cstrdup (const char *s) | |
376 | { | |
9fc09d00 | 377 | MALLOC_CHECK; |
b0e82b74 CF |
378 | char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1); |
379 | if (!p) | |
380 | return NULL; | |
381 | strcpy (p, s); | |
9fc09d00 | 382 | MALLOC_CHECK; |
b0e82b74 CF |
383 | return p; |
384 | } | |
e5648465 CF |
385 | |
386 | extern "C" char *__stdcall | |
387 | cstrdup1 (const char *s) | |
388 | { | |
9fc09d00 | 389 | MALLOC_CHECK; |
e5648465 CF |
390 | char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1); |
391 | if (!p) | |
392 | return NULL; | |
393 | strcpy (p, s); | |
9fc09d00 | 394 | MALLOC_CHECK; |
e5648465 CF |
395 | return p; |
396 | } | |
1f0f8e12 | 397 | |
7ceb1cac CF |
398 | void |
399 | cygheap_root::set (const char *posix, const char *native) | |
1f0f8e12 | 400 | { |
96a3f4ae CF |
401 | if (*posix == '/' && posix[1] == '\0') |
402 | { | |
403 | if (m) | |
404 | { | |
405 | cfree (m); | |
406 | m = NULL; | |
407 | } | |
408 | return; | |
409 | } | |
7ceb1cac CF |
410 | if (!m) |
411 | m = (struct cygheap_root_mount_info *) ccalloc (HEAP_MOUNT, 1, sizeof (*m)); | |
412 | strcpy (m->posix_path, posix); | |
413 | m->posix_pathlen = strlen (posix); | |
414 | if (m->posix_pathlen >= 1 && m->posix_path[m->posix_pathlen - 1] == '/') | |
415 | m->posix_path[--m->posix_pathlen] = '\0'; | |
416 | ||
417 | strcpy (m->native_path, native); | |
418 | m->native_pathlen = strlen (native); | |
419 | if (m->native_pathlen >= 1 && m->native_path[m->native_pathlen - 1] == '\\') | |
420 | m->native_path[--m->native_pathlen] = '\0'; | |
1f0f8e12 CV |
421 | } |
422 | ||
423 | cygheap_user::~cygheap_user () | |
424 | { | |
cb503978 | 425 | #if 0 |
1f0f8e12 CV |
426 | if (pname) |
427 | cfree (pname); | |
428 | if (plogsrv) | |
5682a6dd | 429 | cfree (plogsrv - 2); |
1f0f8e12 CV |
430 | if (pdomain) |
431 | cfree (pdomain); | |
432 | if (psid) | |
433 | cfree (psid); | |
cb503978 | 434 | #endif |
1f0f8e12 CV |
435 | } |
436 | ||
437 | void | |
438 | cygheap_user::set_name (const char *new_name) | |
439 | { | |
c99902b9 | 440 | bool allocated = !!pname; |
b3e2d035 | 441 | |
c99902b9 | 442 | if (allocated) |
b3e2d035 CF |
443 | { |
444 | if (strcasematch (new_name, pname)) | |
445 | return; | |
446 | cfree (pname); | |
447 | } | |
c99902b9 | 448 | |
1f0f8e12 | 449 | pname = cstrdup (new_name ? new_name : ""); |
c99902b9 CF |
450 | if (!allocated) |
451 | return; /* Initializing. Don't bother with other stuff. */ | |
452 | ||
179cae11 CF |
453 | cfree_and_set (homedrive); |
454 | cfree_and_set (homepath); | |
455 | cfree_and_set (plogsrv); | |
456 | cfree_and_set (pdomain); | |
094d5193 | 457 | cfree_and_set (pwinname); |
1f0f8e12 | 458 | } |