diff options
| author | Andrew Innes | 1999-01-17 19:22:55 +0000 |
|---|---|---|
| committer | Andrew Innes | 1999-01-17 19:22:55 +0000 |
| commit | 30d2b1c27b6a85742c49521edf6b76d5e1fbaf95 (patch) | |
| tree | 24dd566c908b687fa2c0864ce0f37978ecd4ac40 /src | |
| parent | 5b79dba5b941740286727d2d24091bdec94e2f6f (diff) | |
| download | emacs-30d2b1c27b6a85742c49521edf6b76d5e1fbaf95.tar.gz emacs-30d2b1c27b6a85742c49521edf6b76d5e1fbaf95.zip | |
(RVA_TO_PTR): Redefine to convert RVA to address in
current process.
(round_to_next): Obsolete function removed.
(preload_heap_section): New variable.
(data_region_size): Obsolete variable removed.
(allocate_heap): Modified to determine end of static heap section
used during preload, and use that as initial base address for
dynamic heap instead of hard-coded value.
(sbrk): Remove call to allocate_heap; handled by init_heap. Skip
calls to commit or decommit pages when allocating from static heap
section during preload.
(recreate_heap): Obsolete function removed.
(init_heap): New function to initialize internal sbrk heap
variables. Uses static heap section during preload, otherwise
calls allocate_heap to reserve a heap region dynamically.
(round_heap): Use ROUND_UP macro instead of round_to_next.
Diffstat (limited to 'src')
| -rw-r--r-- | src/w32heap.c | 173 |
1 files changed, 69 insertions, 104 deletions
diff --git a/src/w32heap.c b/src/w32heap.c index 8051ce10cb5..38f7ffe0534 100644 --- a/src/w32heap.c +++ b/src/w32heap.c | |||
| @@ -29,6 +29,9 @@ Boston, MA 02111-1307, USA. | |||
| 29 | #include "w32heap.h" | 29 | #include "w32heap.h" |
| 30 | #include "lisp.h" /* for VALMASK */ | 30 | #include "lisp.h" /* for VALMASK */ |
| 31 | 31 | ||
| 32 | #undef RVA_TO_PTR | ||
| 33 | #define RVA_TO_PTR(rva) ((DWORD)(rva) + (DWORD)GetModuleHandle (NULL)) | ||
| 34 | |||
| 32 | /* This gives us the page size and the size of the allocation unit on NT. */ | 35 | /* This gives us the page size and the size of the allocation unit on NT. */ |
| 33 | SYSTEM_INFO sysinfo_cache; | 36 | SYSTEM_INFO sysinfo_cache; |
| 34 | unsigned long syspage_mask = 0; | 37 | unsigned long syspage_mask = 0; |
| @@ -81,23 +84,14 @@ getpagesize (void) | |||
| 81 | return sysinfo_cache.dwPageSize; | 84 | return sysinfo_cache.dwPageSize; |
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | /* Round ADDRESS up to be aligned with ALIGN. */ | 87 | /* Info for managing our preload heap, which is essentially a fixed size |
| 85 | unsigned char * | 88 | data area in the executable. */ |
| 86 | round_to_next (unsigned char *address, unsigned long align) | 89 | PIMAGE_SECTION_HEADER preload_heap_section; |
| 87 | { | ||
| 88 | unsigned long tmp; | ||
| 89 | |||
| 90 | tmp = (unsigned long) address; | ||
| 91 | tmp = (tmp + align - 1) / align; | ||
| 92 | |||
| 93 | return (unsigned char *) (tmp * align); | ||
| 94 | } | ||
| 95 | 90 | ||
| 96 | /* Info for keeping track of our heap. */ | 91 | /* Info for keeping track of our heap. */ |
| 97 | unsigned char *data_region_base = NULL; | 92 | unsigned char *data_region_base = NULL; |
| 98 | unsigned char *data_region_end = NULL; | 93 | unsigned char *data_region_end = NULL; |
| 99 | unsigned char *real_data_region_end = NULL; | 94 | unsigned char *real_data_region_end = NULL; |
| 100 | unsigned long data_region_size = 0; | ||
| 101 | unsigned long reserved_heap_size = 0; | 95 | unsigned long reserved_heap_size = 0; |
| 102 | 96 | ||
| 103 | /* The start of the data segment. */ | 97 | /* The start of the data segment. */ |
| @@ -117,49 +111,17 @@ get_data_end (void) | |||
| 117 | static char * | 111 | static char * |
| 118 | allocate_heap (void) | 112 | allocate_heap (void) |
| 119 | { | 113 | { |
| 120 | /* The base address for our GNU malloc heap is chosen in conjuction | 114 | /* Try to get as much as possible of the address range from the end of |
| 121 | with the link settings for temacs.exe which control the stack size, | 115 | the preload heap section up to the usable address limit. Since GNU |
| 122 | the initial default process heap size and the executable image base | 116 | malloc can handle gaps in the memory it gets from sbrk, we can |
| 123 | address. The link settings and the malloc heap base below must all | 117 | simply set the sbrk pointer to the base of the new heap region. */ |
| 124 | correspond; the relationship between these values depends on how NT | 118 | unsigned long base = |
| 125 | and Windows 95 arrange the virtual address space for a process (and on | 119 | ROUND_UP ((RVA_TO_PTR (preload_heap_section->VirtualAddress) |
| 126 | the size of the code and data segments in temacs.exe). | 120 | + preload_heap_section->Misc.VirtualSize), |
| 127 | 121 | get_allocation_unit ()); | |
| 128 | The most important thing is to make base address for the executable | ||
| 129 | image high enough to leave enough room between it and the 4MB floor | ||
| 130 | of the process address space on Windows 95 for the primary thread stack, | ||
| 131 | the process default heap, and other assorted odds and ends | ||
| 132 | (eg. environment strings, private system dll memory etc) that are | ||
| 133 | allocated before temacs has a chance to grab its malloc arena. The | ||
| 134 | malloc heap base can then be set several MB higher than the | ||
| 135 | executable image base, leaving enough room for the code and data | ||
| 136 | segments. | ||
| 137 | |||
| 138 | Because some parts of Emacs can use rather a lot of stack space | ||
| 139 | (for instance, the regular expression routines can potentially | ||
| 140 | allocate several MB of stack space) we allow 8MB for the stack. | ||
| 141 | |||
| 142 | Allowing 1MB for the default process heap, and 1MB for odds and | ||
| 143 | ends, we can base the executable at 16MB and still have a generous | ||
| 144 | safety margin. At the moment, the executable has about 810KB of | ||
| 145 | code (for x86) and about 550KB of data - on RISC platforms the code | ||
| 146 | size could be roughly double, so if we allow 4MB for the executable | ||
| 147 | we will have plenty of room for expansion. | ||
| 148 | |||
| 149 | Thus we would like to set the malloc heap base to 20MB. However, | ||
| 150 | Windows 95 refuses to allocate the heap starting at this address, so we | ||
| 151 | set the base to 27MB to make it happy. Since Emacs now leaves | ||
| 152 | 28 bits available for pointers, this lets us use the remainder of | ||
| 153 | the region below the 256MB line for our malloc arena - 229MB is | ||
| 154 | still a pretty decent arena to play in! */ | ||
| 155 | |||
| 156 | unsigned long base = 0x01B00000; /* 27MB */ | ||
| 157 | unsigned long end = 1 << VALBITS; /* 256MB */ | 122 | unsigned long end = 1 << VALBITS; /* 256MB */ |
| 158 | void *ptr = NULL; | 123 | void *ptr = NULL; |
| 159 | 124 | ||
| 160 | #define NTHEAP_PROBE_BASE 1 | ||
| 161 | #if NTHEAP_PROBE_BASE | ||
| 162 | /* Try various addresses looking for one the kernel will let us have. */ | ||
| 163 | while (!ptr && (base < end)) | 125 | while (!ptr && (base < end)) |
| 164 | { | 126 | { |
| 165 | reserved_heap_size = end - base; | 127 | reserved_heap_size = end - base; |
| @@ -169,13 +131,6 @@ allocate_heap (void) | |||
| 169 | PAGE_NOACCESS); | 131 | PAGE_NOACCESS); |
| 170 | base += 0x00100000; /* 1MB increment */ | 132 | base += 0x00100000; /* 1MB increment */ |
| 171 | } | 133 | } |
| 172 | #else | ||
| 173 | reserved_heap_size = end - base; | ||
| 174 | ptr = VirtualAlloc ((void *) base, | ||
| 175 | get_reserved_heap_size (), | ||
| 176 | MEM_RESERVE, | ||
| 177 | PAGE_NOACCESS); | ||
| 178 | #endif | ||
| 179 | 134 | ||
| 180 | return ptr; | 135 | return ptr; |
| 181 | } | 136 | } |
| @@ -188,26 +143,6 @@ sbrk (unsigned long increment) | |||
| 188 | void *result; | 143 | void *result; |
| 189 | long size = (long) increment; | 144 | long size = (long) increment; |
| 190 | 145 | ||
| 191 | /* Allocate our heap if we haven't done so already. */ | ||
| 192 | if (!data_region_base) | ||
| 193 | { | ||
| 194 | data_region_base = allocate_heap (); | ||
| 195 | if (!data_region_base) | ||
| 196 | return NULL; | ||
| 197 | |||
| 198 | /* Ensure that the addresses don't use the upper tag bits since | ||
| 199 | the Lisp type goes there. */ | ||
| 200 | if (((unsigned long) data_region_base & ~VALMASK) != 0) | ||
| 201 | { | ||
| 202 | printf ("Error: The heap was allocated in upper memory.\n"); | ||
| 203 | exit (1); | ||
| 204 | } | ||
| 205 | |||
| 206 | data_region_end = data_region_base; | ||
| 207 | real_data_region_end = data_region_end; | ||
| 208 | data_region_size = get_reserved_heap_size (); | ||
| 209 | } | ||
| 210 | |||
| 211 | result = data_region_end; | 146 | result = data_region_end; |
| 212 | 147 | ||
| 213 | /* If size is negative, shrink the heap by decommitting pages. */ | 148 | /* If size is negative, shrink the heap by decommitting pages. */ |
| @@ -229,10 +164,11 @@ sbrk (unsigned long increment) | |||
| 229 | ((long) (new_data_region_end + syspage_mask) & ~syspage_mask); | 164 | ((long) (new_data_region_end + syspage_mask) & ~syspage_mask); |
| 230 | new_size = real_data_region_end - new_data_region_end; | 165 | new_size = real_data_region_end - new_data_region_end; |
| 231 | real_data_region_end = new_data_region_end; | 166 | real_data_region_end = new_data_region_end; |
| 232 | if (new_size > 0) | 167 | if (new_size > 0) |
| 233 | { | 168 | { |
| 234 | /* Decommit size bytes from the end of the heap. */ | 169 | /* Decommit size bytes from the end of the heap. */ |
| 235 | if (!VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT)) | 170 | if (using_dynamic_heap |
| 171 | && !VirtualFree (real_data_region_end, new_size, MEM_DECOMMIT)) | ||
| 236 | return NULL; | 172 | return NULL; |
| 237 | } | 173 | } |
| 238 | 174 | ||
| @@ -247,8 +183,9 @@ sbrk (unsigned long increment) | |||
| 247 | return NULL; | 183 | return NULL; |
| 248 | 184 | ||
| 249 | /* Commit more of our heap. */ | 185 | /* Commit more of our heap. */ |
| 250 | if (VirtualAlloc (data_region_end, size, MEM_COMMIT, | 186 | if (using_dynamic_heap |
| 251 | PAGE_READWRITE) == NULL) | 187 | && VirtualAlloc (data_region_end, size, MEM_COMMIT, |
| 188 | PAGE_READWRITE) == NULL) | ||
| 252 | return NULL; | 189 | return NULL; |
| 253 | data_region_end += size; | 190 | data_region_end += size; |
| 254 | 191 | ||
| @@ -261,28 +198,56 @@ sbrk (unsigned long increment) | |||
| 261 | return result; | 198 | return result; |
| 262 | } | 199 | } |
| 263 | 200 | ||
| 264 | /* Recreate the heap from the data that was dumped to the executable. | 201 | /* Initialize the internal heap variables used by sbrk. When running in |
| 265 | EXECUTABLE_PATH tells us where to find the executable. */ | 202 | preload phase (ie. in the undumped executable), we rely entirely on a |
| 203 | fixed size heap section included in the .exe itself; this is | ||
| 204 | preserved during dumping, and truncated to the size actually used. | ||
| 205 | |||
| 206 | When running in the dumped executable, we reserve as much as possible | ||
| 207 | of the address range that is addressable by Lisp object pointers, to | ||
| 208 | supplement what is left of the preload heap. Although we cannot rely | ||
| 209 | on the dynamically allocated arena being contiguous with the static | ||
| 210 | heap area, it is not a problem because sbrk can pretend that the gap | ||
| 211 | was allocated by something else; GNU malloc detects when there is a | ||
| 212 | jump in the sbrk values, and starts a new heap block. */ | ||
| 266 | void | 213 | void |
| 267 | recreate_heap (char *executable_path) | 214 | init_heap () |
| 268 | { | 215 | { |
| 269 | unsigned char *tmp; | 216 | PIMAGE_DOS_HEADER dos_header; |
| 270 | 217 | PIMAGE_NT_HEADERS nt_header; | |
| 271 | /* First reserve the upper part of our heap. (We reserve first | 218 | |
| 272 | because there have been problems in the past where doing the | 219 | dos_header = (PIMAGE_DOS_HEADER) RVA_TO_PTR (0); |
| 273 | mapping first has loaded DLLs into the VA space of our heap.) */ | 220 | nt_header = (PIMAGE_NT_HEADERS) (((unsigned long) dos_header) + |
| 274 | tmp = VirtualAlloc ((void *) get_heap_end (), | 221 | dos_header->e_lfanew); |
| 275 | get_reserved_heap_size () - get_committed_heap_size (), | 222 | preload_heap_section = find_section ("EMHEAP", nt_header); |
| 276 | MEM_RESERVE, | 223 | |
| 277 | PAGE_NOACCESS); | 224 | if (using_dynamic_heap) |
| 278 | if (!tmp) | 225 | { |
| 279 | w32_fatal_reload_error ("Reserving upper heap address space."); | 226 | data_region_base = allocate_heap (); |
| 280 | 227 | if (!data_region_base) | |
| 281 | /* We read in the data for the .bss section from the executable | 228 | { |
| 282 | first and map in the heap from the executable second to prevent | 229 | printf ("Error: Could not reserve dynamic heap area.\n"); |
| 283 | any funny interactions between file I/O and file mapping. */ | 230 | exit (1); |
| 284 | read_in_bss (executable_path); | 231 | } |
| 285 | map_in_heap (executable_path); | 232 | |
| 233 | /* Ensure that the addresses don't use the upper tag bits since | ||
| 234 | the Lisp type goes there. */ | ||
| 235 | if (((unsigned long) data_region_base & ~VALMASK) != 0) | ||
| 236 | { | ||
| 237 | printf ("Error: The heap was allocated in upper memory.\n"); | ||
| 238 | exit (1); | ||
| 239 | } | ||
| 240 | |||
| 241 | data_region_end = data_region_base; | ||
| 242 | real_data_region_end = data_region_end; | ||
| 243 | } | ||
| 244 | else | ||
| 245 | { | ||
| 246 | data_region_base = RVA_TO_PTR (preload_heap_section->VirtualAddress); | ||
| 247 | data_region_end = data_region_base; | ||
| 248 | real_data_region_end = data_region_end; | ||
| 249 | reserved_heap_size = preload_heap_section->Misc.VirtualSize; | ||
| 250 | } | ||
| 286 | 251 | ||
| 287 | /* Update system version information to match current system. */ | 252 | /* Update system version information to match current system. */ |
| 288 | cache_system_info (); | 253 | cache_system_info (); |
| @@ -295,7 +260,7 @@ round_heap (unsigned long align) | |||
| 295 | unsigned long needs_to_be; | 260 | unsigned long needs_to_be; |
| 296 | unsigned long need_to_alloc; | 261 | unsigned long need_to_alloc; |
| 297 | 262 | ||
| 298 | needs_to_be = (unsigned long) round_to_next (get_heap_end (), align); | 263 | needs_to_be = (unsigned long) ROUND_UP (get_heap_end (), align); |
| 299 | need_to_alloc = needs_to_be - (unsigned long) get_heap_end (); | 264 | need_to_alloc = needs_to_be - (unsigned long) get_heap_end (); |
| 300 | 265 | ||
| 301 | if (need_to_alloc) | 266 | if (need_to_alloc) |