OSDN Git Service

* cygheap.cc (cygheap_fixup_in_child): Use user_heap element in cygheap.
[pf3gnuchains/sourceware.git] / winsup / cygwin / cygheap.cc
1 /* cygheap.cc: Cygwin heap manager.
2
3    Copyright 2000, 2001, 2002 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 "path.h"
19 #include "dtable.h"
20 #include "cygerrno.h"
21 #include "cygheap.h"
22 #include "child_info.h"
23 #include "heap.h"
24 #include "sync.h"
25 #include "shared_info.h"
26
27 init_cygheap NO_COPY *cygheap;
28 void NO_COPY *cygheap_max;
29
30 static NO_COPY muto *cygheap_protect;
31
32 struct cygheap_entry
33   {
34     int type;
35     struct cygheap_entry *next;
36     char data[0];
37   };
38
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)))
42
43 #define CFMAP_OPTIONS (SEC_RESERVE | PAGE_READWRITE)
44 #define MVMAP_OPTIONS (FILE_MAP_WRITE)
45
46 extern "C" {
47 static void __stdcall _cfree (void *ptr) __attribute__((regparm(1)));
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       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);
62     }
63   cygheap_max = cygheap;
64 }
65
66 static void dup_now (void *, child_info *, unsigned) __attribute__ ((regparm(3)));
67 static void
68 dup_now (void *newcygheap, child_info *ci, unsigned n)
69 {
70   if (!VirtualAlloc (newcygheap, n, MEM_COMMIT, PAGE_READWRITE))
71     api_fatal ("couldn't allocate new cygwin heap %p, %d for child, %E",
72                newcygheap, n);
73   memcpy (newcygheap, cygheap, n);
74 }
75
76 void *__stdcall
77 cygheap_setup_for_child (child_info *ci, bool dup_later)
78 {
79   void *newcygheap;
80   cygheap_protect->acquire ();
81   unsigned n = (char *) cygheap_max - (char *) cygheap;
82   unsigned size = CYGHEAPSIZE;
83   if (size < n)
84     size = n + (128 * 1024);
85   ci->cygheap_h = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_none,
86                                      CFMAP_OPTIONS, 0, size, NULL);
87   if (!ci->cygheap_h)
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);
91   if (!dup_later)
92     dup_now (newcygheap, ci, n);
93   cygheap_protect->release ();
94   ci->cygheap = cygheap;
95   ci->cygheap_max = cygheap_max;
96   return newcygheap;
97 }
98
99 void __stdcall
100 cygheap_setup_for_child_cleanup (void *newcygheap, child_info *ci,
101                                  bool dup_it_now)
102 {
103   if (dup_it_now)
104     {
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 ();
111     }
112   UnmapViewOfFile (newcygheap);
113   ForceCloseHandle1 (ci->cygheap_h, passed_cygheap_h);
114 }
115
116 /* Called by fork or spawn to reallocate cygwin heap */
117 void __stdcall
118 cygheap_fixup_in_child (bool execed)
119 {
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;
123   void *newaddr;
124
125   newaddr = MapViewOfFileEx (child_proc_info->cygheap_h, MVMAP_OPTIONS, 0, 0, 0, addr);
126   if (newaddr != cygheap)
127     {
128       if (!newaddr)
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))
133         {
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");
138
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);
142         }
143
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",
147                    cygheap, n);
148       memcpy (cygheap, newaddr, n);
149       UnmapViewOfFile (newaddr);
150     }
151
152   ForceCloseHandle1 (child_proc_info->cygheap_h, passed_cygheap_h);
153
154   cygheap_init ();
155   debug_fixup_after_fork_exec ();
156
157   if (execed)
158     {
159       cygheap->user_heap.base = NULL;           /* We can allocate the heap anywhere */
160       /* Walk the allocated memory chain looking for orphaned memory from
161          previous execs */
162       for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev)
163         {
164           cygheap_entry *ce = (cygheap_entry *) rvc->data;
165           if (!rvc->ptr || rvc->b >= NBUCKETS || ce->type <= HEAP_1_START)
166             continue;
167           else if (ce->type < HEAP_1_MAX)
168             ce->type += HEAP_1_MAX;     /* Mark for freeing after next exec */
169           else
170             _cfree (ce);                /* Marked by parent for freeing in child */
171         }
172     }
173 }
174
175 #define pagetrunc(x) ((void *) (((DWORD) (x)) & ~(4096 - 1)))
176
177 static void *__stdcall
178 _csbrk (int sbs)
179 {
180   void *prebrk = cygheap_max;
181   void *prebrka = pagetrunc (prebrk);
182   (char *) cygheap_max += sbs;
183   if (!sbs || (prebrk != prebrka && prebrka == pagetrunc (cygheap_max)))
184     /* nothing to do */;
185   else if (!VirtualAlloc (prebrk, (DWORD) sbs, MEM_COMMIT, PAGE_READWRITE))
186     {
187       malloc_printf ("couldn't commit memory for cygwin heap, %E");
188       __seterrno ();
189       (char *) cygheap_max -= sbs;
190       return NULL;
191     }
192
193   return prebrk;
194 }
195
196 extern "C" void __stdcall
197 cygheap_init ()
198 {
199   new_muto (cygheap_protect);
200   if (!cygheap)
201     {
202       init_cheap ();
203       (void) _csbrk (sizeof (*cygheap));
204     }
205   if (!cygheap->fdtab)
206     cygheap->fdtab.init ();
207 }
208
209 /* Copyright (C) 1997, 2000 DJ Delorie */
210
211 static void *_cmalloc (int size) __attribute ((regparm(1)));
212 static void *__stdcall _crealloc (void *ptr, int size) __attribute ((regparm(2)));
213
214 static void *__stdcall
215 _cmalloc (int size)
216 {
217   _cmalloc_entry *rvc;
218   unsigned b, sz;
219
220   /* Calculate "bit bucket" and size as a power of two. */
221   for (b = 3, sz = 8; sz && sz < (size + sizeof (_cmalloc_entry));
222        b++, sz <<= 1)
223     continue;
224
225   cygheap_protect->acquire ();
226   if (cygheap->buckets[b])
227     {
228       rvc = (_cmalloc_entry *) cygheap->buckets[b];
229       cygheap->buckets[b] = rvc->ptr;
230       rvc->b = b;
231     }
232   else
233     {
234       size = sz + sizeof (_cmalloc_entry);
235       rvc = (_cmalloc_entry *) _csbrk (size);
236       if (!rvc)
237         {
238           cygheap_protect->release ();
239           return NULL;
240         }
241
242       rvc->b = b;
243       rvc->prev = cygheap->chain;
244       cygheap->chain = rvc;
245     }
246   cygheap_protect->release ();
247   return rvc->data;
248 }
249
250 static void __stdcall
251 _cfree (void *ptr)
252 {
253   cygheap_protect->acquire ();
254   _cmalloc_entry *rvc = to_cmalloc (ptr);
255   DWORD b = rvc->b;
256   rvc->ptr = cygheap->buckets[b];
257   cygheap->buckets[b] = (char *) rvc;
258   cygheap_protect->release ();
259 }
260
261 static void *__stdcall _crealloc (void *ptr, int size) __attribute__((regparm(2)));
262 static void *__stdcall
263 _crealloc (void *ptr, int size)
264 {
265   void *newptr;
266   if (ptr == NULL)
267     newptr = _cmalloc (size);
268   else
269     {
270       int oldsize = 1 << to_cmalloc (ptr)->b;
271       if (size <= oldsize)
272         return ptr;
273       newptr = _cmalloc (size);
274       memcpy (newptr, ptr, oldsize);
275       _cfree (ptr);
276     }
277   return newptr;
278 }
279
280 /* End Copyright (C) 1997 DJ Delorie */
281
282 #define sizeof_cygheap(n) ((n) + sizeof (cygheap_entry))
283
284 #define N ((cygheap_entry *) NULL)
285 #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data)))
286
287 inline static void *
288 creturn (cygheap_types x, cygheap_entry * c, int len)
289 {
290   if (!c)
291     {
292       __seterrno ();
293       return NULL;
294     }
295   c->type = x;
296   char *cend = ((char *) c + sizeof (*c) + len);
297   if (cygheap_max < cend)
298     cygheap_max = cend;
299   MALLOC_CHECK;
300   return (void *) c->data;
301 }
302
303 extern "C" void *__stdcall
304 cmalloc (cygheap_types x, DWORD n)
305 {
306   cygheap_entry *c;
307   MALLOC_CHECK;
308   c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
309   if (!c)
310     system_printf ("cmalloc returned NULL");
311   return creturn (x, c, n);
312 }
313
314 extern "C" void *__stdcall
315 crealloc (void *s, DWORD n)
316 {
317   MALLOC_CHECK;
318   if (s == NULL)
319     return cmalloc (HEAP_STR, n);       // kludge
320
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));
325   if (!c)
326     system_printf ("crealloc returned NULL");
327   return creturn (t, c, n);
328 }
329
330 extern "C" void __stdcall
331 cfree (void *s)
332 {
333   assert (!inheap (s));
334   (void) _cfree (tocygheap (s));
335   MALLOC_CHECK;
336 }
337
338 extern "C" void __stdcall
339 cfree_and_set (char *&s, char *what)
340 {
341   if (s && s != almost_null)
342     cfree (s);
343   s = what;
344 }
345
346 extern "C" void *__stdcall
347 ccalloc (cygheap_types x, DWORD n, DWORD size)
348 {
349   cygheap_entry *c;
350   MALLOC_CHECK;
351   n *= size;
352   c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
353   if (c)
354     memset (c->data, 0, n);
355   if (!c)
356     system_printf ("ccalloc returned NULL");
357   return creturn (x, c, n);
358 }
359
360 extern "C" char *__stdcall
361 cstrdup (const char *s)
362 {
363   MALLOC_CHECK;
364   char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1);
365   if (!p)
366     return NULL;
367   strcpy (p, s);
368   MALLOC_CHECK;
369   return p;
370 }
371
372 extern "C" char *__stdcall
373 cstrdup1 (const char *s)
374 {
375   MALLOC_CHECK;
376   char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1);
377   if (!p)
378     return NULL;
379   strcpy (p, s);
380   MALLOC_CHECK;
381   return p;
382 }
383
384 bool
385 init_cygheap::etc_changed ()
386 {
387   bool res = 0;
388
389   if (!etc_changed_h)
390     {
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,
396                        etc_changed_h);
397       else if (!DuplicateHandle (hMainProc, etc_changed_h, hMainProc,
398                                  &etc_changed_h, 0, TRUE,
399                                  DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
400         {
401           system_printf ("Can't inherit /etc handle, %E", (char *) pwd,
402                          etc_changed_h);
403           etc_changed_h = INVALID_HANDLE_VALUE;
404         }
405     }
406
407    if (etc_changed_h != INVALID_HANDLE_VALUE
408        && WaitForSingleObject (etc_changed_h, 0) == WAIT_OBJECT_0)
409      {
410        (void) FindNextChangeNotification (etc_changed_h);
411        res = 1;
412      }
413
414   return res;
415 }
416
417 void
418 cygheap_root::set (const char *posix, const char *native)
419 {
420   if (*posix == '/' && posix[1] == '\0')
421     {
422       if (m)
423         {
424           cfree (m);
425           m = NULL;
426         }
427       return;
428     }
429   if (!m)
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';
435
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';
440 }
441
442 cygheap_user::~cygheap_user ()
443 {
444 #if 0
445   if (pname)
446     cfree (pname);
447   if (plogsrv)
448     cfree (plogsrv - 2);
449   if (pdomain)
450     cfree (pdomain);
451   if (psid)
452     cfree (psid);
453 #endif
454 }
455
456 void
457 cygheap_user::set_name (const char *new_name)
458 {
459   bool allocated = !!pname;
460
461   if (allocated)
462     {
463       if (strcasematch (new_name, pname))
464         return;
465       cfree (pname);
466     }
467
468   pname = cstrdup (new_name ? new_name : "");
469   if (!allocated)
470     return;             /* Initializing.  Don't bother with other stuff. */
471
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);
477 }
478
479 BOOL
480 cygheap_user::set_sid (PSID new_sid)
481 {
482   if (new_sid)
483     {
484       if (!psid)
485         psid = cmalloc (HEAP_STR, MAX_SID_LEN);
486       if (psid)
487         return CopySid (MAX_SID_LEN, psid, new_sid);
488     }
489   return FALSE;
490 }
491
492 BOOL
493 cygheap_user::set_orig_sid ()
494 {
495   if (psid)
496     {
497       if (!orig_psid) orig_psid = cmalloc (HEAP_STR, MAX_SID_LEN);
498       if (orig_psid)
499           return CopySid (MAX_SID_LEN, orig_psid, psid);
500     }
501   return FALSE;
502 }