]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/cygheap.cc
* cygheap.cc (init_cygheap::etc_changed): New method to signal
[newlib-cygwin.git] / winsup / cygwin / cygheap.cc
CommitLineData
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 27init_cygheap NO_COPY *cygheap;
1ec4f618 28void NO_COPY *cygheap_max = NULL;
8d82847a 29
9fc09d00
CF
30static NO_COPY muto *cygheap_protect = NULL;
31
5457dfcb
CF
32struct 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
46extern "C" {
47static void __stdcall _cfree (void *ptr) __attribute__((regparm(1)));
5835f2cf 48extern void *_cygheap_start;
5457dfcb
CF
49}
50
b0e82b74
CF
51inline static void
52init_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
67void __stdcall
68cygheap_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
87void __stdcall
88cygheap_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 */
94void __stdcall
95cygheap_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
152static 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
178extern "C" void __stdcall
179cygheap_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
189static void *_cmalloc (int size) __attribute ((regparm(1)));
190static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2)));
191
b0e82b74
CF
192static 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
223static 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 234static void *__stdcall _crealloc (void *ptr, int size) __attribute__((regparm(2)));
b0e82b74
CF
235static 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 260inline static void *
b0e82b74
CF
261creturn (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
276extern "C" void *__stdcall
277cmalloc (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
287extern "C" void *__stdcall
288crealloc (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
303extern "C" void __stdcall
304cfree (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
312extern "C" void *__stdcall
313ccalloc (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
325extern "C" char *__stdcall
326cstrdup (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
337extern "C" char *__stdcall
338cstrdup1 (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
349bool
350init_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
382void
383cygheap_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
407cygheap_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
421void
422cygheap_user::set_name (const char *new_name)
423{
424 if (pname)
425 cfree (pname);
426 pname = cstrdup (new_name ? new_name : "");
427}
428
429void
430cygheap_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
437void
438cygheap_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
445BOOL
446cygheap_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}
This page took 0.105676 seconds and 5 git commands to generate.