OSDN Git Service

af5140a5683c9caa947e7c5fd5a85e7cf9632b4c
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / cygheap.cc
1 /* cygheap.cc: Cygwin heap manager.
2
3    Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 <assert.h>
13 #include <stdlib.h>
14 #include "cygerrno.h"
15 #include "security.h"
16 #include "path.h"
17 #include "fhandler.h"
18 #include "dtable.h"
19 #include "cygheap.h"
20 #include "child_info.h"
21 #include "heap.h"
22 #include "sigproc.h"
23 #include "pinfo.h"
24 #include <unistd.h>
25 #include <wchar.h>
26
27 static mini_cygheap NO_COPY cygheap_at_start =
28 {
29   {__utf8_mbtowc, __utf8_wctomb}
30 };
31
32 init_cygheap NO_COPY *cygheap = (init_cygheap *) &cygheap_at_start;
33 void NO_COPY *cygheap_max;
34
35 extern "C" char  _cygheap_mid[] __attribute__((section(".cygheap")));
36 extern "C" char  _cygheap_end[];
37
38 static NO_COPY muto cygheap_protect;
39
40 struct cygheap_entry
41 {
42   int type;
43   struct cygheap_entry *next;
44   char data[0];
45 };
46
47 #define NBUCKETS (sizeof (cygheap->buckets) / sizeof (cygheap->buckets[0]))
48 #define N0 ((_cmalloc_entry *) NULL)
49 #define to_cmalloc(s) ((_cmalloc_entry *) (((char *) (s)) - (unsigned) (N0->data)))
50
51 #define CFMAP_OPTIONS (SEC_RESERVE | PAGE_READWRITE)
52 #define MVMAP_OPTIONS (FILE_MAP_WRITE)
53
54 extern "C" {
55 static void __stdcall _cfree (void *) __attribute__((regparm(1)));
56 static void *__stdcall _csbrk (int);
57 }
58
59 /* Called by fork or spawn to reallocate cygwin heap */
60 void __stdcall
61 cygheap_fixup_in_child (bool execed)
62 {
63   cygheap_max = child_proc_info->cygheap;
64   cygheap = (init_cygheap *) cygheap_max;
65   _csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap);
66   child_copy (child_proc_info->parent, false, "cygheap", cygheap, cygheap_max, NULL);
67   cygheap_init ();
68   debug_fixup_after_fork_exec ();
69   if (execed)
70     {
71       cygheap->hooks.next = NULL;
72       cygheap->user_heap.base = NULL;           /* We can allocate the heap anywhere */
73       /* Walk the allocated memory chain looking for orphaned memory from
74          previous execs */
75       for (_cmalloc_entry *rvc = cygheap->chain; rvc; rvc = rvc->prev)
76         {
77           cygheap_entry *ce = (cygheap_entry *) rvc->data;
78           if (!rvc->ptr || rvc->b >= NBUCKETS || ce->type <= HEAP_1_START)
79             continue;
80           else if (ce->type < HEAP_1_MAX)
81             ce->type += HEAP_1_MAX;     /* Mark for freeing after next exec */
82           else
83             _cfree (ce);                /* Marked by parent for freeing in child */
84         }
85     }
86 }
87
88 int
89 init_cygheap::manage_console_count (const char *something, int amount, bool avoid_freeing_console)
90 {
91   if (console_count == 0 && amount > 0)
92     init_console_handler (true);
93   console_count += amount;
94   debug_printf ("%s: console_count %d, amount %d, %s, avoid_freeing_console %d",
95                 something, console_count, amount, myctty (), avoid_freeing_console);
96   if (!avoid_freeing_console && amount <= 0 && !console_count && myself->ctty == -1)
97     {
98       BOOL res = FreeConsole ();
99       debug_printf ("freed console, res %d", res);
100       init_console_handler (false);
101     }
102   return console_count;
103 }
104
105 void
106 init_cygheap::close_ctty ()
107 {
108   debug_printf ("closing cygheap->ctty %p", cygheap->ctty);
109   cygheap->ctty->close ();
110   cygheap->ctty = NULL;
111 }
112
113 #define nextpage(x) ((char *) (((DWORD) ((char *) x + granmask)) & ~granmask))
114 #define allocsize(x) ((DWORD) nextpage (x))
115 #ifdef DEBUGGING
116 #define somekinda_printf debug_printf
117 #else
118 #define somekinda_printf malloc_printf
119 #endif
120
121 static void *__stdcall
122 _csbrk (int sbs)
123 {
124   void *prebrk = cygheap_max;
125   size_t granmask = getpagesize () - 1;
126   char *newbase = nextpage (prebrk);
127   cygheap_max = (char *) cygheap_max + sbs;
128   if (!sbs || (newbase >= cygheap_max) || (cygheap_max <= _cygheap_end))
129     /* nothing to do */;
130   else
131     {
132       if (prebrk <= _cygheap_end)
133         newbase = _cygheap_end;
134
135       DWORD adjsbs = allocsize ((char *) cygheap_max - newbase);
136       if (adjsbs && !VirtualAlloc (newbase, adjsbs, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))
137         {
138           MEMORY_BASIC_INFORMATION m;
139           if (!VirtualQuery (newbase, &m, sizeof m))
140             system_printf ("couldn't get memory info, %E");
141           somekinda_printf ("Couldn't reserve/commit %d bytes of space for cygwin's heap, %E",
142                             adjsbs);
143           somekinda_printf ("AllocationBase %p, BaseAddress %p, RegionSize %p, State %p\n",
144                             m.AllocationBase, m.BaseAddress, m.RegionSize, m.State);
145           __seterrno ();
146           cygheap_max = (char *) cygheap_max - sbs;
147           return NULL;
148         }
149     }
150
151   return prebrk;
152 }
153
154 void __stdcall
155 cygheap_init ()
156 {
157   cygheap_protect.init ("cygheap_protect");
158   if (cygheap == &cygheap_at_start)
159     {
160       cygheap = (init_cygheap *) memset (_cygheap_start, 0,
161                                          _cygheap_mid - _cygheap_start);
162       cygheap_max = cygheap;
163       _csbrk (sizeof (*cygheap));
164       /* Default locale settings. */
165       cygheap->locale.mbtowc = __utf8_mbtowc;
166       cygheap->locale.wctomb = __utf8_wctomb;
167       strcpy (cygheap->locale.charset, "ASCII");
168       /* Set umask to a sane default. */
169       cygheap->umask = 022;
170     }
171   if (!cygheap->fdtab)
172     cygheap->fdtab.init ();
173   if (!cygheap->sigs)
174     sigalloc ();
175 }
176
177 /* Copyright (C) 1997, 2000 DJ Delorie */
178
179 static void *_cmalloc (unsigned size) __attribute ((regparm(1)));
180 static void *__stdcall _crealloc (void *ptr, unsigned size) __attribute ((regparm(2)));
181
182 static void *__stdcall
183 _cmalloc (unsigned size)
184 {
185   _cmalloc_entry *rvc;
186   unsigned b, sz;
187
188   /* Calculate "bit bucket" and size as a power of two. */
189   for (b = 3, sz = 8; sz && sz < size; b++, sz <<= 1)
190     continue;
191
192   cygheap_protect.acquire ();
193   if (cygheap->buckets[b])
194     {
195       rvc = (_cmalloc_entry *) cygheap->buckets[b];
196       cygheap->buckets[b] = rvc->ptr;
197       rvc->b = b;
198     }
199   else
200     {
201       rvc = (_cmalloc_entry *) _csbrk (sz + sizeof (_cmalloc_entry));
202       if (!rvc)
203         {
204           cygheap_protect.release ();
205           return NULL;
206         }
207
208       rvc->b = b;
209       rvc->prev = cygheap->chain;
210       cygheap->chain = rvc;
211     }
212   cygheap_protect.release ();
213   return rvc->data;
214 }
215
216 static void __stdcall
217 _cfree (void *ptr)
218 {
219   cygheap_protect.acquire ();
220   _cmalloc_entry *rvc = to_cmalloc (ptr);
221   DWORD b = rvc->b;
222   rvc->ptr = cygheap->buckets[b];
223   cygheap->buckets[b] = (char *) rvc;
224   cygheap_protect.release ();
225 }
226
227 static void *__stdcall
228 _crealloc (void *ptr, unsigned size)
229 {
230   void *newptr;
231   if (ptr == NULL)
232     newptr = _cmalloc (size);
233   else
234     {
235       unsigned oldsize = 1 << to_cmalloc (ptr)->b;
236       if (size <= oldsize)
237         return ptr;
238       newptr = _cmalloc (size);
239       if (newptr)
240         {
241           memcpy (newptr, ptr, oldsize);
242           _cfree (ptr);
243         }
244     }
245   return newptr;
246 }
247
248 /* End Copyright (C) 1997 DJ Delorie */
249
250 #define sizeof_cygheap(n) ((n) + sizeof (cygheap_entry))
251
252 #define N ((cygheap_entry *) NULL)
253 #define tocygheap(s) ((cygheap_entry *) (((char *) (s)) - (int) (N->data)))
254
255 inline static void *
256 creturn (cygheap_types x, cygheap_entry * c, unsigned len, const char *fn = NULL)
257 {
258   if (c)
259     /* nothing to do */;
260   else if (fn)
261     api_fatal ("%s would have returned NULL", fn);
262   else
263     {
264       set_errno (ENOMEM);
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 inline static void *
276 cmalloc (cygheap_types x, DWORD n, const char *fn)
277 {
278   cygheap_entry *c;
279   MALLOC_CHECK;
280   c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
281   return creturn (x, c, n, fn);
282 }
283
284 extern "C" void *
285 cmalloc (cygheap_types x, DWORD n)
286 {
287   return cmalloc (x, n, NULL);
288 }
289
290 extern "C" void *
291 cmalloc_abort (cygheap_types x, DWORD n)
292 {
293   return cmalloc (x, n, "cmalloc");
294 }
295
296 inline static void *
297 crealloc (void *s, DWORD n, const char *fn)
298 {
299   MALLOC_CHECK;
300   if (s == NULL)
301     return cmalloc (HEAP_STR, n);       // kludge
302
303   assert (!inheap (s));
304   cygheap_entry *c = tocygheap (s);
305   cygheap_types t = (cygheap_types) c->type;
306   c = (cygheap_entry *) _crealloc (c, sizeof_cygheap (n));
307   return creturn (t, c, n, fn);
308 }
309
310 extern "C" void *__stdcall
311 crealloc (void *s, DWORD n)
312 {
313   return crealloc (s, n, NULL);
314 }
315
316 extern "C" void *__stdcall
317 crealloc_abort (void *s, DWORD n)
318 {
319   return crealloc (s, n, "crealloc");
320 }
321
322 extern "C" void __stdcall
323 cfree (void *s)
324 {
325   assert (!inheap (s));
326   _cfree (tocygheap (s));
327   MALLOC_CHECK;
328 }
329
330 extern "C" void __stdcall
331 cfree_and_set (char *&s, char *what)
332 {
333   if (s && s != almost_null)
334     cfree (s);
335   s = what;
336 }
337
338 inline static void *
339 ccalloc (cygheap_types x, DWORD n, DWORD size, const char *fn)
340 {
341   cygheap_entry *c;
342   MALLOC_CHECK;
343   n *= size;
344   c = (cygheap_entry *) _cmalloc (sizeof_cygheap (n));
345   if (c)
346     memset (c->data, 0, n);
347   return creturn (x, c, n, fn);
348 }
349
350 extern "C" void *__stdcall
351 ccalloc (cygheap_types x, DWORD n, DWORD size)
352 {
353   return ccalloc (x, n, size, NULL);
354 }
355
356 extern "C" void *__stdcall
357 ccalloc_abort (cygheap_types x, DWORD n, DWORD size)
358 {
359   return ccalloc (x, n, size, "ccalloc");
360 }
361
362 extern "C" PWCHAR __stdcall
363 cwcsdup (const PWCHAR s)
364 {
365   MALLOC_CHECK;
366   PWCHAR p = (PWCHAR) cmalloc (HEAP_STR, wcslen (s) + 1);
367   if (!p)
368     return NULL;
369   wcpcpy (p, s);
370   MALLOC_CHECK;
371   return p;
372 }
373
374 extern "C" PWCHAR __stdcall
375 cwcsdup1 (const PWCHAR s)
376 {
377   MALLOC_CHECK;
378   PWCHAR p = (PWCHAR) cmalloc (HEAP_1_STR, wcslen (s) + 1);
379   if (!p)
380     return NULL;
381   wcpcpy (p, s);
382   MALLOC_CHECK;
383   return p;
384 }
385
386 extern "C" char *__stdcall
387 cstrdup (const char *s)
388 {
389   MALLOC_CHECK;
390   char *p = (char *) cmalloc (HEAP_STR, strlen (s) + 1);
391   if (!p)
392     return NULL;
393   strcpy (p, s);
394   MALLOC_CHECK;
395   return p;
396 }
397
398 extern "C" char *__stdcall
399 cstrdup1 (const char *s)
400 {
401   MALLOC_CHECK;
402   char *p = (char *) cmalloc (HEAP_1_STR, strlen (s) + 1);
403   if (!p)
404     return NULL;
405   strcpy (p, s);
406   MALLOC_CHECK;
407   return p;
408 }
409
410 void
411 cygheap_root::set (const char *posix, const char *native, bool caseinsensitive)
412 {
413   if (*posix == '/' && posix[1] == '\0')
414     {
415       if (m)
416         {
417           cfree (m);
418           m = NULL;
419         }
420       return;
421     }
422   if (!m)
423     m = (struct cygheap_root_mount_info *) ccalloc (HEAP_MOUNT, 1, sizeof (*m));
424   strcpy (m->posix_path, posix);
425   m->posix_pathlen = strlen (posix);
426   if (m->posix_pathlen >= 1 && m->posix_path[m->posix_pathlen - 1] == '/')
427     m->posix_path[--m->posix_pathlen] = '\0';
428
429   strcpy (m->native_path, native);
430   m->native_pathlen = strlen (native);
431   if (m->native_pathlen >= 1 && m->native_path[m->native_pathlen - 1] == '\\')
432     m->native_path[--m->native_pathlen] = '\0';
433   m->caseinsensitive = caseinsensitive;
434 }
435
436 cygheap_user::~cygheap_user ()
437 {
438 }
439
440 void
441 cygheap_user::set_name (const char *new_name)
442 {
443   bool allocated = !!pname;
444
445   if (allocated)
446     {
447       if (strcasematch (new_name, pname))
448         return;
449       cfree (pname);
450     }
451
452   pname = cstrdup (new_name ? new_name : "");
453   if (!allocated)
454     return;             /* Initializing.  Don't bother with other stuff. */
455
456   cfree_and_set (homedrive);
457   cfree_and_set (homepath);
458   cfree_and_set (plogsrv);
459   cfree_and_set (pdomain);
460   cfree_and_set (pwinname);
461 }