This source file includes following definitions.
- heap_alloc
- heap_realloc
- dumped_data_commit
- init_heap
- malloc_after_dump
- malloc_before_dump
- realloc_after_dump
- realloc_before_dump
- free_after_dump
- free_before_dump
- malloc_after_dump_9x
- realloc_after_dump_9x
- free_after_dump_9x
- sys_calloc
- report_temacs_memory_usage
- getpagesize
- sbrk
- mmap_alloc
- mmap_free
- mmap_realloc
- getrlimit
- setrlimit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #include <config.h>
49 #include <stdio.h>
50 #include <errno.h>
51
52 #include <sys/mman.h>
53 #include <sys/resource.h>
54 #include "w32common.h"
55 #include "w32heap.h"
56 #include "lisp.h"
57 #include "w32.h"
58
59
60
61
62
63
64
65
66
67 typedef PVOID (WINAPI * RtlCreateHeap_Proc) (
68 ULONG Flags,
69 PVOID HeapBase,
70 SIZE_T ReserveSize,
71 SIZE_T CommitSize,
72 PVOID Lock,
73 PVOID Parameters
74 );
75
76 typedef LONG NTSTATUS;
77
78 typedef NTSTATUS (NTAPI *PRTL_HEAP_COMMIT_ROUTINE) (
79 IN PVOID Base,
80 IN OUT PVOID *CommitAddress,
81 IN OUT PSIZE_T CommitSize
82 );
83
84 typedef struct _RTL_HEAP_PARAMETERS {
85 ULONG Length;
86 SIZE_T SegmentReserve;
87 SIZE_T SegmentCommit;
88 SIZE_T DeCommitFreeBlockThreshold;
89 SIZE_T DeCommitTotalFreeThreshold;
90 SIZE_T MaximumAllocationSize;
91 SIZE_T VirtualMemoryThreshold;
92 SIZE_T InitialCommit;
93 SIZE_T InitialReserve;
94 PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
95 SIZE_T Reserved[ 2 ];
96 } RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 #ifndef HAVE_UNEXEC
119
120
121 # define DUMPED_HEAP_SIZE 10
122 #else
123 # if defined _WIN64 || defined WIDE_EMACS_INT
124 # define DUMPED_HEAP_SIZE (28*1024*1024)
125 # else
126 # define DUMPED_HEAP_SIZE (18*1024*1024)
127 # endif
128 #endif
129
130 static unsigned char dumped_data[DUMPED_HEAP_SIZE];
131
132
133 unsigned char *data_region_base = NULL;
134 unsigned char *data_region_end = NULL;
135 static DWORD_PTR committed = 0;
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 #define PAGE_SIZE 0x1000
167 #define MaxBlockSize (0x80000 - PAGE_SIZE)
168
169 #define MAX_BLOCKS 0x40
170
171 static struct
172 {
173 unsigned char *address;
174 size_t size;
175 DWORD occupied;
176 } blocks[MAX_BLOCKS];
177
178 static DWORD blocks_number = 0;
179 static unsigned char *bc_limit;
180
181
182
183
184
185 HANDLE heap = NULL;
186
187
188 malloc_fn the_malloc_fn;
189 realloc_fn the_realloc_fn;
190 free_fn the_free_fn;
191
192 static void *
193 heap_alloc (size_t size)
194 {
195 void *p = size <= PTRDIFF_MAX ? HeapAlloc (heap, 0, size | !size) : NULL;
196 if (!p)
197 errno = ENOMEM;
198 return p;
199 }
200
201 static void *
202 heap_realloc (void *ptr, size_t size)
203 {
204 void *p = (size <= PTRDIFF_MAX
205 ? HeapReAlloc (heap, 0, ptr, size | !size)
206 : NULL);
207 if (!p)
208 errno = ENOMEM;
209 return p;
210 }
211
212
213
214
215
216
217
218
219
220 static NTSTATUS NTAPI
221 dumped_data_commit (PVOID Base, PVOID *CommitAddress, PSIZE_T CommitSize)
222 {
223
224
225
226
227
228 *CommitAddress = data_region_base + committed;
229 committed += *CommitSize;
230
231 if (((unsigned char *)(*CommitAddress)) + *CommitSize >= bc_limit)
232 {
233 fprintf (stderr,
234 "dumped_data_commit: memory exhausted.\nEnlarge dumped_data[]!\n");
235 exit (-1);
236 }
237 return 0;
238 }
239
240
241
242
243
244 #ifndef MINGW_W64
245 typedef enum _HEAP_INFORMATION_CLASS {
246 HeapCompatibilityInformation
247 } HEAP_INFORMATION_CLASS;
248
249 typedef WINBASEAPI BOOL (WINAPI * HeapSetInformation_Proc)(HANDLE,HEAP_INFORMATION_CLASS,PVOID,SIZE_T);
250 #endif
251
252 void
253 init_heap (bool use_dynamic_heap)
254 {
255
256
257
258 if (use_dynamic_heap)
259 {
260
261
262
263
264
265
266
267
268
269
270 data_region_end = data_region_base;
271
272
273 heap = HeapCreate (0, 0, 0);
274
275 #ifndef MINGW_W64
276 unsigned long enable_lfh = 2;
277
278 HMODULE hm_kernel32dll = LoadLibrary ("kernel32.dll");
279 HeapSetInformation_Proc s_pfn_Heap_Set_Information =
280 (HeapSetInformation_Proc) get_proc_addr (hm_kernel32dll,
281 "HeapSetInformation");
282 if (s_pfn_Heap_Set_Information != NULL)
283 {
284 if (s_pfn_Heap_Set_Information ((PVOID) heap,
285 HeapCompatibilityInformation,
286 &enable_lfh, sizeof(enable_lfh)) == 0)
287 DebPrint (("Enabling Low Fragmentation Heap failed: error %ld\n",
288 GetLastError ()));
289 }
290 #endif
291
292 if (os_subtype == OS_SUBTYPE_9X)
293 {
294 the_malloc_fn = malloc_after_dump_9x;
295 the_realloc_fn = realloc_after_dump_9x;
296 the_free_fn = free_after_dump_9x;
297 }
298 else
299 {
300 the_malloc_fn = malloc_after_dump;
301 the_realloc_fn = realloc_after_dump;
302 the_free_fn = free_after_dump;
303 }
304 }
305 else
306 {
307
308
309
310 HMODULE hm_ntdll = LoadLibrary ("ntdll.dll");
311 RtlCreateHeap_Proc s_pfn_Rtl_Create_Heap
312 = (RtlCreateHeap_Proc) get_proc_addr (hm_ntdll, "RtlCreateHeap");
313
314 RTL_HEAP_PARAMETERS params;
315 ZeroMemory (¶ms, sizeof(params));
316 params.Length = sizeof(RTL_HEAP_PARAMETERS);
317
318 data_region_base = (unsigned char *)ROUND_UP (dumped_data, 0x1000);
319 data_region_end = bc_limit = dumped_data + DUMPED_HEAP_SIZE;
320
321 params.InitialCommit = committed = 0x1000;
322 params.InitialReserve = sizeof(dumped_data);
323
324
325 params.CommitRoutine = &dumped_data_commit;
326
327
328 if (s_pfn_Rtl_Create_Heap == NULL)
329 {
330 fprintf (stderr, "Cannot build Emacs without RtlCreateHeap being available; exiting.\n");
331 exit (-1);
332 }
333 heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, ¶ms);
334
335 if (os_subtype == OS_SUBTYPE_9X)
336 {
337 fprintf (stderr, "Cannot dump Emacs on Windows 9X; exiting.\n");
338 exit (-1);
339 }
340 else
341 {
342 the_malloc_fn = malloc_before_dump;
343 the_realloc_fn = realloc_before_dump;
344 the_free_fn = free_before_dump;
345 }
346 }
347
348
349 cache_system_info ();
350 }
351
352
353
354
355 #undef malloc
356 #undef realloc
357 #undef free
358
359
360 #define FREEABLE_P(addr) \
361 ((DWORD_PTR)(unsigned char *)(addr) > 0 \
362 && ((unsigned char *)(addr) < dumped_data \
363 || (unsigned char *)(addr) >= dumped_data + DUMPED_HEAP_SIZE))
364
365 void *
366 malloc_after_dump (size_t size)
367 {
368
369 void *p = heap_alloc (size);
370
371
372 if (p)
373 {
374 unsigned char *new_brk = (unsigned char *)p + size;
375
376 if (new_brk > data_region_end)
377 data_region_end = new_brk;
378 }
379 return p;
380 }
381
382
383
384 void *
385 malloc_before_dump (size_t size)
386 {
387 void *p;
388
389
390
391 if (size < MaxBlockSize)
392 {
393
394 p = heap_alloc (size);
395 }
396 else
397 {
398
399 int i = 0;
400
401 for (i = 0; i < blocks_number; i++)
402 {
403 if (blocks[i].occupied == 0 && blocks[i].size >= size)
404 break;
405 }
406 if (i < blocks_number)
407 {
408
409 p = blocks[i].address;
410 blocks[i].occupied = TRUE;
411 }
412 else
413 {
414
415
416 if (blocks_number >= MAX_BLOCKS)
417 {
418 fprintf (stderr,
419 "malloc_before_dump: no more big chunks available.\nEnlarge MAX_BLOCKS!\n");
420 exit (-1);
421 }
422 bc_limit -= size;
423 bc_limit = (unsigned char *)ROUND_DOWN (bc_limit, 0x10);
424 p = bc_limit;
425 blocks[blocks_number].address = p;
426 blocks[blocks_number].size = size;
427 blocks[blocks_number].occupied = TRUE;
428 blocks_number++;
429
430 if (bc_limit < dumped_data + committed)
431 {
432 fprintf (stderr,
433 "malloc_before_dump: memory exhausted.\nEnlarge dumped_data[]!\n");
434 exit (-1);
435 }
436 }
437 }
438 return p;
439 }
440
441
442
443 void *
444 realloc_after_dump (void *ptr, size_t size)
445 {
446 void *p;
447
448
449 if (FREEABLE_P (ptr))
450 {
451
452 p = heap_realloc (ptr, size);
453 }
454 else
455 {
456
457
458 p = heap_alloc (size);
459 if (p && ptr)
460 CopyMemory (p, ptr, size);
461 }
462
463 if (p)
464 {
465 unsigned char *new_brk = (unsigned char *)p + size;
466
467 if (new_brk > data_region_end)
468 data_region_end = new_brk;
469 }
470 return p;
471 }
472
473 void *
474 realloc_before_dump (void *ptr, size_t size)
475 {
476 void *p;
477
478
479 if (dumped_data < (unsigned char *)ptr
480 && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize)
481 {
482 p = heap_realloc (ptr, size);
483 }
484 else
485 {
486
487
488
489
490 p = malloc_before_dump (size);
491
492
493
494
495
496
497 if (p && ptr)
498 {
499 CopyMemory (p, ptr, size);
500 free_before_dump (ptr);
501 }
502 }
503 return p;
504 }
505
506
507 void
508 free_after_dump (void *ptr)
509 {
510
511 if (FREEABLE_P (ptr))
512 {
513
514 HeapFree (heap, 0, ptr);
515 }
516 }
517
518 void
519 free_before_dump (void *ptr)
520 {
521 if (!ptr)
522 return;
523
524
525 if (dumped_data < (unsigned char *)ptr
526 && (unsigned char *)ptr < bc_limit)
527 {
528
529 HeapFree (heap, 0, ptr);
530 }
531 else
532 {
533
534 int i;
535
536 for (i = 0; i < blocks_number; i++)
537 {
538 if (blocks[i].address == ptr)
539 {
540
541 blocks[i].occupied = 0;
542 break;
543 }
544
545
546 eassert (i < blocks_number);
547 }
548 }
549 }
550
551
552
553
554
555
556 void *
557 malloc_after_dump_9x (size_t size)
558 {
559 void *p = malloc_after_dump (size + 8);
560 void *pa;
561 if (p == NULL)
562 return p;
563 pa = (void*)(((intptr_t)p + 8) & ~7);
564 *((void**)pa-1) = p;
565 return pa;
566 }
567
568 void *
569 realloc_after_dump_9x (void *ptr, size_t size)
570 {
571 if (FREEABLE_P (ptr))
572 {
573 void *po = *((void**)ptr-1);
574 void *p;
575 void *pa;
576 p = realloc_after_dump (po, size + 8);
577 if (p == NULL)
578 return p;
579 pa = (void*)(((intptr_t)p + 8) & ~7);
580 if (ptr != NULL &&
581 (char*)pa - (char*)p != (char*)ptr - (char*)po)
582 {
583
584
585 MoveMemory (pa, (void*)((char*)p + ((char*)ptr - (char*)po)), size);
586 }
587 *((void**)pa-1) = p;
588 return pa;
589 }
590 else
591 {
592
593
594 void* p = malloc_after_dump_9x (size);
595 if (p != NULL)
596 CopyMemory (p, ptr, size);
597 return p;
598 }
599 }
600
601 void
602 free_after_dump_9x (void *ptr)
603 {
604 if (FREEABLE_P (ptr))
605 {
606 free_after_dump (*((void**)ptr-1));
607 }
608 }
609
610 void *
611 sys_calloc (size_t number, size_t size)
612 {
613 size_t nbytes = number * size;
614 void *ptr = (*the_malloc_fn) (nbytes);
615 if (ptr)
616 memset (ptr, 0, nbytes);
617 return ptr;
618 }
619
620 #if defined HAVE_UNEXEC && defined ENABLE_CHECKING
621 void
622 report_temacs_memory_usage (void)
623 {
624 DWORD blocks_used = 0;
625 size_t large_mem_used = 0;
626 int i;
627
628 for (i = 0; i < blocks_number; i++)
629 if (blocks[i].occupied)
630 {
631 blocks_used++;
632 large_mem_used += blocks[i].size;
633 }
634
635
636
637 fprintf (stderr,
638 "Dump memory usage: Heap: %" PRIu64 " Large blocks(%lu/%lu): %" PRIu64 "/%" PRIu64 "\n",
639 (unsigned long long)committed, blocks_used, blocks_number,
640 (unsigned long long)large_mem_used,
641 (unsigned long long)(dumped_data + DUMPED_HEAP_SIZE - bc_limit));
642 }
643 #endif
644
645
646 int
647 getpagesize (void)
648 {
649 return sysinfo_cache.dwPageSize;
650 }
651
652 void *
653 sbrk (ptrdiff_t increment)
654 {
655
656
657
658
659 eassert (increment == 0);
660 return data_region_end;
661 }
662
663
664
665
666
667 #define MAX_BUFFER_SIZE (512 * 1024 * 1024)
668
669 void *
670 mmap_alloc (void **var, size_t nbytes)
671 {
672 void *p = NULL;
673
674
675
676
677
678
679
680
681
682 if (nbytes < MAX_BUFFER_SIZE)
683 p = VirtualAlloc (NULL, ROUND_UP (nbytes * 2, get_allocation_unit ()),
684 MEM_RESERVE, PAGE_READWRITE);
685
686
687
688 if (p == NULL)
689 p = VirtualAlloc (NULL, ROUND_UP (nbytes, get_allocation_unit ()),
690 MEM_RESERVE, PAGE_READWRITE);
691
692 if (p != NULL)
693 {
694
695 *var = VirtualAlloc (p, nbytes, MEM_COMMIT, PAGE_READWRITE);
696 if (*var == NULL)
697 p = *var;
698 }
699
700 if (!p)
701 {
702 DWORD e = GetLastError ();
703
704 if (e == ERROR_NOT_ENOUGH_MEMORY)
705 errno = ENOMEM;
706 else
707 {
708 DebPrint (("mmap_alloc: error %ld\n", e));
709 errno = EINVAL;
710 }
711 }
712
713 return *var = p;
714 }
715
716 void
717 mmap_free (void **var)
718 {
719 if (*var)
720 {
721 if (VirtualFree (*var, 0, MEM_RELEASE) == 0)
722 DebPrint (("mmap_free: error %ld\n", GetLastError ()));
723 *var = NULL;
724 }
725 }
726
727 void *
728 mmap_realloc (void **var, size_t nbytes)
729 {
730 MEMORY_BASIC_INFORMATION memInfo, m2;
731 void *old_ptr;
732
733 if (*var == NULL)
734 return mmap_alloc (var, nbytes);
735
736
737 if (nbytes == 0)
738 {
739 mmap_free (var);
740 return mmap_alloc (var, nbytes);
741 }
742
743 memset (&memInfo, 0, sizeof (memInfo));
744 if (VirtualQuery (*var, &memInfo, sizeof (memInfo)) == 0)
745 DebPrint (("mmap_realloc: VirtualQuery error = %ld\n", GetLastError ()));
746
747
748 if (memInfo.RegionSize < nbytes)
749 {
750 memset (&m2, 0, sizeof (m2));
751 if (VirtualQuery ((char *)*var + memInfo.RegionSize, &m2, sizeof(m2)) == 0)
752 DebPrint (("mmap_realloc: VirtualQuery error = %ld\n",
753 GetLastError ()));
754
755
756 if (m2.State == MEM_RESERVE
757 && m2.AllocationBase == memInfo.AllocationBase
758 && nbytes <= memInfo.RegionSize + m2.RegionSize)
759 {
760 void *p;
761
762 p = VirtualAlloc (*var, nbytes, MEM_COMMIT, PAGE_READWRITE);
763 if (!p )
764 {
765 DebPrint (("realloc enlarge: VirtualAlloc (%p + %I64x, %I64x) error %ld\n",
766 *var, (uint64_t)memInfo.RegionSize,
767 (uint64_t)(nbytes - memInfo.RegionSize),
768 GetLastError ()));
769 DebPrint (("next region: %p %p %I64x %x\n", m2.BaseAddress,
770 m2.AllocationBase, (uint64_t)m2.RegionSize,
771 m2.AllocationProtect));
772 }
773 else
774 return *var;
775 }
776
777
778 old_ptr = *var;
779
780 if (mmap_alloc (var, nbytes))
781 {
782 CopyMemory (*var, old_ptr, memInfo.RegionSize);
783 mmap_free (&old_ptr);
784 return *var;
785 }
786 else
787 {
788
789 *var = old_ptr;
790 return NULL;
791 }
792 }
793
794
795 if (memInfo.RegionSize > nbytes + getpagesize())
796 {
797
798 if ((memInfo.RegionSize / 2) > nbytes)
799 {
800
801
802 old_ptr = *var;
803
804 if (mmap_alloc (var, nbytes))
805 {
806 CopyMemory (*var, old_ptr, nbytes);
807 mmap_free (&old_ptr);
808 return *var;
809 }
810 else
811 {
812
813
814
815 *var = old_ptr;
816 return *var;
817 }
818 }
819
820
821 if (VirtualFree ((char *)*var + nbytes + get_page_size(),
822 memInfo.RegionSize - nbytes - get_page_size(),
823 MEM_DECOMMIT) == 0)
824 DebPrint (("mmap_realloc: VirtualFree error %ld\n", GetLastError ()));
825 return *var;
826 }
827
828
829 return *var;
830 }
831
832
833
834
835 int
836 getrlimit (rlimit_resource_t rltype, struct rlimit *rlp)
837 {
838 int retval = -1;
839
840 switch (rltype)
841 {
842 case RLIMIT_STACK:
843 {
844 MEMORY_BASIC_INFORMATION m;
845
846
847
848
849
850
851
852
853 if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))
854 errno = EPERM;
855 else
856 {
857 rlp->rlim_cur = (DWORD_PTR) &m - (DWORD_PTR) m.AllocationBase;
858 rlp->rlim_max =
859 (DWORD_PTR) m.BaseAddress + m.RegionSize
860 - (DWORD_PTR) m.AllocationBase;
861
862
863 rlp->rlim_cur -= getpagesize ();
864 rlp->rlim_max -= getpagesize ();
865 retval = 0;
866 }
867 }
868 break;
869 case RLIMIT_NOFILE:
870
871
872
873
874
875
876 rlp->rlim_cur = FD_SETSIZE;
877 rlp->rlim_max = 2048;
878 retval = 0;
879 break;
880 default:
881
882
883
884 errno = ENOSYS;
885 break;
886 }
887 return retval;
888 }
889
890 int
891 setrlimit (rlimit_resource_t rltype, const struct rlimit *rlp)
892 {
893 switch (rltype)
894 {
895 case RLIMIT_STACK:
896 case RLIMIT_NOFILE:
897
898 errno = EPERM;
899 break;
900 default:
901 errno = ENOSYS;
902 break;
903 }
904 return -1;
905 }