Files

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 */