16884
|
1 /* Heap management routines for GNU Emacs on the Microsoft W32 API.
|
9803
|
2 Copyright (C) 1994 Free Software Foundation, Inc.
|
|
3
|
14186
|
4 This file is part of GNU Emacs.
|
9803
|
5
|
14186
|
6 GNU Emacs is free software; you can redistribute it and/or modify
|
|
7 it under the terms of the GNU General Public License as published by
|
|
8 the Free Software Foundation; either version 2, or (at your option)
|
|
9 any later version.
|
9803
|
10
|
14186
|
11 GNU Emacs is distributed in the hope that it will be useful,
|
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 GNU General Public License for more details.
|
9803
|
15
|
14186
|
16 You should have received a copy of the GNU General Public License
|
|
17 along with GNU Emacs; see the file COPYING. If not, write to
|
|
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
19 Boston, MA 02111-1307, USA.
|
9803
|
20
|
|
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
|
|
22 */
|
|
23
|
42469
|
24 #ifdef HAVE_CONFIG_H
|
|
25 #include <config.h>
|
|
26 #endif
|
12452
|
27
|
9803
|
28 #include <stdlib.h>
|
|
29 #include <stdio.h>
|
|
30
|
16593
|
31 #include "w32heap.h"
|
15143
|
32 #include "lisp.h" /* for VALMASK */
|
9803
|
33
|
24103
|
34 #undef RVA_TO_PTR
|
31111
|
35 #define RVA_TO_PTR(rva) ((unsigned char *)((DWORD)(rva) + (DWORD)GetModuleHandle (NULL)))
|
24103
|
36
|
9803
|
37 /* This gives us the page size and the size of the allocation unit on NT. */
|
|
38 SYSTEM_INFO sysinfo_cache;
|
24886
|
39
|
|
40 /* This gives us version, build, and platform identification. */
|
|
41 OSVERSIONINFO osinfo_cache;
|
|
42
|
12452
|
43 unsigned long syspage_mask = 0;
|
9803
|
44
|
|
45 /* These are defined to get Emacs to compile, but are not used. */
|
|
46 int edata;
|
|
47 int etext;
|
|
48
|
|
49 /* The major and minor versions of NT. */
|
16588
|
50 int w32_major_version;
|
|
51 int w32_minor_version;
|
33215
|
52 int w32_build_number;
|
9803
|
53
|
19708
|
54 /* Distinguish between Windows NT and Windows 95. */
|
|
55 int os_subtype;
|
|
56
|
9803
|
57 /* Cache information describing the NT system for later use. */
|
|
58 void
|
|
59 cache_system_info (void)
|
|
60 {
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
61 union
|
9803
|
62 {
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
63 struct info
|
9803
|
64 {
|
|
65 char major;
|
|
66 char minor;
|
|
67 short platform;
|
|
68 } info;
|
|
69 DWORD data;
|
|
70 } version;
|
|
71
|
|
72 /* Cache the version of the operating system. */
|
|
73 version.data = GetVersion ();
|
16588
|
74 w32_major_version = version.info.major;
|
|
75 w32_minor_version = version.info.minor;
|
9803
|
76
|
19708
|
77 if (version.info.platform & 0x8000)
|
|
78 os_subtype = OS_WIN95;
|
|
79 else
|
|
80 os_subtype = OS_NT;
|
|
81
|
9803
|
82 /* Cache page size, allocation unit, processor type, etc. */
|
|
83 GetSystemInfo (&sysinfo_cache);
|
12452
|
84 syspage_mask = sysinfo_cache.dwPageSize - 1;
|
24886
|
85
|
|
86 /* Cache os info. */
|
|
87 osinfo_cache.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
88 GetVersionEx (&osinfo_cache);
|
33215
|
89
|
|
90 w32_build_number = osinfo_cache.dwBuildNumber;
|
|
91 if (os_subtype == OS_WIN95)
|
|
92 w32_build_number &= 0xffff;
|
9803
|
93 }
|
|
94
|
18506
|
95 /* Emulate getpagesize. */
|
|
96 int
|
|
97 getpagesize (void)
|
|
98 {
|
|
99 return sysinfo_cache.dwPageSize;
|
|
100 }
|
|
101
|
24103
|
102 /* Info for managing our preload heap, which is essentially a fixed size
|
|
103 data area in the executable. */
|
|
104 PIMAGE_SECTION_HEADER preload_heap_section;
|
9803
|
105
|
|
106 /* Info for keeping track of our heap. */
|
|
107 unsigned char *data_region_base = NULL;
|
|
108 unsigned char *data_region_end = NULL;
|
12452
|
109 unsigned char *real_data_region_end = NULL;
|
11943
|
110 unsigned long reserved_heap_size = 0;
|
9803
|
111
|
|
112 /* The start of the data segment. */
|
|
113 unsigned char *
|
|
114 get_data_start (void)
|
|
115 {
|
|
116 return data_region_base;
|
|
117 }
|
|
118
|
|
119 /* The end of the data segment. */
|
|
120 unsigned char *
|
|
121 get_data_end (void)
|
|
122 {
|
|
123 return data_region_end;
|
|
124 }
|
|
125
|
11943
|
126 static char *
|
|
127 allocate_heap (void)
|
|
128 {
|
24103
|
129 /* Try to get as much as possible of the address range from the end of
|
|
130 the preload heap section up to the usable address limit. Since GNU
|
|
131 malloc can handle gaps in the memory it gets from sbrk, we can
|
|
132 simply set the sbrk pointer to the base of the new heap region. */
|
|
133 unsigned long base =
|
|
134 ROUND_UP ((RVA_TO_PTR (preload_heap_section->VirtualAddress)
|
|
135 + preload_heap_section->Misc.VirtualSize),
|
|
136 get_allocation_unit ());
|
15143
|
137 unsigned long end = 1 << VALBITS; /* 256MB */
|
15208
|
138 void *ptr = NULL;
|
11943
|
139
|
15208
|
140 while (!ptr && (base < end))
|
|
141 {
|
|
142 reserved_heap_size = end - base;
|
|
143 ptr = VirtualAlloc ((void *) base,
|
|
144 get_reserved_heap_size (),
|
|
145 MEM_RESERVE,
|
|
146 PAGE_NOACCESS);
|
|
147 base += 0x00100000; /* 1MB increment */
|
|
148 }
|
15228
|
149
|
15208
|
150 return ptr;
|
11943
|
151 }
|
|
152
|
|
153
|
9803
|
154 /* Emulate Unix sbrk. */
|
|
155 void *
|
|
156 sbrk (unsigned long increment)
|
|
157 {
|
|
158 void *result;
|
|
159 long size = (long) increment;
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
160
|
9803
|
161 result = data_region_end;
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
162
|
9803
|
163 /* If size is negative, shrink the heap by decommitting pages. */
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
164 if (size < 0)
|
9803
|
165 {
|
12452
|
166 int new_size;
|
|
167 unsigned char *new_data_region_end;
|
|
168
|
9803
|
169 size = -size;
|
|
170
|
|
171 /* Sanity checks. */
|
|
172 if ((data_region_end - size) < data_region_base)
|
|
173 return NULL;
|
|
174
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
175 /* We can only decommit full pages, so allow for
|
12452
|
176 partial deallocation [cga]. */
|
|
177 new_data_region_end = (data_region_end - size);
|
|
178 new_data_region_end = (unsigned char *)
|
|
179 ((long) (new_data_region_end + syspage_mask) & ~syspage_mask);
|
|
180 new_size = real_data_region_end - new_data_region_end;
|
|
181 real_data_region_end = new_data_region_end;
|
24103
|
182 if (new_size > 0)
|
12452
|
183 {
|
|
184 /* Decommit size bytes from the end of the heap. */
|
24103
|
185 if (using_dynamic_heap
|
|
186 && !VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
|
12452
|
187 return NULL;
|
|
188 }
|
9803
|
189
|
|
190 data_region_end -= size;
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
191 }
|
9803
|
192 /* If size is positive, grow the heap by committing reserved pages. */
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
193 else if (size > 0)
|
9803
|
194 {
|
|
195 /* Sanity checks. */
|
|
196 if ((data_region_end + size) >
|
|
197 (data_region_base + get_reserved_heap_size ()))
|
|
198 return NULL;
|
|
199
|
|
200 /* Commit more of our heap. */
|
24103
|
201 if (using_dynamic_heap
|
|
202 && VirtualAlloc (data_region_end, size, MEM_COMMIT,
|
|
203 PAGE_READWRITE) == NULL)
|
9803
|
204 return NULL;
|
|
205 data_region_end += size;
|
12452
|
206
|
|
207 /* We really only commit full pages, so record where
|
|
208 the real end of committed memory is [cga]. */
|
|
209 real_data_region_end = (unsigned char *)
|
|
210 ((long) (data_region_end + syspage_mask) & ~syspage_mask);
|
9803
|
211 }
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
212
|
9803
|
213 return result;
|
|
214 }
|
|
215
|
24103
|
216 /* Initialize the internal heap variables used by sbrk. When running in
|
|
217 preload phase (ie. in the undumped executable), we rely entirely on a
|
|
218 fixed size heap section included in the .exe itself; this is
|
|
219 preserved during dumping, and truncated to the size actually used.
|
|
220
|
|
221 When running in the dumped executable, we reserve as much as possible
|
|
222 of the address range that is addressable by Lisp object pointers, to
|
|
223 supplement what is left of the preload heap. Although we cannot rely
|
|
224 on the dynamically allocated arena being contiguous with the static
|
|
225 heap area, it is not a problem because sbrk can pretend that the gap
|
|
226 was allocated by something else; GNU malloc detects when there is a
|
|
227 jump in the sbrk values, and starts a new heap block. */
|
9803
|
228 void
|
24103
|
229 init_heap ()
|
9803
|
230 {
|
24103
|
231 PIMAGE_DOS_HEADER dos_header;
|
|
232 PIMAGE_NT_HEADERS nt_header;
|
|
233
|
|
234 dos_header = (PIMAGE_DOS_HEADER) RVA_TO_PTR (0);
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
235 nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) +
|
24103
|
236 dos_header->e_lfanew);
|
|
237 preload_heap_section = find_section ("EMHEAP", nt_header);
|
9803
|
238
|
24103
|
239 if (using_dynamic_heap)
|
|
240 {
|
|
241 data_region_base = allocate_heap ();
|
|
242 if (!data_region_base)
|
|
243 {
|
|
244 printf ("Error: Could not reserve dynamic heap area.\n");
|
|
245 exit (1);
|
|
246 }
|
9803
|
247
|
24103
|
248 /* Ensure that the addresses don't use the upper tag bits since
|
|
249 the Lisp type goes there. */
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
250 if (((unsigned long) data_region_base & ~VALMASK) != 0)
|
24103
|
251 {
|
|
252 printf ("Error: The heap was allocated in upper memory.\n");
|
|
253 exit (1);
|
|
254 }
|
|
255
|
|
256 data_region_end = data_region_base;
|
|
257 real_data_region_end = data_region_end;
|
|
258 }
|
|
259 else
|
|
260 {
|
|
261 data_region_base = RVA_TO_PTR (preload_heap_section->VirtualAddress);
|
|
262 data_region_end = data_region_base;
|
|
263 real_data_region_end = data_region_end;
|
|
264 reserved_heap_size = preload_heap_section->Misc.VirtualSize;
|
|
265 }
|
19708
|
266
|
|
267 /* Update system version information to match current system. */
|
|
268 cache_system_info ();
|
9803
|
269 }
|
|
270
|
|
271 /* Round the heap up to the given alignment. */
|
|
272 void
|
|
273 round_heap (unsigned long align)
|
|
274 {
|
|
275 unsigned long needs_to_be;
|
|
276 unsigned long need_to_alloc;
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
277
|
24103
|
278 needs_to_be = (unsigned long) ROUND_UP (get_heap_end (), align);
|
9803
|
279 need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
280
|
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
281 if (need_to_alloc)
|
9803
|
282 sbrk (need_to_alloc);
|
|
283 }
|
19708
|
284
|
48046
e81472bb5044
Don't redefine _heap_init and _heap_term on MSVC 7 build environments. Patch
Juanma Barranquero <lekktu@gmail.com>
diff
changeset
|
285 #if (_MSC_VER >= 1000 && _MSC_VER < 1300 && !defined(USE_CRT_DLL))
|
19708
|
286
|
|
287 /* MSVC 4.2 invokes these functions from mainCRTStartup to initialize
|
|
288 a heap via HeapCreate. They are normally defined by the runtime,
|
|
289 but we override them here so that the unnecessary HeapCreate call
|
|
290 is not performed. */
|
|
291
|
|
292 int __cdecl
|
|
293 _heap_init (void)
|
|
294 {
|
|
295 /* Stepping through the assembly indicates that mainCRTStartup is
|
|
296 expecting a nonzero success return value. */
|
|
297 return 1;
|
|
298 }
|
|
299
|
|
300 void __cdecl
|
|
301 _heap_term (void)
|
|
302 {
|
|
303 return;
|
|
304 }
|
|
305
|
|
306 #endif
|