(f90-hilit-patterns): Avoid using undefined variables.
[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
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
29#include "ntheap.h"
8dfdd41f 30#include "lisp.h" /* for VALMASK */
95ed0025
RS
31
32/* This gives us the page size and the size of the allocation unit on NT. */
33SYSTEM_INFO sysinfo_cache;
3bbabc43 34unsigned long syspage_mask = 0;
95ed0025
RS
35
36/* These are defined to get Emacs to compile, but are not used. */
37int edata;
38int etext;
39
40/* The major and minor versions of NT. */
41int nt_major_version;
42int nt_minor_version;
43
44/* Cache information describing the NT system for later use. */
45void
46cache_system_info (void)
47{
48 union
49 {
50 struct info
51 {
52 char major;
53 char minor;
54 short platform;
55 } info;
56 DWORD data;
57 } version;
58
59 /* Cache the version of the operating system. */
60 version.data = GetVersion ();
61 nt_major_version = version.info.major;
62 nt_minor_version = version.info.minor;
63
64 /* Cache page size, allocation unit, processor type, etc. */
65 GetSystemInfo (&sysinfo_cache);
3bbabc43 66 syspage_mask = sysinfo_cache.dwPageSize - 1;
95ed0025
RS
67}
68
69/* Round ADDRESS up to be aligned with ALIGN. */
70unsigned char *
71round_to_next (unsigned char *address, unsigned long align)
72{
73 unsigned long tmp;
74
75 tmp = (unsigned long) address;
76 tmp = (tmp + align - 1) / align;
77
78 return (unsigned char *) (tmp * align);
79}
80
81/* Info for keeping track of our heap. */
82unsigned char *data_region_base = NULL;
83unsigned char *data_region_end = NULL;
3bbabc43 84unsigned char *real_data_region_end = NULL;
95ed0025 85unsigned long data_region_size = 0;
011db670 86unsigned long reserved_heap_size = 0;
95ed0025
RS
87
88/* The start of the data segment. */
89unsigned char *
90get_data_start (void)
91{
92 return data_region_base;
93}
94
95/* The end of the data segment. */
96unsigned char *
97get_data_end (void)
98{
99 return data_region_end;
100}
101
011db670
GV
102static char *
103allocate_heap (void)
104{
8dfdd41f
GV
105 /* The base address for our GNU malloc heap is chosen in conjuction
106 with the link settings for temacs.exe which control the stack size,
107 the initial default process heap size and the executable image base
108 address. The link settings and the malloc heap base below must all
109 correspond; the relationship between these values depends on how NT
110 and Win95 arrange the virtual address space for a process (and on
111 the size of the code and data segments in temacs.exe).
112
113 The most important thing is to make base address for the executable
114 image high enough to leave enough room between it and the 4MB floor
115 of the process address space on Win95 for the primary thread stack,
116 the process default heap, and other assorted odds and ends
117 (eg. environment strings, private system dll memory etc) that are
118 allocated before temacs has a chance to grab its malloc arena. The
119 malloc heap base can then be set several MB higher than the
120 executable image base, leaving enough room for the code and data
121 segments.
122
123 Because some parts of Emacs can use rather a lot of stack space
124 (for instance, the regular expression routines can potentially
125 allocate several MB of stack space) we allow 8MB for the stack.
126
127 Allowing 1MB for the default process heap, and 1MB for odds and
128 ends, we can base the executable at 16MB and still have a generous
129 safety margin. At the moment, the executable has about 810KB of
130 code (for x86) and about 550KB of data - on RISC platforms the code
131 size could be roughly double, so if we allow 4MB for the executable
132 we will have plenty of room for expansion.
133
134 Thus we set the malloc heap base to 20MB. Since Emacs now leaves
135 28 bits available for pointers, this lets us use the remainder of
136 the region below the 256MB line for our malloc arena - 236MB is
137 still a pretty decent arena to play in! */
138
139 unsigned long base = 0x01400000; /* 20MB */
140 unsigned long end = 1 << VALBITS; /* 256MB */
011db670
GV
141
142 reserved_heap_size = end - base;
143
144 return VirtualAlloc ((void *) base,
145 get_reserved_heap_size (),
146 MEM_RESERVE,
147 PAGE_NOACCESS);
148}
011db670
GV
149
150
95ed0025
RS
151/* Emulate Unix sbrk. */
152void *
153sbrk (unsigned long increment)
154{
155 void *result;
156 long size = (long) increment;
157
158 /* Allocate our heap if we haven't done so already. */
159 if (!data_region_base)
160 {
011db670 161 data_region_base = allocate_heap ();
95ed0025
RS
162 if (!data_region_base)
163 return NULL;
164
8dfdd41f
GV
165 /* Ensure that the addresses don't use the upper tag bits since
166 the Lisp type goes there. */
167 if (((unsigned long) data_region_base & ~VALMASK) != 0)
95ed0025
RS
168 {
169 printf ("Error: The heap was allocated in upper memory.\n");
170 exit (1);
171 }
172
173 data_region_end = data_region_base;
3bbabc43 174 real_data_region_end = data_region_end;
95ed0025
RS
175 data_region_size = get_reserved_heap_size ();
176 }
177
178 result = data_region_end;
179
180 /* If size is negative, shrink the heap by decommitting pages. */
181 if (size < 0)
182 {
3bbabc43
GV
183 int new_size;
184 unsigned char *new_data_region_end;
185
95ed0025
RS
186 size = -size;
187
188 /* Sanity checks. */
95ed0025
RS
189 if ((data_region_end - size) < data_region_base)
190 return NULL;
191
3bbabc43
GV
192 /* We can only decommit full pages, so allow for
193 partial deallocation [cga]. */
194 new_data_region_end = (data_region_end - size);
195 new_data_region_end = (unsigned char *)
196 ((long) (new_data_region_end + syspage_mask) & ~syspage_mask);
197 new_size = real_data_region_end - new_data_region_end;
198 real_data_region_end = new_data_region_end;
199 if (new_size > 0)
200 {
201 /* Decommit size bytes from the end of the heap. */
202 if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
203 return NULL;
204 }
95ed0025
RS
205
206 data_region_end -= size;
207 }
208 /* If size is positive, grow the heap by committing reserved pages. */
209 else if (size > 0)
210 {
211 /* Sanity checks. */
95ed0025
RS
212 if ((data_region_end + size) >
213 (data_region_base + get_reserved_heap_size ()))
214 return NULL;
215
216 /* Commit more of our heap. */
217 if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
218 PAGE_READWRITE) == NULL)
219 return NULL;
220 data_region_end += size;
3bbabc43
GV
221
222 /* We really only commit full pages, so record where
223 the real end of committed memory is [cga]. */
224 real_data_region_end = (unsigned char *)
225 ((long) (data_region_end + syspage_mask) & ~syspage_mask);
95ed0025
RS
226 }
227
228 return result;
229}
230
231/* Recreate the heap from the data that was dumped to the executable.
232 EXECUTABLE_PATH tells us where to find the executable. */
233void
234recreate_heap (char *executable_path)
235{
236 unsigned char *tmp;
237
238 /* First reserve the upper part of our heap. (We reserve first
239 because there have been problems in the past where doing the
240 mapping first has loaded DLLs into the VA space of our heap.) */
241 tmp = VirtualAlloc ((void *) get_heap_end (),
242 get_reserved_heap_size () - get_committed_heap_size (),
243 MEM_RESERVE,
244 PAGE_NOACCESS);
245 if (!tmp)
246 exit (1);
247
248 /* We read in the data for the .bss section from the executable
249 first and map in the heap from the executable second to prevent
250 any funny interactions between file I/O and file mapping. */
251 read_in_bss (executable_path);
252 map_in_heap (executable_path);
253}
254
255/* Round the heap up to the given alignment. */
256void
257round_heap (unsigned long align)
258{
259 unsigned long needs_to_be;
260 unsigned long need_to_alloc;
261
262 needs_to_be = (unsigned long) round_to_next (get_heap_end (), align);
263 need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
264
265 if (need_to_alloc)
266 sbrk (need_to_alloc);
267}