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