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