diff options
| author | Gerd Moellmann | 2000-10-20 15:55:14 +0000 |
|---|---|---|
| committer | Gerd Moellmann | 2000-10-20 15:55:14 +0000 |
| commit | 877935b1f574db32339050788147d677fc3cce27 (patch) | |
| tree | 07b5e106282e381a23c0c9f14b7af84eb625a5ff /src/alloc.c | |
| parent | b86c791c0fce7721bee869de8d7158a824c74dc7 (diff) | |
| download | emacs-877935b1f574db32339050788147d677fc3cce27.tar.gz emacs-877935b1f574db32339050788147d677fc3cce27.zip | |
(toplevel) [SYSTEM_MALLOC || DOUG_LEA_MALLOC]: Undef
GC_MALLOC_CHECK.
(toplevel) [GC_MARK_STACK || GC_MALLOC_CHECK]: Move mem_node
structure definition and related variabled to the top of the file.
Include this code when GC_MALLOC_CHECK is defined.
(lisp_malloc, lisp_free) [GC_MALLOC_CHECK]: Don't
register/unregister allocated region.
(emacs_blocked_free) [GC_MALLOC_CHECK]: Check if freeing something
which isn't allocated.
(emacs_blocked_malloc) [GC_MALLOC_CHECK]: Check if returning
something which is already in use.
(emacs_blocked_realloc) [GC_MALLOC_CHECK]: Likewise.
(mem_insert) [GC_MALLOC_CHECK]: Use _malloc_internal.
(mem_delete) [GC_MALLOC_CHECK]: Use _free_internal.
(init_alloc_once) [GC_MALLOC_CHECK]: Call mem_init.
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 241 |
1 files changed, 177 insertions, 64 deletions
diff --git a/src/alloc.c b/src/alloc.c index 510d4671183..74ac7845cea 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -27,11 +27,18 @@ Boston, MA 02111-1307, USA. */ | |||
| 27 | #include <signal.h> | 27 | #include <signal.h> |
| 28 | 28 | ||
| 29 | /* Define this temporarily to hunt a bug. If defined, the size of | 29 | /* Define this temporarily to hunt a bug. If defined, the size of |
| 30 | strings is always recorded in sdata structures so that it can be | 30 | strings is redundantly recorded in sdata structures so that it can |
| 31 | compared to the sizes recorded in Lisp strings. */ | 31 | be compared to the sizes recorded in Lisp strings. */ |
| 32 | 32 | ||
| 33 | #define GC_CHECK_STRING_BYTES 1 | 33 | #define GC_CHECK_STRING_BYTES 1 |
| 34 | 34 | ||
| 35 | /* GC_MALLOC_CHECK defined means perform validity checks of malloc'd | ||
| 36 | memory. Can do this only if using gmalloc.c. */ | ||
| 37 | |||
| 38 | #if defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC | ||
| 39 | #undef GC_MALLOC_CHECK | ||
| 40 | #endif | ||
| 41 | |||
| 35 | /* This file is part of the core Lisp implementation, and thus must | 42 | /* This file is part of the core Lisp implementation, and thus must |
| 36 | deal with the real data structures. If the Lisp implementation is | 43 | deal with the real data structures. If the Lisp implementation is |
| 37 | replaced, this file likely will not be used. */ | 44 | replaced, this file likely will not be used. */ |
| @@ -278,7 +285,7 @@ enum mem_type | |||
| 278 | MEM_TYPE_VECTOR | 285 | MEM_TYPE_VECTOR |
| 279 | }; | 286 | }; |
| 280 | 287 | ||
| 281 | #if GC_MARK_STACK | 288 | #if GC_MARK_STACK || defined GC_MALLOC_CHECK |
| 282 | 289 | ||
| 283 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES | 290 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES |
| 284 | #include <stdio.h> /* For fprintf. */ | 291 | #include <stdio.h> /* For fprintf. */ |
| @@ -289,7 +296,64 @@ enum mem_type | |||
| 289 | 296 | ||
| 290 | Lisp_Object Vdead; | 297 | Lisp_Object Vdead; |
| 291 | 298 | ||
| 292 | struct mem_node; | 299 | #ifdef GC_MALLOC_CHECK |
| 300 | |||
| 301 | enum mem_type allocated_mem_type; | ||
| 302 | int dont_register_blocks; | ||
| 303 | |||
| 304 | #endif /* GC_MALLOC_CHECK */ | ||
| 305 | |||
| 306 | /* A node in the red-black tree describing allocated memory containing | ||
| 307 | Lisp data. Each such block is recorded with its start and end | ||
| 308 | address when it is allocated, and removed from the tree when it | ||
| 309 | is freed. | ||
| 310 | |||
| 311 | A red-black tree is a balanced binary tree with the following | ||
| 312 | properties: | ||
| 313 | |||
| 314 | 1. Every node is either red or black. | ||
| 315 | 2. Every leaf is black. | ||
| 316 | 3. If a node is red, then both of its children are black. | ||
| 317 | 4. Every simple path from a node to a descendant leaf contains | ||
| 318 | the same number of black nodes. | ||
| 319 | 5. The root is always black. | ||
| 320 | |||
| 321 | When nodes are inserted into the tree, or deleted from the tree, | ||
| 322 | the tree is "fixed" so that these properties are always true. | ||
| 323 | |||
| 324 | A red-black tree with N internal nodes has height at most 2 | ||
| 325 | log(N+1). Searches, insertions and deletions are done in O(log N). | ||
| 326 | Please see a text book about data structures for a detailed | ||
| 327 | description of red-black trees. Any book worth its salt should | ||
| 328 | describe them. */ | ||
| 329 | |||
| 330 | struct mem_node | ||
| 331 | { | ||
| 332 | struct mem_node *left, *right, *parent; | ||
| 333 | |||
| 334 | /* Start and end of allocated region. */ | ||
| 335 | void *start, *end; | ||
| 336 | |||
| 337 | /* Node color. */ | ||
| 338 | enum {MEM_BLACK, MEM_RED} color; | ||
| 339 | |||
| 340 | /* Memory type. */ | ||
| 341 | enum mem_type type; | ||
| 342 | }; | ||
| 343 | |||
| 344 | /* Base address of stack. Set in main. */ | ||
| 345 | |||
| 346 | Lisp_Object *stack_base; | ||
| 347 | |||
| 348 | /* Root of the tree describing allocated Lisp memory. */ | ||
| 349 | |||
| 350 | static struct mem_node *mem_root; | ||
| 351 | |||
| 352 | /* Sentinel node of the tree. */ | ||
| 353 | |||
| 354 | static struct mem_node mem_z; | ||
| 355 | #define MEM_NIL &mem_z | ||
| 356 | |||
| 293 | static POINTER_TYPE *lisp_malloc P_ ((size_t, enum mem_type)); | 357 | static POINTER_TYPE *lisp_malloc P_ ((size_t, enum mem_type)); |
| 294 | static void lisp_free P_ ((POINTER_TYPE *)); | 358 | static void lisp_free P_ ((POINTER_TYPE *)); |
| 295 | static void mark_stack P_ ((void)); | 359 | static void mark_stack P_ ((void)); |
| @@ -316,7 +380,7 @@ static INLINE struct mem_node *mem_find P_ ((void *)); | |||
| 316 | static void check_gcpros P_ ((void)); | 380 | static void check_gcpros P_ ((void)); |
| 317 | #endif | 381 | #endif |
| 318 | 382 | ||
| 319 | #endif /* GC_MARK_STACK != 0 */ | 383 | #endif /* GC_MARK_STACK || GC_MALLOC_CHECK */ |
| 320 | 384 | ||
| 321 | /* Recording what needs to be marked for gc. */ | 385 | /* Recording what needs to be marked for gc. */ |
| 322 | 386 | ||
| @@ -515,13 +579,18 @@ lisp_malloc (nbytes, type) | |||
| 515 | register void *val; | 579 | register void *val; |
| 516 | 580 | ||
| 517 | BLOCK_INPUT; | 581 | BLOCK_INPUT; |
| 582 | |||
| 583 | #ifdef GC_MALLOC_CHECK | ||
| 584 | allocated_mem_type = type; | ||
| 585 | #endif | ||
| 586 | |||
| 518 | val = (void *) malloc (nbytes); | 587 | val = (void *) malloc (nbytes); |
| 519 | 588 | ||
| 520 | #if GC_MARK_STACK | 589 | #if GC_MARK_STACK && !defined GC_MALLOC_CHECK |
| 521 | if (val && type != MEM_TYPE_NON_LISP) | 590 | if (val && type != MEM_TYPE_NON_LISP) |
| 522 | mem_insert (val, (char *) val + nbytes, type); | 591 | mem_insert (val, (char *) val + nbytes, type); |
| 523 | #endif | 592 | #endif |
| 524 | 593 | ||
| 525 | UNBLOCK_INPUT; | 594 | UNBLOCK_INPUT; |
| 526 | if (!val && nbytes) | 595 | if (!val && nbytes) |
| 527 | memory_full (); | 596 | memory_full (); |
| @@ -549,7 +618,7 @@ lisp_free (block) | |||
| 549 | { | 618 | { |
| 550 | BLOCK_INPUT; | 619 | BLOCK_INPUT; |
| 551 | free (block); | 620 | free (block); |
| 552 | #if GC_MARK_STACK | 621 | #if GC_MARK_STACK && !defined GC_MALLOC_CHECK |
| 553 | mem_delete (mem_find (block)); | 622 | mem_delete (mem_find (block)); |
| 554 | #endif | 623 | #endif |
| 555 | UNBLOCK_INPUT; | 624 | UNBLOCK_INPUT; |
| @@ -584,8 +653,29 @@ emacs_blocked_free (ptr) | |||
| 584 | void *ptr; | 653 | void *ptr; |
| 585 | { | 654 | { |
| 586 | BLOCK_INPUT; | 655 | BLOCK_INPUT; |
| 656 | |||
| 657 | #ifdef GC_MALLOC_CHECK | ||
| 658 | { | ||
| 659 | struct mem_node *m; | ||
| 660 | |||
| 661 | m = mem_find (ptr); | ||
| 662 | if (m == MEM_NIL || m->start != ptr) | ||
| 663 | { | ||
| 664 | fprintf (stderr, | ||
| 665 | "Freeing `%p' which wasn't allocated with malloc\n", ptr); | ||
| 666 | abort (); | ||
| 667 | } | ||
| 668 | else | ||
| 669 | { | ||
| 670 | /* fprintf (stderr, "free %p...%p (%p)\n", m->start, m->end, ptr); */ | ||
| 671 | mem_delete (m); | ||
| 672 | } | ||
| 673 | } | ||
| 674 | #endif /* GC_MALLOC_CHECK */ | ||
| 675 | |||
| 587 | __free_hook = old_free_hook; | 676 | __free_hook = old_free_hook; |
| 588 | free (ptr); | 677 | free (ptr); |
| 678 | |||
| 589 | /* If we released our reserve (due to running out of memory), | 679 | /* If we released our reserve (due to running out of memory), |
| 590 | and we have a fair amount free once again, | 680 | and we have a fair amount free once again, |
| 591 | try to set aside another reserve in case we run out once more. */ | 681 | try to set aside another reserve in case we run out once more. */ |
| @@ -632,10 +722,34 @@ emacs_blocked_malloc (size) | |||
| 632 | #else | 722 | #else |
| 633 | __malloc_extra_blocks = malloc_hysteresis; | 723 | __malloc_extra_blocks = malloc_hysteresis; |
| 634 | #endif | 724 | #endif |
| 725 | |||
| 635 | value = (void *) malloc (size); | 726 | value = (void *) malloc (size); |
| 727 | |||
| 728 | #ifdef GC_MALLOC_CHECK | ||
| 729 | { | ||
| 730 | struct mem_node *m = mem_find (value); | ||
| 731 | if (m != MEM_NIL) | ||
| 732 | { | ||
| 733 | fprintf (stderr, "Malloc returned %p which is already in use\n", | ||
| 734 | value); | ||
| 735 | fprintf (stderr, "Region in use is %p...%p, %u bytes, type %d\n", | ||
| 736 | m->start, m->end, (char *) m->end - (char *) m->start, | ||
| 737 | m->type); | ||
| 738 | abort (); | ||
| 739 | } | ||
| 740 | |||
| 741 | if (!dont_register_blocks) | ||
| 742 | { | ||
| 743 | mem_insert (value, (char *) value + max (1, size), allocated_mem_type); | ||
| 744 | allocated_mem_type = MEM_TYPE_NON_LISP; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | #endif /* GC_MALLOC_CHECK */ | ||
| 748 | |||
| 636 | __malloc_hook = emacs_blocked_malloc; | 749 | __malloc_hook = emacs_blocked_malloc; |
| 637 | UNBLOCK_INPUT; | 750 | UNBLOCK_INPUT; |
| 638 | 751 | ||
| 752 | /* fprintf (stderr, "%p malloc\n", value); */ | ||
| 639 | return value; | 753 | return value; |
| 640 | } | 754 | } |
| 641 | 755 | ||
| @@ -651,7 +765,48 @@ emacs_blocked_realloc (ptr, size) | |||
| 651 | 765 | ||
| 652 | BLOCK_INPUT; | 766 | BLOCK_INPUT; |
| 653 | __realloc_hook = old_realloc_hook; | 767 | __realloc_hook = old_realloc_hook; |
| 768 | |||
| 769 | #ifdef GC_MALLOC_CHECK | ||
| 770 | if (ptr) | ||
| 771 | { | ||
| 772 | struct mem_node *m = mem_find (ptr); | ||
| 773 | if (m == MEM_NIL || m->start != ptr) | ||
| 774 | { | ||
| 775 | fprintf (stderr, | ||
| 776 | "Realloc of %p which wasn't allocated with malloc\n", | ||
| 777 | ptr); | ||
| 778 | abort (); | ||
| 779 | } | ||
| 780 | |||
| 781 | mem_delete (m); | ||
| 782 | } | ||
| 783 | |||
| 784 | /* fprintf (stderr, "%p -> realloc\n", ptr); */ | ||
| 785 | |||
| 786 | /* Prevent malloc from registering blocks. */ | ||
| 787 | dont_register_blocks = 1; | ||
| 788 | #endif /* GC_MALLOC_CHECK */ | ||
| 789 | |||
| 654 | value = (void *) realloc (ptr, size); | 790 | value = (void *) realloc (ptr, size); |
| 791 | |||
| 792 | #ifdef GC_MALLOC_CHECK | ||
| 793 | dont_register_blocks = 0; | ||
| 794 | |||
| 795 | { | ||
| 796 | struct mem_node *m = mem_find (value); | ||
| 797 | if (m != MEM_NIL) | ||
| 798 | { | ||
| 799 | fprintf (stderr, "Realloc returns memory that is already in use\n"); | ||
| 800 | abort (); | ||
| 801 | } | ||
| 802 | |||
| 803 | /* Can't handle zero size regions in the red-black tree. */ | ||
| 804 | mem_insert (value, (char *) value + max (size, 1), MEM_TYPE_NON_LISP); | ||
| 805 | } | ||
| 806 | |||
| 807 | /* fprintf (stderr, "%p <- realloc\n", value); */ | ||
| 808 | #endif /* GC_MALLOC_CHECK */ | ||
| 809 | |||
| 655 | __realloc_hook = emacs_blocked_realloc; | 810 | __realloc_hook = emacs_blocked_realloc; |
| 656 | UNBLOCK_INPUT; | 811 | UNBLOCK_INPUT; |
| 657 | 812 | ||
| @@ -2375,61 +2530,6 @@ make_event_array (nargs, args) | |||
| 2375 | C Stack Marking | 2530 | C Stack Marking |
| 2376 | ************************************************************************/ | 2531 | ************************************************************************/ |
| 2377 | 2532 | ||
| 2378 | #if GC_MARK_STACK | ||
| 2379 | |||
| 2380 | |||
| 2381 | /* Base address of stack. Set in main. */ | ||
| 2382 | |||
| 2383 | Lisp_Object *stack_base; | ||
| 2384 | |||
| 2385 | /* A node in the red-black tree describing allocated memory containing | ||
| 2386 | Lisp data. Each such block is recorded with its start and end | ||
| 2387 | address when it is allocated, and removed from the tree when it | ||
| 2388 | is freed. | ||
| 2389 | |||
| 2390 | A red-black tree is a balanced binary tree with the following | ||
| 2391 | properties: | ||
| 2392 | |||
| 2393 | 1. Every node is either red or black. | ||
| 2394 | 2. Every leaf is black. | ||
| 2395 | 3. If a node is red, then both of its children are black. | ||
| 2396 | 4. Every simple path from a node to a descendant leaf contains | ||
| 2397 | the same number of black nodes. | ||
| 2398 | 5. The root is always black. | ||
| 2399 | |||
| 2400 | When nodes are inserted into the tree, or deleted from the tree, | ||
| 2401 | the tree is "fixed" so that these properties are always true. | ||
| 2402 | |||
| 2403 | A red-black tree with N internal nodes has height at most 2 | ||
| 2404 | log(N+1). Searches, insertions and deletions are done in O(log N). | ||
| 2405 | Please see a text book about data structures for a detailed | ||
| 2406 | description of red-black trees. Any book worth its salt should | ||
| 2407 | describe them. */ | ||
| 2408 | |||
| 2409 | struct mem_node | ||
| 2410 | { | ||
| 2411 | struct mem_node *left, *right, *parent; | ||
| 2412 | |||
| 2413 | /* Start and end of allocated region. */ | ||
| 2414 | void *start, *end; | ||
| 2415 | |||
| 2416 | /* Node color. */ | ||
| 2417 | enum {MEM_BLACK, MEM_RED} color; | ||
| 2418 | |||
| 2419 | /* Memory type. */ | ||
| 2420 | enum mem_type type; | ||
| 2421 | }; | ||
| 2422 | |||
| 2423 | /* Root of the tree describing allocated Lisp memory. */ | ||
| 2424 | |||
| 2425 | static struct mem_node *mem_root; | ||
| 2426 | |||
| 2427 | /* Sentinel node of the tree. */ | ||
| 2428 | |||
| 2429 | static struct mem_node mem_z; | ||
| 2430 | #define MEM_NIL &mem_z | ||
| 2431 | |||
| 2432 | |||
| 2433 | /* Initialize this part of alloc.c. */ | 2533 | /* Initialize this part of alloc.c. */ |
| 2434 | 2534 | ||
| 2435 | static void | 2535 | static void |
| @@ -2501,7 +2601,13 @@ mem_insert (start, end, type) | |||
| 2501 | #endif /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */ | 2601 | #endif /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */ |
| 2502 | 2602 | ||
| 2503 | /* Create a new node. */ | 2603 | /* Create a new node. */ |
| 2604 | #ifdef GC_MALLOC_CHECK | ||
| 2605 | x = (struct mem_node *) _malloc_internal (sizeof *x); | ||
| 2606 | if (x == NULL) | ||
| 2607 | abort (); | ||
| 2608 | #else | ||
| 2504 | x = (struct mem_node *) xmalloc (sizeof *x); | 2609 | x = (struct mem_node *) xmalloc (sizeof *x); |
| 2610 | #endif | ||
| 2505 | x->start = start; | 2611 | x->start = start; |
| 2506 | x->end = end; | 2612 | x->end = end; |
| 2507 | x->type = type; | 2613 | x->type = type; |
| @@ -2522,6 +2628,7 @@ mem_insert (start, end, type) | |||
| 2522 | 2628 | ||
| 2523 | /* Re-establish red-black tree properties. */ | 2629 | /* Re-establish red-black tree properties. */ |
| 2524 | mem_insert_fixup (x); | 2630 | mem_insert_fixup (x); |
| 2631 | |||
| 2525 | return x; | 2632 | return x; |
| 2526 | } | 2633 | } |
| 2527 | 2634 | ||
| @@ -2721,7 +2828,12 @@ mem_delete (z) | |||
| 2721 | 2828 | ||
| 2722 | if (y->color == MEM_BLACK) | 2829 | if (y->color == MEM_BLACK) |
| 2723 | mem_delete_fixup (x); | 2830 | mem_delete_fixup (x); |
| 2831 | |||
| 2832 | #ifdef GC_MALLOC_CHECK | ||
| 2833 | _free_internal (y); | ||
| 2834 | #else | ||
| 2724 | xfree (y); | 2835 | xfree (y); |
| 2836 | #endif | ||
| 2725 | } | 2837 | } |
| 2726 | 2838 | ||
| 2727 | 2839 | ||
| @@ -2961,6 +3073,7 @@ live_buffer_p (m, p) | |||
| 2961 | && !NILP (((struct buffer *) p)->name)); | 3073 | && !NILP (((struct buffer *) p)->name)); |
| 2962 | } | 3074 | } |
| 2963 | 3075 | ||
| 3076 | #if GC_MARK_STACK | ||
| 2964 | 3077 | ||
| 2965 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES | 3078 | #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES |
| 2966 | 3079 | ||
| @@ -4907,7 +5020,7 @@ init_alloc_once () | |||
| 4907 | { | 5020 | { |
| 4908 | /* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet! */ | 5021 | /* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet! */ |
| 4909 | pure_bytes_used = 0; | 5022 | pure_bytes_used = 0; |
| 4910 | #if GC_MARK_STACK | 5023 | #if GC_MARK_STACK || defined GC_MALLOC_CHECK |
| 4911 | mem_init (); | 5024 | mem_init (); |
| 4912 | Vdead = make_pure_string ("DEAD", 4, 4, 0); | 5025 | Vdead = make_pure_string ("DEAD", 4, 4, 0); |
| 4913 | #endif | 5026 | #endif |