(Fdocumentation, Fdocumentation_property, Fsubstitute_command_keys):
[bpt/emacs.git] / src / w32heap.c
CommitLineData
95ed0025
RS
1/* Heap management routines for GNU Emacs on Windows NT.
2 Copyright (C) 1994 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs 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 later
9 version.
10
11 GNU Emacs 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 for
14 more details.
15
16 You should have received a copy of the GNU General Public License along
17 with GNU Emacs; see the file COPYING. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
21*/
22
3bbabc43
GV
23#include "config.h"
24
95ed0025
RS
25#include <stdlib.h>
26#include <stdio.h>
27
28#include "ntheap.h"
29
30/* This gives us the page size and the size of the allocation unit on NT. */
31SYSTEM_INFO sysinfo_cache;
3bbabc43 32unsigned long syspage_mask = 0;
95ed0025
RS
33
34/* These are defined to get Emacs to compile, but are not used. */
35int edata;
36int etext;
37
38/* The major and minor versions of NT. */
39int nt_major_version;
40int nt_minor_version;
41
42/* Cache information describing the NT system for later use. */
43void
44cache_system_info (void)
45{
46 union
47 {
48 struct info
49 {
50 char major;
51 char minor;
52 short platform;
53 } info;
54 DWORD data;
55 } version;
56
57 /* Cache the version of the operating system. */
58 version.data = GetVersion ();
59 nt_major_version = version.info.major;
60 nt_minor_version = version.info.minor;
61
62 /* Cache page size, allocation unit, processor type, etc. */
63 GetSystemInfo (&sysinfo_cache);
3bbabc43 64 syspage_mask = sysinfo_cache.dwPageSize - 1;
95ed0025
RS
65}
66
67/* Round ADDRESS up to be aligned with ALIGN. */
68unsigned char *
69round_to_next (unsigned char *address, unsigned long align)
70{
71 unsigned long tmp;
72
73 tmp = (unsigned long) address;
74 tmp = (tmp + align - 1) / align;
75
76 return (unsigned char *) (tmp * align);
77}
78
79/* Info for keeping track of our heap. */
80unsigned char *data_region_base = NULL;
81unsigned char *data_region_end = NULL;
3bbabc43 82unsigned char *real_data_region_end = NULL;
95ed0025 83unsigned long data_region_size = 0;
011db670 84unsigned long reserved_heap_size = 0;
95ed0025
RS
85
86/* The start of the data segment. */
87unsigned char *
88get_data_start (void)
89{
90 return data_region_base;
91}
92
93/* The end of the data segment. */
94unsigned char *
95get_data_end (void)
96{
97 return data_region_end;
98}
99
3bbabc43 100#ifndef WINDOWS95
011db670
GV
101static char *
102allocate_heap (void)
103{
104 unsigned long base = 0x00030000;
105 unsigned long end = 0x00D00000;
106
107 reserved_heap_size = end - base;
108
109 return VirtualAlloc ((void *) base,
110 get_reserved_heap_size (),
111 MEM_RESERVE,
112 PAGE_NOACCESS);
113}
114#else
115static char *
116allocate_heap (void)
117{
118 unsigned long start = 0x400000;
3bbabc43 119 unsigned long stop = 0xD00000;
011db670
GV
120 unsigned long increment = 0x100000;
121 char *ptr, *begin = NULL, *end = NULL;
122 int i;
123
124 for (i = start; i < stop; i += increment)
125 {
126 ptr = VirtualAlloc ((void *) i, increment, MEM_RESERVE, PAGE_NOACCESS);
127 if (ptr)
128 begin = begin ? begin : ptr;
129 else if (begin)
130 {
131 end = ptr;
132 break;
133 }
134 }
135
136 if (begin && !end)
137 end = (char *) i;
138
139 if (!begin)
140 /* We couldn't allocate any memory for the heap. Exit. */
141 exit (-2);
142
143 reserved_heap_size = end - begin;
144 return begin;
145}
146#endif
147
148
95ed0025
RS
149/* Emulate Unix sbrk. */
150void *
151sbrk (unsigned long increment)
152{
153 void *result;
154 long size = (long) increment;
155
156 /* Allocate our heap if we haven't done so already. */
157 if (!data_region_base)
158 {
011db670 159 data_region_base = allocate_heap ();
95ed0025
RS
160 if (!data_region_base)
161 return NULL;
162
163 /* Ensure that the addresses don't use the upper 8 bits since
164 the Lisp type goes there (yucko). */
165 if (((unsigned long) data_region_base & 0xFF000000) != 0)
166 {
167 printf ("Error: The heap was allocated in upper memory.\n");
168 exit (1);
169 }
170
171 data_region_end = data_region_base;
3bbabc43 172 real_data_region_end = data_region_end;
95ed0025
RS
173 data_region_size = get_reserved_heap_size ();
174 }
175
176 result = data_region_end;
177
178 /* If size is negative, shrink the heap by decommitting pages. */
179 if (size < 0)
180 {
3bbabc43
GV
181 int new_size;
182 unsigned char *new_data_region_end;
183
95ed0025
RS
184 size = -size;
185
186 /* Sanity checks. */
95ed0025
RS
187 if ((data_region_end - size) < data_region_base)
188 return NULL;
189
3bbabc43
GV
190 /* We can only decommit full pages, so allow for
191 partial deallocation [cga]. */
192 new_data_region_end = (data_region_end - size);
193 new_data_region_end = (unsigned char *)
194 ((long) (new_data_region_end + syspage_mask) & ~syspage_mask);
195 new_size = real_data_region_end - new_data_region_end;
196 real_data_region_end = new_data_region_end;
197 if (new_size > 0)
198 {
199 /* Decommit size bytes from the end of the heap. */
200 if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
201 return NULL;
202 }
95ed0025
RS
203
204 data_region_end -= size;
205 }
206 /* If size is positive, grow the heap by committing reserved pages. */
207 else if (size > 0)
208 {
209 /* Sanity checks. */
95ed0025
RS
210 if ((data_region_end + size) >
211 (data_region_base + get_reserved_heap_size ()))
212 return NULL;
213
214 /* Commit more of our heap. */
215 if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
216 PAGE_READWRITE) == NULL)
217 return NULL;
218 data_region_end += size;
3bbabc43
GV
219
220 /* We really only commit full pages, so record where
221 the real end of committed memory is [cga]. */
222 real_data_region_end = (unsigned char *)
223 ((long) (data_region_end + syspage_mask) & ~syspage_mask);
95ed0025
RS
224 }
225
226 return result;
227}
228
229/* Recreate the heap from the data that was dumped to the executable.
230 EXECUTABLE_PATH tells us where to find the executable. */
231void
232recreate_heap (char *executable_path)
233{
234 unsigned char *tmp;
235
236 /* First reserve the upper part of our heap. (We reserve first
237 because there have been problems in the past where doing the
238 mapping first has loaded DLLs into the VA space of our heap.) */
239 tmp = VirtualAlloc ((void *) get_heap_end (),
240 get_reserved_heap_size () - get_committed_heap_size (),
241 MEM_RESERVE,
242 PAGE_NOACCESS);
243 if (!tmp)
244 exit (1);
245
246 /* We read in the data for the .bss section from the executable
247 first and map in the heap from the executable second to prevent
248 any funny interactions between file I/O and file mapping. */
249 read_in_bss (executable_path);
250 map_in_heap (executable_path);
251}
252
253/* Round the heap up to the given alignment. */
254void
255round_heap (unsigned long align)
256{
257 unsigned long needs_to_be;
258 unsigned long need_to_alloc;
259
260 needs_to_be = (unsigned long) round_to_next (get_heap_end (), align);
261 need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
262
263 if (need_to_alloc)
264 sbrk (need_to_alloc);
265}