]>
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" | |
17743fbc | 12 | #include <string.h> |
b0e82b74 | 13 | #include <errno.h> |
b0e82b74 | 14 | #include <assert.h> |
9fc09d00 | 15 | #include <stdlib.h> |
6b91b8d5 | 16 | #include "security.h" |
0381fec6 CF |
17 | #include "fhandler.h" |
18 | #include "dtable.h" | |
49eef6d5 | 19 | #include "path.h" |
b0e82b74 | 20 | #include "cygheap.h" |
5457dfcb | 21 | #include "child_info.h" |
b0e82b74 CF |
22 | #include "heap.h" |
23 | #include "cygerrno.h" | |
9fc09d00 | 24 | #include "sync.h" |
2a6fc028 | 25 | #include "shared_info.h" |
b0e82b74 | 26 | |
a4785603 | 27 | init_cygheap NO_COPY *cygheap; |
1ec4f618 | 28 | void NO_COPY *cygheap_max = NULL; |
8d82847a | 29 | |
9fc09d00 CF |
30 | static NO_COPY muto *cygheap_protect = NULL; |
31 | ||
5457dfcb CF |
32 | struct cygheap_entry |
33 | { | |
34 | int type; | |
35 | struct cygheap_entry *next; | |
36 | char data[0]; | |
37 | }; | |
38 | ||
4ce15a49 | 39 | #define NBUCKETS (sizeof (cygheap->buckets) / sizeof (cygheap->buckets[0])) |
5457dfcb CF |
40 | #define N0 ((_cmalloc_entry *) NULL) |
41 | #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data))) | |
42 | ||
e5ba4c06 CF |
43 | #define CFMAP_OPTIONS (SEC_RESERVE | PAGE_READWRITE) |
44 | #define MVMAP_OPTIONS (FILE_MAP_WRITE) | |
45 | ||
5457dfcb CF |
46 | extern "C" { |
47 | static void __stdcall _cfree (void *ptr) __attribute__((regparm(1))); | |
5835f2cf | 48 | extern void *_cygheap_start; |
5457dfcb CF |
49 | } |
50 | ||
b0e82b74 CF |
51 | inline static void |
52 | init_cheap () | |
53 | { | |
5835f2cf CF |
54 | cygheap = (init_cygheap *) VirtualAlloc ((void *) &_cygheap_start, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS); |
55 | if (!cygheap) | |
b1d0b907 | 56 | { |
5835f2cf CF |
57 | MEMORY_BASIC_INFORMATION m; |
58 | if (!VirtualQuery ((LPCVOID) &_cygheap_start, &m, sizeof m)) | |
59 | system_printf ("couldn't get memory info, %E"); | |
60 | small_printf ("AllocationBase %p, BaseAddress %p, RegionSize %p, State %p\n", | |
61 | m.AllocationBase, m.BaseAddress, m.RegionSize, m.State); | |
62 | api_fatal ("Couldn't reserve space for cygwin's heap, %E"); | |
b1d0b907 CF |
63 | } |
64 | cygheap_max = cygheap + 1; | |
b0e82b74 CF |
65 | } |
66 | ||
5457dfcb CF |
67 | void __stdcall |
68 | cygheap_setup_for_child (child_info *ci) | |
69 | { | |
70 | void *newcygheap; | |
71 | cygheap_protect->acquire (); | |
72 | unsigned n = (char *) cygheap_max - (char *) cygheap; | |
73 | ci->cygheap_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none, | |
e5ba4c06 CF |
74 | CFMAP_OPTIONS, 0, CYGHEAPSIZE, NULL); |
75 | newcygheap = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL); | |
5457dfcb | 76 | if (!VirtualAlloc (newcygheap, n, MEM_COMMIT, PAGE_READWRITE)) |
a7670c1e | 77 | api_fatal ("couldn't allocate new cygwin heap for child, %E"); |
5457dfcb CF |
78 | memcpy (newcygheap, cygheap, n); |
79 | UnmapViewOfFile (newcygheap); | |
80 | ci->cygheap = cygheap; | |
81 | ci->cygheap_max = cygheap_max; | |
82 | ProtectHandle1 (ci->cygheap_h, passed_cygheap_h); | |
83 | cygheap_protect->release (); | |
84 | return; | |
85 | } | |
86 | ||
e5ba4c06 CF |
87 | void __stdcall |
88 | cygheap_setup_for_child_cleanup (child_info *ci) | |
89 | { | |
90 | ForceCloseHandle1 (ci->cygheap_h, passed_cygheap_h); | |
91 | } | |
92 | ||
5457dfcb CF |
93 | /* Called by fork or spawn to reallocate cygwin heap */ |
94 | void __stdcall | |
95 | cygheap_fixup_in_child (child_info *ci, bool execed) | |
96 | { | |
97 | cygheap = ci->cygheap; | |
98 | cygheap_max = ci->cygheap_max; | |
e5ba4c06 CF |
99 | void *addr = iswinnt ? cygheap : NULL; |
100 | void *newaddr; | |
5835f2cf | 101 | |
e5ba4c06 | 102 | newaddr = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, addr); |
5835f2cf | 103 | if (newaddr != cygheap) |
e5ba4c06 | 104 | { |
5835f2cf CF |
105 | if (!newaddr) |
106 | newaddr = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL); | |
e5ba4c06 CF |
107 | DWORD n = (DWORD) cygheap_max - (DWORD) cygheap; |
108 | /* Reserve cygwin heap in same spot as parent */ | |
109 | if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS)) | |
5835f2cf CF |
110 | { |
111 | MEMORY_BASIC_INFORMATION m; | |
112 | memset (&m, 0, sizeof m); | |
113 | if (!VirtualQuery ((LPCVOID) cygheap, &m, sizeof m)) | |
114 | system_printf ("couldn't get memory info, %E"); | |
115 | ||
116 | small_printf ("m.AllocationBase %p, m.BaseAddress %p, m.RegionSize %p, m.State %p\n", | |
117 | m.AllocationBase, m.BaseAddress, m.RegionSize, m.State); | |
118 | api_fatal ("Couldn't reserve space for cygwin's heap (%p <%p>) in child, %E", cygheap, newaddr); | |
119 | } | |
e5ba4c06 CF |
120 | |
121 | /* Allocate same amount of memory as parent */ | |
122 | if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE)) | |
5835f2cf CF |
123 | api_fatal ("Couldn't allocate space for child's heap %p, size %d, %E", |
124 | cygheap, n); | |
e5ba4c06 CF |
125 | memcpy (cygheap, newaddr, n); |
126 | UnmapViewOfFile (newaddr); | |
127 | } | |
5457dfcb CF |
128 | |
129 | ForceCloseHandle1 (ci->cygheap_h, passed_cygheap_h); | |
e5ba4c06 | 130 | |
5457dfcb CF |
131 | cygheap_init (); |
132 | ||
133 | if (execed) | |
134 | { | |
135 | /* Walk the allocated memory chain looking for orphaned memory from | |
136 | previous execs */ | |
137 | for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev) | |
138 | { | |
139 | cygheap_entry *ce = (cygheap_entry *) rvc->data; | |
b2bfade3 | 140 | if (!rvc->ptr || rvc->b >= NBUCKETS || ce->type <= HEAP_1_START) |
5457dfcb CF |
141 | continue; |
142 | else if (ce->type < HEAP_1_MAX) | |
143 | ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */ | |
144 | else | |
145 | _cfree (ce); /* Marked by parent for freeing in child */ | |
146 | } | |
147 | } | |
148 | } | |
149 | ||
b0e82b74 | 150 | #define pagetrunc(x) ((void *) (((DWORD) (x)) & ~(4096 - 1))) |
8d82847a | 151 | |
b0e82b74 CF |
152 | static void *__stdcall |
153 | _csbrk (int sbs) | |
154 | { | |
155 | void *lastheap; | |
8d82847a CF |
156 | bool needalloc; |
157 | ||
158 | if (cygheap) | |
159 | needalloc = 0; | |
160 | else | |
161 | { | |
162 | init_cheap (); | |
163 | needalloc = 1; | |
164 | } | |
165 | ||
b0e82b74 CF |
166 | lastheap = cygheap_max; |
167 | (char *) cygheap_max += sbs; | |
168 | void *heapalign = (void *) pagetrunc (lastheap); | |
8d82847a CF |
169 | |
170 | if (!needalloc) | |
171 | needalloc = sbs && ((heapalign == lastheap) || heapalign != pagetrunc (cygheap_max)); | |
a4785603 | 172 | if (needalloc && !VirtualAlloc (lastheap, (DWORD) sbs ?: 1, MEM_COMMIT, PAGE_READWRITE)) |
b0e82b74 CF |
173 | api_fatal ("couldn't commit memory for cygwin heap, %E"); |
174 | ||
175 | return lastheap; | |
176 | } | |
177 | ||
a4785603 CF |
178 | extern "C" void __stdcall |
179 | cygheap_init () | |
180 | { | |
181 | cygheap_protect = new_muto (FALSE, "cygheap_protect"); | |
182 | _csbrk (0); | |
0381fec6 CF |
183 | if (!cygheap->fdtab) |
184 | cygheap->fdtab.init (); | |
a4785603 CF |
185 | } |
186 | ||
b0e82b74 CF |
187 | /* Copyright (C) 1997, 2000 DJ Delorie */ |
188 | ||
166b2571 CF |
189 | static void *_cmalloc (int size) __attribute ((regparm(1))); |
190 | static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2))); | |
191 | ||
b0e82b74 CF |
192 | static void *__stdcall |
193 | _cmalloc (int size) | |
194 | { | |
8d82847a | 195 | _cmalloc_entry *rvc; |
16828fc5 | 196 | unsigned b, sz; |
b0e82b74 | 197 | |
166b2571 | 198 | /* Calculate "bit bucket" and size as a power of two. */ |
16828fc5 CF |
199 | for (b = 3, sz = 8; sz && sz < (size + sizeof (_cmalloc_entry)); |
200 | b++, sz <<= 1) | |
166b2571 | 201 | continue; |
b0e82b74 | 202 | |
9fc09d00 | 203 | cygheap_protect->acquire (); |
4ce15a49 | 204 | if (cygheap->buckets[b]) |
b0e82b74 | 205 | { |
4ce15a49 CF |
206 | rvc = (_cmalloc_entry *) cygheap->buckets[b]; |
207 | cygheap->buckets[b] = rvc->ptr; | |
8d82847a | 208 | rvc->b = b; |
b0e82b74 | 209 | } |
9fc09d00 CF |
210 | else |
211 | { | |
166b2571 | 212 | size = sz + sizeof (_cmalloc_entry); |
9fc09d00 | 213 | rvc = (_cmalloc_entry *) _csbrk (size); |
b0e82b74 | 214 | |
9fc09d00 | 215 | rvc->b = b; |
a4785603 CF |
216 | rvc->prev = cygheap->chain; |
217 | cygheap->chain = rvc; | |
9fc09d00 CF |
218 | } |
219 | cygheap_protect->release (); | |
8d82847a | 220 | return rvc->data; |
b0e82b74 CF |
221 | } |
222 | ||
223 | static void __stdcall | |
224 | _cfree (void *ptr) | |
225 | { | |
9fc09d00 | 226 | cygheap_protect->acquire (); |
8d82847a CF |
227 | _cmalloc_entry *rvc = to_cmalloc (ptr); |
228 | DWORD b = rvc->b; | |
4ce15a49 CF |
229 | rvc->ptr = cygheap->buckets[b]; |
230 | cygheap->buckets[b] = (char *) rvc; | |
9fc09d00 | 231 | cygheap_protect->release (); |
b0e82b74 CF |
232 | } |
233 | ||
79201150 | 234 | static void *__stdcall _crealloc (void *ptr, int size) __attribute__((regparm(2))); |
b0e82b74 CF |
235 | static void *__stdcall |
236 | _crealloc (void *ptr, int size) | |
237 | { | |
7e24f1bf CF |
238 | void *newptr; |
239 | if (ptr == NULL) | |
240 | newptr = _cmalloc (size); | |
241 | else | |
242 | { | |
166b2571 | 243 | int oldsize = 1 << to_cmalloc (ptr)->b; |
7e24f1bf CF |
244 | if (size <= oldsize) |
245 | return ptr; | |
246 | newptr = _cmalloc (size); | |
247 | memcpy (newptr, ptr, oldsize); | |
248 | _cfree (ptr); | |
249 | } | |
b0e82b74 CF |
250 | return newptr; |
251 | } | |
252 | ||
253 | /* End Copyright (C) 1997 DJ Delorie */ | |
254 | ||
b0e82b74 CF |
255 | #define sizeof_cygheap(n) ((n) + sizeof(cygheap_entry)) |
256 | ||
b0e82b74 CF |
257 | #define N ((cygheap_entry *) NULL) |
258 | #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data))) | |
259 | ||
166b2571 | 260 | inline static void * |
b0e82b74 CF |
261 | creturn (cygheap_types x, cygheap_entry * c, int len) |
262 | { | |
263 | if (!c) | |
264 | { | |
265 | __seterrno (); | |
266 | return NULL; | |
267 | } | |
268 | c->type = x; | |
47f81092 CF |
269 | char *cend = ((char *) c + sizeof (*c) + len); |
270 | if (cygheap_max < cend) | |
271 | cygheap_max = cend; | |
9fc09d00 | 272 | MALLOC_CHECK; |
b0e82b74 CF |
273 | return (void *) c->data; |
274 | } | |
275 | ||
276 | extern "C" void *__stdcall | |
277 | cmalloc (cygheap_types x, DWORD n) | |
278 | { | |
279 | cygheap_entry *c; | |
9fc09d00 | 280 | MALLOC_CHECK; |
b0e82b74 CF |
281 | c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n)); |
282 | if (!c) | |
283 | system_printf ("cmalloc returned NULL"); | |
284 | return creturn (x, c, n); | |
285 | } | |
286 | ||
287 | extern "C" void *__stdcall | |
288 | crealloc (void *s, DWORD n) | |
289 | { | |
9fc09d00 | 290 | MALLOC_CHECK; |
b0e82b74 CF |
291 | if (s == NULL) |
292 | return cmalloc (HEAP_STR, n); // kludge | |
293 | ||
294 | assert (!inheap (s)); | |
295 | cygheap_entry *c = tocygheap (s); | |
8d82847a | 296 | cygheap_types t = (cygheap_types) c->type; |
b0e82b74 CF |
297 | c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n)); |
298 | if (!c) | |
299 | system_printf ("crealloc returned NULL"); | |
300 | return creturn (t, c, n); | |
301 | } | |
302 | ||
303 | extern "C" void __stdcall | |
304 | cfree (void *s) | |
305 | { | |
9fc09d00 | 306 | MALLOC_CHECK; |
b0e82b74 CF |
307 | assert (!inheap (s)); |
308 | (void) _cfree (tocygheap (s)); | |
9fc09d00 | 309 | MALLOC_CHECK; |
b0e82b74 CF |
310 | } |
311 | ||
312 | extern "C" void *__stdcall | |
313 | ccalloc (cygheap_types x, DWORD n, DWORD size) | |
314 | { | |
315 | cygheap_entry *c; | |
9fc09d00 | 316 | MALLOC_CHECK; |
b0e82b74 CF |
317 | c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n * size)); |
318 | if (c) | |
bb5d559a | 319 | memset (c->data, 0, n * size); |
b0e82b74 CF |
320 | if (!c) |
321 | system_printf ("ccalloc returned NULL"); | |
322 | return creturn (x, c, n); | |
323 | } | |
324 | ||
325 | extern "C" char *__stdcall | |
326 | cstrdup (const char *s) | |
327 | { | |
9fc09d00 | 328 | MALLOC_CHECK; |
b0e82b74 CF |
329 | char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1); |
330 | if (!p) | |
331 | return NULL; | |
332 | strcpy (p, s); | |
9fc09d00 | 333 | MALLOC_CHECK; |
b0e82b74 CF |
334 | return p; |
335 | } | |
e5648465 CF |
336 | |
337 | extern "C" char *__stdcall | |
338 | cstrdup1 (const char *s) | |
339 | { | |
9fc09d00 | 340 | MALLOC_CHECK; |
e5648465 CF |
341 | char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1); |
342 | if (!p) | |
343 | return NULL; | |
344 | strcpy (p, s); | |
9fc09d00 | 345 | MALLOC_CHECK; |
e5648465 CF |
346 | return p; |
347 | } | |
1f0f8e12 | 348 | |
49eef6d5 CV |
349 | bool |
350 | init_cygheap::etc_changed () | |
351 | { | |
352 | bool res = 0; | |
353 | ||
354 | if (!etc_changed_h) | |
355 | { | |
356 | path_conv pwd ("/etc"); | |
357 | etc_changed_h = FindFirstChangeNotification (pwd, FALSE, | |
358 | FILE_NOTIFY_CHANGE_LAST_WRITE); | |
359 | if (etc_changed_h == INVALID_HANDLE_VALUE) | |
360 | system_printf ("Can't open /etc for checking, %E", (char *) pwd, | |
361 | etc_changed_h); | |
362 | else if (!DuplicateHandle (hMainProc, etc_changed_h, hMainProc, | |
363 | &etc_changed_h, 0, TRUE, | |
364 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) | |
365 | { | |
366 | system_printf ("Can't inherit /etc handle, %E", (char *) pwd, | |
367 | etc_changed_h); | |
368 | etc_changed_h = INVALID_HANDLE_VALUE; | |
369 | } | |
370 | } | |
371 | ||
372 | if (etc_changed_h != INVALID_HANDLE_VALUE | |
373 | && WaitForSingleObject (etc_changed_h, 0) == WAIT_OBJECT_0) | |
374 | { | |
375 | (void) FindNextChangeNotification (etc_changed_h); | |
376 | res = 1; | |
377 | } | |
378 | ||
379 | return res; | |
380 | } | |
381 | ||
7ceb1cac CF |
382 | void |
383 | cygheap_root::set (const char *posix, const char *native) | |
1f0f8e12 | 384 | { |
96a3f4ae CF |
385 | if (*posix == '/' && posix[1] == '\0') |
386 | { | |
387 | if (m) | |
388 | { | |
389 | cfree (m); | |
390 | m = NULL; | |
391 | } | |
392 | return; | |
393 | } | |
7ceb1cac CF |
394 | if (!m) |
395 | m = (struct cygheap_root_mount_info *) ccalloc (HEAP_MOUNT, 1, sizeof (*m)); | |
396 | strcpy (m->posix_path, posix); | |
397 | m->posix_pathlen = strlen (posix); | |
398 | if (m->posix_pathlen >= 1 && m->posix_path[m->posix_pathlen - 1] == '/') | |
399 | m->posix_path[--m->posix_pathlen] = '\0'; | |
400 | ||
401 | strcpy (m->native_path, native); | |
402 | m->native_pathlen = strlen (native); | |
403 | if (m->native_pathlen >= 1 && m->native_path[m->native_pathlen - 1] == '\\') | |
404 | m->native_path[--m->native_pathlen] = '\0'; | |
1f0f8e12 CV |
405 | } |
406 | ||
407 | cygheap_user::~cygheap_user () | |
408 | { | |
cb503978 | 409 | #if 0 |
1f0f8e12 CV |
410 | if (pname) |
411 | cfree (pname); | |
412 | if (plogsrv) | |
413 | cfree (plogsrv); | |
414 | if (pdomain) | |
415 | cfree (pdomain); | |
416 | if (psid) | |
417 | cfree (psid); | |
cb503978 | 418 | #endif |
1f0f8e12 CV |
419 | } |
420 | ||
421 | void | |
422 | cygheap_user::set_name (const char *new_name) | |
423 | { | |
424 | if (pname) | |
425 | cfree (pname); | |
426 | pname = cstrdup (new_name ? new_name : ""); | |
427 | } | |
428 | ||
429 | void | |
430 | cygheap_user::set_logsrv (const char *new_logsrv) | |
431 | { | |
432 | if (plogsrv) | |
433 | cfree (plogsrv); | |
434 | plogsrv = (new_logsrv && *new_logsrv) ? cstrdup (new_logsrv) : NULL; | |
435 | } | |
436 | ||
437 | void | |
438 | cygheap_user::set_domain (const char *new_domain) | |
439 | { | |
440 | if (pdomain) | |
441 | cfree (pdomain); | |
442 | pdomain = (new_domain && *new_domain) ? cstrdup (new_domain) : NULL; | |
443 | } | |
444 | ||
445 | BOOL | |
446 | cygheap_user::set_sid (PSID new_sid) | |
447 | { | |
448 | if (!new_sid) | |
449 | { | |
450 | if (psid) | |
fff42f41 | 451 | cfree (psid); |
1f0f8e12 CV |
452 | psid = NULL; |
453 | return TRUE; | |
454 | } | |
455 | else | |
456 | { | |
457 | if (!psid) | |
458 | psid = cmalloc (HEAP_STR, MAX_SID_LEN); | |
459 | return CopySid (MAX_SID_LEN, psid, new_sid); | |
460 | } | |
461 | } |