📄 stubborn.c
字号:
/* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to use or copy this program * for any purpose, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. *//* Boehm, July 31, 1995 5:02 pm PDT */#include "private/gc_priv.h"# ifdef STUBBORN_ALLOC/* Stubborn object (hard to change, nearly immutable) allocation. */extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */#define GENERAL_MALLOC(lb,k) \ (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))/* Data structure representing immutable objects that *//* are still being initialized. *//* This is a bit baroque in order to avoid acquiring *//* the lock twice for a typical allocation. */GC_PTR * GC_changing_list_start;void GC_push_stubborn_structures GC_PROTO((void)){ GC_push_all((ptr_t)(&GC_changing_list_start), (ptr_t)(&GC_changing_list_start) + sizeof(GC_PTR *));}# ifdef THREADS VOLATILE GC_PTR * VOLATILE GC_changing_list_current;# else GC_PTR * GC_changing_list_current;# endif /* Points at last added element. Also (ab)used for */ /* synchronization. Updates and reads are assumed atomic. */GC_PTR * GC_changing_list_limit; /* Points at the last word of the buffer, which is always 0 */ /* All entries in (GC_changing_list_current, */ /* GC_changing_list_limit] are 0 */void GC_stubborn_init(){# define INIT_SIZE 10 GC_changing_list_start = (GC_PTR *) GC_INTERNAL_MALLOC( (word)(INIT_SIZE * sizeof(GC_PTR)), PTRFREE); BZERO(GC_changing_list_start, INIT_SIZE * sizeof(GC_PTR)); if (GC_changing_list_start == 0) { GC_err_printf0("Insufficient space to start up\n"); ABORT("GC_stubborn_init: put of space"); } GC_changing_list_current = GC_changing_list_start; GC_changing_list_limit = GC_changing_list_start + INIT_SIZE - 1; * GC_changing_list_limit = 0;}/* Compact and possibly grow GC_uninit_list. The old copy is *//* left alone. Lock must be held. *//* When called GC_changing_list_current == GC_changing_list_limit *//* which is one past the current element. *//* When we finish GC_changing_list_current again points one past last *//* element. *//* Invariant while this is running: GC_changing_list_current *//* points at a word containing 0. *//* Returns FALSE on failure. */GC_bool GC_compact_changing_list(){ register GC_PTR *p, *q; register word count = 0; word old_size = (char **)GC_changing_list_limit - (char **)GC_changing_list_start+1; /* The casts are needed as a workaround for an Amiga bug */ register word new_size = old_size; GC_PTR * new_list; for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) { if (*p != 0) count++; } if (2 * count > old_size) new_size = 2 * count; new_list = (GC_PTR *) GC_INTERNAL_MALLOC( new_size * sizeof(GC_PTR), PTRFREE); /* PTRFREE is a lie. But we don't want the collector to */ /* consider these. We do want the list itself to be */ /* collectable. */ if (new_list == 0) return(FALSE); BZERO(new_list, new_size * sizeof(GC_PTR)); q = new_list; for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) { if (*p != 0) *q++ = *p; } GC_changing_list_start = new_list; GC_changing_list_limit = new_list + new_size - 1; GC_changing_list_current = q; return(TRUE);}/* Add p to changing list. Clear p on failure. */# define ADD_CHANGING(p) \ { \ register struct hblk * h = HBLKPTR(p); \ register word index = PHT_HASH(h); \ \ set_pht_entry_from_index(GC_changed_pages, index); \ } \ if (*GC_changing_list_current != 0 \ && ++GC_changing_list_current == GC_changing_list_limit) { \ if (!GC_compact_changing_list()) (p) = 0; \ } \ *GC_changing_list_current = p;void GC_change_stubborn(p)GC_PTR p;{ DCL_LOCK_STATE; DISABLE_SIGNALS(); LOCK(); ADD_CHANGING(p); UNLOCK(); ENABLE_SIGNALS();}void GC_end_stubborn_change(p)GC_PTR p;{# ifdef THREADS register VOLATILE GC_PTR * my_current = GC_changing_list_current;# else register GC_PTR * my_current = GC_changing_list_current;# endif register GC_bool tried_quick; DCL_LOCK_STATE; if (*my_current == p) { /* Hopefully the normal case. */ /* Compaction could not have been running when we started. */ *my_current = 0;# ifdef THREADS if (my_current == GC_changing_list_current) { /* Compaction can't have run in the interim. */ /* We got away with the quick and dirty approach. */ return; } tried_quick = TRUE;# else return;# endif } else { tried_quick = FALSE; } DISABLE_SIGNALS(); LOCK(); my_current = GC_changing_list_current; for (; my_current >= GC_changing_list_start; my_current--) { if (*my_current == p) { *my_current = 0; UNLOCK(); ENABLE_SIGNALS(); return; } } if (!tried_quick) { GC_err_printf1("Bad arg to GC_end_stubborn_change: 0x%lx\n", (unsigned long)p); ABORT("Bad arg to GC_end_stubborn_change"); } UNLOCK(); ENABLE_SIGNALS();}/* Allocate lb bytes of composite (pointerful) data *//* No pointer fields may be changed after a call to *//* GC_end_stubborn_change(p) where p is the value *//* returned by GC_malloc_stubborn. */# ifdef __STDC__ GC_PTR GC_malloc_stubborn(size_t lb)# else GC_PTR GC_malloc_stubborn(lb) size_t lb;# endif{register ptr_t op;register ptr_t *opp;register word lw;ptr_t result;DCL_LOCK_STATE; if( SMALL_OBJ(lb) ) {# ifdef MERGE_SIZES lw = GC_size_map[lb];# else lw = ALIGNED_WORDS(lb);# endif opp = &(GC_sobjfreelist[lw]); FASTLOCK(); if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) { FASTUNLOCK(); result = GC_generic_malloc((word)lb, STUBBORN); goto record; } *opp = obj_link(op); obj_link(op) = 0; GC_words_allocd += lw; result = (GC_PTR) op; ADD_CHANGING(result); FASTUNLOCK(); return((GC_PTR)result); } else { result = (GC_PTR) GC_generic_malloc((word)lb, STUBBORN); }record: DISABLE_SIGNALS(); LOCK(); ADD_CHANGING(result); UNLOCK(); ENABLE_SIGNALS(); return((GC_PTR)GC_clear_stack(result));}/* Functions analogous to GC_read_dirty and GC_page_was_dirty. *//* Report pages on which stubborn objects were changed. */void GC_read_changed(){ register GC_PTR * p = GC_changing_list_start; register GC_PTR q; register struct hblk * h; register word index; if (p == 0) /* initializing */ return; BCOPY(GC_changed_pages, GC_prev_changed_pages, (sizeof GC_changed_pages)); BZERO(GC_changed_pages, (sizeof GC_changed_pages)); for (; p <= GC_changing_list_current; p++) { if ((q = *p) != 0) { h = HBLKPTR(q); index = PHT_HASH(h); set_pht_entry_from_index(GC_changed_pages, index); } }}GC_bool GC_page_was_changed(h)struct hblk * h;{ register word index = PHT_HASH(h); return(get_pht_entry_from_index(GC_prev_changed_pages, index));}/* Remove unreachable entries from changed list. Should only be *//* called with mark bits consistent and lock held. */void GC_clean_changing_list(){ register GC_PTR * p = GC_changing_list_start; register GC_PTR q; register ptr_t r; register unsigned long count = 0; register unsigned long dropped_count = 0; if (p == 0) /* initializing */ return; for (; p <= GC_changing_list_current; p++) { if ((q = *p) != 0) { count++; r = (ptr_t)GC_base(q); if (r == 0 || !GC_is_marked(r)) { *p = 0; dropped_count++; } } }# ifdef PRINTSTATS if (count > 0) { GC_printf2("%lu entries in changing list: reclaimed %lu\n", (unsigned long)count, (unsigned long)dropped_count); }# endif}#else /* !STUBBORN_ALLOC */# ifdef __STDC__ GC_PTR GC_malloc_stubborn(size_t lb)# else GC_PTR GC_malloc_stubborn(lb) size_t lb;# endif{ return(GC_malloc(lb));}/*ARGSUSED*/void GC_end_stubborn_change(p)GC_PTR p;{}/*ARGSUSED*/void GC_change_stubborn(p)GC_PTR p;{}void GC_push_stubborn_structures GC_PROTO((void)){}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -