diff options
| author | Eli Zaretskii | 2019-01-18 17:04:00 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2019-01-18 17:04:00 +0200 |
| commit | 5e3b0f5239027a413775d375f04376a3c97d0bf9 (patch) | |
| tree | 7d6e6dbe03a405a2bd7e527e39a12fbf0dd1aa64 /src | |
| parent | f943409183559b0af0e89f52bf0a93f8431c2dcf (diff) | |
| download | emacs-5e3b0f5239027a413775d375f04376a3c97d0bf9.tar.gz emacs-5e3b0f5239027a413775d375f04376a3c97d0bf9.zip | |
Clean up memory allocation and unexec support on MS-Windows
* src/w32heap.c (report_temacs_memory_usage): Condition on
!CANNOT_DUMP, in addition to ENABLE_CHECKING.
(init_heap): Accept an argument, which tells us what heap
allocation method to use.
(DUMPED_HEAP_SIZE) [CANNOT_DUMP]: Define to a small value, as
we don't use dumped_data[] in this case.
* src/w32heap.h (init_heap): Adjust prototype.
<using_dynamic_heap>: Remove declaration.
* src/emacs.c (main) [WINDOWSNT]: Determine heap allocation
method based on whether we are in temacs and whether unexec
will be used to dump Emacs. Pass the heap allocation method
to init_heap, which is now called after parsing the
--temacs=METHOD option.
* src/unexw32.c (unexec): Don't fiddle with using_dynamic_heap.
<using_dynamic_heap>: Remove definition.
* src/w32proc.c (malloc_before_init, realloc_before_init)
(free_before_init): New functions, to catch memory allocation
before heap allocation method is set up.
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs.c | 19 | ||||
| -rw-r--r-- | src/unexw32.c | 10 | ||||
| -rw-r--r-- | src/w32heap.c | 49 | ||||
| -rw-r--r-- | src/w32heap.h | 3 | ||||
| -rw-r--r-- | src/w32proc.c | 37 |
5 files changed, 78 insertions, 40 deletions
diff --git a/src/emacs.c b/src/emacs.c index 834f55b6f32..b9f50397241 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -871,8 +871,25 @@ main (int argc, char **argv) | |||
| 871 | #endif | 871 | #endif |
| 872 | 872 | ||
| 873 | #if defined WINDOWSNT || defined HAVE_NTGUI | 873 | #if defined WINDOWSNT || defined HAVE_NTGUI |
| 874 | /* Grab our malloc arena space now, before anything important | ||
| 875 | happens. This relies on the static heap being needed only in | ||
| 876 | temacs and only if we are going to dump with unexec. */ | ||
| 877 | bool use_dynamic_heap = false; | ||
| 878 | if (strstr (argv[0], "temacs") != NULL) | ||
| 879 | { | ||
| 880 | eassert (temacs); | ||
| 881 | /* Note that gflags are set at this point only if we have been | ||
| 882 | called with the --temacs=METHOD option. We assume here that | ||
| 883 | temacs is always called that way, otherwise the functions | ||
| 884 | that rely on gflags, like will_dump_with_pdumper_p below, | ||
| 885 | will not do their job. */ | ||
| 886 | use_dynamic_heap = will_dump_with_pdumper_p (); | ||
| 887 | } | ||
| 888 | else | ||
| 889 | use_dynamic_heap = true; | ||
| 890 | init_heap (use_dynamic_heap); | ||
| 874 | /* Set global variables used to detect Windows version. Do this as | 891 | /* Set global variables used to detect Windows version. Do this as |
| 875 | early as possible. (unexw32.c calls this function as well, but | 892 | early as possible. (w32proc.c calls this function as well, but |
| 876 | the additional call here is harmless.) */ | 893 | the additional call here is harmless.) */ |
| 877 | cache_system_info (); | 894 | cache_system_info (); |
| 878 | #ifdef WINDOWSNT | 895 | #ifdef WINDOWSNT |
diff --git a/src/unexw32.c b/src/unexw32.c index 6fa0fa055a6..59feaa74b9f 100644 --- a/src/unexw32.c +++ b/src/unexw32.c | |||
| @@ -45,9 +45,6 @@ extern char *my_begbss_static; | |||
| 45 | 45 | ||
| 46 | #include "w32heap.h" | 46 | #include "w32heap.h" |
| 47 | 47 | ||
| 48 | /* Basically, our "initialized" flag. */ | ||
| 49 | BOOL using_dynamic_heap = FALSE; | ||
| 50 | |||
| 51 | void get_section_info (file_data *p_file); | 48 | void get_section_info (file_data *p_file); |
| 52 | void copy_executable_and_dump_data (file_data *, file_data *); | 49 | void copy_executable_and_dump_data (file_data *, file_data *); |
| 53 | void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); | 50 | void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); |
| @@ -649,15 +646,8 @@ unexec (const char *new_name, const char *old_name) | |||
| 649 | exit (1); | 646 | exit (1); |
| 650 | } | 647 | } |
| 651 | 648 | ||
| 652 | /* Set the flag (before dumping). */ | ||
| 653 | using_dynamic_heap = TRUE; | ||
| 654 | |||
| 655 | copy_executable_and_dump_data (&in_file, &out_file); | 649 | copy_executable_and_dump_data (&in_file, &out_file); |
| 656 | 650 | ||
| 657 | /* Unset it because it is plain wrong to keep it after dumping. | ||
| 658 | Malloc can still occur! */ | ||
| 659 | using_dynamic_heap = FALSE; | ||
| 660 | |||
| 661 | /* Patch up header fields; profiler is picky about this. */ | 651 | /* Patch up header fields; profiler is picky about this. */ |
| 662 | { | 652 | { |
| 663 | PIMAGE_DOS_HEADER dos_header; | 653 | PIMAGE_DOS_HEADER dos_header; |
diff --git a/src/w32heap.c b/src/w32heap.c index 3de8f245ccc..8a2c1b5877b 100644 --- a/src/w32heap.c +++ b/src/w32heap.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | Memory allocation scheme for w32/w64: | 28 | Memory allocation scheme for w32/w64: |
| 29 | 29 | ||
| 30 | - Buffers are mmap'ed using a very simple emulation of mmap/munmap | 30 | - Buffers are mmap'ed using a very simple emulation of mmap/munmap |
| 31 | - During the temacs phase: | 31 | - During the temacs phase, if unexec is to be used: |
| 32 | * we use a private heap declared to be stored into the `dumped_data' | 32 | * we use a private heap declared to be stored into the `dumped_data' |
| 33 | * unfortunately, this heap cannot be made growable, so the size of | 33 | * unfortunately, this heap cannot be made growable, so the size of |
| 34 | blocks it can allocate is limited to (0x80000 - pagesize) | 34 | blocks it can allocate is limited to (0x80000 - pagesize) |
| @@ -37,7 +37,7 @@ | |||
| 37 | We use a very simple first-fit scheme to reuse those blocks. | 37 | We use a very simple first-fit scheme to reuse those blocks. |
| 38 | * we check that the private heap does not cross the area used | 38 | * we check that the private heap does not cross the area used |
| 39 | by the bigger chunks. | 39 | by the bigger chunks. |
| 40 | - During the emacs phase: | 40 | - During the emacs phase, or always if pdumper is used: |
| 41 | * we create a private heap for new memory blocks | 41 | * we create a private heap for new memory blocks |
| 42 | * we make sure that we never free a block that has been dumped. | 42 | * we make sure that we never free a block that has been dumped. |
| 43 | Freeing a dumped block could work in principle, but may prove | 43 | Freeing a dumped block could work in principle, but may prove |
| @@ -115,10 +115,16 @@ typedef struct _RTL_HEAP_PARAMETERS { | |||
| 115 | than half of the size stated below. It would be nice to find a way | 115 | than half of the size stated below. It would be nice to find a way |
| 116 | to build only the first bootstrap-emacs.exe with the large size, | 116 | to build only the first bootstrap-emacs.exe with the large size, |
| 117 | and reset that to a lower value afterwards. */ | 117 | and reset that to a lower value afterwards. */ |
| 118 | #if defined _WIN64 || defined WIDE_EMACS_INT | 118 | #ifdef CANNOT_DUMP |
| 119 | # define DUMPED_HEAP_SIZE (23*1024*1024) | 119 | /* We don't use dumped_data[] when CANNOT_DUMP, so define to a small |
| 120 | size that won't matter. */ | ||
| 121 | # define DUMPED_HEAP_SIZE 10 | ||
| 120 | #else | 122 | #else |
| 121 | # define DUMPED_HEAP_SIZE (13*1024*1024) | 123 | # if defined _WIN64 || defined WIDE_EMACS_INT |
| 124 | # define DUMPED_HEAP_SIZE (23*1024*1024) | ||
| 125 | # else | ||
| 126 | # define DUMPED_HEAP_SIZE (13*1024*1024) | ||
| 127 | # endif | ||
| 122 | #endif | 128 | #endif |
| 123 | 129 | ||
| 124 | static unsigned char dumped_data[DUMPED_HEAP_SIZE]; | 130 | static unsigned char dumped_data[DUMPED_HEAP_SIZE]; |
| @@ -173,8 +179,8 @@ static DWORD blocks_number = 0; | |||
| 173 | static unsigned char *bc_limit; | 179 | static unsigned char *bc_limit; |
| 174 | 180 | ||
| 175 | /* Handle for the private heap: | 181 | /* Handle for the private heap: |
| 176 | - inside the dumped_data[] array before dump, | 182 | - inside the dumped_data[] array before dump with unexec, |
| 177 | - outside of it after dump. | 183 | - outside of it after dump, or always if pdumper is used. |
| 178 | */ | 184 | */ |
| 179 | HANDLE heap = NULL; | 185 | HANDLE heap = NULL; |
| 180 | 186 | ||
| @@ -188,8 +194,8 @@ free_fn the_free_fn; | |||
| 188 | http://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping */ | 194 | http://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping */ |
| 189 | 195 | ||
| 190 | /* This is the function to commit memory when the heap allocator | 196 | /* This is the function to commit memory when the heap allocator |
| 191 | claims for new memory. Before dumping, we allocate space | 197 | claims for new memory. Before dumping with unexec, we allocate |
| 192 | from the fixed size dumped_data[] array. | 198 | space from the fixed size dumped_data[] array. |
| 193 | */ | 199 | */ |
| 194 | static NTSTATUS NTAPI | 200 | static NTSTATUS NTAPI |
| 195 | dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize) | 201 | dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize) |
| @@ -223,22 +229,14 @@ typedef enum _HEAP_INFORMATION_CLASS { | |||
| 223 | typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); | 229 | typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T); |
| 224 | #endif | 230 | #endif |
| 225 | 231 | ||
| 226 | #ifdef HAVE_PDUMPER | ||
| 227 | BOOL using_dynamic_heap = FALSE; | ||
| 228 | #endif | ||
| 229 | |||
| 230 | void | 232 | void |
| 231 | init_heap (void) | 233 | init_heap (bool use_dynamic_heap) |
| 232 | { | 234 | { |
| 233 | #ifdef HAVE_PDUMPER | 235 | /* FIXME: Remove the condition, the 'else' branch below, and all the |
| 234 | using_dynamic_heap = TRUE; | 236 | related definitions and code, including dumped_data[], when unexec |
| 235 | #endif | 237 | support is removed from Emacs. */ |
| 236 | if (using_dynamic_heap) | 238 | if (use_dynamic_heap) |
| 237 | { | 239 | { |
| 238 | #ifndef MINGW_W64 | ||
| 239 | unsigned long enable_lfh = 2; | ||
| 240 | #endif | ||
| 241 | |||
| 242 | /* After dumping, use a new private heap. We explicitly enable | 240 | /* After dumping, use a new private heap. We explicitly enable |
| 243 | the low fragmentation heap (LFH) here, for the sake of pre | 241 | the low fragmentation heap (LFH) here, for the sake of pre |
| 244 | Vista versions. Note: this will harmlessly fail on Vista and | 242 | Vista versions. Note: this will harmlessly fail on Vista and |
| @@ -255,6 +253,7 @@ init_heap (void) | |||
| 255 | heap = HeapCreate (0, 0, 0); | 253 | heap = HeapCreate (0, 0, 0); |
| 256 | 254 | ||
| 257 | #ifndef MINGW_W64 | 255 | #ifndef MINGW_W64 |
| 256 | unsigned long enable_lfh = 2; | ||
| 258 | /* Set the low-fragmentation heap for OS before Vista. */ | 257 | /* Set the low-fragmentation heap for OS before Vista. */ |
| 259 | HMODULE hm_kernel32dll = LoadLibrary ("kernel32.dll"); | 258 | HMODULE hm_kernel32dll = LoadLibrary ("kernel32.dll"); |
| 260 | HeapSetInformation_Proc s_pfn_Heap_Set_Information = | 259 | HeapSetInformation_Proc s_pfn_Heap_Set_Information = |
| @@ -283,7 +282,7 @@ init_heap (void) | |||
| 283 | the_free_fn = free_after_dump; | 282 | the_free_fn = free_after_dump; |
| 284 | } | 283 | } |
| 285 | } | 284 | } |
| 286 | else | 285 | else /* Before dumping with unexec: use static heap. */ |
| 287 | { | 286 | { |
| 288 | /* Find the RtlCreateHeap function. Headers for this function | 287 | /* Find the RtlCreateHeap function. Headers for this function |
| 289 | are provided with the w32 DDK, but the function is available | 288 | are provided with the w32 DDK, but the function is available |
| @@ -362,6 +361,8 @@ malloc_after_dump (size_t size) | |||
| 362 | return p; | 361 | return p; |
| 363 | } | 362 | } |
| 364 | 363 | ||
| 364 | /* FIXME: The *_before_dump functions should be removed when pdumper | ||
| 365 | becomes the only dumping method. */ | ||
| 365 | void * | 366 | void * |
| 366 | malloc_before_dump (size_t size) | 367 | malloc_before_dump (size_t size) |
| 367 | { | 368 | { |
| @@ -596,7 +597,7 @@ free_after_dump_9x (void *ptr) | |||
| 596 | } | 597 | } |
| 597 | } | 598 | } |
| 598 | 599 | ||
| 599 | #ifdef ENABLE_CHECKING | 600 | #if !defined (CANNOT_DUMP) && defined (ENABLE_CHECKING) |
| 600 | void | 601 | void |
| 601 | report_temacs_memory_usage (void) | 602 | report_temacs_memory_usage (void) |
| 602 | { | 603 | { |
diff --git a/src/w32heap.h b/src/w32heap.h index 6b9dca38a3b..13f7a6325b2 100644 --- a/src/w32heap.h +++ b/src/w32heap.h | |||
| @@ -31,7 +31,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | |||
| 31 | extern unsigned char *get_data_start (void); | 31 | extern unsigned char *get_data_start (void); |
| 32 | extern unsigned char *get_data_end (void); | 32 | extern unsigned char *get_data_end (void); |
| 33 | extern size_t reserved_heap_size; | 33 | extern size_t reserved_heap_size; |
| 34 | extern BOOL using_dynamic_heap; | ||
| 35 | 34 | ||
| 36 | extern void *mmap_realloc (void **, size_t); | 35 | extern void *mmap_realloc (void **, size_t); |
| 37 | extern void mmap_free (void **); | 36 | extern void mmap_free (void **); |
| @@ -43,7 +42,7 @@ extern void report_temacs_memory_usage (void); | |||
| 43 | extern void *sbrk (ptrdiff_t size); | 42 | extern void *sbrk (ptrdiff_t size); |
| 44 | 43 | ||
| 45 | /* Initialize heap structures for sbrk on startup. */ | 44 | /* Initialize heap structures for sbrk on startup. */ |
| 46 | extern void init_heap (void); | 45 | extern void init_heap (bool); |
| 47 | 46 | ||
| 48 | /* ----------------------------------------------------------------- */ | 47 | /* ----------------------------------------------------------------- */ |
| 49 | /* Useful routines for manipulating memory-mapped files. */ | 48 | /* Useful routines for manipulating memory-mapped files. */ |
diff --git a/src/w32proc.c b/src/w32proc.c index a5d08f60117..05e6c46b336 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -81,6 +81,36 @@ static sigset_t sig_mask; | |||
| 81 | 81 | ||
| 82 | static CRITICAL_SECTION crit_sig; | 82 | static CRITICAL_SECTION crit_sig; |
| 83 | 83 | ||
| 84 | /* Catch memory allocation before the heap allocation scheme is set | ||
| 85 | up. These functions should never be called, unless code is added | ||
| 86 | early on in 'main' that runs before init_heap is called. */ | ||
| 87 | _Noreturn void * malloc_before_init (size_t); | ||
| 88 | _Noreturn void * realloc_before_init (void *, size_t); | ||
| 89 | _Noreturn void free_before_init (void *); | ||
| 90 | |||
| 91 | _Noreturn void * | ||
| 92 | malloc_before_init (size_t size) | ||
| 93 | { | ||
| 94 | fprintf (stderr, | ||
| 95 | "error: 'malloc' called before setting up heap allocation; exiting.\n"); | ||
| 96 | exit (-1); | ||
| 97 | } | ||
| 98 | |||
| 99 | _Noreturn void * | ||
| 100 | realloc_before_init (void *ptr, size_t size) | ||
| 101 | { | ||
| 102 | fprintf (stderr, | ||
| 103 | "error: 'realloc' called before setting up heap allocation; exiting.\n"); | ||
| 104 | exit (-1); | ||
| 105 | } | ||
| 106 | |||
| 107 | _Noreturn void | ||
| 108 | free_before_init (void *ptr) | ||
| 109 | { | ||
| 110 | fprintf (stderr, | ||
| 111 | "error: 'free' called before setting up heap allocation; exiting.\n"); | ||
| 112 | exit (-1); | ||
| 113 | } | ||
| 84 | 114 | ||
| 85 | extern BOOL ctrl_c_handler (unsigned long type); | 115 | extern BOOL ctrl_c_handler (unsigned long type); |
| 86 | 116 | ||
| @@ -110,12 +140,13 @@ _start (void) | |||
| 110 | DebugBreak (); | 140 | DebugBreak (); |
| 111 | #endif | 141 | #endif |
| 112 | 142 | ||
| 143 | the_malloc_fn = malloc_before_init; | ||
| 144 | the_realloc_fn = realloc_before_init; | ||
| 145 | the_free_fn = free_before_init; | ||
| 146 | |||
| 113 | /* Cache system info, e.g., the NT page size. */ | 147 | /* Cache system info, e.g., the NT page size. */ |
| 114 | cache_system_info (); | 148 | cache_system_info (); |
| 115 | 149 | ||
| 116 | /* Grab our malloc arena space now, before CRT starts up. */ | ||
| 117 | init_heap (); | ||
| 118 | |||
| 119 | /* This prevents ctrl-c's in shells running while we're suspended from | 150 | /* This prevents ctrl-c's in shells running while we're suspended from |
| 120 | having us exit. */ | 151 | having us exit. */ |
| 121 | SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); | 152 | SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); |