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