comparison src/ntheap.c @ 100:4be1180a9e89 r20-1b2

Import from CVS: tag r20-1b2
author cvs
date Mon, 13 Aug 2007 09:15:11 +0200
parents
children 15872534500d
comparison
equal deleted inserted replaced
99:2d83cbd90d8d 100:4be1180a9e89
1 /* Heap management routines for XEmacs on Windows NT.
2 Copyright (C) 1994 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */
22
23 /* Adapted for XEmacs by David Hobley <david@spook-le0.cia.com.au> */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 #include "ntheap.h"
31 #include "lisp.h" /* for VALMASK */
32
33 /* This gives us the page size and the size of the allocation unit on NT. */
34 SYSTEM_INFO sysinfo_cache;
35 unsigned long syspage_mask = 0;
36
37 /* These are defined to get Emacs to compile, but are not used. */
38 int edata;
39 int etext;
40
41 /* The major and minor versions of NT. */
42 int nt_major_version;
43 int nt_minor_version;
44
45 /* Cache information describing the NT system for later use. */
46 void
47 cache_system_info (void)
48 {
49 union
50 {
51 struct info
52 {
53 char major;
54 char minor;
55 short platform;
56 } info;
57 DWORD data;
58 } version;
59
60 /* Cache the version of the operating system. */
61 version.data = GetVersion ();
62 nt_major_version = version.info.major;
63 nt_minor_version = version.info.minor;
64
65 /* Cache page size, allocation unit, processor type, etc. */
66 GetSystemInfo (&sysinfo_cache);
67 syspage_mask = sysinfo_cache.dwPageSize - 1;
68 }
69
70 /* Round ADDRESS up to be aligned with ALIGN. */
71 unsigned char *
72 round_to_next (unsigned char *address, unsigned long align)
73 {
74 unsigned long tmp;
75
76 tmp = (unsigned long) address;
77 tmp = (tmp + align - 1) / align;
78
79 return (unsigned char *) (tmp * align);
80 }
81
82 /* Info for keeping track of our heap. */
83 unsigned char *data_region_base = NULL;
84 unsigned char *data_region_end = NULL;
85 unsigned char *real_data_region_end = NULL;
86 unsigned long data_region_size = 0;
87 unsigned long reserved_heap_size = 0;
88
89 /* The start of the data segment. */
90 unsigned char *
91 get_data_start (void)
92 {
93 return data_region_base;
94 }
95
96 /* The end of the data segment. */
97 unsigned char *
98 get_data_end (void)
99 {
100 return data_region_end;
101 }
102
103 static char *
104 allocate_heap (void)
105 {
106 /* The base address for our GNU malloc heap is chosen in conjuction
107 with the link settings for temacs.exe which control the stack size,
108 the initial default process heap size and the executable image base
109 address. The link settings and the malloc heap base below must all
110 correspond; the relationship between these values depends on how NT
111 and Win95 arrange the virtual address space for a process (and on
112 the size of the code and data segments in temacs.exe).
113
114 The most important thing is to make base address for the executable
115 image high enough to leave enough room between it and the 4MB floor
116 of the process address space on Win95 for the primary thread stack,
117 the process default heap, and other assorted odds and ends
118 (eg. environment strings, private system dll memory etc) that are
119 allocated before temacs has a chance to grab its malloc arena. The
120 malloc heap base can then be set several MB higher than the
121 executable image base, leaving enough room for the code and data
122 segments.
123
124 Because some parts of Emacs can use rather a lot of stack space
125 (for instance, the regular expression routines can potentially
126 allocate several MB of stack space) we allow 8MB for the stack.
127
128 Allowing 1MB for the default process heap, and 1MB for odds and
129 ends, we can base the executable at 16MB and still have a generous
130 safety margin. At the moment, the executable has about 810KB of
131 code (for x86) and about 550KB of data - on RISC platforms the code
132 size could be roughly double, so if we allow 4MB for the executable
133 we will have plenty of room for expansion.
134
135 Thus we would like to set the malloc heap base to 20MB. However,
136 Win95 refuses to allocate the heap starting at this address, so we
137 set the base to 27MB to make it happy. Since Emacs now leaves
138 28 bits available for pointers, this lets us use the remainder of
139 the region below the 256MB line for our malloc arena - 229MB is
140 still a pretty decent arena to play in! */
141
142 unsigned long base = 0x01B00000; /* 27MB */
143 unsigned long end = 1 << VALBITS; /* 256MB */
144 void *ptr = NULL;
145
146 #if NTHEAP_PROBE_BASE /* This is never normally defined */
147 /* Try various addresses looking for one the kernel will let us have. */
148 while (!ptr && (base < end))
149 {
150 reserved_heap_size = end - base;
151 ptr = VirtualAlloc ((void *) base,
152 get_reserved_heap_size (),
153 MEM_RESERVE,
154 PAGE_NOACCESS);
155 base += 0x00100000; /* 1MB increment */
156 }
157 #else
158 reserved_heap_size = end - base;
159 ptr = VirtualAlloc ((void *) base,
160 get_reserved_heap_size (),
161 MEM_RESERVE,
162 PAGE_NOACCESS);
163 #endif
164
165 return ptr;
166 }
167
168
169 /* Emulate Unix sbrk. */
170 void *
171 sbrk (unsigned long increment)
172 {
173 void *result;
174 long size = (long) increment;
175
176 /* Allocate our heap if we haven't done so already. */
177 if (!data_region_base)
178 {
179 data_region_base = allocate_heap ();
180 if (!data_region_base)
181 return NULL;
182
183 /* Ensure that the addresses don't use the upper tag bits since
184 the Lisp type goes there. */
185 if (((unsigned long) data_region_base & ~VALMASK) != 0)
186 {
187 printf ("Error: The heap was allocated in upper memory.\n");
188 exit (1);
189 }
190
191 data_region_end = data_region_base;
192 real_data_region_end = data_region_end;
193 data_region_size = get_reserved_heap_size ();
194 }
195
196 result = data_region_end;
197
198 /* If size is negative, shrink the heap by decommitting pages. */
199 if (size < 0)
200 {
201 int new_size;
202 unsigned char *new_data_region_end;
203
204 size = -size;
205
206 /* Sanity checks. */
207 if ((data_region_end - size) < data_region_base)
208 return NULL;
209
210 /* We can only decommit full pages, so allow for
211 partial deallocation [cga]. */
212 new_data_region_end = (data_region_end - size);
213 new_data_region_end = (unsigned char *)
214 ((long) (new_data_region_end + syspage_mask) & ~syspage_mask);
215 new_size = real_data_region_end - new_data_region_end;
216 real_data_region_end = new_data_region_end;
217 if (new_size > 0)
218 {
219 /* Decommit size bytes from the end of the heap. */
220 if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
221 return NULL;
222 }
223
224 data_region_end -= size;
225 }
226 /* If size is positive, grow the heap by committing reserved pages. */
227 else if (size > 0)
228 {
229 /* Sanity checks. */
230 if ((data_region_end + size) >
231 (data_region_base + get_reserved_heap_size ()))
232 return NULL;
233
234 /* Commit more of our heap. */
235 if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
236 PAGE_READWRITE) == NULL)
237 return NULL;
238 data_region_end += size;
239
240 /* We really only commit full pages, so record where
241 the real end of committed memory is [cga]. */
242 real_data_region_end = (unsigned char *)
243 ((long) (data_region_end + syspage_mask) & ~syspage_mask);
244 }
245
246 return result;
247 }
248
249 #ifndef CANNOT_DUMP
250
251 /* Recreate the heap from the data that was dumped to the executable.
252 EXECUTABLE_PATH tells us where to find the executable. */
253 void
254 recreate_heap (char *executable_path)
255 {
256 unsigned char *tmp;
257
258 /* First reserve the upper part of our heap. (We reserve first
259 because there have been problems in the past where doing the
260 mapping first has loaded DLLs into the VA space of our heap.) */
261 tmp = VirtualAlloc ((void *) get_heap_end (),
262 get_reserved_heap_size () - get_committed_heap_size (),
263 MEM_RESERVE,
264 PAGE_NOACCESS);
265 if (!tmp)
266 exit (1);
267
268 /* We read in the data for the .bss section from the executable
269 first and map in the heap from the executable second to prevent
270 any funny interactions between file I/O and file mapping. */
271 read_in_bss (executable_path);
272 map_in_heap (executable_path);
273 }
274
275 #endif /* CANNOT_DUMP */
276
277 /* Round the heap up to the given alignment. */
278 void
279 round_heap (unsigned long align)
280 {
281 unsigned long needs_to_be;
282 unsigned long need_to_alloc;
283
284 needs_to_be = (unsigned long) round_to_next (get_heap_end (), align);
285 need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
286
287 if (need_to_alloc)
288 sbrk (need_to_alloc);
289 }