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