Initial revision
[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
23#include <stdlib.h>
24#include <stdio.h>
25
26#include "ntheap.h"
27
28/* This gives us the page size and the size of the allocation unit on NT. */
29SYSTEM_INFO sysinfo_cache;
30
31/* These are defined to get Emacs to compile, but are not used. */
32int edata;
33int etext;
34
35/* The major and minor versions of NT. */
36int nt_major_version;
37int nt_minor_version;
38
39/* Cache information describing the NT system for later use. */
40void
41cache_system_info (void)
42{
43 union
44 {
45 struct info
46 {
47 char major;
48 char minor;
49 short platform;
50 } info;
51 DWORD data;
52 } version;
53
54 /* Cache the version of the operating system. */
55 version.data = GetVersion ();
56 nt_major_version = version.info.major;
57 nt_minor_version = version.info.minor;
58
59 /* Cache page size, allocation unit, processor type, etc. */
60 GetSystemInfo (&sysinfo_cache);
61}
62
63/* Round ADDRESS up to be aligned with ALIGN. */
64unsigned char *
65round_to_next (unsigned char *address, unsigned long align)
66{
67 unsigned long tmp;
68
69 tmp = (unsigned long) address;
70 tmp = (tmp + align - 1) / align;
71
72 return (unsigned char *) (tmp * align);
73}
74
75/* Info for keeping track of our heap. */
76unsigned char *data_region_base = NULL;
77unsigned char *data_region_end = NULL;
78unsigned long data_region_size = 0;
79
80/* The start of the data segment. */
81unsigned char *
82get_data_start (void)
83{
84 return data_region_base;
85}
86
87/* The end of the data segment. */
88unsigned char *
89get_data_end (void)
90{
91 return data_region_end;
92}
93
94/* Emulate Unix sbrk. */
95void *
96sbrk (unsigned long increment)
97{
98 void *result;
99 long size = (long) increment;
100
101 /* Allocate our heap if we haven't done so already. */
102 if (!data_region_base)
103 {
104 data_region_base = VirtualAlloc ((void *) get_data_region_base (),
105 get_reserved_heap_size (),
106 MEM_RESERVE,
107 PAGE_NOACCESS);
108 if (!data_region_base)
109 return NULL;
110
111 /* Ensure that the addresses don't use the upper 8 bits since
112 the Lisp type goes there (yucko). */
113 if (((unsigned long) data_region_base & 0xFF000000) != 0)
114 {
115 printf ("Error: The heap was allocated in upper memory.\n");
116 exit (1);
117 }
118
119 data_region_end = data_region_base;
120 data_region_size = get_reserved_heap_size ();
121 }
122
123 result = data_region_end;
124
125 /* If size is negative, shrink the heap by decommitting pages. */
126 if (size < 0)
127 {
128 size = -size;
129
130 /* Sanity checks. */
131 if (size % get_page_size () != 0)
132 return NULL;
133 if ((data_region_end - size) < data_region_base)
134 return NULL;
135
136 /* Decommit size bytes from the end of the heap. */
137 if (!VirtualFree (data_region_end - size, size, MEM_DECOMMIT))
138 return NULL;
139
140 data_region_end -= size;
141 }
142 /* If size is positive, grow the heap by committing reserved pages. */
143 else if (size > 0)
144 {
145 /* Sanity checks. */
146 if (size % get_page_size () != 0)
147 return NULL;
148 if ((data_region_end + size) >
149 (data_region_base + get_reserved_heap_size ()))
150 return NULL;
151
152 /* Commit more of our heap. */
153 if (VirtualAlloc (data_region_end, size, MEM_COMMIT,
154 PAGE_READWRITE) == NULL)
155 return NULL;
156 data_region_end += size;
157 }
158
159 return result;
160}
161
162/* Recreate the heap from the data that was dumped to the executable.
163 EXECUTABLE_PATH tells us where to find the executable. */
164void
165recreate_heap (char *executable_path)
166{
167 unsigned char *tmp;
168
169 /* First reserve the upper part of our heap. (We reserve first
170 because there have been problems in the past where doing the
171 mapping first has loaded DLLs into the VA space of our heap.) */
172 tmp = VirtualAlloc ((void *) get_heap_end (),
173 get_reserved_heap_size () - get_committed_heap_size (),
174 MEM_RESERVE,
175 PAGE_NOACCESS);
176 if (!tmp)
177 exit (1);
178
179 /* We read in the data for the .bss section from the executable
180 first and map in the heap from the executable second to prevent
181 any funny interactions between file I/O and file mapping. */
182 read_in_bss (executable_path);
183 map_in_heap (executable_path);
184}
185
186/* Round the heap up to the given alignment. */
187void
188round_heap (unsigned long align)
189{
190 unsigned long needs_to_be;
191 unsigned long need_to_alloc;
192
193 needs_to_be = (unsigned long) round_to_next (get_heap_end (), align);
194 need_to_alloc = needs_to_be - (unsigned long) get_heap_end ();
195
196 if (need_to_alloc)
197 sbrk (need_to_alloc);
198}