1 /* cygheap.cc: Cygwin heap manager.
3 Copyright 2000, 2001, 2002 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
22 #include "child_info.h"
25 #include "shared_info.h"
27 init_cygheap NO_COPY *cygheap;
28 void NO_COPY *cygheap_max;
30 static NO_COPY muto *cygheap_protect;
35 struct cygheap_entry *next;
39 #define NBUCKETS (sizeof (cygheap->buckets) / sizeof (cygheap->buckets[0]))
40 #define N0 ((_cmalloc_entry *) NULL)
41 #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (int) (N0->data)))
43 #define CFMAP_OPTIONS (SEC_RESERVE | PAGE_READWRITE)
44 #define MVMAP_OPTIONS (FILE_MAP_WRITE)
47 static void __stdcall _cfree (void *ptr) __attribute__((regparm(1)));
53 cygheap = (init_cygheap *) VirtualAlloc ((void *) &_cygheap_start, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS);
56 MEMORY_BASIC_INFORMATION m;
57 if (!VirtualQuery ((LPCVOID) &_cygheap_start, &m, sizeof m))
58 system_printf ("couldn't get memory info, %E");
59 system_printf ("Couldn't reserve space for cygwin's heap, %E");
60 api_fatal ("AllocationBase %p, BaseAddress %p, RegionSize %p, State %p\n",
61 m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
63 cygheap_max = cygheap;
66 static void dup_now (void *, child_info *, unsigned) __attribute__ ((regparm(3)));
68 dup_now (void *newcygheap, child_info *ci, unsigned n)
70 if (!VirtualAlloc (newcygheap, n, MEM_COMMIT, PAGE_READWRITE))
71 api_fatal ("couldn't allocate new cygwin heap %p, %d for child, %E",
73 memcpy (newcygheap, cygheap, n);
77 cygheap_setup_for_child (child_info *ci, bool dup_later)
80 cygheap_protect->acquire ();
81 unsigned n = (char *) cygheap_max - (char *) cygheap;
82 unsigned size = CYGHEAPSIZE;
84 size = n + (128 * 1024);
85 ci->cygheap_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none,
86 CFMAP_OPTIONS, 0, size, NULL);
88 api_fatal ("Couldn't create heap for child, size %d, %E", CYGHEAPSIZE);
89 newcygheap = MapViewOfFileEx (ci->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL);
90 ProtectHandle1INH (ci->cygheap_h, passed_cygheap_h);
92 dup_now (newcygheap, ci, n);
93 cygheap_protect->release ();
94 ci->cygheap = cygheap;
95 ci->cygheap_max = cygheap_max;
100 cygheap_setup_for_child_cleanup (void *newcygheap, child_info *ci,
105 /* NOTE: There is an assumption here that cygheap_max has not changed
106 between the time that cygheap_setup_for_child was called and now.
107 Make sure that this is a correct assumption. */
108 cygheap_protect->acquire ();
109 dup_now (newcygheap, ci, (char *) cygheap_max - (char *) cygheap);
110 cygheap_protect->release ();
112 UnmapViewOfFile (newcygheap);
113 ForceCloseHandle1 (ci->cygheap_h, passed_cygheap_h);
116 /* Called by fork or spawn to reallocate cygwin heap */
118 cygheap_fixup_in_child (bool execed)
120 cygheap = child_proc_info->cygheap;
121 cygheap_max = child_proc_info->cygheap_max;
122 void *addr = !wincap.map_view_of_file_ex_sucks () ? cygheap : NULL;
125 newaddr = MapViewOfFileEx (child_proc_info->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, addr);
126 if (newaddr != cygheap)
129 newaddr = MapViewOfFileEx (child_proc_info->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, NULL);
130 DWORD n = (DWORD) cygheap_max - (DWORD) cygheap;
131 /* Reserve cygwin heap in same spot as parent */
132 if (!VirtualAlloc (cygheap, CYGHEAPSIZE, MEM_RESERVE, PAGE_NOACCESS))
134 MEMORY_BASIC_INFORMATION m;
135 memset (&m, 0, sizeof m);
136 if (!VirtualQuery ((LPCVOID) cygheap, &m, sizeof m))
137 system_printf ("couldn't get memory info, %E");
139 system_printf ("Couldn't reserve space for cygwin's heap (%p <%p>) in child, %E", cygheap, newaddr);
140 api_fatal ("m.AllocationBase %p, m.BaseAddress %p, m.RegionSize %p, m.State %p\n",
141 m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
144 /* Allocate same amount of memory as parent */
145 if (!VirtualAlloc (cygheap, n, MEM_COMMIT, PAGE_READWRITE))
146 api_fatal ("Couldn't allocate space for child's heap %p, size %d, %E",
148 memcpy (cygheap, newaddr, n);
149 UnmapViewOfFile (newaddr);
152 ForceCloseHandle1 (child_proc_info->cygheap_h, passed_cygheap_h);
155 debug_fixup_after_fork_exec ();
159 cygheap->user_heap.base = NULL; /* We can allocate the heap anywhere */
160 /* Walk the allocated memory chain looking for orphaned memory from
162 for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev)
164 cygheap_entry *ce = (cygheap_entry *) rvc->data;
165 if (!rvc->ptr || rvc->b >= NBUCKETS || ce->type <= HEAP_1_START)
167 else if (ce->type < HEAP_1_MAX)
168 ce->type += HEAP_1_MAX; /* Mark for freeing after next exec */
170 _cfree (ce); /* Marked by parent for freeing in child */
175 #define pagetrunc(x) ((void *) (((DWORD) (x)) & ~(4096 - 1)))
177 static void *__stdcall
180 void *prebrk = cygheap_max;
181 void *prebrka = pagetrunc (prebrk);
182 (char *) cygheap_max += sbs;
183 if (!sbs || (prebrk != prebrka && prebrka == pagetrunc (cygheap_max)))
185 else if (!VirtualAlloc (prebrk, (DWORD) sbs, MEM_COMMIT, PAGE_READWRITE))
187 malloc_printf ("couldn't commit memory for cygwin heap, %E");
189 (char *) cygheap_max -= sbs;
196 extern "C" void __stdcall
199 new_muto (cygheap_protect);
203 (void) _csbrk (sizeof (*cygheap));
206 cygheap->fdtab.init ();
209 /* Copyright (C) 1997, 2000 DJ Delorie */
211 static void *_cmalloc (int size) __attribute ((regparm(1)));
212 static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2)));
214 static void *__stdcall
220 /* Calculate "bit bucket" and size as a power of two. */
221 for (b = 3, sz = 8; sz && sz < (size + sizeof (_cmalloc_entry));
225 cygheap_protect->acquire ();
226 if (cygheap->buckets[b])
228 rvc = (_cmalloc_entry *) cygheap->buckets[b];
229 cygheap->buckets[b] = rvc->ptr;
234 size = sz + sizeof (_cmalloc_entry);
235 rvc = (_cmalloc_entry *) _csbrk (size);
238 cygheap_protect->release ();
243 rvc->prev = cygheap->chain;
244 cygheap->chain = rvc;
246 cygheap_protect->release ();
250 static void __stdcall
253 cygheap_protect->acquire ();
254 _cmalloc_entry *rvc = to_cmalloc (ptr);
256 rvc->ptr = cygheap->buckets[b];
257 cygheap->buckets[b] = (char *) rvc;
258 cygheap_protect->release ();
261 static void *__stdcall _crealloc (void *ptr, int size) __attribute__((regparm(2)));
262 static void *__stdcall
263 _crealloc (void *ptr, int size)
267 newptr = _cmalloc (size);
270 int oldsize = 1 << to_cmalloc (ptr)->b;
273 newptr = _cmalloc (size);
274 memcpy (newptr, ptr, oldsize);
280 /* End Copyright (C) 1997 DJ Delorie */
282 #define sizeof_cygheap(n) ((n) + sizeof (cygheap_entry))
284 #define N ((cygheap_entry *) NULL)
285 #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data)))
288 creturn (cygheap_types x, cygheap_entry * c, int len)
296 char *cend = ((char *) c + sizeof (*c) + len);
297 if (cygheap_max < cend)
300 return (void *) c->data;
303 extern "C" void *__stdcall
304 cmalloc (cygheap_types x, DWORD n)
308 c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
310 system_printf ("cmalloc returned NULL");
311 return creturn (x, c, n);
314 extern "C" void *__stdcall
315 crealloc (void *s, DWORD n)
319 return cmalloc (HEAP_STR, n); // kludge
321 assert (!inheap (s));
322 cygheap_entry *c = tocygheap (s);
323 cygheap_types t = (cygheap_types) c->type;
324 c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n));
326 system_printf ("crealloc returned NULL");
327 return creturn (t, c, n);
330 extern "C" void __stdcall
333 assert (!inheap (s));
334 (void) _cfree (tocygheap (s));
338 extern "C" void __stdcall
339 cfree_and_set (char *&s, char *what)
341 if (s && s != almost_null)
346 extern "C" void *__stdcall
347 ccalloc (cygheap_types x, DWORD n, DWORD size)
352 c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
354 memset (c->data, 0, n);
356 system_printf ("ccalloc returned NULL");
357 return creturn (x, c, n);
360 extern "C" char *__stdcall
361 cstrdup (const char *s)
364 char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1);
372 extern "C" char *__stdcall
373 cstrdup1 (const char *s)
376 char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1);
385 init_cygheap::etc_changed ()
391 path_conv pwd ("/etc");
392 etc_changed_h = FindFirstChangeNotification (pwd, FALSE,
393 FILE_NOTIFY_CHANGE_LAST_WRITE);
394 if (etc_changed_h == INVALID_HANDLE_VALUE)
395 system_printf ("Can't open /etc for checking, %E", (char *) pwd,
397 else if (!DuplicateHandle (hMainProc, etc_changed_h, hMainProc,
398 &etc_changed_h, 0, TRUE,
399 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
401 system_printf ("Can't inherit /etc handle, %E", (char *) pwd,
403 etc_changed_h = INVALID_HANDLE_VALUE;
407 if (etc_changed_h != INVALID_HANDLE_VALUE
408 && WaitForSingleObject (etc_changed_h, 0) == WAIT_OBJECT_0)
410 (void) FindNextChangeNotification (etc_changed_h);
418 cygheap_root::set (const char *posix, const char *native)
420 if (*posix == '/' && posix[1] == '\0')
430 m = (struct cygheap_root_mount_info *) ccalloc (HEAP_MOUNT, 1, sizeof (*m));
431 strcpy (m->posix_path, posix);
432 m->posix_pathlen = strlen (posix);
433 if (m->posix_pathlen >= 1 && m->posix_path[m->posix_pathlen - 1] == '/')
434 m->posix_path[--m->posix_pathlen] = '\0';
436 strcpy (m->native_path, native);
437 m->native_pathlen = strlen (native);
438 if (m->native_pathlen >= 1 && m->native_path[m->native_pathlen - 1] == '\\')
439 m->native_path[--m->native_pathlen] = '\0';
442 cygheap_user::~cygheap_user ()
457 cygheap_user::set_name (const char *new_name)
459 bool allocated = !!pname;
463 if (strcasematch (new_name, pname))
468 pname = cstrdup (new_name ? new_name : "");
470 return; /* Initializing. Don't bother with other stuff. */
472 cfree_and_set (homedrive);
473 cfree_and_set (homepath);
474 cfree_and_set (plogsrv);
475 cfree_and_set (pdomain);
476 cfree_and_set (pwinname);
480 cygheap_user::set_sid (PSID new_sid)
485 psid = cmalloc (HEAP_STR, MAX_SID_LEN);
487 return CopySid (MAX_SID_LEN, psid, new_sid);
493 cygheap_user::set_orig_sid ()
497 if (!orig_psid) orig_psid = cmalloc (HEAP_STR, MAX_SID_LEN);
499 return CopySid (MAX_SID_LEN, orig_psid, psid);