Merge from trunk + rename the event. Not tested yet.
[bpt/emacs.git] / src / w32heap.c
CommitLineData
b46a6a83 1/* Heap management routines for GNU Emacs on the Microsoft Windows API.
acaf905b 2 Copyright (C) 1994, 2001-2012 Free Software Foundation, Inc.
95ed0025 3
3b7ad313 4This file is part of GNU Emacs.
95ed0025 5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any 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 16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
95ed0025 18
9ec0b715 19/*
95ed0025
RS
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
21*/
22
4838e624 23#include <config.h>
95ed0025
RS
24#include <stdio.h>
25
501199a3 26#include "w32common.h"
489f9371 27#include "w32heap.h"
8dfdd41f 28#include "lisp.h" /* for VALMASK */
95ed0025 29
62aba0d4 30#define RVA_TO_PTR(rva) ((unsigned char *)((DWORD_PTR)(rva) + (DWORD_PTR)GetModuleHandle (NULL)))
30d2b1c2 31
e54c8cd1
GV
32/* Emulate getpagesize. */
33int
34getpagesize (void)
35{
36 return sysinfo_cache.dwPageSize;
37}
38
30d2b1c2
AI
39/* Info for managing our preload heap, which is essentially a fixed size
40 data area in the executable. */
41PIMAGE_SECTION_HEADER preload_heap_section;
95ed0025
RS
42
43/* Info for keeping track of our heap. */
44unsigned char *data_region_base = NULL;
45unsigned char *data_region_end = NULL;
3bbabc43 46unsigned char *real_data_region_end = NULL;
62aba0d4 47size_t reserved_heap_size = 0;
95ed0025
RS
48
49/* The start of the data segment. */
50unsigned char *
51get_data_start (void)
52{
53 return data_region_base;
54}
55
56/* The end of the data segment. */
57unsigned char *
58get_data_end (void)
59{
60 return data_region_end;
61}
62
646b5f55 63#if !USE_LSB_TAG
011db670
GV
64static char *
65allocate_heap (void)
66{
30d2b1c2
AI
67 /* Try to get as much as possible of the address range from the end of
68 the preload heap section up to the usable address limit. Since GNU
69 malloc can handle gaps in the memory it gets from sbrk, we can
70 simply set the sbrk pointer to the base of the new heap region. */
62aba0d4 71 DWORD_PTR base =
30d2b1c2
AI
72 ROUND_UP ((RVA_TO_PTR (preload_heap_section->VirtualAddress)
73 + preload_heap_section->Misc.VirtualSize),
74 get_allocation_unit ());
62aba0d4 75 DWORD_PTR end = ((unsigned __int64)1) << VALBITS; /* 256MB */
709fd16b 76 void *ptr = NULL;
011db670 77
709fd16b
GV
78 while (!ptr && (base < end))
79 {
62aba0d4
FP
80#ifdef _WIN64
81 reserved_heap_size = min(end - base, 0x4000000000i64); /* Limit to 256Gb */
82#else
709fd16b 83 reserved_heap_size = end - base;
62aba0d4 84#endif
709fd16b
GV
85 ptr = VirtualAlloc ((void *) base,
86 get_reserved_heap_size (),
87 MEM_RESERVE,
88 PAGE_NOACCESS);
709fd16b
GV
89 base += 0x00100000; /* 1MB increment */
90 }
0d05360d 91
709fd16b 92 return ptr;
011db670 93}
646b5f55 94#else /* USE_LSB_TAG */
fab624aa
EZ
95static char *
96allocate_heap (void)
97{
62aba0d4
FP
98#ifdef _WIN64
99 size_t size = 0x4000000000i64; /* start by asking for 32GB */
100#else
101 size_t size = 0x80000000; /* start by asking for 2GB */
102#endif
fab624aa
EZ
103 void *ptr = NULL;
104
105 while (!ptr && size > 0x00100000)
106 {
107 reserved_heap_size = size;
108 ptr = VirtualAlloc (NULL,
109 get_reserved_heap_size (),
110 MEM_RESERVE,
111 PAGE_NOACCESS);
112 size -= 0x00800000; /* if failed, decrease request by 8MB */
113 }
114
115 return ptr;
116}
646b5f55 117#endif /* USE_LSB_TAG */
011db670
GV
118
119
fab624aa
EZ
120/* Emulate Unix sbrk. Note that ralloc.c expects the return value to
121 be the address of the _start_ (not end) of the new block in case of
122 success, and zero (not -1) in case of failure. */
95ed0025 123void *
62aba0d4 124sbrk (ptrdiff_t increment)
95ed0025
RS
125{
126 void *result;
62aba0d4 127 ptrdiff_t size = increment;
ce20e03e 128
95ed0025 129 result = data_region_end;
ce20e03e 130
95ed0025 131 /* If size is negative, shrink the heap by decommitting pages. */
ce20e03e 132 if (size < 0)
95ed0025 133 {
62aba0d4 134 ptrdiff_t new_size;
3bbabc43
GV
135 unsigned char *new_data_region_end;
136
95ed0025
RS
137 size = -size;
138
139 /* Sanity checks. */
95ed0025
RS
140 if ((data_region_end - size) < data_region_base)
141 return NULL;
142
ce20e03e 143 /* We can only decommit full pages, so allow for
3bbabc43
GV
144 partial deallocation [cga]. */
145 new_data_region_end = (data_region_end - size);
146 new_data_region_end = (unsigned char *)
62aba0d4 147 ((DWORD_PTR) (new_data_region_end + syspage_mask) & ~syspage_mask);
3bbabc43
GV
148 new_size = real_data_region_end - new_data_region_end;
149 real_data_region_end = new_data_region_end;
30d2b1c2 150 if (new_size > 0)
3bbabc43
GV
151 {
152 /* Decommit size bytes from the end of the heap. */
30d2b1c2
AI
153 if (using_dynamic_heap
154 && !VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT))
3bbabc43
GV
155 return NULL;
156 }
95ed0025
RS
157
158 data_region_end -= size;
ce20e03e 159 }
95ed0025 160 /* If size is positive, grow the heap by committing reserved pages. */
ce20e03e 161 else if (size > 0)
95ed0025
RS
162 {
163 /* Sanity checks. */
95ed0025
RS
164 if ((data_region_end + size) >
165 (data_region_base + get_reserved_heap_size ()))
166 return NULL;
167
168 /* Commit more of our heap. */
30d2b1c2
AI
169 if (using_dynamic_heap
170 && VirtualAlloc (data_region_end, size, MEM_COMMIT,
171 PAGE_READWRITE) == NULL)
95ed0025
RS
172 return NULL;
173 data_region_end += size;
3bbabc43
GV
174
175 /* We really only commit full pages, so record where
176 the real end of committed memory is [cga]. */
177 real_data_region_end = (unsigned char *)
62aba0d4 178 ((DWORD_PTR) (data_region_end + syspage_mask) & ~syspage_mask);
95ed0025 179 }
ce20e03e 180
95ed0025
RS
181 return result;
182}
183
30d2b1c2
AI
184/* Initialize the internal heap variables used by sbrk. When running in
185 preload phase (ie. in the undumped executable), we rely entirely on a
186 fixed size heap section included in the .exe itself; this is
187 preserved during dumping, and truncated to the size actually used.
188
189 When running in the dumped executable, we reserve as much as possible
190 of the address range that is addressable by Lisp object pointers, to
191 supplement what is left of the preload heap. Although we cannot rely
192 on the dynamically allocated arena being contiguous with the static
193 heap area, it is not a problem because sbrk can pretend that the gap
194 was allocated by something else; GNU malloc detects when there is a
195 jump in the sbrk values, and starts a new heap block. */
95ed0025 196void
b56ceb92 197init_heap (void)
95ed0025 198{
30d2b1c2
AI
199 PIMAGE_DOS_HEADER dos_header;
200 PIMAGE_NT_HEADERS nt_header;
201
202 dos_header = (PIMAGE_DOS_HEADER) RVA_TO_PTR (0);
62aba0d4 203 nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) +
30d2b1c2
AI
204 dos_header->e_lfanew);
205 preload_heap_section = find_section ("EMHEAP", nt_header);
206
207 if (using_dynamic_heap)
208 {
209 data_region_base = allocate_heap ();
210 if (!data_region_base)
211 {
212 printf ("Error: Could not reserve dynamic heap area.\n");
213 exit (1);
214 }
215
646b5f55 216#if !USE_LSB_TAG
30d2b1c2
AI
217 /* Ensure that the addresses don't use the upper tag bits since
218 the Lisp type goes there. */
62aba0d4 219 if (((DWORD_PTR) data_region_base & ~VALMASK) != 0)
30d2b1c2
AI
220 {
221 printf ("Error: The heap was allocated in upper memory.\n");
222 exit (1);
223 }
3ae12c8d 224#endif
30d2b1c2
AI
225 data_region_end = data_region_base;
226 real_data_region_end = data_region_end;
227 }
228 else
229 {
230 data_region_base = RVA_TO_PTR (preload_heap_section->VirtualAddress);
231 data_region_end = data_region_base;
232 real_data_region_end = data_region_end;
233 reserved_heap_size = preload_heap_section->Misc.VirtualSize;
234 }
801f68b9
GV
235
236 /* Update system version information to match current system. */
237 cache_system_info ();
95ed0025
RS
238}
239
240/* Round the heap up to the given alignment. */
241void
62aba0d4 242round_heap (size_t align)
95ed0025 243{
62aba0d4
FP
244 DWORD_PTR needs_to_be;
245 DWORD_PTR need_to_alloc;
ce20e03e 246
62aba0d4
FP
247 needs_to_be = (DWORD_PTR) ROUND_UP (get_heap_end (), align);
248 need_to_alloc = needs_to_be - (DWORD_PTR) get_heap_end ();
ce20e03e
JB
249
250 if (need_to_alloc)
95ed0025
RS
251 sbrk (need_to_alloc);
252}