2827 lines
121 KiB
C
2827 lines
121 KiB
C
/*
|
|
* Copyright (c) 1988-1989 Hans-J. Boehm, Alan J. Demers
|
|
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
|
|
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
|
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
|
|
* Copyright (c) 2007 Free Software Foundation, Inc.
|
|
* Copyright (c) 2000-2011 by Hewlett-Packard Development Company.
|
|
* Copyright (c) 2009-2025 Ivan Maidanski
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* Note that this defines a large number of tuning hooks, which can
|
|
* safely be ignored in nearly all cases. For normal use it suffices
|
|
* to call only `GC_MALLOC` and, perhaps, `GC_REALLOC`.
|
|
* For better performance, also look at `GC_MALLOC_ATOMIC`, and
|
|
* `GC_enable_incremental`. If you need an action to be performed
|
|
* immediately before an object is collected, look at `GC_register_finalizer`.
|
|
* Everything else is best ignored unless you encounter performance
|
|
* problems.
|
|
*/
|
|
|
|
#ifndef GC_H
|
|
#define GC_H
|
|
|
|
/* Help debug mixed up preprocessor symbols. */
|
|
#if defined(WIN64) && !defined(_WIN64) && defined(_MSC_VER)
|
|
# pragma message("Warning: Expecting _WIN64 for x64 targets!")
|
|
#endif
|
|
|
|
/*
|
|
* Define version numbers here to allow test on build machine for
|
|
* cross-builds. Note that this defines the header version number,
|
|
* which may or may not match that of the dynamic library.
|
|
* `GC_get_version()` can be used to obtain the latter.
|
|
*/
|
|
#include "gc_version.h"
|
|
|
|
#include "gc_config_macros.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef void *GC_PTR; /*< preserved only for backward compatibility */
|
|
|
|
/**
|
|
* Define public `word` and `signed_word` to be unsigned and signed types
|
|
* of the size same as of `size_t`, `ptrdiff_t`, and of the address part
|
|
* of data pointers (like `char *` and `void *`).
|
|
*/
|
|
typedef GC_UNSIGNEDWORD GC_word;
|
|
typedef GC_SIGNEDWORD GC_signed_word;
|
|
#undef GC_SIGNEDWORD
|
|
#undef GC_UNSIGNEDWORD
|
|
|
|
#if (defined(_UINTPTR_T) || defined(_UINTPTR_T_DECLARED) \
|
|
|| defined(_UINTPTR_T_DEFINED)) \
|
|
&& !defined(__CYGWIN__) && !defined(__MSYS__)
|
|
/* Note: Cygwin and MSYS2 might provide `__uintptr_t` but not `uintptr_t`. */
|
|
typedef uintptr_t GC_uintptr_t;
|
|
#else
|
|
typedef GC_word GC_uintptr_t;
|
|
#endif
|
|
|
|
/**
|
|
* Is first pointer has a smaller address than the second one?
|
|
* The arguments should be of the same pointer type, e.g. of `char *` type.
|
|
* Ancient compilers might treat a pointer as a signed value, thus we
|
|
* need a cast to unsigned `word` of each compared pointer.
|
|
*/
|
|
#if defined(__GNUC__) && !defined(__CHERI_PURE_CAPABILITY__)
|
|
# define GC_ADDR_LT(p, q) ((p) < (q))
|
|
#else
|
|
# define GC_ADDR_LT(p, q) \
|
|
((GC_word)(GC_uintptr_t)(p) < (GC_word)(GC_uintptr_t)(q))
|
|
#endif
|
|
|
|
/**
|
|
* Get the collector library version. The returned value is a constant
|
|
* in the form:
|
|
* `((version_major << 16) | (version_minor << 8) | version_micro)`.
|
|
*/
|
|
GC_API GC_VERSION_VAL_T GC_CALL GC_get_version(void);
|
|
|
|
/*
|
|
* Public read-only variables. The supplied getter functions are
|
|
* preferred for new client code.
|
|
*/
|
|
|
|
/**
|
|
* Counter incremented once per collection. Includes empty collections
|
|
* at startup. `GC_get_gc_no()` is unsynchronized, so it requires
|
|
* `GC_call_with_reader_lock()` to avoid data race on multiprocessors.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED GC_word GC_gc_no;
|
|
GC_API GC_word GC_CALL GC_get_gc_no(void);
|
|
|
|
#ifdef GC_THREADS
|
|
/**
|
|
* GC is parallelized for performance on multiprocessors.
|
|
* Set to a nonzero value when client calls `GC_start_mark_threads()`
|
|
* directly or starts the first non-main thread, provided the
|
|
* collector is built with `PARALLEL_MARK` macro defined, and either
|
|
* `GC_MARKERS` (or `GC_NPROCS`) environment variable is set to a value
|
|
* bigger than 1, or multiple cores (processors) are available, or
|
|
* the client calls `GC_set_markers_count()` before the collector
|
|
* initialization. After setting, `GC_parallel` value is equal to the
|
|
* number of marker threads minus one (i.e. the number of existing
|
|
* parallel marker threads excluding the initiating one).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_parallel;
|
|
#endif
|
|
|
|
/** Return value of `GC_parallel`. Does not acquire the allocator lock. */
|
|
GC_API int GC_CALL GC_get_parallel(void);
|
|
|
|
/**
|
|
* Set the number of marker threads (including the initiating one)
|
|
* to the desired value at start-up. Zero value means the collector
|
|
* is to decide. If the correct nonzero value is passed, then
|
|
* `GC_parallel` will be set to the value minus one later. Has no effect
|
|
* if called after the collector initialization. Does not itself cause
|
|
* creation of the marker threads. Does not use any synchronization.
|
|
*/
|
|
GC_API void GC_CALL GC_set_markers_count(unsigned);
|
|
|
|
/*
|
|
* Public R/W variables. The supplied setter and getter functions are
|
|
* preferred for new client code.
|
|
*/
|
|
|
|
/**
|
|
* When there is insufficient memory to satisfy an allocation request,
|
|
* we return `(*GC_oom_fn)(size)`. If it returns, it must return either
|
|
* `NULL` or a valid pointer to a previously allocated heap object.
|
|
* By default, this just returns `NULL`. If it points to a function which
|
|
* never returns `NULL`, probably by aborting the program instead, then
|
|
* invocations of `GC_MALLOC()` and friends (that are additionally marked
|
|
* as "never returning NULL unless GC_oom_fn returns NULL") do not need to
|
|
* be followed by code that checks for the `NULL` result.
|
|
* `GC_oom_fn` must not be 0. Both the setter and the getter acquire
|
|
* the allocator lock (in the reader mode in case of the getter) to
|
|
* avoid data race.
|
|
*/
|
|
typedef void *(GC_CALLBACK *GC_oom_func)(size_t /* `bytes_requested` */);
|
|
GC_API GC_ATTR_DEPRECATED GC_oom_func GC_oom_fn;
|
|
GC_API void GC_CALL GC_set_oom_fn(GC_oom_func) GC_ATTR_NONNULL(1);
|
|
GC_API GC_oom_func GC_CALL GC_get_oom_fn(void);
|
|
|
|
/**
|
|
* Invoked when the heap grows or shrinks. Called with the world
|
|
* stopped (and the allocator lock held). May be 0. Both the setter
|
|
* and the getter acquire the allocator lock (in the reader mode in
|
|
* case of the getter).
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_on_heap_resize_proc)(GC_word /* new_size */);
|
|
GC_API GC_ATTR_DEPRECATED GC_on_heap_resize_proc GC_on_heap_resize;
|
|
GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc);
|
|
GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void);
|
|
|
|
typedef enum {
|
|
GC_EVENT_START, /*< start collection */
|
|
GC_EVENT_MARK_START,
|
|
GC_EVENT_MARK_END,
|
|
GC_EVENT_RECLAIM_START,
|
|
GC_EVENT_RECLAIM_END,
|
|
GC_EVENT_END, /*< end collection */
|
|
GC_EVENT_PRE_STOP_WORLD, /*< begin stopping world */
|
|
GC_EVENT_POST_STOP_WORLD, /*< end stopping world */
|
|
GC_EVENT_PRE_START_WORLD, /*< begin restarting world */
|
|
GC_EVENT_POST_START_WORLD, /*< end restarting world */
|
|
GC_EVENT_THREAD_SUSPENDED,
|
|
GC_EVENT_THREAD_UNSUSPENDED
|
|
} GC_EventType;
|
|
|
|
/**
|
|
* Invoked to indicate progress through the collection process.
|
|
* Not used for thread suspend/resume notifications. Called with the
|
|
* allocator lock held (or, even, the world stopped). May be 0 (means
|
|
* no notifier). Both the setter and the getter acquire the allocator
|
|
* lock (in the reader mode in case of the getter).
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_on_collection_event_proc)(GC_EventType);
|
|
GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc);
|
|
GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void);
|
|
|
|
#ifdef GC_THREADS
|
|
/**
|
|
* Invoked when a thread is suspended or resumed during collection.
|
|
* Called with the allocator lock held (and the world stopped partially).
|
|
* May be 0 (means no notifier). Both the setter and the getter acquire
|
|
* the allocator lock (in the reader mode in case of the getter).
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_on_thread_event_proc)(GC_EventType,
|
|
void * /* `thread_id` */);
|
|
GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc);
|
|
GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void);
|
|
#endif
|
|
|
|
/**
|
|
* Turn on the find-leak mode (do not actually garbage collect, but
|
|
* simply report inaccessible memory that was not deallocated with
|
|
* `GC_FREE()`). Initial value is determined by `FIND_LEAK` macro.
|
|
* The value should not typically be modified after the collector
|
|
* initialization (and, thus, it does not use or need synchronization).
|
|
* The mode is supported only if the library has been compiled without
|
|
* `NO_FIND_LEAK` macro defined.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_find_leak;
|
|
GC_API void GC_CALL GC_set_find_leak(int);
|
|
GC_API int GC_CALL GC_get_find_leak(void);
|
|
|
|
/**
|
|
* Arrange for pointers to object interiors to be recognized as valid.
|
|
* Typically should not be changed after the collector initialization
|
|
* (in case of calling it after the collector is initialized, the
|
|
* setter acquires the allocator lock). Must be only 0 or 1.
|
|
* The initial value depends on whether the collector is built with
|
|
* `ALL_INTERIOR_POINTERS` macro defined or not. This also affects,
|
|
* unless `GC_get_dont_add_byte_at_end()` returns a nonzero value,
|
|
* whether the object sizes are increased by at least a byte to allow
|
|
* "off-the-end" pointer recognition (but the size is not increased
|
|
* for uncollectible objects as well as for ignore-off-page objects of
|
|
* at least heap block size).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_all_interior_pointers;
|
|
GC_API void GC_CALL GC_set_all_interior_pointers(int);
|
|
GC_API int GC_CALL GC_get_all_interior_pointers(void);
|
|
|
|
/**
|
|
* If nonzero, finalizers will only be run in response to an explicit
|
|
* `GC_invoke_finalizers()` call. The default is determined by whether
|
|
* the `FINALIZE_ON_DEMAND` macro is defined when the collector is built.
|
|
* The setter and the getter are unsynchronized.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_finalize_on_demand;
|
|
GC_API void GC_CALL GC_set_finalize_on_demand(int);
|
|
GC_API int GC_CALL GC_get_finalize_on_demand(void);
|
|
|
|
/**
|
|
* Mark objects reachable from finalizable objects in a separate post-pass.
|
|
* This makes it a bit safer to use non-topologically-ordered finalization.
|
|
* Default value is determined by `JAVA_FINALIZATION` macro.
|
|
* Enables `GC_register_finalizer_unreachable()` to work correctly.
|
|
* The setter and the getter are unsynchronized.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_java_finalization;
|
|
GC_API void GC_CALL GC_set_java_finalization(int);
|
|
GC_API int GC_CALL GC_get_java_finalization(void);
|
|
|
|
/**
|
|
* Invoked by the collector when there are objects to be finalized.
|
|
* Invoked at most once per collection cycle. Never invoked unless
|
|
* `GC_finalize_on_demand` is set. Typically this will notify
|
|
* a finalization thread, which will call `GC_invoke_finalizers()` in
|
|
* response. May be 0 (means no notifier). Both the setter and the getter
|
|
* acquire the allocator lock (in the reader mode in case of the getter).
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_finalizer_notifier_proc)(void);
|
|
GC_API GC_ATTR_DEPRECATED GC_finalizer_notifier_proc GC_finalizer_notifier;
|
|
GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc);
|
|
GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void);
|
|
|
|
/**
|
|
* The functions called to report pointer checking errors. Called without
|
|
* the allocator lock held. The default behavior is to fail with the
|
|
* appropriate message which includes the pointers. The functions
|
|
* (variables) must not be 0. Both the setters and the getters are
|
|
* unsynchronized.
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_valid_ptr_print_proc_t)(void *);
|
|
typedef void(GC_CALLBACK *GC_same_obj_print_proc_t)(void * /* `p` */,
|
|
void * /* `q` */);
|
|
GC_API GC_ATTR_DEPRECATED GC_same_obj_print_proc_t GC_same_obj_print_proc;
|
|
GC_API GC_ATTR_DEPRECATED GC_valid_ptr_print_proc_t
|
|
GC_is_valid_displacement_print_proc;
|
|
GC_API GC_ATTR_DEPRECATED GC_valid_ptr_print_proc_t GC_is_visible_print_proc;
|
|
GC_API void GC_CALL GC_set_same_obj_print_proc(GC_same_obj_print_proc_t)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_same_obj_print_proc_t GC_CALL GC_get_same_obj_print_proc(void);
|
|
GC_API void
|
|
GC_CALL GC_set_is_valid_displacement_print_proc(GC_valid_ptr_print_proc_t)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_valid_ptr_print_proc_t GC_CALL
|
|
GC_get_is_valid_displacement_print_proc(void);
|
|
GC_API void GC_CALL GC_set_is_visible_print_proc(GC_valid_ptr_print_proc_t)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_valid_ptr_print_proc_t GC_CALL GC_get_is_visible_print_proc(void);
|
|
|
|
/*
|
|
* A flag indicating "do not collect" mode. This overrides explicit
|
|
* `GC_gcollect()` calls as well. Used as a counter, so that nested
|
|
* enabling and disabling work correctly. Should normally be updated
|
|
* with `GC_enable()` and `GC_disable()` calls. Direct assignment to
|
|
* `GC_dont_gc` variable is deprecated. To check whether collections
|
|
* are disabled, `GC_is_disabled()` is preferred for new code.
|
|
*/
|
|
GC_API
|
|
#ifndef GC_DONT_GC
|
|
GC_ATTR_DEPRECATED
|
|
#endif
|
|
int GC_dont_gc;
|
|
|
|
/**
|
|
* Do not expand the heap unless explicitly requested or forced to.
|
|
* The setter and the getter are unsynchronized.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_dont_expand;
|
|
GC_API void GC_CALL GC_set_dont_expand(int);
|
|
GC_API int GC_CALL GC_get_dont_expand(void);
|
|
|
|
/**
|
|
* Causes the non-incremental collector to use the entire heap before
|
|
* collecting. This sometimes results in more large-block fragmentation,
|
|
* since very large blocks will tend to get broken up during each
|
|
* collection cycle. It is likely to result in a larger working set, but
|
|
* lower collection frequencies, and hence fewer instructions executed in
|
|
* the collector.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_use_entire_heap;
|
|
|
|
/**
|
|
* Number of partial collections between full collections. Matters only
|
|
* if `GC_is_incremental_mode()`. Full collections are also triggered
|
|
* if the collector detects a substantial increase in the number of the
|
|
* in-use heap blocks. Values in the tens are now perfectly reasonable.
|
|
* The setter and the getter are unsynchronized, so
|
|
* `GC_call_with_alloc_lock()` (`GC_call_with_reader_lock()` in case
|
|
* of the getter) is required to avoid data race (if the value is
|
|
* modified after the collector is put into the multi-threaded mode).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_full_freq;
|
|
GC_API void GC_CALL GC_set_full_freq(int);
|
|
GC_API int GC_CALL GC_get_full_freq(void);
|
|
|
|
/**
|
|
* Bytes not considered candidates for collection. Used only to control
|
|
* scheduling of collections. Updated by `GC_malloc_uncollectable()` and
|
|
* `GC_free()`. Wizards only. The setter and the getter are unsynchronized,
|
|
* so `GC_call_with_alloc_lock()` (`GC_call_with_reader_lock()` in case of
|
|
* the getter) is required to avoid data race (if the value is modified
|
|
* after the collector is put into the multi-threaded mode).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED GC_word GC_non_gc_bytes;
|
|
GC_API void GC_CALL GC_set_non_gc_bytes(GC_word);
|
|
GC_API GC_word GC_CALL GC_get_non_gc_bytes(void);
|
|
|
|
/**
|
|
* Do not register dynamic library data segments automatically.
|
|
* Also, if set by the collector itself (during a collection), this
|
|
* means that such a registration is not supported. Wizards only.
|
|
* Should be set only if the client explicitly registers all roots.
|
|
* (In some environments like Microsoft Windows and Apple's Darwin,
|
|
* this may also prevent registration of the main data segment as a part
|
|
* of the root set.) The setter and the getter are unsynchronized.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_no_dls;
|
|
GC_API void GC_CALL GC_set_no_dls(int);
|
|
GC_API int GC_CALL GC_get_no_dls(void);
|
|
|
|
/**
|
|
* We try to make sure that we allocate at least
|
|
* `N / GC_free_space_divisor` bytes between collections, where `N` is
|
|
* twice the number of traced bytes, plus the number of untraced bytes
|
|
* (i.e. bytes in the "atomic" objects), plus a rough estimate of the
|
|
* root set size. `N` approximates GC tracing work per collection.
|
|
* The initial value is given by `GC_FREE_SPACE_DIVISOR` macro.
|
|
* Increasing its value will use less space but more collection time.
|
|
* Decreasing it will appreciably decrease total collection time at the
|
|
* expense of space. The setter and the getter are unsynchronized, so
|
|
* `GC_call_with_alloc_lock()` (`GC_call_with_reader_lock()` in case of
|
|
* the getter) is required to avoid data race (if the value is modified
|
|
* after the collector is put into the multi-threaded mode).
|
|
* In GC v7.1 and before, the setter returned the old value.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
|
|
GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
|
|
GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
|
|
|
|
/**
|
|
* The maximum number of collections attempted before reporting out of
|
|
* memory after heap expansion fails. Initially 0. The setter and
|
|
* getter are unsynchronized, so `GC_call_with_alloc_lock()`
|
|
* (`GC_call_with_reader_lock()` in case of the getter) is required to
|
|
* avoid data race (if the value is modified after the collector is put
|
|
* into the multi-threaded mode).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED GC_word GC_max_retries;
|
|
GC_API void GC_CALL GC_set_max_retries(GC_word);
|
|
GC_API GC_word GC_CALL GC_get_max_retries(void);
|
|
|
|
/**
|
|
* The cold end (bottom) of user stack. May be set in the client prior
|
|
* to calling any `GC_` routines. This avoids some overhead, and
|
|
* potentially some signals that can confuse debuggers. Otherwise the
|
|
* collector attempts to set it automatically. For multi-threaded
|
|
* code, this is the cold end of the stack for the primordial thread.
|
|
* For multi-threaded code, altering `GC_stackbottom` value directly
|
|
* after the collector initialization has no effect. Portable clients
|
|
* should use `GC_set_stackbottom()`, `GC_get_stack_base()`,
|
|
* `GC_call_with_gc_active()` and `GC_register_my_thread()` instead.
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED char *GC_stackbottom;
|
|
|
|
/**
|
|
* Do not collect as part of the collector initialization. Should be
|
|
* set only if the client wants a chance to manually initialize the
|
|
* root set before the first collection. Interferes with black-listing.
|
|
* Wizards only. The setter and the getter are unsynchronized (and no
|
|
* external locking is needed since the value is accessed at the collector
|
|
* initialization only).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED int GC_dont_precollect;
|
|
GC_API void GC_CALL GC_set_dont_precollect(int);
|
|
GC_API int GC_CALL GC_get_dont_precollect(void);
|
|
|
|
/**
|
|
* If incremental collection is enabled, we try to terminate collections
|
|
* after this many milliseconds (plus the amount of nanoseconds as given in
|
|
* the latest `GC_set_time_limit_tv()` call, if any). Not a hard time bound.
|
|
* Setting this variable to `GC_TIME_UNLIMITED` essentially disables
|
|
* incremental collection (i.e. disables the "pause time exceeded" tests)
|
|
* while leaving generational collection enabled. The setter and the
|
|
* getter are unsynchronized, so `GC_call_with_alloc_lock()`
|
|
* (`GC_call_with_reader_lock()` in case of the getter) is required to
|
|
* avoid data race (if the value is modified after the collector is put
|
|
* into the multi-threaded mode). The setter does not update the value
|
|
* of the nanosecond part of the time limit (it is zero unless ever set
|
|
* by `GC_set_time_limit_tv()` call).
|
|
*/
|
|
GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
|
|
#define GC_TIME_UNLIMITED 999999
|
|
GC_API void GC_CALL GC_set_time_limit(unsigned long);
|
|
GC_API unsigned long GC_CALL GC_get_time_limit(void);
|
|
|
|
/** A portable type definition of time with a nanosecond precision. */
|
|
struct GC_timeval_s {
|
|
unsigned long tv_ms; /*< time in milliseconds */
|
|
unsigned long tv_nsec; /*< nanoseconds fraction (less than 1000000) */
|
|
};
|
|
|
|
/* Public procedures */
|
|
|
|
/**
|
|
* Set/get the time limit of the incremental collections. This is
|
|
* similar to `GC_set_time_limit` and `GC_get_time_limit` but the time
|
|
* is provided with the nanosecond precision. The value of `tv_nsec`
|
|
* part should be less than a million. If the value of `tv_ms` part is
|
|
* `GC_TIME_UNLIMITED`, then `tv_nsec` part is ignored. Initially, the
|
|
* value of `tv_nsec` part of the time limit is zero. The functions do
|
|
* not use any synchronization. Defined only if the library has been
|
|
* compiled without `NO_CLOCK` macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s);
|
|
GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void);
|
|
|
|
/**
|
|
* Set/get the minimum value of the ratio of allocated bytes since
|
|
* garbage collection to the amount of finalizers created since that
|
|
* collection (so value is greater than
|
|
* `GC_bytes_allocd / (GC_fo_entries - last_fo_entries)`) which
|
|
* triggers the collection instead heap expansion. The value has no
|
|
* effect in the collector incremental mode. The default value is
|
|
* 10000 unless `GC_ALLOCD_BYTES_PER_FINALIZER` macro with a custom value
|
|
* is defined to build the collector. The default value might be not the
|
|
* right choice for clients where e.g. most objects have a finalizer.
|
|
* Zero value effectively disables taking amount of finalizers in the
|
|
* decision whether to collect or not. The functions do not use any
|
|
* synchronization.
|
|
*/
|
|
GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word);
|
|
GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void);
|
|
|
|
/**
|
|
* Tell the collector to start various performance measurements.
|
|
* Only the total time taken by full collections and the average time
|
|
* spent in the world-stopped collections are calculated, as of now.
|
|
* And, currently, there is no way to stop the measurements.
|
|
* The function does not use any synchronization. Defined only if the
|
|
* library has been compiled without `NO_CLOCK` macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_start_performance_measurement(void);
|
|
|
|
/**
|
|
* Get the total time of all full collections since the start of the
|
|
* performance measurements. Includes time spent in the supplementary
|
|
* actions like blacklists promotion, marks clearing, free lists
|
|
* reconstruction and objects finalization. The measurement unit is a
|
|
* millisecond. Note that the returned value wraps around on overflow.
|
|
* The function does not use any synchronization. Defined only if the
|
|
* library has been compiled without `NO_CLOCK` macro defined.
|
|
*/
|
|
GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void);
|
|
|
|
/**
|
|
* Same as `GC_get_full_gc_total_time` but takes into account all mark
|
|
* phases with the world stopped and nothing else.
|
|
*/
|
|
GC_API unsigned long GC_CALL GC_get_stopped_mark_total_time(void);
|
|
|
|
/**
|
|
* Get the average time spent in all mark phases with the world stopped.
|
|
* The average value is computed since the start of the performance
|
|
* measurements (or right since the collector initialization if the
|
|
* collector logging is enabled). The result is in nanoseconds.
|
|
* The function acquires the allocator lock (in the reader mode) to avoid
|
|
* data race. Defined only if the library has been compiled without
|
|
* `NO_CLOCK` macro defined.
|
|
*/
|
|
GC_API unsigned long GC_CALL GC_get_avg_stopped_mark_time_ns(void);
|
|
|
|
/**
|
|
* Set whether the garbage collector will allocate executable memory
|
|
* pages or not. A nonzero argument instructs the collector to
|
|
* allocate memory with the executable flag on. Must be called before
|
|
* the collector is initialized. May have no effect on some platforms.
|
|
* The default value is controlled by `NO_EXECUTE_PERMISSION` macro (if
|
|
* present then the flag is off). Portable clients should have
|
|
* `GC_set_pages_executable(1)` call (before `GC_INIT()` one) provided
|
|
* they are going to execute code on any of the GC-allocated memory objects.
|
|
*/
|
|
GC_API void GC_CALL GC_set_pages_executable(int);
|
|
|
|
/**
|
|
* Returns nonzero value if the garbage collector is set to the
|
|
* allocate-executable-memory mode. The mode could be changed by
|
|
* `GC_set_pages_executable` (before `GC_INIT()` call) unless the former
|
|
* has no effect on the platform. Does not use or need synchronization.
|
|
*/
|
|
GC_API int GC_CALL GC_get_pages_executable(void);
|
|
|
|
/**
|
|
* The setter and the getter of the minimum value returned by the internal
|
|
* `min_bytes_allocd()`. The value should not be zero; the default value
|
|
* is one. Not synchronized.
|
|
*/
|
|
GC_API void GC_CALL GC_set_min_bytes_allocd(size_t);
|
|
GC_API size_t GC_CALL GC_get_min_bytes_allocd(void);
|
|
|
|
/**
|
|
* Set/get the size in pages of units operated by `GC_collect_a_little()`.
|
|
* The value should not be zero. Not synchronized.
|
|
*/
|
|
GC_API void GC_CALL GC_set_rate(int);
|
|
GC_API int GC_CALL GC_get_rate(void);
|
|
|
|
/**
|
|
* Set/get the maximum number of prior attempts at the world-stop marking.
|
|
* Not synchronized.
|
|
*/
|
|
GC_API void GC_CALL GC_set_max_prior_attempts(int);
|
|
GC_API int GC_CALL GC_get_max_prior_attempts(void);
|
|
|
|
/**
|
|
* Control whether to disable algorithm deciding if a collection should
|
|
* be started when we allocated enough to amortize the collection.
|
|
* Both the setter and the getter acquire the allocator lock (in the reader
|
|
* mode in case of the getter) to avoid data race.
|
|
*/
|
|
GC_API void GC_CALL GC_set_disable_automatic_collection(int);
|
|
GC_API int GC_CALL GC_get_disable_automatic_collection(void);
|
|
|
|
/**
|
|
* Overrides the default handle-fork mode. A nonzero value means GC
|
|
* should install proper `pthread_atfork` handlers. Has effect only
|
|
* if called before the collector initialization. Clients should call
|
|
* `GC_set_handle_fork()` with nonzero argument if going to use `fork`
|
|
* with the GC functions called in the child process. (Note that such
|
|
* client and at-fork handler activities are not fully POSIX-compliant.)
|
|
* `GC_set_handle_fork()` instructs `GC_init` to setup GC fork handlers
|
|
* using `pthread_atfork()`, the latter might fail (or, even, absent on
|
|
* some targets) causing `abort` at the collector initialization.
|
|
* Issues with missing (or failed) `pthread_atfork()` could be avoided
|
|
* by invocation of `GC_set_handle_fork(-1)` at application start-up and
|
|
* surrounding each `fork()` with the relevant
|
|
* `GC_atfork_prepare`/`GC_atfork_parent`/`GC_atfork_child` calls.
|
|
*/
|
|
GC_API void GC_CALL GC_set_handle_fork(int);
|
|
|
|
/**
|
|
* Routines to handle POSIX `fork()` manually (no-op if handled
|
|
* automatically). `GC_atfork_prepare()` should be called immediately
|
|
* before `fork()`; `GC_atfork_parent()` should be invoked just after
|
|
* `fork` in the branch that corresponds to parent process (i.e.,
|
|
* `fork` result is nonzero); `GC_atfork_child()` is to be called
|
|
* immediately in the child branch (i.e., `fork` result is 0).
|
|
* Note that `GC_atfork_child()` call should, of course, precede
|
|
* `GC_start_mark_threads()` call, if any.
|
|
*/
|
|
GC_API void GC_CALL GC_atfork_prepare(void);
|
|
GC_API void GC_CALL GC_atfork_parent(void);
|
|
GC_API void GC_CALL GC_atfork_child(void);
|
|
|
|
/**
|
|
* Initialize the collector. Portable clients should call `GC_INIT()`
|
|
* from the program's `main()` instead.
|
|
*/
|
|
GC_API void GC_CALL GC_init(void);
|
|
|
|
/**
|
|
* Return 1 (true) if the collector is initialized (or, at least, the
|
|
* initialization is in progress), 0 otherwise.
|
|
*/
|
|
GC_API int GC_CALL GC_is_init_called(void);
|
|
|
|
/**
|
|
* Perform the collector shutdown. (E.g. dispose critical sections on
|
|
* Windows target.) A duplicate invocation is a no-op. In case of Windows,
|
|
* typically, the client should also call `GC_win32_free_heap()` before this
|
|
* function call.
|
|
* TODO: The collector reinitialization after shutdown might work in certain
|
|
* configurations, but not tested.
|
|
*/
|
|
GC_API void GC_CALL GC_deinit(void);
|
|
|
|
/**
|
|
* General-purpose allocation functions, with roughly `malloc` calling
|
|
* conventions. The atomic variants promise that no relevant pointers
|
|
* are contained in the object. The non-atomic variants guarantee that
|
|
* the new object is cleared. `GC_malloc_uncollectable()` allocates
|
|
* an object that is scanned for pointers to collectible objects, but
|
|
* is not itself collectible. The object is scanned even if it does
|
|
* not appear to be reachable. `GC_malloc_uncollectable()` and `GC_free()`
|
|
* called on the resulting object implicitly update `GC_non_gc_bytes`
|
|
* appropriately. All these functions (`GC_malloc`, `GC_malloc_atomic`,
|
|
* `GC_strdup`, `GC_strndup`, `GC_malloc_uncollectable`) are guaranteed
|
|
* never to return `NULL` unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_malloc(size_t /* `size_in_bytes` */);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_malloc_atomic(size_t /* `size_in_bytes` */);
|
|
GC_API GC_ATTR_MALLOC char *GC_CALL GC_strdup(const char *);
|
|
GC_API GC_ATTR_MALLOC char *GC_CALL GC_strndup(const char *, size_t)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_malloc_uncollectable(size_t /* `size_in_bytes` */);
|
|
|
|
/**
|
|
* The allocation function which guarantees the requested alignment of
|
|
* the allocated memory object. The `align` argument should be nonzero
|
|
* and a power of two. It is guaranteed never to return `NULL` unless
|
|
* `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void *GC_CALL
|
|
GC_memalign(size_t /* `align` */, size_t /* `lb` */);
|
|
|
|
/**
|
|
* A function similar to `GC_memalign` but existing largely for
|
|
* redirection in the find-leak mode. The `align` argument should be
|
|
* nonzero and a power of two, but additionally the argument is
|
|
* required to be not less than size of a pointer. Note that the
|
|
* function does not change value of `*memptr` in case of failure
|
|
* (i.e. when the result is nonzero). It is guaranteed never to return
|
|
* `NULL` unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API int GC_CALL GC_posix_memalign(void ** /* `memptr` */,
|
|
size_t /* `align` */, size_t /* `lb` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
#ifndef GC_NO_VALLOC
|
|
/**
|
|
* The allocation functions that guarantee the memory page alignment of
|
|
* the returned object. Exist largely for redirection in the find-leak
|
|
* mode. All these functions (`GC_pvalloc`, `GC_valloc`) are guaranteed
|
|
* never to return `NULL` unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_valloc(size_t /* `lb` */);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_pvalloc(size_t /* `lb` */);
|
|
#endif
|
|
|
|
/**
|
|
* Explicitly deallocate an object. Dangerous if used incorrectly.
|
|
* Requires a pointer to the base of an object. An object should not
|
|
* be enabled for finalization (and it should not contain registered
|
|
* disappearing links of any kind) when it is explicitly deallocated.
|
|
* `GC_free(0)` is a no-op, as required by ANSI C for `free()`.
|
|
*/
|
|
GC_API void GC_CALL GC_free(void *);
|
|
GC_API void GC_CALL GC_debug_free(void *);
|
|
|
|
/**
|
|
* A symbol to be intercepted by heap profilers so that they can
|
|
* accurately track allocations. Programs such as Valgrind `massif`
|
|
* and KDE heaptrack do tracking of allocated objects by overriding
|
|
* common allocator methods (e.g. `malloc` and `free`). However,
|
|
* because the collector does not work by calling standard allocation
|
|
* methods on objects that were reclaimed, we need a way to tell the
|
|
* profiler that an object has been freed. This function is not
|
|
* intended to be called by the client, it should be used for the
|
|
* interception purpose only. The collector calls this function
|
|
* internally whenever an object is freed. Defined only if the library
|
|
* has been compiled with `VALGRIND_TRACKING` macro defined.
|
|
*/
|
|
GC_API void GC_CALLBACK GC_free_profiler_hook(void *);
|
|
|
|
#if (defined(GC_CAN_SAVE_CALL_STACKS) || defined(GC_ADD_CALLER)) \
|
|
&& !defined(GC_RETURN_ADDR_T_DEFINED)
|
|
/*
|
|
* A type to hold a function return address (pointer). Never used for
|
|
* calling a function.
|
|
*/
|
|
# if defined(__GNUC__)
|
|
/*
|
|
* Defined as a data (object) pointer type to avoid the compiler complain
|
|
* that ISO C forbids conversion between object and function pointer types.
|
|
*/
|
|
typedef void *GC_return_addr_t;
|
|
# else
|
|
typedef void (*GC_return_addr_t)(void);
|
|
# endif
|
|
# define GC_RETURN_ADDR_T_DEFINED
|
|
#endif /* GC_CAN_SAVE_CALL_STACKS || GC_ADD_CALLER */
|
|
|
|
#ifdef GC_ADD_CALLER
|
|
# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
|
|
# define GC_EXTRA_PARAMS GC_return_addr_t ra, const char *s, int i
|
|
#else
|
|
# define GC_EXTRAS __FILE__, __LINE__
|
|
# define GC_EXTRA_PARAMS const char *s, int i
|
|
#endif
|
|
|
|
/*
|
|
* The "stubborn" objects allocation is not supported anymore.
|
|
* Exists only for the backward compatibility.
|
|
*/
|
|
#define GC_MALLOC_STUBBORN(sz) GC_MALLOC(sz)
|
|
#define GC_NEW_STUBBORN(t) GC_NEW(t)
|
|
#define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
|
|
GC_API GC_ATTR_DEPRECATED void GC_CALL GC_change_stubborn(const void *);
|
|
GC_API GC_ATTR_DEPRECATED void GC_CALL GC_debug_change_stubborn(const void *);
|
|
GC_API GC_ATTR_ALLOC_SIZE(1) GC_ATTR_DEPRECATED void *GC_CALL
|
|
GC_malloc_stubborn(size_t);
|
|
GC_API GC_ATTR_ALLOC_SIZE(1) GC_ATTR_DEPRECATED void *GC_CALL
|
|
GC_debug_malloc_stubborn(size_t, GC_EXTRA_PARAMS);
|
|
|
|
/**
|
|
* Inform the collector that the object has been changed.
|
|
* Only non-`NULL` pointer stores into the object are considered to be
|
|
* changes. Matters only if the incremental collection is enabled in
|
|
* the manual VDB (virtual dirty bits) mode; otherwise the function
|
|
* does nothing. Should be followed typically by `GC_reachable_here()`
|
|
* called for each of the stored pointers.
|
|
*/
|
|
GC_API void GC_CALL GC_end_stubborn_change(const void *) GC_ATTR_NONNULL(1);
|
|
GC_API void GC_CALL GC_debug_end_stubborn_change(const void *)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Return a pointer to the base (lowest address) of an object given
|
|
* a pointer to a location within the object. I.e., map an interior
|
|
* pointer to the corresponding base pointer. Note that with debugging
|
|
* allocation, this returns a pointer to the actual base of the object,
|
|
* i.e. the debug information, not to the base of the user object.
|
|
* Return `NULL` if `displaced_pointer` does not point to within
|
|
* a valid object. Note that a deallocated object in the garbage
|
|
* collected heap may be considered valid, even if it has been
|
|
* deallocated with `GC_free()`.
|
|
*/
|
|
GC_API void *GC_CALL GC_base(void * /* `displaced_pointer` */);
|
|
|
|
/**
|
|
* Return 1 (true) if the argument points to somewhere in the garbage
|
|
* collected heap, 0 otherwise. Primary use is as a fast alternative to
|
|
* `GC_base()` to check whether the given object is allocated by the
|
|
* collector or not. It is assumed that the collector is already initialized.
|
|
*/
|
|
GC_API int GC_CALL GC_is_heap_ptr(const void *);
|
|
|
|
/**
|
|
* Given a pointer to the base of an object, return its size in bytes.
|
|
* (For small objects this also happens to work from interior pointers,
|
|
* but that should not be relied upon.) The returned size may be slightly
|
|
* larger than what was originally requested. The argument may be `NULL`
|
|
* (causing 0 to be returned).
|
|
*/
|
|
GC_API size_t GC_CALL GC_size(const void * /* `obj` */);
|
|
|
|
/**
|
|
* For compatibility with C library. This is occasionally faster than
|
|
* a `malloc` followed by a `bcopy`. But if you rely on that, either
|
|
* here or with the standard C library, your code is broken.
|
|
* Probably, it should not have been invented, but now we are stuck.
|
|
* The resulting object has the same kind as the original one.
|
|
* It is an error to have changes enabled for the original object.
|
|
* It does not change the content of the object from its beginning to
|
|
* the minimum of old size and `new_size_in_bytes`; the content above in
|
|
* case of object size growth is initialized to zero (not guaranteed for
|
|
* atomic object type). The function follows ANSI conventions for `NULL`
|
|
* `old_object` (i.e., equivalent to `GC_malloc` regardless of
|
|
* `new_size_in_bytes`). If `new_size_in_bytes` is zero (and
|
|
* `old_object` is non-`NULL`), then the call is equivalent to
|
|
* `GC_free` (and `NULL` is returned). If `old_object` is non-`NULL`,
|
|
* it must have been returned by an earlier call to `GC_realloc`,
|
|
* `GC_malloc` or friends. In case of the allocation failure, the
|
|
* memory pointed by `old_object` is untouched (and not freed). If the
|
|
* returned pointer is not the same as `old_object` and both of them
|
|
* are non-`NULL`, then `old_object` is freed. Returns either `NULL`
|
|
* (in case of the allocation failure or zero `new_size_in_bytes`) or
|
|
* pointer to the allocated memory. For a nonzero `new_size_in_bytes`,
|
|
* the function (including its debug variant) is guaranteed never to
|
|
* return `NULL` unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API void *GC_CALL GC_realloc(void * /* `old_object` */,
|
|
size_t /* `new_size_in_bytes` */)
|
|
/* `realloc` attribute */ GC_ATTR_ALLOC_SIZE(2);
|
|
GC_API void *GC_CALL GC_debug_realloc(void * /* `old_object` */,
|
|
size_t /* `new_size_in_bytes` */,
|
|
GC_EXTRA_PARAMS)
|
|
/* `realloc` attribute */ GC_ATTR_ALLOC_SIZE(2);
|
|
|
|
/**
|
|
* Increase the heap size explicitly. The performed increase is at
|
|
* least `number_of_bytes`. Does the collector initialization as well
|
|
* (if not yet). Returns 0 on failure, 1 on success.
|
|
*/
|
|
GC_API int GC_CALL GC_expand_hp(size_t /* `number_of_bytes` */);
|
|
|
|
/**
|
|
* Limit the heap size to `n` bytes. Useful when you are debugging,
|
|
* especially on systems that do not handle running out of memory well.
|
|
* A zero `n` means the heap is unbounded; this is the default.
|
|
* This setter function is unsynchronized (so it might require
|
|
* `GC_call_with_alloc_lock` to avoid data race).
|
|
*/
|
|
GC_API void GC_CALL GC_set_max_heap_size(GC_word /* `n` */);
|
|
|
|
/**
|
|
* Inform the collector that a certain section of statically allocated
|
|
* memory contains no pointers to garbage-collected memory. Thus it does
|
|
* not need to be scanned. This is sometimes important if the application
|
|
* maps large read/write files into the address space, which could be
|
|
* mistaken for dynamic library data segments on some systems.
|
|
* Both section start (`low_address`) and end (`high_address_plus_1`)
|
|
* are not needed to be pointer-aligned.
|
|
*/
|
|
GC_API void GC_CALL GC_exclude_static_roots(
|
|
void * /* `low_address` */, void * /* `high_address_plus_1` */);
|
|
|
|
/**
|
|
* Clear the number of entries in the exclusion table. Wizards only.
|
|
* Should be called typically with the allocator lock held, but no
|
|
* assertion about it by design.
|
|
*/
|
|
GC_API void GC_CALL GC_clear_exclusion_table(void);
|
|
|
|
/** Clear the set of root segments. Wizards only. */
|
|
GC_API void GC_CALL GC_clear_roots(void);
|
|
|
|
/**
|
|
* Add a root segment. Wizards only. May merge adjacent or overlapping
|
|
* segments if appropriate. Both segment start (`low_address`) and
|
|
* end (`high_address_plus_1`) are not needed to be pointer-aligned.
|
|
* `low_address` must not be greater than `high_address_plus_1`.
|
|
*/
|
|
GC_API void GC_CALL GC_add_roots(void * /* `low_address` */,
|
|
void * /* `high_address_plus_1` */);
|
|
|
|
/** Remove root segments located fully in the region. Wizards only. */
|
|
GC_API void GC_CALL GC_remove_roots(void * /* `low_address` */,
|
|
void * /* `high_address_plus_1` */);
|
|
|
|
/**
|
|
* Add a displacement to the set of those considered valid by the
|
|
* collector. `GC_register_displacement(offset)` means that if `p` was
|
|
* returned by `GC_malloc()`, then `(char *)p + offset` will be
|
|
* considered to be a valid pointer to `p`. `offset` must be less than
|
|
* the size of a heap block. (All pointers to the interior of objects
|
|
* from the stack are considered valid in any case. This applies to
|
|
* heap objects and static data.) Preferably, this should be called
|
|
* before any other GC procedures. Calling it later adds to the
|
|
* probability of excess memory retention. This is a no-op if the
|
|
* collector has recognition of arbitrary interior pointers enabled,
|
|
* which is the default (assuming the collector is built with
|
|
* `ALL_INTERIOR_POINTERS` macro defined). The debugging variant should
|
|
* be used if any debugging allocation is being done.
|
|
*/
|
|
GC_API void GC_CALL GC_register_displacement(size_t /* `offset` */);
|
|
GC_API void GC_CALL GC_debug_register_displacement(size_t /* `offset` */);
|
|
|
|
/** Explicitly trigger a full, world-stop collection. */
|
|
GC_API void GC_CALL GC_gcollect(void);
|
|
|
|
/**
|
|
* Same as above but ignores the default `stop_func` setting and tries
|
|
* to unmap as much memory as possible (regardless of the corresponding
|
|
* switch setting). The recommended usage: on receiving a system
|
|
* low-memory event; before retrying a system call failed because of
|
|
* the system is running out of resources.
|
|
*/
|
|
GC_API void GC_CALL GC_gcollect_and_unmap(void);
|
|
|
|
/**
|
|
* Trigger a full world-stopped collection. Abort the collection if
|
|
* and when `stop_func()` returns a nonzero value. `stop_func()` will
|
|
* be called frequently, and should be reasonably fast.
|
|
* (`stop_func()` is called with the allocator lock held and the world
|
|
* might be stopped; it is not allowed for `stop_func()` to manipulate
|
|
* pointers to the garbage-collected heap or call most of GC functions.)
|
|
* This works even if no virtual dirty bits, and hence incremental
|
|
* collection is not available for the architecture. Collections can
|
|
* be aborted faster than normal pause times for incremental collection;
|
|
* however, aborted collections do no useful work; the next collection
|
|
* needs to start from the beginning. `stop_func` must not be 0.
|
|
* `GC_try_to_collect()` returns 0 if the collection was aborted (or the
|
|
* collections are disabled), 1 if it succeeded.
|
|
*/
|
|
typedef int(GC_CALLBACK *GC_stop_func)(void);
|
|
GC_API int GC_CALL GC_try_to_collect(GC_stop_func /* `stop_func` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Set/get the default `stop_func`. The latter is used by `GC_gcollect()`
|
|
* and by implicitly triggered collections (except for the case when
|
|
* handling out of memory). Must not be 0. Both the setter and the getter
|
|
* acquire the allocator lock (in the reader mode in case of the getter)
|
|
* to avoid data race.
|
|
*/
|
|
GC_API void GC_CALL GC_set_stop_func(GC_stop_func /* `stop_func` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_stop_func GC_CALL GC_get_stop_func(void);
|
|
|
|
/**
|
|
* Return the number of bytes in the heap. Excludes collector private
|
|
* data structures; excludes the unmapped memory (returned to the OS).
|
|
* Includes empty blocks and fragmentation loss. Includes some pages
|
|
* that were allocated but never written. This is an unsynchronized
|
|
* getter, so it should be called typically with the allocator lock
|
|
* held, at least in the reader mode, to avoid data race on
|
|
* multiprocessors (the alternative way is to use `GC_get_prof_stats`
|
|
* or `GC_get_heap_usage_safe` API calls instead).
|
|
* This getter remains lock-free (unsynchronized) for compatibility
|
|
* reason since some existing clients call it from a GC callback
|
|
* holding the allocator lock. (This API function and the following
|
|
* four ones below were made thread-safe in GC v7.2alpha1 and
|
|
* reverted back in v7.2alpha7 for the reason described.)
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_heap_size(void);
|
|
|
|
/**
|
|
* Return a lower bound on the number of free bytes in the heap
|
|
* (excluding the unmapped memory space). This is an unsynchronized
|
|
* getter (see `GC_get_heap_size` comment regarding thread-safety).
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_free_bytes(void);
|
|
|
|
/**
|
|
* Return the size (in bytes) of the unmapped memory (which is returned
|
|
* to the OS but could be remapped back by the collector later unless
|
|
* the OS runs out of system/virtual memory). This is an unsynchronized
|
|
* getter (see `GC_get_heap_size` comment regarding thread-safety).
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_unmapped_bytes(void);
|
|
|
|
/**
|
|
* Return the number of bytes allocated since the last collection.
|
|
* This is an unsynchronized getter (see `GC_get_heap_size` comment
|
|
* regarding thread-safety).
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_bytes_since_gc(void);
|
|
|
|
/**
|
|
* Return the number of explicitly deallocated bytes of memory since
|
|
* the recent collection. This is an unsynchronized getter.
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void);
|
|
|
|
/**
|
|
* Return the total number of bytes allocated in this process.
|
|
* Never decreases, except due to wrapping. This is an unsynchronized
|
|
* getter (see `GC_get_heap_size` comment regarding thread-safety).
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_total_bytes(void);
|
|
|
|
/**
|
|
* Return the total number of bytes obtained from OS. Includes the
|
|
* unmapped memory. Never decreases. It is an unsynchronized getter.
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_obtained_from_os_bytes(void);
|
|
|
|
/**
|
|
* Return the heap usage information. This is a thread-safe (atomic)
|
|
* alternative for the five above getters. (This function acquires
|
|
* the allocator lock in the reader mode, thus preventing data race and
|
|
* returning the consistent result.) Passing `NULL` pointer is allowed
|
|
* for any argument. Returned (filled in) values are of `GC_word` type.
|
|
*/
|
|
GC_API void GC_CALL GC_get_heap_usage_safe(GC_word * /* `pheap_size` */,
|
|
GC_word * /* `pfree_bytes` */,
|
|
GC_word * /* `punmapped_bytes` */,
|
|
GC_word * /* `pbytes_since_gc` */,
|
|
GC_word * /* `ptotal_bytes` */);
|
|
|
|
/**
|
|
* Structure used to query the GC statistics (profiling information).
|
|
* More fields could be added in the future. To preserve compatibility
|
|
* new fields should be added only to the end, and no deprecated fields
|
|
* should be removed from.
|
|
*/
|
|
struct GC_prof_stats_s {
|
|
/**
|
|
* Heap size in bytes (including the area unmapped to OS).
|
|
* Same as value of `GC_get_heap_size() + GC_get_unmapped_bytes()`.
|
|
*/
|
|
GC_word heapsize_full;
|
|
|
|
/**
|
|
* Total bytes contained in free and unmapped blocks.
|
|
* Same as result of `GC_get_free_bytes() + GC_get_unmapped_bytes()`.
|
|
*/
|
|
GC_word free_bytes_full;
|
|
|
|
/**
|
|
* Amount of memory unmapped to OS. Same as the value returned by
|
|
* `GC_get_unmapped_bytes()`.
|
|
*/
|
|
GC_word unmapped_bytes;
|
|
|
|
/**
|
|
* Number of bytes allocated since the recent collection.
|
|
* Same as the value returned by `GC_get_bytes_since_gc()`.
|
|
*/
|
|
GC_word bytes_allocd_since_gc;
|
|
|
|
/**
|
|
* Number of bytes allocated before the recent garbage collection.
|
|
* The value may wrap. Same as the result of
|
|
* `GC_get_total_bytes() - GC_get_bytes_since_gc()`.
|
|
*/
|
|
GC_word allocd_bytes_before_gc;
|
|
|
|
/**
|
|
* Number of bytes not considered candidates for garbage collection.
|
|
* Same as the value returned by `GC_get_non_gc_bytes()`.
|
|
*/
|
|
GC_word non_gc_bytes;
|
|
|
|
/**
|
|
* Garbage collection cycle number. The value may wrap. Same as the
|
|
* value returned by `GC_get_gc_no()`.
|
|
*/
|
|
GC_word gc_no;
|
|
|
|
/**
|
|
* Number of marker threads (excluding the initiating one). Same as
|
|
* the value returned by `GC_get_parallel()` (or 0 if the collector
|
|
* is single-threaded).
|
|
*/
|
|
GC_word markers_m1;
|
|
|
|
/**
|
|
* Approximate number of reclaimed bytes after the recent garbage
|
|
* collection.
|
|
*/
|
|
GC_word bytes_reclaimed_since_gc;
|
|
|
|
/**
|
|
* Approximate number of bytes reclaimed before the recent garbage
|
|
* collection. The value may wrap.
|
|
*/
|
|
GC_word reclaimed_bytes_before_gc;
|
|
|
|
/**
|
|
* Number of bytes freed explicitly since the recent garbage collection.
|
|
* Same as the value returned by `GC_get_expl_freed_bytes_since_gc()`.
|
|
*/
|
|
GC_word expl_freed_bytes_since_gc;
|
|
|
|
/** Total amount of memory obtained from OS, in bytes. */
|
|
GC_word obtained_from_os_bytes;
|
|
};
|
|
|
|
/**
|
|
* Atomically get the collector statistics (various global counters).
|
|
* Clients should pass the size of the buffer (of `GC_prof_stats_s` type)
|
|
* to fill in the values - this is for interoperability between different
|
|
* collector versions: an old client could have fewer fields, and vice
|
|
* versa, client could use newer `gc.h` file (with more entries declared
|
|
* in the structure) than that of the linked collector library; in the
|
|
* latter case, unsupported (unknown) fields are filled in with -1 (`~0`).
|
|
* Return the size (in bytes) of the filled in part of the structure
|
|
* (excluding all unknown fields, if any).
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *,
|
|
size_t /* `stats_sz` */);
|
|
#ifdef GC_THREADS
|
|
/**
|
|
* Same as `GC_get_prof_stats` but unsynchronized (i.e., not holding
|
|
* the allocator lock). Clients should call it using
|
|
* `GC_call_with_reader_lock()` to avoid data race on multiprocessors.
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_prof_stats_unsafe(struct GC_prof_stats_s *,
|
|
size_t /* `stats_sz` */);
|
|
#endif
|
|
|
|
/**
|
|
* Get the element value (converted to bytes) at a given index of
|
|
* `GC_size_map` table which provides requested-to-actual allocation size
|
|
* mapping. Assumes the collector is initialized. Returns -1 (`~0`) if
|
|
* the index is out of `GC_size_map` table bounds. Does not use
|
|
* synchronization, thus clients should call it using
|
|
* `GC_call_with_reader_lock()` typically to avoid data race on
|
|
* multiprocessors.
|
|
*/
|
|
GC_API size_t GC_CALL GC_get_size_map_at(int i);
|
|
|
|
/**
|
|
* Return the total memory use (in bytes) by all allocated blocks.
|
|
* The result is equal to `GC_get_heap_size() - GC_get_free_bytes()`.
|
|
* Acquires the allocator lock in the reader mode.
|
|
*/
|
|
GC_API GC_word GC_CALL GC_get_memory_use(void);
|
|
|
|
/**
|
|
* Disable garbage collection. Even `GC_gcollect()` calls will be
|
|
* ineffective.
|
|
*/
|
|
GC_API void GC_CALL GC_disable(void);
|
|
|
|
/**
|
|
* Return 1 (true) if the garbage collection is disabled (i.e., the
|
|
* value of `GC_dont_gc` is nonzero), 0 otherwise. Does not acquire
|
|
* the allocator lock.
|
|
*/
|
|
GC_API int GC_CALL GC_is_disabled(void);
|
|
|
|
/**
|
|
* Try to re-enable garbage collection. `GC_disable()` and `GC_enable()`
|
|
* calls could be nested. Garbage collection is enabled if the number of
|
|
* calls to both functions is equal.
|
|
*/
|
|
GC_API void GC_CALL GC_enable(void);
|
|
|
|
/**
|
|
* Select whether to use the manual VDB (virtual dirty bits) mode for
|
|
* the incremental collection. Has no effect if called after enabling
|
|
* the incremental collection. The default value is off unless the
|
|
* collector is compiled with `MANUAL_VDB` macro defined. The manual
|
|
* VDB mode should be used only if the client has the appropriate
|
|
* `GC_END_STUBBORN_CHANGE()` and `GC_reachable_here()` (or,
|
|
* alternatively, `GC_PTR_STORE_AND_DIRTY()`) calls (to ensure proper
|
|
* write barriers). The setter and the getter are not synchronized.
|
|
*/
|
|
GC_API void GC_CALL GC_set_manual_vdb_allowed(int);
|
|
GC_API int GC_CALL GC_get_manual_vdb_allowed(void);
|
|
|
|
/*
|
|
* The constants to represent available VDB (virtual dirty bits)
|
|
* techniques.
|
|
*/
|
|
|
|
/** Means the incremental mode is unsupported. */
|
|
#define GC_VDB_NONE 0
|
|
|
|
#define GC_VDB_MPROTECT 0x1
|
|
|
|
/** Means `GC_set_manual_vdb_allowed(1)` has effect. */
|
|
#define GC_VDB_MANUAL 0x2
|
|
|
|
/** Means no other technique is usable. */
|
|
#define GC_VDB_DEFAULT 0x4
|
|
|
|
#define GC_VDB_GWW 0x8
|
|
|
|
#define GC_VDB_PROC 0x20
|
|
#define GC_VDB_SOFT 0x40
|
|
|
|
/**
|
|
* Get the list of available VDB (virtual dirty bits) techniques.
|
|
* The returned value is a constant one, either `GC_VDB_NONE`, or one
|
|
* or more of the above `GC_VDB_` constants, or'ed together. May be
|
|
* called before the collector is initialized.
|
|
*/
|
|
GC_API unsigned GC_CALL GC_get_supported_vdbs(void);
|
|
|
|
/**
|
|
* Enable incremental/generational collection. Not advisable unless
|
|
* dirty bits are available or most heap objects are pointer-free
|
|
* (atomic) or immutable. Do not use in the find-leak mode.
|
|
* Ignored if `GC_dont_gc` is nonzero. Only the generational piece of
|
|
* this is functional if `GC_time_limit` is set to `GC_TIME_UNLIMITED`.
|
|
* Causes thread-local variant of `GC_gcj_malloc()` to revert to locked
|
|
* allocation. Must be called before any such `GC_gcj_malloc()` calls.
|
|
* For best performance, should be called as early as possible.
|
|
* On some platforms, calling it later may have adverse effects.
|
|
* Safe to call before the collector initialization; it performs the
|
|
* latter if not done yet.
|
|
*/
|
|
GC_API void GC_CALL GC_enable_incremental(void);
|
|
|
|
/**
|
|
* Return 1 (true) if the incremental mode is on, 0 otherwise.
|
|
* Does not acquire the allocator lock.
|
|
*/
|
|
GC_API int GC_CALL GC_is_incremental_mode(void);
|
|
|
|
/**
|
|
* An extended variant of `GC_is_incremental_mode()` to return one of
|
|
* `GC_VDB_` constants designating which VDB (virtual dirty bits)
|
|
* technique is used exactly. Does not acquire the allocator lock.
|
|
*/
|
|
GC_API unsigned GC_CALL GC_get_actual_vdb(void);
|
|
|
|
/** May protect non-atomic objects. */
|
|
#define GC_PROTECTS_POINTER_HEAP 1
|
|
|
|
#define GC_PROTECTS_PTRFREE_HEAP 2
|
|
|
|
/* Protects static data. But this is currently never. */
|
|
#define GC_PROTECTS_STATIC_DATA 4
|
|
|
|
/* Deprecated. It is probably impractical to protect stacks. */
|
|
#define GC_PROTECTS_STACK 8
|
|
|
|
#define GC_PROTECTS_NONE 0
|
|
|
|
/**
|
|
* Does incremental mode write-protect pages? Returns zero or
|
|
* more of the above `GC_PROTECTS_` constants, or'ed together.
|
|
* The collector is assumed to be initialized before this call.
|
|
* The result is not affected by `GC_set_manual_vdb_allowed()`.
|
|
* Call of `GC_enable_incremental()` may change the result to
|
|
* `GC_PROTECTS_NONE` if some implementation is chosen at
|
|
* runtime not needing to write-protect the pages.
|
|
*/
|
|
GC_API int GC_CALL GC_incremental_protection_needs(void);
|
|
|
|
/**
|
|
* Force start of incremental collection. Acquires the allocator lock.
|
|
* No-op unless the incremental mode is on.
|
|
*/
|
|
GC_API void GC_CALL GC_start_incremental_collection(void);
|
|
|
|
/**
|
|
* Perform some garbage collection work, if appropriate.
|
|
* Return 0 if there is no more work to be done (including the
|
|
* case when garbage collection is not appropriate).
|
|
* Typically performs an amount of work corresponding roughly
|
|
* to marking from one page. May do more work if further
|
|
* progress requires it, e.g. if incremental collection is
|
|
* disabled. It is reasonable to call this in a wait loop
|
|
* until it returns 0. If the garbage collection is disabled
|
|
* but the incremental collection is already ongoing, then
|
|
* perform marking anyway but not stopping the world (and
|
|
* without the reclaim phase).
|
|
*/
|
|
GC_API int GC_CALL GC_collect_a_little(void);
|
|
|
|
/**
|
|
* Allocate an object of size `lb` bytes. The client guarantees that
|
|
* as long as the object is live, it will be referenced by a pointer
|
|
* that points to somewhere within the first GC heap block (`hblk`) of
|
|
* the object. (This should normally be declared `volatile` to prevent
|
|
* the compiler from invalidating this assertion.) This function is
|
|
* only useful if a large array is being allocated. It reduces the
|
|
* chance of accidentally retaining such an array as a result of
|
|
* scanning an integer that happens to be an address inside the array.
|
|
* (Actually, it reduces the chance of the allocator not finding space
|
|
* for such an array, since it will try hard to avoid introducing such
|
|
* a false reference.) On a SunOS 4.x or Windows system this is
|
|
* recommended for arrays likely to be larger than 100 KB or so.
|
|
* For other systems, or if the collector is not configured to
|
|
* recognize all interior pointers, the threshold is normally much
|
|
* higher. These functions are guaranteed never to return `NULL`
|
|
* unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_malloc_ignore_off_page(size_t /* `lb` */);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_malloc_atomic_ignore_off_page(size_t /* `lb` */);
|
|
|
|
/**
|
|
* Allocate `lb` bytes of pointer-free, untraced, uncollectible data.
|
|
* This is normally roughly equivalent to the system `malloc`. But it
|
|
* may be useful if `malloc` is redefined. The function (including its
|
|
* debug variant) is guaranteed never to return `NULL` unless
|
|
* `GC_oom_fn()` returns `NULL`. Defined only if the library has been
|
|
* compiled with `GC_ATOMIC_UNCOLLECTABLE` macro defined.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_malloc_atomic_uncollectable(size_t /* `size_in_bytes` */);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc_atomic_uncollectable(size_t, GC_EXTRA_PARAMS);
|
|
|
|
/**
|
|
* Debugging (annotated) allocation. `GC_gcollect()` will check
|
|
* objects allocated in this way for overwrites, etc.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc(size_t /* `size_in_bytes` */, GC_EXTRA_PARAMS);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc_atomic(size_t /* `size_in_bytes` */, GC_EXTRA_PARAMS);
|
|
GC_API GC_ATTR_MALLOC char *GC_CALL GC_debug_strdup(const char *,
|
|
GC_EXTRA_PARAMS);
|
|
GC_API GC_ATTR_MALLOC char *GC_CALL GC_debug_strndup(const char *, size_t,
|
|
GC_EXTRA_PARAMS)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc_uncollectable(size_t /* `size_in_bytes` */,
|
|
GC_EXTRA_PARAMS);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc_ignore_off_page(size_t /* `size_in_bytes` */,
|
|
GC_EXTRA_PARAMS);
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc_atomic_ignore_off_page(size_t /* `size_in_bytes` */,
|
|
GC_EXTRA_PARAMS);
|
|
|
|
/**
|
|
* The functions that allocate objects with debug information (like the
|
|
* above), but just fill in dummy file and line number information.
|
|
* Thus they can serve as drop-in `malloc`/`realloc` replacements.
|
|
* This can be useful for two reasons:
|
|
* 1. It allows the collector to be built with `DBG_HDRS_ALL` macro
|
|
* defined even if some allocation calls come from 3rd-party
|
|
* libraries that cannot be recompiled.
|
|
* 2. On some platforms, the file and line information is redundant,
|
|
* since it can be reconstructed from a stack trace. On such
|
|
* platforms it may be more convenient not to recompile, e.g. for
|
|
* leak detection. This can be accomplished by instructing the
|
|
* linker to replace `malloc`/`realloc` with these.
|
|
*
|
|
* Note that these functions (for a nonzero new size in case of
|
|
* `realloc`) are guaranteed never to return `NULL` unless
|
|
* `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void *GC_CALL
|
|
GC_debug_malloc_replacement(size_t /* `size_in_bytes` */);
|
|
GC_API /* `realloc` attribute */ GC_ATTR_ALLOC_SIZE(2) void *GC_CALL
|
|
GC_debug_realloc_replacement(void * /* `obj` */,
|
|
size_t /* `size_in_bytes` */);
|
|
|
|
#ifdef __cplusplus
|
|
# define GC_CAST_AWAY_CONST_PVOID(p) \
|
|
reinterpret_cast</* no const */ void *>(reinterpret_cast<GC_uintptr_t>(p))
|
|
#else
|
|
# define GC_CAST_AWAY_CONST_PVOID(p) \
|
|
((/* no const */ void *)(GC_uintptr_t)(p))
|
|
#endif
|
|
|
|
/**
|
|
* Convenient macros for disappearing links registration working both
|
|
* for debug and non-debug allocated objects, and accepting interior
|
|
* pointers to object.
|
|
*/
|
|
#define GC_GENERAL_REGISTER_DISAPPEARING_LINK_SAFE(link, obj) \
|
|
GC_general_register_disappearing_link( \
|
|
link, GC_base(GC_CAST_AWAY_CONST_PVOID(obj)))
|
|
#define GC_REGISTER_LONG_LINK_SAFE(link, obj) \
|
|
GC_register_long_link(link, GC_base(GC_CAST_AWAY_CONST_PVOID(obj)))
|
|
|
|
/*
|
|
* Convenient macros over debug and non-debug allocation functions.
|
|
* All these macros (`GC_MALLOC`, `GC_REALLOC`, `GC_MALLOC_ATOMIC`,
|
|
* `GC_STRDUP`, `GC_STRNDUP`, `GC_MALLOC_ATOMIC_UNCOLLECTABLE`,
|
|
* `GC_MALLOC_UNCOLLECTABLE`, `GC_MALLOC_IGNORE_OFF_PAGE`,
|
|
* `GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE`) are guaranteed never to return
|
|
* `NULL` (for a nonzero new size in case of `GC_REALLOC`) unless
|
|
* `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
#ifdef GC_DEBUG_REPLACEMENT
|
|
# define GC_MALLOC(sz) GC_debug_malloc_replacement(sz)
|
|
# define GC_REALLOC(old, sz) GC_debug_realloc_replacement(old, sz)
|
|
#elif defined(GC_DEBUG)
|
|
# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
|
|
# define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
|
|
#else
|
|
# define GC_MALLOC(sz) GC_malloc(sz)
|
|
# define GC_REALLOC(old, sz) GC_realloc(old, sz)
|
|
#endif /* !GC_DEBUG_REPLACEMENT && !GC_DEBUG */
|
|
#ifdef GC_DEBUG
|
|
# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
|
|
# define GC_STRDUP(s) GC_debug_strdup(s, GC_EXTRAS)
|
|
# define GC_STRNDUP(s, sz) GC_debug_strndup(s, sz, GC_EXTRAS)
|
|
# define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) \
|
|
GC_debug_malloc_atomic_uncollectable(sz, GC_EXTRAS)
|
|
# define GC_MALLOC_UNCOLLECTABLE(sz) \
|
|
GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
|
|
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
|
|
GC_debug_malloc_ignore_off_page(sz, GC_EXTRAS)
|
|
# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
|
|
GC_debug_malloc_atomic_ignore_off_page(sz, GC_EXTRAS)
|
|
#else
|
|
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
|
|
# define GC_STRDUP(s) GC_strdup(s)
|
|
# define GC_STRNDUP(s, sz) GC_strndup(s, sz)
|
|
# define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) GC_malloc_atomic_uncollectable(sz)
|
|
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
|
|
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) GC_malloc_ignore_off_page(sz)
|
|
# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
|
|
GC_malloc_atomic_ignore_off_page(sz)
|
|
#endif /* !GC_DEBUG */
|
|
|
|
#ifdef GC_DEBUG
|
|
# define GC_FREE(p) GC_debug_free(p)
|
|
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
|
|
GC_debug_register_finalizer(p, f, d, of, od)
|
|
# define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
|
|
GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
|
|
# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
|
|
GC_debug_register_finalizer_no_order(p, f, d, of, od)
|
|
# define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
|
|
GC_debug_register_finalizer_unreachable(p, f, d, of, od)
|
|
# define GC_TOGGLEREF_ADD(p, is_strong) GC_debug_toggleref_add(p, is_strong)
|
|
# define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
|
|
# define GC_PTR_STORE_AND_DIRTY(p, q) GC_debug_ptr_store_and_dirty(p, q)
|
|
# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
|
|
GC_GENERAL_REGISTER_DISAPPEARING_LINK_SAFE(link, obj)
|
|
# define GC_REGISTER_LONG_LINK(link, obj) \
|
|
GC_REGISTER_LONG_LINK_SAFE(link, obj)
|
|
# define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
|
|
#else
|
|
# define GC_FREE(p) GC_free(p)
|
|
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
|
|
GC_register_finalizer(p, f, d, of, od)
|
|
# define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
|
|
GC_register_finalizer_ignore_self(p, f, d, of, od)
|
|
# define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
|
|
GC_register_finalizer_no_order(p, f, d, of, od)
|
|
# define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
|
|
GC_register_finalizer_unreachable(p, f, d, of, od)
|
|
# define GC_TOGGLEREF_ADD(p, is_strong) GC_toggleref_add(p, is_strong)
|
|
# define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
|
|
# define GC_PTR_STORE_AND_DIRTY(p, q) GC_ptr_store_and_dirty(p, q)
|
|
# define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
|
|
GC_general_register_disappearing_link(link, obj)
|
|
# define GC_REGISTER_LONG_LINK(link, obj) GC_register_long_link(link, obj)
|
|
# define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
|
|
#endif /* !GC_DEBUG */
|
|
|
|
/**
|
|
* Convenient macros for object allocation in C++ style. The use of
|
|
* them also reduces the chance for a misspecified size argument.
|
|
* But, note, that they may expand to something syntactically incorrect
|
|
* if the argument is a complicated type expression. Note also, unlike
|
|
* C++ new operator, these ones may return `NULL` (in case of out of
|
|
* memory); however these macros are guaranteed never to return `NULL`
|
|
* unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
#define GC_NEW(t) ((t *)GC_MALLOC(sizeof(t)))
|
|
#define GC_NEW_ATOMIC(t) ((t *)GC_MALLOC_ATOMIC(sizeof(t)))
|
|
#define GC_NEW_UNCOLLECTABLE(t) ((t *)GC_MALLOC_UNCOLLECTABLE(sizeof(t)))
|
|
|
|
#ifdef GC_REQUIRE_WCSDUP
|
|
/**
|
|
* Same as `GC_strdup` but for a `wchar_t` string. Might be
|
|
* unavailable on some targets (or not needed). `wchar_t` type should
|
|
* be defined in the platform `stddef.h` file. The function (including
|
|
* its debug variant) is guaranteed never to return `NULL` unless
|
|
* `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC wchar_t *GC_CALL GC_wcsdup(const wchar_t *)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_ATTR_MALLOC wchar_t *GC_CALL GC_debug_wcsdup(const wchar_t *,
|
|
GC_EXTRA_PARAMS)
|
|
GC_ATTR_NONNULL(1);
|
|
# ifdef GC_DEBUG
|
|
# define GC_WCSDUP(s) GC_debug_wcsdup(s, GC_EXTRAS)
|
|
# else
|
|
# define GC_WCSDUP(s) GC_wcsdup(s)
|
|
# endif
|
|
#endif /* GC_REQUIRE_WCSDUP */
|
|
|
|
/*
|
|
* The finalization. Some of these primitives are grossly unsafe.
|
|
* The idea is to make them both cheap, and sufficient to build
|
|
* a safer layer, closer to Modula-3, Java, or PCedar finalization.
|
|
* The interface represents my conclusions from a long discussion
|
|
* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes,
|
|
* Christian Jacobi, and Russ Atkinson. It is not perfect, and
|
|
* probably nobody else agrees with it.
|
|
*/
|
|
|
|
typedef void(GC_CALLBACK *GC_finalization_proc)(void * /* `obj` */,
|
|
void * /* `client_data` */);
|
|
|
|
/**
|
|
* When `obj` is no longer accessible, invoke `(*fn)(obj, cd)`. If `a`
|
|
* and `b` are inaccessible, and `a` points to `b` (after disappearing
|
|
* links have been made to disappear), then only `a` will be finalized.
|
|
* (If this does not create any new pointers to `b`, then `b` will be
|
|
* finalized after the next collection.) Any finalizable object that
|
|
* is reachable from itself by following one or more pointers will not
|
|
* be finalized (or collected). Thus cycles involving finalizable
|
|
* objects should be avoided, or broken by disappearing links. All but
|
|
* the last finalizer registered for an object is ignored. No-op in
|
|
* the find-leak mode. Finalization may be removed by passing 0 as
|
|
* `fn`. Finalizers are implicitly unregistered when they are enqueued
|
|
* for finalization (i.e. become ready to be finalized). The old
|
|
* finalizer and client data are stored in `*ofn` and `*ocd`,
|
|
* respectively. (`ofn` and/or `ocd` may be `NULL`. The allocator
|
|
* lock is held while `*ofn` and `*ocd` are updated. In case of error
|
|
* (no memory to register new finalizer), `*ofn` and `*ocd` remain
|
|
* unchanged.) `fn` is never invoked on an accessible object, provided
|
|
* hidden pointers are converted to real pointers only if the allocator
|
|
* lock is held, at least in the reader mode, and such conversions are
|
|
* not performed by finalization routines.
|
|
* If `GC_register_finalizer()` is aborted as a result of a signal,
|
|
* then the object may be left with no finalization, even if neither
|
|
* the old nor new finalizer were `NULL`. `obj` should be the starting
|
|
* address of an object allocated by `GC_malloc` or friends. `obj` may
|
|
* also be `NULL` or point to something outside the collector heap (in
|
|
* this case, `fn` is ignored, `*ofn` and `*ocd` are set to `NULL`).
|
|
* Note that any garbage collectible object referenced by `cd` will be
|
|
* considered accessible until the finalizer is invoked.
|
|
*/
|
|
GC_API void GC_CALL GC_register_finalizer(void * /* `obj` */,
|
|
GC_finalization_proc /* `fn` */,
|
|
void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */,
|
|
void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API void GC_CALL GC_debug_register_finalizer(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Another variant of `GC_register_finalizer` but ignoring self-cycles,
|
|
* i.e. pointers from a finalizable object to itself. There is
|
|
* a stylistic argument that this is wrong, but it is unavoidable for
|
|
* C++, since the compiler may silently introduce these. It is also
|
|
* benign in that specific case. And it helps if finalizable objects
|
|
* are split to avoid cycles. Note that `cd` will still be viewed as
|
|
* accessible, even if it refers to the object itself.
|
|
*/
|
|
GC_API void GC_CALL GC_register_finalizer_ignore_self(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API void GC_CALL GC_debug_register_finalizer_ignore_self(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Another variant of `GC_register_finalizer` which ignores all cycles.
|
|
* It should probably only be used by Java implementations. Note that
|
|
* `cd` will still be viewed as accessible, even if it refers to the
|
|
* object itself.
|
|
*/
|
|
GC_API void GC_CALL GC_register_finalizer_no_order(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API void GC_CALL GC_debug_register_finalizer_no_order(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* This is a special finalizer that is useful when an object's finalizer
|
|
* must be run when the object is known to be no longer reachable, not even
|
|
* from other finalizable objects. It behaves like "normal" finalization,
|
|
* except that the finalizer is not run while the object is reachable from
|
|
* other objects specifying unordered finalization. Effectively it allows
|
|
* an object referenced, possibly indirectly, from an unordered finalizable
|
|
* object to override the unordered finalization request. This can be used
|
|
* in combination with `GC_register_finalizer_no_order` so as to release
|
|
* resources that must not be released while an object can still be brought
|
|
* back to life by other finalizers. Only works if `GC_java_finalization`
|
|
* is set. Probably only of interest when implementing a language that
|
|
* requires unordered finalization (e.g. Java, C#).
|
|
*/
|
|
GC_API void GC_CALL GC_register_finalizer_unreachable(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API void GC_CALL GC_debug_register_finalizer_unreachable(
|
|
void * /* `obj` */, GC_finalization_proc /* `fn` */, void * /* `cd` */,
|
|
GC_finalization_proc * /* `ofn` */, void ** /* `ocd` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/** A constant indicating a failure due to lack of memory. */
|
|
#define GC_NO_MEMORY 2
|
|
|
|
/**
|
|
* This routine may be used to break cycles between finalizable objects,
|
|
* thus causing cyclic finalizable objects to be finalized in
|
|
* the correct order. The standard use involves calling
|
|
* `GC_register_disappearing_link(&p)`, where `p` is a pointer that is
|
|
* not followed by finalization code, and should not be considered in
|
|
* determining finalization order. `link` should point to a field of
|
|
* a heap-allocated object. `*link` will be cleared when the object is
|
|
* found to be inaccessible. This happens before any finalization code
|
|
* is invoked, and before any decisions about finalization order are
|
|
* made. This is useful in telling the finalizer that some pointers
|
|
* are not essential for proper finalization. This may avoid
|
|
* finalization cycles. Note that the object may be resurrected by
|
|
* another finalizer, and thus the clearing of `*link` may be visible
|
|
* to non-finalization code. There is an argument that an arbitrary
|
|
* action should be allowed here, instead of just clearing a pointer.
|
|
* But this causes problems if that action alters, or examines
|
|
* connectivity. Returns `GC_DUPLICATE` if given `link` was already
|
|
* registered, `GC_SUCCESS` if registration succeeded, `GC_NO_MEMORY`
|
|
* if it failed for lack of memory (and `GC_oom_fn` did not handle the
|
|
* problem). Only exists for backward compatibility, use
|
|
* `GC_general_register_disappearing_link()` instead.
|
|
*/
|
|
GC_API int GC_CALL GC_register_disappearing_link(void ** /* `link` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* A slight generalization of `GC_register_disappearing_link`.
|
|
* `*link` is cleared when `obj` first becomes inaccessible. This can be
|
|
* used to implement weak pointers easily and safely. Typically `link`
|
|
* will point to a location (in a GC-allocated object or not) holding
|
|
* a disguised pointer to `obj`. (A pointer inside an "atomic" object
|
|
* is effectively disguised.) In this way, weak pointers are broken
|
|
* before any object reachable from them gets finalized. Each `link`
|
|
* may be registered only with one `obj` value, i.e. all objects but
|
|
* the last one (`link` registered with) are ignored. `link` must be
|
|
* non-`NULL` (and be properly aligned). `obj` must be a pointer to
|
|
* the beginning of an object allocated by `GC_malloc` or friends.
|
|
* A link disappears when it is unregistered manually, or when `*link`
|
|
* is cleared, or when the object containing this `link` is garbage
|
|
* collected. It is unsafe to explicitly deallocate the object
|
|
* containing `link`. Explicit deallocation of `obj` may or may not
|
|
* cause `link` to eventually be cleared. No-op in the find-leak mode.
|
|
* This function can be used to implement certain types of weak pointers.
|
|
* Note, however, this generally requires that the allocator lock is held,
|
|
* at least in the reader mode (e.g. using `GC_call_with_reader_lock()`),
|
|
* when the disguised pointer is accessed. Otherwise a strong pointer
|
|
* could be recreated between the time the collector decides to reclaim
|
|
* the object and the link is cleared. Returns `GC_SUCCESS` if
|
|
* registration succeeded (a new link is registered), `GC_DUPLICATE` if
|
|
* `link` was already registered (with some object), `GC_NO_MEMORY` if
|
|
* registration failed for lack of memory (and `GC_oom_fn` did not handle
|
|
* the problem), `GC_UNIMPLEMENTED` if `GC_find_leak` is true.
|
|
*/
|
|
GC_API int GC_CALL GC_general_register_disappearing_link(
|
|
void ** /* `link` */, const void * /* `obj` */) GC_ATTR_NONNULL(1)
|
|
GC_ATTR_NONNULL(2);
|
|
|
|
/**
|
|
* Moves a `link` previously registered via
|
|
* `GC_general_register_disappearing_link` (or
|
|
* `GC_register_disappearing_link`). Does not change the target object
|
|
* of the weak reference. Does not change `*new_link` content. May be
|
|
* called with `new_link` equal to `link` (to check whether `link` has
|
|
* been registered). Returns `GC_SUCCESS` on success, `GC_DUPLICATE`
|
|
* if there is already another disappearing link at the new location
|
|
* (never returned if `new_link` is equal to `link`), `GC_NOT_FOUND`
|
|
* if no `link` is registered at the original location.
|
|
*/
|
|
GC_API int GC_CALL GC_move_disappearing_link(void ** /* `link` */,
|
|
void ** /* `new_link` */)
|
|
GC_ATTR_NONNULL(2);
|
|
|
|
/**
|
|
* Undoes a registration by either `GC_register_disappearing_link()` or
|
|
* `GC_general_register_disappearing_link()`. Returns 0 if `link` was
|
|
* not actually registered (otherwise returns 1).
|
|
*/
|
|
GC_API int GC_CALL GC_unregister_disappearing_link(void ** /* `link` */);
|
|
|
|
/**
|
|
* Similar to `GC_general_register_disappearing_link` but `*link` only
|
|
* gets cleared when `obj` becomes truly inaccessible. An object becomes
|
|
* truly inaccessible when it can no longer be resurrected from its
|
|
* finalizer (e.g. by assigning itself to a pointer traceable from root).
|
|
* This can be used to implement "long" weak pointers easily and safely.
|
|
*/
|
|
GC_API int GC_CALL GC_register_long_link(void ** /* `link` */,
|
|
const void * /* `obj` */)
|
|
GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2);
|
|
|
|
/**
|
|
* Similar to `GC_move_disappearing_link` but for a `link` previously
|
|
* registered via `GC_register_long_link`.
|
|
*/
|
|
GC_API int GC_CALL GC_move_long_link(void ** /* `link` */,
|
|
void ** /* `new_link` */)
|
|
GC_ATTR_NONNULL(2);
|
|
|
|
/**
|
|
* Similar to `GC_unregister_disappearing_link` but for `link`
|
|
* registration done by `GC_register_long_link()`.
|
|
*/
|
|
GC_API int GC_CALL GC_unregister_long_link(void ** /* `link` */);
|
|
|
|
/*
|
|
* Support of "toggle-refs" style of external memory management without
|
|
* hooking up to the host retain/release machinery. The idea of
|
|
* "toggle-refs" is that an external reference to an object is kept and
|
|
* it can be either a strong or weak reference; a weak reference is
|
|
* used when the external peer has no interest in the object, and
|
|
* a strong otherwise.
|
|
*/
|
|
|
|
typedef enum {
|
|
GC_TOGGLE_REF_DROP,
|
|
GC_TOGGLE_REF_STRONG,
|
|
GC_TOGGLE_REF_WEAK
|
|
} GC_ToggleRefStatus;
|
|
|
|
/**
|
|
* The callback is to decide (return) the new state of a given object.
|
|
* Invoked by the collector for all objects registered for "toggle-refs"
|
|
* processing. Invoked with the allocator lock held but the world is
|
|
* running.
|
|
*/
|
|
typedef GC_ToggleRefStatus(GC_CALLBACK *GC_toggleref_func)(void * /* `obj` */);
|
|
|
|
/**
|
|
* Set (register) a callback that decides the state of a given object (by,
|
|
* probably, inspecting its native state). The argument may be 0 (means
|
|
* no callback). Both the setter and the getter acquire the allocator lock
|
|
* (in the reader mode in case of the getter).
|
|
*/
|
|
GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func);
|
|
GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void);
|
|
|
|
/**
|
|
* Register a given object for "toggle-refs" processing. It will be
|
|
* stored internally and the "toggle-refs" callback will be invoked on
|
|
* the object until the callback returns `GC_TOGGLE_REF_DROP` or the
|
|
* object is collected. If `is_strong`, then the object is registered
|
|
* with a strong ref, a weak one otherwise. `obj` should be the starting
|
|
* address of an object allocated by `GC_malloc` (`GC_debug_malloc`)
|
|
* or friends. Returns `GC_SUCCESS` if registration succeeded (or no
|
|
* callback is registered yet), `GC_NO_MEMORY` if it failed for a lack
|
|
* of memory reason.
|
|
*/
|
|
GC_API int GC_CALL GC_toggleref_add(void * /* `obj` */, int /* `is_strong` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API int GC_CALL GC_debug_toggleref_add(void * /* `obj` */,
|
|
int /* `is_strong` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Finalizer callback support. Invoked by the collector (with the allocator
|
|
* lock held) for each unreachable object enqueued for finalization.
|
|
* Zero means no callback. The setter and the getter acquire the allocator
|
|
* lock too (in the reader mode in case of the getter).
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_await_finalize_proc)(void * /* `obj` */);
|
|
GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc);
|
|
GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void);
|
|
|
|
/**
|
|
* Returns a nonzero value (true) if `GC_invoke_finalizers()` has
|
|
* something to do. (Useful if finalizers can only be called from some
|
|
* kind of "safe state" and getting into that safe state is expensive.)
|
|
* Does not use any synchronization.
|
|
*/
|
|
GC_API int GC_CALL GC_should_invoke_finalizers(void);
|
|
|
|
/**
|
|
* Set maximum amount of finalizers to run during a single invocation
|
|
* of `GC_invoke_finalizers()`. Zero means no limit. Both the setter
|
|
* and the getter acquire the allocator lock (in the reader mode in
|
|
* case of the getter). Note that invocation of `GC_finalize_all()`
|
|
* resets the maximum amount value.
|
|
*/
|
|
GC_API void GC_CALL GC_set_interrupt_finalizers(unsigned);
|
|
GC_API unsigned GC_CALL GC_get_interrupt_finalizers(void);
|
|
|
|
/**
|
|
* Run finalizers for all objects that are ready to be finalized.
|
|
* Return the number of finalizers that were run. Normally this is
|
|
* also called implicitly during some allocations.
|
|
* If `GC_finalize_on_demand` is nonzero, it must be called explicitly.
|
|
*/
|
|
GC_API int GC_CALL GC_invoke_finalizers(void);
|
|
|
|
/*
|
|
* Explicitly tell the collector that an object is reachable
|
|
* at a particular program point. This prevents the argument
|
|
* pointer from being optimized away, even it is otherwise no
|
|
* longer needed. It should have no visible effect in the
|
|
* absence of finalizers or disappearing links. But it may be
|
|
* needed to prevent finalizers from running while the
|
|
* associated external resource is still in use.
|
|
* The function is sometimes called to keep some object alive.
|
|
*/
|
|
#if defined(__GNUC__) && !defined(__INTEL_COMPILER) \
|
|
&& !(defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) \
|
|
&& defined(__TINYC__))
|
|
/* TCC (as of v0.9.28rc) does not support asm on macOS/arm (32 or 64 bit). */
|
|
# if defined(__CHERI_PURE_CAPABILITY__) || defined(__TINYC__)
|
|
# define GC_reachable_here(ptr) \
|
|
__asm__ __volatile__(" " : : "g"(ptr) : "memory")
|
|
# elif defined(__e2k__)
|
|
# define GC_reachable_here(ptr) \
|
|
__asm__ __volatile__(" " : : "r"(ptr) : "memory")
|
|
# else
|
|
# define GC_reachable_here(ptr) \
|
|
__asm__ __volatile__(" " : : "X"(ptr) : "memory")
|
|
# endif
|
|
#elif defined(LINT2)
|
|
/* The definition is similar to that of `COVERT_DATAFLOW()`. */
|
|
# define GC_reachable_here(ptr) GC_noop1(~(GC_word)(ptr) ^ (~(GC_word)0))
|
|
#else
|
|
# define GC_reachable_here(ptr) GC_noop1_ptr(GC_CAST_AWAY_CONST_PVOID(ptr))
|
|
#endif
|
|
|
|
/**
|
|
* Make the argument of `GC_word` type appear live to compiler.
|
|
* This could be used to prevent certain compiler false positive (FP)
|
|
* warnings and misoptimizations. Should be robust against the whole
|
|
* program analysis.
|
|
*/
|
|
GC_API void GC_CALL GC_noop1(GC_word);
|
|
|
|
/** Same as `GC_noop1()` but for a pointer. */
|
|
GC_API void GC_CALL GC_noop1_ptr(volatile void *);
|
|
|
|
/**
|
|
* `GC_set_warn_proc` can be used to redirect or filter warning messages.
|
|
* `p` may not be a `NULL` pointer. `msg` is a `printf` format string
|
|
* (`arg` must match the format). Both the setter and the getter acquire
|
|
* the allocator lock (in the reader mode in case of the getter) to avoid
|
|
* data race. In GC v7.1 and before: the setter returned the value of
|
|
* old `warn_proc`. In GC v8.2.x and before: `msg` pointer type had
|
|
* no `const` qualifier.
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_warn_proc)(const char * /* `msg` */,
|
|
GC_uintptr_t /* `arg` */);
|
|
GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc /* `p` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void);
|
|
|
|
/**
|
|
* `GC_ignore_warn_proc` may be used as an argument for `GC_set_warn_proc()`
|
|
* to suppress all warnings (unless statistics printing is turned on).
|
|
* This is recommended for production code (release).
|
|
*/
|
|
GC_API void GC_CALLBACK GC_ignore_warn_proc(const char *, GC_uintptr_t);
|
|
|
|
/**
|
|
* Change file descriptor of the collector log. Unavailable on some
|
|
* targets.
|
|
*/
|
|
GC_API void GC_CALL GC_set_log_fd(int);
|
|
|
|
/**
|
|
* This is invoked on the collector fatal aborts (just before
|
|
* OS-dependent `abort()` or `exit(1)` is called). Must be non-`NULL`.
|
|
* The default one outputs `msg` to the platform `stderr` provided
|
|
* `msg` is non-`NULL`. `msg` is `NULL` if invoked before `exit(1)`
|
|
* otherwise `msg` is non-`NULL` (i.e., if invoked before `abort`).
|
|
* Both the setter and the getter acquire the allocator lock (in the reader
|
|
* mode in case of the getter). The setter does not change `GC_abort_func`
|
|
* if the library has been compiled with `SMALL_CONFIG` macro defined.
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_abort_func)(const char * /* `msg` */);
|
|
GC_API void GC_CALL GC_set_abort_func(GC_abort_func) GC_ATTR_NONNULL(1);
|
|
GC_API GC_abort_func GC_CALL GC_get_abort_func(void);
|
|
|
|
/*
|
|
* Clients should define `GC_EXIT_LACKS_NORETURN` macro if the platform
|
|
* `exit()` does not have a `noreturn` attribute.
|
|
*/
|
|
#ifdef GC_EXIT_LACKS_NORETURN
|
|
# define GC_OOM_ABORT_THROW_ATTRIBUTE /*< empty */
|
|
#else
|
|
# define GC_OOM_ABORT_THROW_ATTRIBUTE GC_ATTR_NORETURN
|
|
#endif
|
|
|
|
/** A portable way to abort the application because of not enough memory. */
|
|
GC_API GC_OOM_ABORT_THROW_ATTRIBUTE void GC_CALL GC_abort_on_oom(void);
|
|
|
|
/*
|
|
* The following is intended to be used by a higher level (e.g.
|
|
* Java-like) finalization facility. It is expected that finalization
|
|
* code will arrange for hidden pointers to disappear. Otherwise,
|
|
* objects can be accessed after they have been collected. Should not
|
|
* be used in the find-leak mode.
|
|
* Note that putting pointers in atomic objects or in non-pointer slots
|
|
* of "typed" objects is equivalent to disguising them in this way, and
|
|
* may have other advantages. Note also that some code relies on that
|
|
* the least significant bit of the argument (including for `NULL`) is
|
|
* inverted by these primitives.
|
|
* Important: converting a hidden pointer to a real pointer requires
|
|
* verifying that the object still exists; this should involve
|
|
* acquiring the allocator lock, at least in the reader mode, to avoid
|
|
* a race with the collector (e.g., one thread might fetch hidden link
|
|
* value, while another thread might collect the relevant object and
|
|
* reuse the free space for another object).
|
|
*/
|
|
typedef GC_uintptr_t GC_hidden_pointer;
|
|
#define GC_HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
|
|
#define GC_REVEAL_POINTER(p) ((void *)GC_HIDE_POINTER(p))
|
|
|
|
#if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
|
|
/*
|
|
* This exists only for compatibility (the GC-prefixed symbols are
|
|
* preferred for new code).
|
|
*/
|
|
# define HIDE_POINTER(p) GC_HIDE_POINTER(p)
|
|
# define REVEAL_POINTER(p) GC_REVEAL_POINTER(p)
|
|
#endif
|
|
|
|
/*
|
|
* A slightly modified variant of `GC_HIDE_POINTER` which guarantees
|
|
* not to "hide" `NULL` (i.e. passing zero argument gives zero result).
|
|
* This might be useful in conjunction with `GC_register_disappearing_link`.
|
|
* Note that unlike `GC_HIDE_POINTER`, inversion of the least significant
|
|
* bit of the argument is not guaranteed.
|
|
*/
|
|
#if defined(__CHERI_PURE_CAPABILITY__)
|
|
# define GC_HIDE_NZ_POINTER(p) ((GC_hidden_pointer)(-(intptr_t)(p)))
|
|
#else
|
|
# define GC_HIDE_NZ_POINTER(p) ((GC_hidden_pointer)(-(GC_signed_word)(p)))
|
|
#endif
|
|
#define GC_REVEAL_NZ_POINTER(p) ((void *)GC_HIDE_NZ_POINTER(p))
|
|
|
|
/*
|
|
* The routines to acquire/release the GC (allocator) lock.
|
|
* The lock is not reentrant. `GC_alloc_unlock()` should not be called
|
|
* unless the allocator lock is acquired by the current thread.
|
|
*/
|
|
#ifdef GC_THREADS
|
|
GC_API void GC_CALL GC_alloc_lock(void);
|
|
GC_API void GC_CALL GC_alloc_unlock(void);
|
|
#else
|
|
/* No need for real locking if the client is single-threaded. */
|
|
# define GC_alloc_lock() (void)0
|
|
# define GC_alloc_unlock() (void)0
|
|
#endif /* !GC_THREADS */
|
|
|
|
typedef void *(GC_CALLBACK *GC_fn_type)(void * /* `client_data` */);
|
|
|
|
/**
|
|
* Execute given function with the allocator lock held (in the exclusive
|
|
* mode).
|
|
*/
|
|
GC_API void *GC_CALL GC_call_with_alloc_lock(GC_fn_type /* `fn` */,
|
|
void * /* `client_data` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/*
|
|
* Execute given function with the allocator lock held in the reader
|
|
* (shared) mode. The 3rd argument (`release`), if nonzero, indicates
|
|
* that `fn` might write some data that should be made visible to the
|
|
* thread which acquires the allocator lock in the exclusive mode later.
|
|
*/
|
|
#ifdef GC_THREADS
|
|
GC_API void *GC_CALL GC_call_with_reader_lock(GC_fn_type /* `fn` */,
|
|
void * /* `client_data` */,
|
|
int /* `release` */)
|
|
GC_ATTR_NONNULL(1);
|
|
#else
|
|
# define GC_call_with_reader_lock(fn, cd, r) ((void)(r), (fn)(cd))
|
|
#endif
|
|
|
|
/*
|
|
* These routines are intended to explicitly notify the collector
|
|
* of new threads. Often this is unnecessary because thread creation
|
|
* is implicitly intercepted by the collector, using header-file defines,
|
|
* or linker-based interception. In the long run, the intent is to
|
|
* always make redundant registration safe. In the short run, this is
|
|
* being implemented a platform at a time. The interface is complicated
|
|
* by the fact that we probably will not ever be able to automatically
|
|
* determine the stack bottom for thread stacks on all platforms.
|
|
*/
|
|
|
|
/**
|
|
* Structure representing the bottom (cold end) of a thread stack.
|
|
* On most platforms this contains just a single address.
|
|
*/
|
|
struct GC_stack_base {
|
|
/* The bottom of the general-purpose stack. */
|
|
void *mem_base;
|
|
#if defined(__e2k__) || defined(__ia64) || defined(__ia64__) \
|
|
|| defined(_M_IA64)
|
|
/* The bottom of the register stack. */
|
|
void *reg_base;
|
|
#endif
|
|
};
|
|
|
|
typedef void *(GC_CALLBACK *GC_stack_base_func)(
|
|
struct GC_stack_base * /* `sb` */, void * /* `arg` */);
|
|
|
|
/**
|
|
* Call a function with a stack base structure corresponding to somewhere in
|
|
* the `GC_call_with_stack_base` frame. This often can be used to provide
|
|
* a sufficiently accurate stack bottom. And we implement it everywhere.
|
|
*/
|
|
GC_API void *GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
|
|
void * /* arg */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
#define GC_SUCCESS 0
|
|
|
|
/** Means was already registered. */
|
|
#define GC_DUPLICATE 1
|
|
|
|
/* Deprecated. No thread support in the collector. */
|
|
#define GC_NO_THREADS 2
|
|
|
|
/** Not yet implemented on this platform. */
|
|
#define GC_UNIMPLEMENTED 3
|
|
|
|
/** Requested `link` not found (returned by `GC_move_disappearing_link()`). */
|
|
#define GC_NOT_FOUND 4
|
|
|
|
/**
|
|
* Start the parallel marker threads, if available. Useful, e.g.,
|
|
* after POSIX `fork` in a child process (provided not followed by
|
|
* `exec()`) or in single-threaded clients (provided it is OK for the
|
|
* client to perform marking in parallel). Acquires the allocator lock
|
|
* to avoid a race.
|
|
*/
|
|
GC_API void GC_CALL GC_start_mark_threads(void);
|
|
|
|
#if defined(GC_DARWIN_THREADS) || defined(GC_WIN32_THREADS)
|
|
/**
|
|
* Use implicit thread registration and processing (via Win32 `DllMain`
|
|
* or Darwin `task_threads`). Deprecated. Must be called before
|
|
* `GC_INIT()` and other GC routines (or, at least, before going
|
|
* multi-threaded). Performs the collector initialization. Should be
|
|
* avoided if `GC_pthread_create`, `GC_beginthreadex` (or `GC_CreateThread`),
|
|
* or `GC_register_my_thread` could be used instead. Disables parallelized
|
|
* garbage collection on Win32.
|
|
*/
|
|
GC_API void GC_CALL GC_use_threads_discovery(void);
|
|
#endif
|
|
|
|
#ifdef GC_THREADS
|
|
/**
|
|
* Suggest the collector to use the specific signal to suspend threads.
|
|
* Has no effect after the collector initialization and on non-POSIX systems.
|
|
*/
|
|
GC_API void GC_CALL GC_set_suspend_signal(int);
|
|
|
|
/**
|
|
* Return the signal number (which is a constant after the collector
|
|
* initialization) used by the collector to suspend threads on POSIX systems.
|
|
* Return -1 otherwise.
|
|
*/
|
|
GC_API int GC_CALL GC_get_suspend_signal(void);
|
|
|
|
/**
|
|
* Suggest the collector to use the specific signal to resume threads.
|
|
* Has no effect after the collector initialization and on non-POSIX systems.
|
|
* The same signal might be used for threads suspension and restart.
|
|
*/
|
|
GC_API void GC_CALL GC_set_thr_restart_signal(int);
|
|
|
|
/**
|
|
* Return the signal number (which is a constant after the collector
|
|
* initialization) used by the collector to restart (resume) threads on
|
|
* POSIX systems. Return -1 otherwise.
|
|
*/
|
|
GC_API int GC_CALL GC_get_thr_restart_signal(void);
|
|
|
|
/**
|
|
* Explicitly enable `GC_register_my_thread()` invocation.
|
|
* Done implicitly if a GC thread-creation function is called
|
|
* (or implicit thread registration is activated, or the collector is
|
|
* compiled with `GC_ALWAYS_MULTITHREADED` macro defined). Otherwise,
|
|
* it must be called from the main (or any previously registered)
|
|
* thread between the collector initialization and the first explicit
|
|
* registering of a thread (it should be called as late as possible).
|
|
* Includes a `GC_start_mark_threads()` call.
|
|
*/
|
|
GC_API void GC_CALL GC_allow_register_threads(void);
|
|
|
|
/**
|
|
* Register the current thread, with the indicated stack bottom, as
|
|
* a new thread whose stack(s) should be traced by the collector.
|
|
* If it is not implicitly called by the collector, this must be called
|
|
* before a thread can allocate garbage-collected memory, or assign
|
|
* pointers to the garbage-collected heap. Once registered, a thread
|
|
* will be stopped during garbage collections. This call must be
|
|
* previously enabled (see `GC_allow_register_threads`). This should
|
|
* never be called from the main thread, where it is always done
|
|
* implicitly. This is normally done implicitly if `GC_` functions are
|
|
* called to create the thread, e.g. by include `gc.h` file (which
|
|
* redefines some system functions) before calling the system thread
|
|
* creation function. Nonetheless, thread cleanup routines (e.g.,
|
|
* `pthreads` key destructor) typically require manual thread
|
|
* registering (and unregistering) if pointers to GC-allocated objects
|
|
* are manipulated inside. It is also always done implicitly on some
|
|
* platforms if `GC_use_threads_discovery()` is called at start-up.
|
|
* Except for the latter case, the explicit call is normally required
|
|
* for threads created by third-party libraries. A manually registered
|
|
* thread requires manual unregistering. Returns `GC_SUCCESS` on
|
|
* success, `GC_DUPLICATE` if already registered.
|
|
*/
|
|
GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Return 1 (true) if the calling (current) thread is registered with the
|
|
* garbage collector, 0 otherwise. Acquires the allocator lock in the
|
|
* reader mode. If the thread is finished (e.g. running in a destructor
|
|
* and not registered manually again), then it is considered as not
|
|
* registered.
|
|
*/
|
|
GC_API int GC_CALL GC_thread_is_registered(void);
|
|
|
|
/**
|
|
* Notify the collector about the stack and the alt-stack of the current
|
|
* thread. `normstack` and `normstack_size` are used to determine the
|
|
* "normal" stack boundaries when a thread is suspended while it is on
|
|
* an alt-stack. Acquires the allocator lock in the reader mode.
|
|
*/
|
|
GC_API void GC_CALL GC_register_altstack(void * /* `normstack` */,
|
|
size_t /* `normstack_size` */,
|
|
void * /* `altstack` */,
|
|
size_t /* `altstack_size` */);
|
|
|
|
/**
|
|
* Unregister the current thread. Only an explicitly registered thread
|
|
* (i.e. for which `GC_register_my_thread()` returns `GC_SUCCESS`)
|
|
* is allowed (and required) to call this function. (As a special
|
|
* exception, it is also allowed to once unregister the main thread.)
|
|
* The thread may no longer allocate garbage-collected memory or
|
|
* manipulate pointers to the garbage-collected heap after making this
|
|
* call. Specifically, if it wants to return or otherwise communicate
|
|
* a pointer to the garbage-collected heap to another thread, it must
|
|
* do this before calling `GC_unregister_my_thread`, most probably by
|
|
* saving it in a global data structure. Must not be called inside
|
|
* a GC callback function (except for `GC_call_with_stack_base()` one).
|
|
* Always returns `GC_SUCCESS`.
|
|
*/
|
|
GC_API int GC_CALL GC_unregister_my_thread(void);
|
|
|
|
/** Stop/start the world explicitly. Not recommended for general use. */
|
|
GC_API void GC_CALL GC_stop_world_external(void);
|
|
GC_API void GC_CALL GC_start_world_external(void);
|
|
|
|
/**
|
|
* Provide a verifier/modifier of the stack pointer when pushing the
|
|
* thread stacks. This might be useful for a crude integration
|
|
* with certain coroutine implementations. `*sp_ptr` is the captured
|
|
* stack pointer of the suspended thread with `pthread_id` (the latter
|
|
* is actually of `pthread_t` type). The functionality is unsupported
|
|
* on some targets (the getter always returns 0 in such a case).
|
|
* Both the setter and the getter acquire the allocator lock (in the reader
|
|
* mode in case of the getter). The client function (if provided) is called
|
|
* with the allocator lock held and, might be, with the world stopped.
|
|
*/
|
|
typedef void(GC_CALLBACK *GC_sp_corrector_proc)(void ** /* `sp_ptr` */,
|
|
void * /* `pthread_id` */);
|
|
GC_API void GC_CALL GC_set_sp_corrector(GC_sp_corrector_proc);
|
|
GC_API GC_sp_corrector_proc GC_CALL GC_get_sp_corrector(void);
|
|
#endif /* GC_THREADS */
|
|
|
|
/**
|
|
* Wrapper for functions that are likely to block (or, at least, do not
|
|
* allocate garbage-collected memory and/or manipulate pointers to the
|
|
* garbage-collected heap) for an appreciable length of time.
|
|
* While `fn` is running, the collector is said to be in the "inactive"
|
|
* state for the current thread (this means that the thread is not
|
|
* suspended and the thread's stack frames "belonging" to the functions
|
|
* in the "inactive" state are not scanned during garbage collections).
|
|
* It is assumed that the collector is already initialized and the
|
|
* current thread is registered. It is allowed for `fn` to call
|
|
* `GC_call_with_gc_active()` (even recursively), thus temporarily
|
|
* toggling the collector's state back to "active". The latter
|
|
* technique might be used to make stack scanning more precise (i.e.
|
|
* scan only stack frames of functions that allocate garbage-collected
|
|
* memory and/or manipulate pointers to the garbage-collected heap).
|
|
* Acquires the allocator lock in the reader mode (but `fn` is called
|
|
* not holding it).
|
|
*/
|
|
GC_API void *GC_CALL GC_do_blocking(GC_fn_type /* `fn` */,
|
|
void * /* `client_data` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Call a function switching to the "active" state of the collector for
|
|
* the current thread (i.e. the user function is temporarily back
|
|
* allowed to call any GC function and/or manipulate pointers to the
|
|
* garbage-collected heap). `GC_call_with_gc_active()` has the
|
|
* functionality opposite to `GC_do_blocking()` one. It is assumed
|
|
* that the collector is already initialized and the current thread is
|
|
* registered. `fn` may toggle the collector thread's state
|
|
* temporarily to "inactive" one by using `GC_do_blocking()`.
|
|
* `GC_call_with_gc_active()` often can be used to provide
|
|
* a sufficiently accurate stack bottom. Acquires the allocator lock
|
|
* in the reader mode (but `fn` is called not holding it).
|
|
*/
|
|
GC_API void *GC_CALL GC_call_with_gc_active(GC_fn_type /* `fn` */,
|
|
void * /* `client_data` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Attempt to fill in the `GC_stack_base` structure with the stack
|
|
* bottom for this thread. This appears to be required to implement
|
|
* anything like the JNI (Java Native Interface) `AttachCurrentThread`
|
|
* in an environment in which new threads are not automatically registered
|
|
* with the collector. It is also unfortunately hard to implement well
|
|
* on many platforms. Returns `GC_SUCCESS` or `GC_UNIMPLEMENTED`.
|
|
* Acquires the allocator lock on some platforms.
|
|
*/
|
|
GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Fill in the GC_stack_base structure with the cold end (bottom) of
|
|
* the stack of the current thread (or coroutine).
|
|
* Unlike `GC_get_stack_base`, it retrieves the value stored in the
|
|
* collector (which is initially set by the collector upon the thread
|
|
* is started or registered manually but it could be later updated by
|
|
* client using `GC_set_stackbottom`). Returns the GC-internal
|
|
* non-`NULL` handle of the thread which could be passed to
|
|
* `GC_set_stackbottom()` later. It is assumed that the collector is
|
|
* already initialized and the thread is registered. Acquires the
|
|
* allocator lock in the reader mode.
|
|
*/
|
|
GC_API void *GC_CALL GC_get_my_stackbottom(struct GC_stack_base *)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Set the cool end of the user (coroutine) stack of the specified thread.
|
|
* The GC thread handle (`gc_thread_handle`) is either the one returned by
|
|
* `GC_get_my_stackbottom()` or `NULL` (the latter designates the current
|
|
* thread). The caller should hold the allocator lock (e.g. using
|
|
* `GC_call_with_reader_lock()` with `release` argument set to 1), the
|
|
* reader mode should be enough typically, at least for the collector
|
|
* itself (the client is responsible to avoid data race between this and
|
|
* `GC_get_my_stackbottom` functions if the client acquires the allocator
|
|
* lock in the reader mode). Also, the function could be used for setting
|
|
* `GC_stackbottom` value (the bottom of the primordial thread) before the
|
|
* collector is initialized (the allocator lock is not needed to be
|
|
* acquired at all in this case).
|
|
*/
|
|
GC_API void GC_CALL GC_set_stackbottom(void * /* `gc_thread_handle` */,
|
|
const struct GC_stack_base *)
|
|
GC_ATTR_NONNULL(2);
|
|
|
|
/*
|
|
* The following routines are primarily intended for use with a preprocessor
|
|
* which inserts calls to check C pointer arithmetic. They indicate failure
|
|
* by invoking the corresponding print procedure (`GC_same_obj_print_proc`,
|
|
* `GC_is_valid_displacement_print_proc` or `GC_is_visible_print_proc`).
|
|
*/
|
|
|
|
/**
|
|
* Checked pointer pre- and post-increment operations. Note that the second
|
|
* argument (`how_much`) is in units of bytes, not multiples of the object
|
|
* size. This should either be invoked from a macro, or the call should be
|
|
* automatically generated.
|
|
*/
|
|
GC_API void *GC_CALL GC_pre_incr(void **, ptrdiff_t /* `how_much` */)
|
|
GC_ATTR_NONNULL(1);
|
|
GC_API void *GC_CALL GC_post_incr(void **, ptrdiff_t /* `how_much` */)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/**
|
|
* Check that `p` and `q` point to the same object.
|
|
* `GC_same_obj_print_proc` is called (fail by default) if they do not.
|
|
* Succeeds, as well, if neither `p` nor `q` points to the heap.
|
|
* (May succeed also if both `p` and `q` point to between heap objects.)
|
|
* Returns the first argument (`p`). (The returned value may be hard to
|
|
* use due to typing issues. But if we had a suitable preprocessor...)
|
|
* We assume this is somewhat performance critical (it should not be
|
|
* called by production code, of course, but it can easily make even
|
|
* debugging intolerably slow).
|
|
*/
|
|
GC_API void *GC_CALL GC_same_obj(void * /* `p` */, void * /* `q` */);
|
|
|
|
/**
|
|
* Check that `p` is visible to the collector as a possibly pointer
|
|
* containing location. If it is not, call `GC_is_visible_print_proc`
|
|
* (fail by default). Always returns the argument (`p`).
|
|
* May erroneously succeed in hard cases. The function is intended for
|
|
* debugging use with untyped allocations. (The idea is that it should
|
|
* be possible, though slow, to add such a call to all indirect pointer
|
|
* stores.) Currently almost useless for the multi-threaded worlds.
|
|
*/
|
|
GC_API void *GC_CALL GC_is_visible(void * /* p */);
|
|
|
|
/**
|
|
* Check that if `p` is a pointer to a heap page, then it points to
|
|
* a valid displacement within a heap object. If it is not, invoke
|
|
* `GC_is_valid_displacement_print_proc` (fail by default).
|
|
* Always returns the argument (`p`). Uninteresting in the
|
|
* all-interior-pointers mode. Note that we do not acquire the
|
|
* allocator lock, since nothing relevant about the header should
|
|
* change while we have a valid object pointer to the block.
|
|
*/
|
|
GC_API void *GC_CALL GC_is_valid_displacement(void * /* `p` */);
|
|
|
|
/**
|
|
* Explicitly dump the collector state. This is most often called from
|
|
* the debugger, or by setting the `GC_DUMP_REGULARLY` environment
|
|
* variable, but it may be useful to call it from client code during
|
|
* debugging. The current collection number is printed in the header
|
|
* of the dump. Acquires the allocator lock in the reader mode to
|
|
* avoid data race. Defined only if the library has been compiled
|
|
* without `NO_DEBUGGING` macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_dump(void);
|
|
|
|
/**
|
|
* The same as `GC_dump` but allows to specify the name of dump and
|
|
* does not acquire the allocator lock. If `name` is non-`NULL`, it is
|
|
* printed to help identifying individual dumps. Otherwise the current
|
|
* collection number is used as the name. Defined only if the library
|
|
* has been compiled without `NO_DEBUGGING` macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_dump_named(const char * /* `name` */);
|
|
|
|
/**
|
|
* Dump information about each block of every GC memory section.
|
|
* Defined only if the library has been compiled without `NO_DEBUGGING`
|
|
* macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_dump_regions(void);
|
|
|
|
/**
|
|
* Dump information about every registered disappearing link and
|
|
* finalizable object. Defined only if the library has been compiled
|
|
* without `NO_DEBUGGING` macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_dump_finalization(void);
|
|
|
|
typedef enum {
|
|
GC_HEAP_SECTION_TYPE_FREE,
|
|
GC_HEAP_SECTION_TYPE_PADDING,
|
|
GC_HEAP_SECTION_TYPE_USED,
|
|
GC_HEAP_SECTION_TYPE_UNMAPPED,
|
|
GC_HEAP_SECTION_TYPE_FORWARDING,
|
|
GC_HEAP_SECTION_TYPE_WHOLE_SECT
|
|
} GC_heap_section_type;
|
|
|
|
typedef void(GC_CALLBACK *GC_heap_section_proc)(
|
|
void * /* `start` */, void * /* `finish` */,
|
|
GC_heap_section_type /* `type` */, void * /* `client_data` */);
|
|
|
|
/**
|
|
* Apply `fn` to each heap section and each heap block inside.
|
|
* Similar to `GC_apply_to_all_blocks()`. Assumes the allocator lock
|
|
* is held at least in the reader mode, but no assertion about it
|
|
* by design. Defined only if the library has been compiled without
|
|
* `NO_DEBUGGING` macro defined.
|
|
*/
|
|
GC_API void GC_CALL GC_foreach_heap_section_inner(GC_heap_section_proc fn,
|
|
void *client_data)
|
|
GC_ATTR_NONNULL(1);
|
|
|
|
/*
|
|
* Safer, but slow, pointer addition. Probably useful mainly with
|
|
* a preprocessor. Useful only for heap pointers. Only the macros
|
|
* without trailing digits are meant to be used by clients. These are
|
|
* designed to model the available C pointer arithmetic expressions.
|
|
* Even then, these are probably more useful as documentation than as
|
|
* a part of the API. Note that `GC_PTR_ADD()` evaluates the first
|
|
* argument more than once.
|
|
*/
|
|
#if defined(GC_DEBUG) && (defined(__GNUC__) || defined(__clang__))
|
|
# define GC_PTR_ADD3(x, n, type_of_result) \
|
|
((type_of_result)GC_same_obj((x) + (n), (x)))
|
|
# define GC_PRE_INCR3(x, n, type_of_result) \
|
|
((type_of_result)GC_pre_incr((void **)&(x), (n) * sizeof(*(x))))
|
|
# define GC_POST_INCR3(x, n, type_of_result) \
|
|
((type_of_result)GC_post_incr((void **)&(x), (n) * sizeof(*(x))))
|
|
# define GC_PTR_ADD(x, n) GC_PTR_ADD3(x, n, __typeof__(x))
|
|
# define GC_PRE_INCR(x, n) GC_PRE_INCR3(x, n, __typeof__(x))
|
|
# define GC_POST_INCR(x) GC_POST_INCR3(x, 1, __typeof__(x))
|
|
# define GC_POST_DECR(x) GC_POST_INCR3(x, -1, __typeof__(x))
|
|
#else /* !GC_DEBUG || !__GNUC__ */
|
|
/*
|
|
* We cannot do this right without `typeof`, which ANSI decided was not
|
|
* sufficiently useful. Without it we resort to the non-debug variant.
|
|
*/
|
|
/* TODO: This should eventually support C++0x `decltype`. */
|
|
# define GC_PTR_ADD(x, n) ((x) + (n))
|
|
# define GC_PRE_INCR(x, n) ((x) += (n))
|
|
# define GC_POST_INCR(x) ((x)++)
|
|
# define GC_POST_DECR(x) ((x)--)
|
|
#endif /* !GC_DEBUG || !__GNUC__ */
|
|
|
|
/* Safer assignment of a pointer to a non-stack location. */
|
|
#ifdef GC_DEBUG
|
|
# define GC_PTR_STORE(p, q) \
|
|
(*(void **)GC_is_visible((void *)(p)) \
|
|
= GC_is_valid_displacement((void *)(q)))
|
|
#else
|
|
# define GC_PTR_STORE(p, q) (*(void **)(p) = (void *)(q))
|
|
#endif
|
|
|
|
/*
|
|
* `GC_PTR_STORE_AND_DIRTY(p, q)` is equivalent to `GC_PTR_STORE(p, q)`
|
|
* followed by `GC_END_STUBBORN_CHANGE(p)` and `GC_reachable_here(q)`
|
|
* (assuming `p` and `q` do not have side effects).
|
|
*/
|
|
GC_API void GC_CALL GC_ptr_store_and_dirty(void * /* `p` */,
|
|
const void * /* `q` */);
|
|
GC_API void GC_CALL GC_debug_ptr_store_and_dirty(void * /* `p` */,
|
|
const void * /* `q` */);
|
|
|
|
#ifdef GC_PTHREADS
|
|
/*
|
|
* For `pthreads` support, we generally need to intercept a number of
|
|
* thread library calls. We do that here by macro defining them.
|
|
*/
|
|
# ifdef __cplusplus
|
|
} /* extern "C" */
|
|
# endif
|
|
# include "gc_pthread_redirects.h"
|
|
# ifdef __cplusplus
|
|
extern "C" {
|
|
# endif
|
|
#endif
|
|
|
|
/**
|
|
* This returns a list of objects with the link pointer located at the
|
|
* beginning of each object. The use of such list can greatly reduce
|
|
* lock contention problems, since the allocator lock can be acquired
|
|
* and released many fewer times. Note that there is no "atomic"
|
|
* variant of this function, as otherwise the links would not be seen
|
|
* by the collector. If the argument (`lb`) is zero, then it is
|
|
* treated as 1. The function is guaranteed never to return `NULL`
|
|
* unless `GC_oom_fn()` returns `NULL`.
|
|
*/
|
|
GC_API GC_ATTR_MALLOC void *GC_CALL GC_malloc_many(size_t /* `lb` */);
|
|
|
|
/* Retrieve the next element in the list returned by `GC_malloc_many()`. */
|
|
#define GC_NEXT(p) (*(void **)(p))
|
|
|
|
/**
|
|
* A filter function to control the scanning of dynamic libraries.
|
|
* If implemented, called by the collector before registering a dynamic
|
|
* library (discovered by the collector) section as a static data root
|
|
* (called only as a last reason not to register). The filename
|
|
* (`dlpi_name`) of the library, the address and the length of the
|
|
* memory region (section) are passed. This routine should return
|
|
* a nonzero value if that region should be scanned. Always called
|
|
* with the allocator lock held. Depending on the platform, might be
|
|
* called with the world stopped.
|
|
*/
|
|
typedef int(GC_CALLBACK *GC_has_static_roots_func)(
|
|
const char * /* `dlpi_name` */, void * /* `section_start` */,
|
|
size_t /* `section_size` */);
|
|
|
|
/**
|
|
* Register a new callback (a user-supplied filter) to control the
|
|
* scanning of dynamic libraries. Replaces any previously registered
|
|
* callback. May be 0 (means no filtering). May be unused on some
|
|
* platforms (if the filtering is unimplemented or inappropriate).
|
|
*/
|
|
GC_API void
|
|
GC_CALL GC_register_has_static_roots_callback(GC_has_static_roots_func);
|
|
|
|
#if !defined(CPPCHECK) && !defined(GC_WINDOWS_H_INCLUDED) && defined(WINAPI)
|
|
/* Platform `windows.h` file is included before `gc.h` file. */
|
|
# define GC_WINDOWS_H_INCLUDED
|
|
#endif
|
|
|
|
#if defined(GC_WIN32_THREADS) \
|
|
&& (!defined(GC_PTHREADS) || defined(GC_BUILD) \
|
|
|| defined(GC_WINDOWS_H_INCLUDED))
|
|
/*
|
|
* Note: for Cygwin and pthreads-win32, this is skipped unless platform
|
|
* `windows.h` file is included before `gc.h` file.
|
|
*/
|
|
|
|
# if (!defined(GC_NO_THREAD_DECLS) || defined(GC_BUILD)) \
|
|
&& !defined(GC_DONT_INCL_WINDOWS_H)
|
|
|
|
/*
|
|
* Including platform `windows.h` file in an `extern "C"` context
|
|
* no longer works.
|
|
*/
|
|
# ifdef __cplusplus
|
|
}
|
|
# endif
|
|
|
|
# if !defined(_WIN32_WCE) && !defined(__CEGCC__)
|
|
# include <process.h> /* for `_beginthreadex`, `_endthreadex` */
|
|
# endif
|
|
|
|
# if defined(GC_BUILD) || !defined(GC_DONT_INCLUDE_WINDOWS_H)
|
|
# include <windows.h>
|
|
# define GC_WINDOWS_H_INCLUDED
|
|
# endif
|
|
|
|
# ifdef __cplusplus
|
|
extern "C" {
|
|
# endif
|
|
|
|
# ifdef GC_UNDERSCORE_STDCALL
|
|
/*
|
|
* Explicitly prefix exported/imported WINAPI (`__stdcall`) symbols
|
|
* with "_" (underscore). Might be useful if MinGW/x86 is used.
|
|
*/
|
|
# define GC_CreateThread _GC_CreateThread
|
|
# define GC_ExitThread _GC_ExitThread
|
|
# endif
|
|
|
|
# ifndef DECLSPEC_NORETURN
|
|
/* Typically defined in platform `winnt.h` file. */
|
|
# ifdef GC_WINDOWS_H_INCLUDED
|
|
# define DECLSPEC_NORETURN /*< empty */
|
|
# else
|
|
# define DECLSPEC_NORETURN GC_ATTR_NORETURN
|
|
# endif
|
|
# endif
|
|
|
|
# ifdef _WIN64
|
|
# define GC_WIN32_SIZE_T GC_uintptr_t
|
|
# elif defined(GC_WINDOWS_H_INCLUDED)
|
|
# define GC_WIN32_SIZE_T DWORD
|
|
# else
|
|
# define GC_WIN32_SIZE_T unsigned long
|
|
# endif
|
|
|
|
# ifdef GC_INSIDE_DLL
|
|
/* Export GC `DllMain()` to be invoked from the client `DllMain`. */
|
|
# ifdef GC_UNDERSCORE_STDCALL
|
|
# define GC_DllMain _GC_DllMain
|
|
# endif
|
|
# ifdef GC_WINDOWS_H_INCLUDED
|
|
GC_API BOOL WINAPI GC_DllMain(HINSTANCE /* `inst` */, ULONG /* `reason` */,
|
|
LPVOID /* `reserved` */);
|
|
# else
|
|
GC_API int __stdcall GC_DllMain(void *, unsigned long, void *);
|
|
# endif
|
|
# endif /* GC_INSIDE_DLL */
|
|
|
|
/*
|
|
* All threads must be created using `GC_CreateThread` or
|
|
* `GC_beginthreadex`, or must explicitly call `GC_register_my_thread`
|
|
* (and call `GC_unregister_my_thread` before thread termination), so
|
|
* that they will be recorded in the thread table. For backward
|
|
* compatibility, it is possible to build the collector with `GC_DLL`
|
|
* macro defined, and to call `GC_use_threads_discovery()`.
|
|
* This implicitly registers all created threads, but appears to be
|
|
* less robust. Currently the collector expects all threads to fall
|
|
* through and terminate normally, or call `GC_endthreadex` or
|
|
* `GC_ExitThread`, so that the thread is properly unregistered.
|
|
*/
|
|
# ifdef GC_WINDOWS_H_INCLUDED
|
|
GC_API HANDLE WINAPI GC_CreateThread(
|
|
LPSECURITY_ATTRIBUTES /* `lpThreadAttributes` */,
|
|
GC_WIN32_SIZE_T /* `dwStackSize` */,
|
|
LPTHREAD_START_ROUTINE /* `lpStartAddress` */, LPVOID /* `lpParameter` */,
|
|
DWORD /* `dwCreationFlags` */, LPDWORD /* `lpThreadId` */);
|
|
|
|
GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(DWORD /* `dwExitCode` */);
|
|
# else
|
|
struct _SECURITY_ATTRIBUTES;
|
|
GC_API void *__stdcall GC_CreateThread(struct _SECURITY_ATTRIBUTES *,
|
|
GC_WIN32_SIZE_T,
|
|
unsigned long(__stdcall *)(void *),
|
|
void *, unsigned long, unsigned long *);
|
|
GC_API DECLSPEC_NORETURN void __stdcall GC_ExitThread(unsigned long);
|
|
# endif
|
|
|
|
# if !defined(_WIN32_WCE) && !defined(__CEGCC__)
|
|
GC_API GC_uintptr_t GC_CALL GC_beginthreadex(void * /* `security` */,
|
|
unsigned /* `stack_size` */,
|
|
unsigned(__stdcall *)(void *),
|
|
void * /* `arglist` */,
|
|
unsigned /* `initflag` */,
|
|
unsigned * /* `thrdaddr` */);
|
|
|
|
/*
|
|
* Note: `_endthreadex()` is not currently marked as `noreturn` in VC++
|
|
* and MinGW headers, so we do not mark it neither.
|
|
*/
|
|
GC_API void GC_CALL GC_endthreadex(unsigned /* `retval` */);
|
|
# endif /* !_WIN32_WCE */
|
|
|
|
# endif /* !GC_NO_THREAD_DECLS */
|
|
|
|
# ifdef GC_WINMAIN_REDIRECT
|
|
/*
|
|
* The collector provides the real `WinMain()`, which starts a new thread
|
|
* to call `GC_WinMain()` after initializing the collector.
|
|
*/
|
|
# define WinMain GC_WinMain
|
|
# endif
|
|
|
|
/* For compatibility only. */
|
|
# define GC_use_DllMain GC_use_threads_discovery
|
|
|
|
# ifndef GC_NO_THREAD_REDIRECTS
|
|
# define CreateThread GC_CreateThread
|
|
# define ExitThread GC_ExitThread
|
|
# undef _beginthreadex
|
|
# define _beginthreadex GC_beginthreadex
|
|
# undef _endthreadex
|
|
# define _endthreadex GC_endthreadex
|
|
/* `#define _beginthread { "Use _beginthreadex instead of _beginthread" }` */
|
|
# endif /* !GC_NO_THREAD_REDIRECTS */
|
|
|
|
#endif /* GC_WIN32_THREADS */
|
|
|
|
/**
|
|
* The setter and the getter for switching "unmap as much as possible"
|
|
* mode on(1) and off(0). Has no effect unless unmapping is turned on.
|
|
* Initial value is controlled by `GC_FORCE_UNMAP_ON_GCOLLECT` macro.
|
|
* The setter and the getter are unsynchronized.
|
|
*/
|
|
GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int);
|
|
GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
|
|
|
|
/*
|
|
* Fully portable code should call `GC_INIT()` from the main program
|
|
* before making any other `GC_` calls. On most platforms this is
|
|
* a no-op and the collector self-initializes. But a number of
|
|
* platforms make that too hard. A `GC_INIT()` call is required if the
|
|
* collector is built with `THREAD_LOCAL_ALLOC` macro defined and the
|
|
* initial allocation call is not to `GC_malloc` or `GC_malloc_atomic`.
|
|
*/
|
|
|
|
#if defined(__CYGWIN32__) || defined(__CYGWIN__)
|
|
/*
|
|
* Similarly gnu-win32 DLLs need explicit initialization from the
|
|
* main program, as does AIX.
|
|
*/
|
|
# ifdef __x86_64__
|
|
/* Cygwin/x86_64 does not add leading underscore to symbols anymore. */
|
|
extern int __data_start__[], __data_end__[];
|
|
extern int __bss_start__[], __bss_end__[];
|
|
# define GC_DATASTART \
|
|
(GC_ADDR_LT((char *)__data_start__, (char *)__bss_start__) \
|
|
? (void *)__data_start__ \
|
|
: (void *)__bss_start__)
|
|
# define GC_DATAEND \
|
|
(GC_ADDR_LT((char *)__bss_end__, (char *)__data_end__) \
|
|
? (void *)__data_end__ \
|
|
: (void *)__bss_end__)
|
|
# else
|
|
extern int _data_start__[], _data_end__[], _bss_start__[], _bss_end__[];
|
|
# define GC_DATASTART \
|
|
(GC_ADDR_LT((char *)_data_start__, (char *)_bss_start__) \
|
|
? (void *)_data_start__ \
|
|
: (void *)_bss_start__)
|
|
# define GC_DATAEND \
|
|
(GC_ADDR_LT((char *)_bss_end__, (char *)_data_end__) \
|
|
? (void *)_data_end__ \
|
|
: (void *)_bss_end__)
|
|
# endif /* !__x86_64__ */
|
|
/*
|
|
* This is required at least if the collector is in a DLL; and does not
|
|
* hurt.
|
|
*/
|
|
# define GC_INIT_CONF_ROOTS \
|
|
GC_add_roots(GC_DATASTART, GC_DATAEND); \
|
|
GC_gcollect() /*< for black-listing */
|
|
#elif defined(_AIX)
|
|
extern int _data[], _end[];
|
|
# define GC_DATASTART ((void *)_data)
|
|
# define GC_DATAEND ((void *)_end)
|
|
# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
|
|
#elif (defined(HOST_ANDROID) || defined(__ANDROID__)) \
|
|
&& defined(IGNORE_DYNAMIC_LOADING)
|
|
/*
|
|
* This is ugly but seems the only way to register data roots of the
|
|
* client shared library if the GC dynamic loading support is off.
|
|
*/
|
|
# pragma weak __dso_handle
|
|
extern int __dso_handle[];
|
|
GC_API void *GC_CALL GC_find_limit(void * /* `start` */, int /* `up` */);
|
|
# define GC_INIT_CONF_ROOTS \
|
|
(void)(__dso_handle != 0 \
|
|
? (GC_add_roots(__dso_handle, \
|
|
GC_find_limit(__dso_handle, 1 /* `up` */)), \
|
|
0) \
|
|
: 0)
|
|
#else
|
|
# define GC_INIT_CONF_ROOTS (void)0
|
|
#endif
|
|
|
|
#ifdef GC_DONT_EXPAND
|
|
/* Set `GC_dont_expand` to true at start-up. */
|
|
# define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1)
|
|
#else
|
|
# define GC_INIT_CONF_DONT_EXPAND (void)0
|
|
#endif
|
|
|
|
#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
|
|
/* Turn on "unmap as much as possible on explicit GC" mode at start-up. */
|
|
# define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT \
|
|
GC_set_force_unmap_on_gcollect(1)
|
|
#else
|
|
# define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT (void)0
|
|
#endif
|
|
|
|
#ifdef GC_DONT_GC
|
|
/*
|
|
* This is for debugging only (useful if environment variables are
|
|
* unsupported); cannot call `GC_disable()` as goes before the
|
|
* collector initialization.
|
|
*/
|
|
# define GC_INIT_CONF_MAX_RETRIES (void)(GC_dont_gc = 1)
|
|
#elif defined(GC_MAX_RETRIES) && !defined(CPPCHECK)
|
|
/* Set `GC_max_retries` to the desired value at start-up. */
|
|
# define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES)
|
|
#else
|
|
# define GC_INIT_CONF_MAX_RETRIES (void)0
|
|
#endif
|
|
|
|
#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK)
|
|
/* Set `GC_allocd_bytes_per_finalizer` to the desired value at start-up. */
|
|
# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER \
|
|
GC_set_allocd_bytes_per_finalizer(GC_ALLOCD_BYTES_PER_FINALIZER)
|
|
#else
|
|
# define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER (void)0
|
|
#endif
|
|
|
|
#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
|
|
/* Set `GC_free_space_divisor` to the desired value at start-up. */
|
|
# define GC_INIT_CONF_FREE_SPACE_DIVISOR \
|
|
GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR)
|
|
#else
|
|
# define GC_INIT_CONF_FREE_SPACE_DIVISOR (void)0
|
|
#endif
|
|
|
|
#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
|
|
/* Set `GC_full_freq` to the desired value at start-up. */
|
|
# define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ)
|
|
#else
|
|
# define GC_INIT_CONF_FULL_FREQ (void)0
|
|
#endif
|
|
|
|
#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
|
|
/* Set `GC_time_limit` (in ms) to the desired value at start-up. */
|
|
# define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
|
|
#else
|
|
# define GC_INIT_CONF_TIME_LIMIT (void)0
|
|
#endif
|
|
|
|
#if defined(GC_MARKERS) && defined(GC_THREADS) && !defined(CPPCHECK)
|
|
/*
|
|
* Set the number of marker threads (including the initiating one) to
|
|
* the desired value at start-up.
|
|
*/
|
|
# define GC_INIT_CONF_MARKERS GC_set_markers_count(GC_MARKERS)
|
|
#else
|
|
# define GC_INIT_CONF_MARKERS (void)0
|
|
#endif
|
|
|
|
#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS) && !defined(CPPCHECK)
|
|
# define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND)
|
|
#else
|
|
# define GC_INIT_CONF_SUSPEND_SIGNAL (void)0
|
|
#endif
|
|
|
|
#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS) && !defined(CPPCHECK)
|
|
# define GC_INIT_CONF_THR_RESTART_SIGNAL \
|
|
GC_set_thr_restart_signal(GC_SIG_THR_RESTART)
|
|
#else
|
|
# define GC_INIT_CONF_THR_RESTART_SIGNAL (void)0
|
|
#endif
|
|
|
|
#if defined(GC_MAXIMUM_HEAP_SIZE) && !defined(CPPCHECK)
|
|
/*
|
|
* Limit the heap size to the desired value (useful for debugging).
|
|
* The limit could be overridden either at the program start-up by
|
|
* the similar environment variable or anytime later by the corresponding
|
|
* API function call.
|
|
*/
|
|
# define GC_INIT_CONF_MAXIMUM_HEAP_SIZE \
|
|
GC_set_max_heap_size(GC_MAXIMUM_HEAP_SIZE)
|
|
#else
|
|
# define GC_INIT_CONF_MAXIMUM_HEAP_SIZE (void)0
|
|
#endif
|
|
|
|
#ifdef GC_IGNORE_WARN
|
|
/* Turn off all warnings at start-up (after the collector initialization). */
|
|
# define GC_INIT_CONF_IGNORE_WARN GC_set_warn_proc(GC_ignore_warn_proc)
|
|
#else
|
|
# define GC_INIT_CONF_IGNORE_WARN (void)0
|
|
#endif
|
|
|
|
#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK)
|
|
/* Set heap size to the desired value at start-up. */
|
|
# define GC_INIT_CONF_INITIAL_HEAP_SIZE \
|
|
{ \
|
|
size_t heap_size = GC_get_heap_size(); \
|
|
if (heap_size < (size_t)(GC_INITIAL_HEAP_SIZE)) \
|
|
(void)GC_expand_hp(((size_t)(GC_INITIAL_HEAP_SIZE)) - heap_size); \
|
|
}
|
|
#else
|
|
# define GC_INIT_CONF_INITIAL_HEAP_SIZE (void)0
|
|
#endif
|
|
|
|
/**
|
|
* Portable clients should call this at the program start-up.
|
|
* More over, some platforms require this call to be done strictly from
|
|
* the primordial thread. Multiple invocations are harmless.
|
|
*/
|
|
#define GC_INIT() \
|
|
{ \
|
|
GC_INIT_CONF_DONT_EXPAND; /*< pre-init */ \
|
|
GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \
|
|
GC_INIT_CONF_MAX_RETRIES; \
|
|
GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER; \
|
|
GC_INIT_CONF_FREE_SPACE_DIVISOR; \
|
|
GC_INIT_CONF_FULL_FREQ; \
|
|
GC_INIT_CONF_TIME_LIMIT; \
|
|
GC_INIT_CONF_MARKERS; \
|
|
GC_INIT_CONF_SUSPEND_SIGNAL; \
|
|
GC_INIT_CONF_THR_RESTART_SIGNAL; \
|
|
GC_INIT_CONF_MAXIMUM_HEAP_SIZE; \
|
|
GC_init(); /*< real GC initialization */ \
|
|
GC_INIT_CONF_ROOTS; /*< post-init */ \
|
|
GC_INIT_CONF_IGNORE_WARN; \
|
|
GC_INIT_CONF_INITIAL_HEAP_SIZE; \
|
|
}
|
|
|
|
/**
|
|
* win32s may not free all resources on process exit.
|
|
* This explicitly deallocates the heap. Defined only for Windows.
|
|
*/
|
|
GC_API void GC_CALL GC_win32_free_heap(void);
|
|
|
|
#if defined(__SYMBIAN32__)
|
|
GC_API void GC_CALL GC_init_global_static_roots(void);
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* GC_H */
|