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