Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
* All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
#ifndef GC_DARWIN_SEMAPHORE_H
#define GC_DARWIN_SEMAPHORE_H
#if !defined(GC_DARWIN_THREADS)
# error darwin_semaphore.h included with GC_DARWIN_THREADS not defined
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* This is a very simple semaphore implementation for Darwin. It is */
/* implemented in terms of pthread calls so it is not async signal */
/* safe. But this is not a problem because signals are not used to */
/* suspend threads on Darwin. */
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int value;
} sem_t;
GC_INLINE int sem_init(sem_t *sem, int pshared, int value) {
if (pshared != 0) {
errno = EPERM; /* unsupported */
return -1;
}
sem->value = value;
if (pthread_mutex_init(&sem->mutex, NULL) != 0)
return -1;
if (pthread_cond_init(&sem->cond, NULL) != 0) {
(void)pthread_mutex_destroy(&sem->mutex);
return -1;
}
return 0;
}
GC_INLINE int sem_post(sem_t *sem) {
if (pthread_mutex_lock(&sem->mutex) != 0)
return -1;
sem->value++;
if (pthread_cond_signal(&sem->cond) != 0) {
(void)pthread_mutex_unlock(&sem->mutex);
return -1;
}
return pthread_mutex_unlock(&sem->mutex) != 0 ? -1 : 0;
}
GC_INLINE int sem_wait(sem_t *sem) {
if (pthread_mutex_lock(&sem->mutex) != 0)
return -1;
while (sem->value == 0) {
if (pthread_cond_wait(&sem->cond, &sem->mutex) != 0) {
(void)pthread_mutex_unlock(&sem->mutex);
return -1;
}
}
sem->value--;
return pthread_mutex_unlock(&sem->mutex) != 0 ? -1 : 0;
}
GC_INLINE int sem_destroy(sem_t *sem) {
return pthread_cond_destroy(&sem->cond) != 0
|| pthread_mutex_destroy(&sem->mutex) != 0 ? -1 : 0;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
* All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
#ifndef GC_DARWIN_STOP_WORLD_H
#define GC_DARWIN_STOP_WORLD_H
#if !defined(GC_DARWIN_THREADS)
# error darwin_stop_world.h included without GC_DARWIN_THREADS defined
#endif
#include <mach/mach.h>
#include <mach/thread_act.h>
EXTERN_C_BEGIN
struct thread_stop_info {
mach_port_t mach_thread;
ptr_t stack_ptr; /* Valid only when thread is in a "blocked" state. */
};
#ifndef DARWIN_DONT_PARSE_STACK
GC_INNER ptr_t GC_FindTopOfStack(unsigned long);
#endif
#ifdef MPROTECT_VDB
GC_INNER void GC_mprotect_stop(void);
GC_INNER void GC_mprotect_resume(void);
# ifndef GC_NO_THREADS_DISCOVERY
GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
# endif
#endif
#if defined(PARALLEL_MARK) && !defined(GC_NO_THREADS_DISCOVERY)
GC_INNER GC_bool GC_is_mach_marker(thread_act_t);
#endif
EXTERN_C_END
#endif

182
external/bdwgc/include/private/dbg_mlc.h vendored Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright (c) 1997 by Silicon Graphics. All rights reserved.
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/*
* This is mostly an internal header file. Typical clients should
* not use it. Clients that define their own object kinds with
* debugging allocators will probably want to include this, however.
* No attempt is made to keep the namespace clean. This should not be
* included from header files that are frequently included by clients.
*/
#ifndef _DBG_MLC_H
#define _DBG_MLC_H
#include "gc_priv.h"
#ifdef KEEP_BACK_PTRS
# include "gc_backptr.h"
#endif
EXTERN_C_BEGIN
#if CPP_WORDSZ == 32
# define START_FLAG (word)0xfedcedcb
# define END_FLAG (word)0xbcdecdef
#else
# define START_FLAG GC_WORD_C(0xFEDCEDCBfedcedcb)
# define END_FLAG GC_WORD_C(0xBCDECDEFbcdecdef)
#endif
/* Stored both one past the end of user object, and one before */
/* the end of the object as seen by the allocator. */
#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \
|| defined(MAKE_BACK_GRAPH)
/* Pointer "source"s that aren't real locations. */
/* Used in oh_back_ptr fields and as "source" */
/* argument to some marking functions. */
# define NOT_MARKED (ptr_t)0
# define MARKED_FOR_FINALIZATION ((ptr_t)(word)2)
/* Object was marked because it is finalizable. */
# define MARKED_FROM_REGISTER ((ptr_t)(word)4)
/* Object was marked from a register. Hence the */
/* source of the reference doesn't have an address. */
#endif /* KEEP_BACK_PTRS || PRINT_BLACK_LIST */
/* Object header */
typedef struct {
# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
/* We potentially keep two different kinds of back */
/* pointers. KEEP_BACK_PTRS stores a single back */
/* pointer in each reachable object to allow reporting */
/* of why an object was retained. MAKE_BACK_GRAPH */
/* builds a graph containing the inverse of all */
/* "points-to" edges including those involving */
/* objects that have just become unreachable. This */
/* allows detection of growing chains of unreachable */
/* objects. It may be possible to eventually combine */
/* both, but for now we keep them separate. Both */
/* kinds of back pointers are hidden using the */
/* following macros. In both cases, the plain version */
/* is constrained to have an least significant bit of 1, */
/* to allow it to be distinguished from a free list */
/* link. This means the plain version must have an */
/* lsb of 0. */
/* Note that blocks dropped by black-listing will */
/* also have the lsb clear once debugging has */
/* started. */
/* We're careful never to overwrite a value with lsb 0. */
# if ALIGNMENT == 1
/* Fudge back pointer to be even. */
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (word)(p))
# else
# define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
# endif
# ifdef KEEP_BACK_PTRS
GC_hidden_pointer oh_back_ptr;
# endif
# ifdef MAKE_BACK_GRAPH
GC_hidden_pointer oh_bg_ptr;
# endif
# if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)
/* Keep double-pointer-sized alignment. */
word oh_dummy;
# endif
# endif
const char * oh_string; /* object descriptor string */
word oh_int; /* object descriptor integers */
# ifdef NEED_CALLINFO
struct callinfo oh_ci[NFRAMES];
# endif
# ifndef SHORT_DBG_HDRS
word oh_sz; /* Original malloc arg. */
word oh_sf; /* start flag */
# endif /* SHORT_DBG_HDRS */
} oh;
/* The size of the above structure is assumed not to de-align things, */
/* and to be a multiple of the word length. */
#ifdef SHORT_DBG_HDRS
# define DEBUG_BYTES (sizeof (oh))
# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
#else
/* Add space for END_FLAG, but use any extra space that was already */
/* added to catch off-the-end pointers. */
/* For uncollectible objects, the extra byte is not added. */
# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
#endif
/* Round bytes to words without adding extra byte at end. */
#define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
/* ADD_CALL_CHAIN stores a (partial) call chain into an object */
/* header; it should be called with the allocation lock held. */
/* PRINT_CALL_CHAIN prints the call chain stored in an object */
/* to stderr. It requires that we do not hold the lock. */
#if defined(SAVE_CALL_CHAIN)
struct callinfo;
GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
#elif defined(GC_ADD_CALLER)
struct callinfo;
GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
#else
# define ADD_CALL_CHAIN(base, ra)
# define PRINT_CALL_CHAIN(base)
#endif
#ifdef GC_ADD_CALLER
# define OPT_RA ra,
#else
# define OPT_RA
#endif
/* Check whether object with base pointer p has debugging info */
/* p is assumed to point to a legitimate object in our part */
/* of the heap. */
#ifdef SHORT_DBG_HDRS
# define GC_has_other_debug_info(p) 1
#else
GC_INNER int GC_has_other_debug_info(ptr_t p);
#endif
#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
# ifdef SHORT_DBG_HDRS
# error Non-ptr stored in object results in GC_HAS_DEBUG_INFO malfunction
/* We may mistakenly conclude that p has a debugging wrapper. */
# endif
# if defined(PARALLEL_MARK) && defined(KEEP_BACK_PTRS)
# define GC_HAS_DEBUG_INFO(p) \
((AO_load((volatile AO_t *)(p)) & 1) != 0 \
&& GC_has_other_debug_info(p) > 0)
/* Atomic load is used as GC_store_back_pointer */
/* stores oh_back_ptr atomically (p might point */
/* to the field); this prevents a TSan warning. */
# else
# define GC_HAS_DEBUG_INFO(p) \
((*(word *)(p) & 1) && GC_has_other_debug_info(p) > 0)
# endif
#else
# define GC_HAS_DEBUG_INFO(p) (GC_has_other_debug_info(p) > 0)
#endif /* !KEEP_BACK_PTRS && !MAKE_BACK_GRAPH */
EXTERN_C_END
#endif /* _DBG_MLC_H */

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2017 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.
*/
/* This is a private GC header which provides an implementation of */
/* libatomic_ops subset primitives sufficient for GC assuming that C11 */
/* atomic intrinsics are available (and have correct implementation). */
/* This is enabled by defining GC_BUILTIN_ATOMIC macro. Otherwise, */
/* libatomic_ops library is used to define the primitives. */
#ifndef GC_ATOMIC_OPS_H
#define GC_ATOMIC_OPS_H
#ifdef GC_BUILTIN_ATOMIC
# include "gc.h" /* for GC_word */
# ifdef __cplusplus
extern "C" {
# endif
typedef GC_word AO_t;
# ifdef GC_PRIVATE_H /* have GC_INLINE */
# define AO_INLINE GC_INLINE
# else
# define AO_INLINE static __inline
# endif
typedef unsigned char AO_TS_t;
# define AO_TS_CLEAR 0
# define AO_TS_INITIALIZER (AO_TS_t)AO_TS_CLEAR
# if defined(__GCC_ATOMIC_TEST_AND_SET_TRUEVAL) && !defined(CPPCHECK)
# define AO_TS_SET __GCC_ATOMIC_TEST_AND_SET_TRUEVAL
# else
# define AO_TS_SET (AO_TS_t)1 /* true */
# endif
# define AO_CLEAR(p) __atomic_clear(p, __ATOMIC_RELEASE)
# define AO_test_and_set_acquire(p) __atomic_test_and_set(p, __ATOMIC_ACQUIRE)
# define AO_HAVE_test_and_set_acquire
# define AO_compiler_barrier() __atomic_signal_fence(__ATOMIC_SEQ_CST)
# define AO_nop_full() __atomic_thread_fence(__ATOMIC_SEQ_CST)
# define AO_HAVE_nop_full
# define AO_fetch_and_add(p, v) __atomic_fetch_add(p, v, __ATOMIC_RELAXED)
# define AO_HAVE_fetch_and_add
# define AO_fetch_and_add1(p) AO_fetch_and_add(p, 1)
# define AO_HAVE_fetch_and_add1
# define AO_or(p, v) (void)__atomic_or_fetch(p, v, __ATOMIC_RELAXED)
# define AO_HAVE_or
# define AO_load(p) __atomic_load_n(p, __ATOMIC_RELAXED)
# define AO_HAVE_load
# define AO_load_acquire(p) __atomic_load_n(p, __ATOMIC_ACQUIRE)
# define AO_HAVE_load_acquire
# define AO_load_acquire_read(p) AO_load_acquire(p)
# define AO_HAVE_load_acquire_read
# define AO_store(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
# define AO_HAVE_store
# define AO_store_release(p, v) __atomic_store_n(p, v, __ATOMIC_RELEASE)
# define AO_HAVE_store_release
# define AO_store_release_write(p, v) AO_store_release(p, v)
# define AO_HAVE_store_release_write
# define AO_char_load(p) __atomic_load_n(p, __ATOMIC_RELAXED)
# define AO_HAVE_char_load
# define AO_char_store(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
# define AO_HAVE_char_store
# ifdef AO_REQUIRE_CAS
AO_INLINE int
AO_compare_and_swap(volatile AO_t *p, AO_t ov, AO_t nv)
{
return (int)__atomic_compare_exchange_n(p, &ov, nv, 0,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
}
AO_INLINE int
AO_compare_and_swap_release(volatile AO_t *p, AO_t ov, AO_t nv)
{
return (int)__atomic_compare_exchange_n(p, &ov, nv, 0,
__ATOMIC_RELEASE, __ATOMIC_RELAXED);
}
# define AO_HAVE_compare_and_swap_release
# endif
# ifdef __cplusplus
} /* extern "C" */
# endif
#elif !defined(NN_PLATFORM_CTR)
/* Fallback to libatomic_ops. */
# include "atomic_ops.h"
/* AO_compiler_barrier, AO_load and AO_store should be defined for */
/* all targets; the rest of the primitives are guaranteed to exist */
/* only if AO_REQUIRE_CAS is defined (or if the corresponding */
/* AO_HAVE_x macro is defined). x86/x64 targets have AO_nop_full, */
/* AO_load_acquire, AO_store_release, at least. */
# if !defined(AO_HAVE_load) || !defined(AO_HAVE_store)
# error AO_load or AO_store is missing; probably old version of atomic_ops
# endif
#endif /* !GC_BUILTIN_ATOMIC */
#endif /* GC_ATOMIC_OPS_H */

214
external/bdwgc/include/private/gc_hdrs.h vendored Normal file
View File

@@ -0,0 +1,214 @@
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
#ifndef GC_HEADERS_H
#define GC_HEADERS_H
#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
# error Get a real machine
#endif
EXTERN_C_BEGIN
typedef struct hblkhdr hdr;
/*
* The 2 level tree data structure that is used to find block headers.
* If there are more than 32 bits in a pointer, the top level is a hash
* table.
*
* This defines HDR, GET_HDR, and SET_HDR, the main macros used to
* retrieve and set object headers.
*
* We take advantage of a header lookup
* cache. This is a locally declared direct mapped cache, used inside
* the marker. The HC_GET_HDR macro uses and maintains this
* cache. Assuming we get reasonable hit rates, this shaves a few
* memory references from each pointer validation.
*/
#if CPP_WORDSZ > 32
# define HASH_TL
#endif
/* Define appropriate out-degrees for each of the two tree levels */
#if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG)
# define LOG_BOTTOM_SZ 10
#else
# define LOG_BOTTOM_SZ 11
/* Keep top index size reasonable with smaller blocks. */
#endif
#define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
#ifndef HASH_TL
# define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
#else
# define LOG_TOP_SZ 11
#endif
#define TOP_SZ (1 << LOG_TOP_SZ)
/* #define COUNT_HDR_CACHE_HITS */
#ifdef COUNT_HDR_CACHE_HITS
extern word GC_hdr_cache_hits; /* used for debugging/profiling */
extern word GC_hdr_cache_misses;
# define HC_HIT() ++GC_hdr_cache_hits
# define HC_MISS() ++GC_hdr_cache_misses
#else
# define HC_HIT()
# define HC_MISS()
#endif
typedef struct hce {
word block_addr; /* right shifted by LOG_HBLKSIZE */
hdr * hce_hdr;
} hdr_cache_entry;
#define HDR_CACHE_SIZE 8 /* power of 2 */
#define DECLARE_HDR_CACHE \
hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
#define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache))
#define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1))
#define HCE_VALID_FOR(hce,h) ((hce) -> block_addr == \
((word)(h) >> LOG_HBLKSIZE))
#define HCE_HDR(h) ((hce) -> hce_hdr)
#ifdef PRINT_BLACK_LIST
GC_INNER hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce,
ptr_t source);
# define HEADER_CACHE_MISS(p, hce, source) \
GC_header_cache_miss(p, hce, source)
#else
GC_INNER hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce);
# define HEADER_CACHE_MISS(p, hce, source) GC_header_cache_miss(p, hce)
#endif
/* Set hhdr to the header for p. Analogous to GET_HDR below, */
/* except that in the case of large objects, it gets the header for */
/* the object beginning if GC_all_interior_pointers is set. */
/* Returns zero if p points to somewhere other than the first page */
/* of an object, and it is not a valid pointer to the object. */
#define HC_GET_HDR(p, hhdr, source) \
{ /* cannot use do-while(0) here */ \
hdr_cache_entry * hce = HCE(p); \
if (EXPECT(HCE_VALID_FOR(hce, p), TRUE)) { \
HC_HIT(); \
hhdr = hce -> hce_hdr; \
} else { \
hhdr = HEADER_CACHE_MISS(p, hce, source); \
if (NULL == hhdr) break; /* go to the enclosing loop end */ \
} \
}
typedef struct bi {
hdr * index[BOTTOM_SZ];
/*
* The bottom level index contains one of three kinds of values:
* 0 means we're not responsible for this block,
* or this is a block other than the first one in a free block.
* 1 < (long)X <= MAX_JUMP means the block starts at least
* X * HBLKSIZE bytes before the current address.
* A valid pointer points to a hdr structure. (The above can't be
* valid pointers due to the GET_MEM return convention.)
*/
struct bi * asc_link; /* All indices are linked in */
/* ascending order... */
struct bi * desc_link; /* ... and in descending order. */
word key; /* high order address bits. */
# ifdef HASH_TL
struct bi * hash_link; /* Hash chain link. */
# endif
} bottom_index;
/* bottom_index GC_all_nils; - really part of GC_arrays */
/* extern bottom_index * GC_top_index []; - really part of GC_arrays */
/* Each entry points to a bottom_index. */
/* On a 32 bit machine, it points to */
/* the index for a set of high order */
/* bits equal to the index. For longer */
/* addresses, we hash the high order */
/* bits to compute the index in */
/* GC_top_index, and each entry points */
/* to a hash chain. */
/* The last entry in each chain is */
/* GC_all_nils. */
#define MAX_JUMP (HBLKSIZE - 1)
#define HDR_FROM_BI(bi, p) \
((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
#ifndef HASH_TL
# define BI(p) (GC_top_index \
[(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
# define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
# ifdef SMALL_CONFIG
# define HDR(p) GC_find_header((ptr_t)(p))
# else
# define HDR(p) HDR_INNER(p)
# endif
# define GET_BI(p, bottom_indx) (void)((bottom_indx) = BI(p))
# define GET_HDR(p, hhdr) (void)((hhdr) = HDR(p))
# define SET_HDR(p, hhdr) (void)(HDR_INNER(p) = (hhdr))
# define GET_HDR_ADDR(p, ha) (void)((ha) = &HDR_INNER(p))
#else /* hash */
/* Hash function for tree top level */
# define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
/* Set bottom_indx to point to the bottom index for address p */
# define GET_BI(p, bottom_indx) \
do { \
REGISTER word hi = (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
REGISTER bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
while (_bi -> key != hi && _bi != GC_all_nils) \
_bi = _bi -> hash_link; \
(bottom_indx) = _bi; \
} while (0)
# define GET_HDR_ADDR(p, ha) \
do { \
REGISTER bottom_index * bi; \
GET_BI(p, bi); \
(ha) = &HDR_FROM_BI(bi, p); \
} while (0)
# define GET_HDR(p, hhdr) \
do { \
REGISTER hdr ** _ha; \
GET_HDR_ADDR(p, _ha); \
(hhdr) = *_ha; \
} while (0)
# define SET_HDR(p, hhdr) \
do { \
REGISTER hdr ** _ha; \
GET_HDR_ADDR(p, _ha); \
*_ha = (hhdr); \
} while (0)
# define HDR(p) GC_find_header((ptr_t)(p))
#endif
/* Is the result a forwarding address to someplace closer to the */
/* beginning of the block or NULL? */
#define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((size_t) (hhdr) <= MAX_JUMP)
/* Get an HBLKSIZE aligned address closer to the beginning of the block */
/* h. Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr). */
#define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (size_t)(hhdr))
EXTERN_C_END
#endif /* GC_HEADERS_H */

View File

@@ -0,0 +1,292 @@
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 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.
*
*
* 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.
*/
#ifndef GC_LOCKS_H
#define GC_LOCKS_H
/*
* Mutual exclusion between allocator/collector routines.
* Needed if there is more than one allocator thread.
* DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK.
*
* Note that I_HOLD_LOCK and I_DONT_HOLD_LOCK are used only positively
* in assertions, and may return TRUE in the "don't know" case.
*/
# ifdef THREADS
# ifdef PCR
# include <base/PCR_Base.h>
# include <th/PCR_Th.h>
# endif
EXTERN_C_BEGIN
# ifdef PCR
GC_EXTERN PCR_Th_ML GC_allocate_ml;
# if defined(CPPCHECK)
# define DCL_LOCK_STATE /* empty */
# else
# define DCL_LOCK_STATE \
PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
# endif
# define UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
# define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
# endif
# if (!defined(AO_HAVE_test_and_set_acquire) || defined(GC_RTEMS_PTHREADS) \
|| defined(SN_TARGET_ORBIS) || defined(SN_TARGET_PS3) \
|| defined(GC_WIN32_THREADS) || defined(LINT2)) && defined(GC_PTHREADS)
# define USE_PTHREAD_LOCKS
# undef USE_SPIN_LOCK
# endif
# if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
# endif
# define NOSERVICE
EXTERN_C_END
# include <windows.h>
EXTERN_C_BEGIN
# define NO_THREAD (DWORD)(-1)
GC_EXTERN CRITICAL_SECTION GC_allocate_ml;
# ifdef GC_ASSERTIONS
GC_EXTERN DWORD GC_lock_holder;
# define SET_LOCK_HOLDER() GC_lock_holder = GetCurrentThreadId()
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
# define I_HOLD_LOCK() (!GC_need_to_lock \
|| GC_lock_holder == GetCurrentThreadId())
# ifdef THREAD_SANITIZER
# define I_DONT_HOLD_LOCK() TRUE /* Conservatively say yes */
# else
# define I_DONT_HOLD_LOCK() (!GC_need_to_lock \
|| GC_lock_holder != GetCurrentThreadId())
# endif
# define UNCOND_LOCK() \
{ GC_ASSERT(I_DONT_HOLD_LOCK()); \
EnterCriticalSection(&GC_allocate_ml); \
SET_LOCK_HOLDER(); }
# define UNCOND_UNLOCK() \
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
LeaveCriticalSection(&GC_allocate_ml); }
# else
# define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml)
# define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
# elif defined(GC_PTHREADS)
EXTERN_C_END
# include <pthread.h>
EXTERN_C_BEGIN
/* Posix allows pthread_t to be a struct, though it rarely is. */
/* Unfortunately, we need to use a pthread_t to index a data */
/* structure. It also helps if comparisons don't involve a */
/* function call. Hence we introduce platform-dependent macros */
/* to compare pthread_t ids and to map them to integers. */
/* The mapping to integers does not need to result in different */
/* integers for each thread, though that should be true as much */
/* as possible. */
/* Refine to exclude platforms on which pthread_t is struct. */
# if !defined(GC_WIN32_PTHREADS)
# define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
# define THREAD_EQUAL(id1, id2) ((id1) == (id2))
# define NUMERIC_THREAD_ID_UNIQUE
# elif defined(__WINPTHREADS_VERSION_MAJOR) /* winpthreads */
# define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
# define THREAD_EQUAL(id1, id2) ((id1) == (id2))
# ifndef _WIN64
/* NUMERIC_THREAD_ID is 32-bit and not unique on Win64. */
# define NUMERIC_THREAD_ID_UNIQUE
# endif
# else /* pthreads-win32 */
# define NUMERIC_THREAD_ID(id) ((unsigned long)(word)(id.p))
/* Using documented internal details of pthreads-win32 library. */
/* Faster than pthread_equal(). Should not change with */
/* future versions of pthreads-win32 library. */
# define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
# undef NUMERIC_THREAD_ID_UNIQUE
/* Generic definitions based on pthread_equal() always work but */
/* will result in poor performance (as NUMERIC_THREAD_ID is */
/* defined to just a constant) and weak assertion checking. */
# endif
# define NO_THREAD ((unsigned long)(-1l))
/* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
# ifdef SN_TARGET_PSP2
EXTERN_C_END
# include "psp2-support.h"
EXTERN_C_BEGIN
GC_EXTERN WapiMutex GC_allocate_ml_PSP2;
# define UNCOND_LOCK() { int res; GC_ASSERT(I_DONT_HOLD_LOCK()); \
res = PSP2_MutexLock(&GC_allocate_ml_PSP2); \
GC_ASSERT(0 == res); (void)res; \
SET_LOCK_HOLDER(); }
# define UNCOND_UNLOCK() { int res; GC_ASSERT(I_HOLD_LOCK()); \
UNSET_LOCK_HOLDER(); \
res = PSP2_MutexUnlock(&GC_allocate_ml_PSP2); \
GC_ASSERT(0 == res); (void)res; }
# elif (!defined(THREAD_LOCAL_ALLOC) || defined(USE_SPIN_LOCK)) \
&& !defined(USE_PTHREAD_LOCKS)
/* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to */
/* be held for long periods, if it is held at all. Thus spinning */
/* and sleeping for fixed periods are likely to result in */
/* significant wasted time. We thus rely mostly on queued locks. */
# undef USE_SPIN_LOCK
# define USE_SPIN_LOCK
GC_EXTERN volatile AO_TS_t GC_allocate_lock;
GC_INNER void GC_lock(void);
/* Allocation lock holder. Only set if acquired by client through */
/* GC_call_with_alloc_lock. */
# ifdef GC_ASSERTIONS
# define UNCOND_LOCK() \
{ GC_ASSERT(I_DONT_HOLD_LOCK()); \
if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
GC_lock(); \
SET_LOCK_HOLDER(); }
# define UNCOND_UNLOCK() \
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
AO_CLEAR(&GC_allocate_lock); }
# else
# define UNCOND_LOCK() \
{ if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
GC_lock(); }
# define UNCOND_UNLOCK() AO_CLEAR(&GC_allocate_lock)
# endif /* !GC_ASSERTIONS */
# else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
# ifndef USE_PTHREAD_LOCKS
# define USE_PTHREAD_LOCKS
# endif
# endif /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
# ifdef USE_PTHREAD_LOCKS
EXTERN_C_END
# include <pthread.h>
EXTERN_C_BEGIN
GC_EXTERN pthread_mutex_t GC_allocate_ml;
# ifdef GC_ASSERTIONS
# define UNCOND_LOCK() { GC_ASSERT(I_DONT_HOLD_LOCK()); \
GC_lock(); SET_LOCK_HOLDER(); }
# define UNCOND_UNLOCK() \
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
# if defined(NO_PTHREAD_TRYLOCK)
# define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
# else
# define UNCOND_LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
GC_lock(); }
# endif
# define UNCOND_UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
# endif /* USE_PTHREAD_LOCKS */
# ifdef GC_ASSERTIONS
GC_EXTERN unsigned long GC_lock_holder;
# define SET_LOCK_HOLDER() \
GC_lock_holder = NUMERIC_THREAD_ID(pthread_self())
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
# define I_HOLD_LOCK() \
(!GC_need_to_lock \
|| GC_lock_holder == NUMERIC_THREAD_ID(pthread_self()))
# if !defined(NUMERIC_THREAD_ID_UNIQUE) || defined(THREAD_SANITIZER)
# define I_DONT_HOLD_LOCK() TRUE /* Conservatively say yes */
# else
# define I_DONT_HOLD_LOCK() \
(!GC_need_to_lock \
|| GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
# endif
# endif /* GC_ASSERTIONS */
# ifndef GC_WIN32_THREADS
GC_EXTERN volatile GC_bool GC_collecting;
# ifdef AO_HAVE_char_store
# define ENTER_GC() AO_char_store((unsigned char*)&GC_collecting, TRUE)
# define EXIT_GC() AO_char_store((unsigned char*)&GC_collecting, FALSE)
# else
# define ENTER_GC() (void)(GC_collecting = TRUE)
# define EXIT_GC() (void)(GC_collecting = FALSE)
# endif
# endif
GC_INNER void GC_lock(void);
# endif /* GC_PTHREADS */
# if defined(GC_ALWAYS_MULTITHREADED) \
&& (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK))
# define GC_need_to_lock TRUE
# define set_need_to_lock() (void)0
# else
# if defined(GC_ALWAYS_MULTITHREADED) && !defined(CPPCHECK)
# error Runtime initialization of GC lock is needed!
# endif
# undef GC_ALWAYS_MULTITHREADED
GC_EXTERN GC_bool GC_need_to_lock;
# ifdef THREAD_SANITIZER
/* To workaround TSan false positive (e.g., when */
/* GC_pthread_create is called from multiple threads in */
/* parallel), do not set GC_need_to_lock if it is already set. */
# define set_need_to_lock() \
(void)(*(GC_bool volatile *)&GC_need_to_lock \
? FALSE \
: (GC_need_to_lock = TRUE))
# else
# define set_need_to_lock() (void)(GC_need_to_lock = TRUE)
/* We are multi-threaded now. */
# endif
# endif
#if !defined(UNCOND_LOCK)
extern void GC_lock(void);
extern void GC_unlock(void);
# define UNCOND_LOCK() GC_lock()
# define UNCOND_UNLOCK() GC_unlock()
#endif
EXTERN_C_END
# else /* !THREADS */
# define LOCK() (void)0
# define UNLOCK() (void)0
# ifdef GC_ASSERTIONS
# define I_HOLD_LOCK() TRUE
# define I_DONT_HOLD_LOCK() TRUE
/* Used only in positive assertions or to test whether */
/* we still need to acquire the lock. TRUE works in */
/* either case. */
# endif
# endif /* !THREADS */
#if defined(UNCOND_LOCK) && !defined(LOCK)
# if (defined(LINT2) && defined(USE_PTHREAD_LOCKS)) \
|| defined(GC_ALWAYS_MULTITHREADED)
/* Instruct code analysis tools not to care about GC_need_to_lock */
/* influence to LOCK/UNLOCK semantic. */
# define LOCK() UNCOND_LOCK()
# define UNLOCK() UNCOND_UNLOCK()
# else
/* At least two thread running; need to lock. */
# define LOCK() do { if (GC_need_to_lock) UNCOND_LOCK(); } while (0)
# define UNLOCK() do { if (GC_need_to_lock) UNCOND_UNLOCK(); } while (0)
# endif
#endif
# ifndef ENTER_GC
# define ENTER_GC()
# define EXIT_GC()
# endif
# ifndef DCL_LOCK_STATE
# define DCL_LOCK_STATE
# endif
#endif /* GC_LOCKS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
6acaabb4d7ff0d1fcb682f7b39d9a0926826e11c

View File

@@ -0,0 +1 @@
7982ce39fa13ddf857c72df12952ddfbf66e9a2c

View File

@@ -0,0 +1,70 @@
/*
Copyright (c) 2004-2005 Andrei Polushin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef GC_MSVC_DBG_H
#define GC_MSVC_DBG_H
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !MSVC_DBG_DLL
#define MSVC_DBG_EXPORT
#elif MSVC_DBG_BUILD
#define MSVC_DBG_EXPORT __declspec(dllexport)
#else
#define MSVC_DBG_EXPORT __declspec(dllimport)
#endif
#ifndef MAX_SYM_NAME
#define MAX_SYM_NAME 2000
#endif
typedef void* HANDLE;
typedef struct _CONTEXT CONTEXT;
MSVC_DBG_EXPORT size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames);
MSVC_DBG_EXPORT size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames);
MSVC_DBG_EXPORT size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size);
MSVC_DBG_EXPORT size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size);
MSVC_DBG_EXPORT size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes);
MSVC_DBG_EXPORT size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes);
MSVC_DBG_EXPORT size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
MSVC_DBG_EXPORT size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
MSVC_DBG_EXPORT size_t GetDescriptionFromAddress(void* address, const char* format, char* description, size_t size);
MSVC_DBG_EXPORT size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size);
/* Compatibility with <execinfo.h> */
MSVC_DBG_EXPORT int backtrace(void* addresses[], int count);
MSVC_DBG_EXPORT char** backtrace_symbols(void*const addresses[], int count);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* GC_MSVC_DBG_H */

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
* All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
#ifndef GC_PTHREAD_STOP_WORLD_H
#define GC_PTHREAD_STOP_WORLD_H
EXTERN_C_BEGIN
struct thread_stop_info {
# if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
# ifdef GC_ATOMIC_OPS_H
volatile AO_t last_stop_count;
# else
word last_stop_count;
# endif
/* The value of GC_stop_count when the thread */
/* last successfully handled a suspend signal. */
# endif
ptr_t stack_ptr; /* Valid only when stopped. */
# ifdef NACL
/* Grab NACL_GC_REG_STORAGE_SIZE pointers off the stack when */
/* going into a syscall. 20 is more than we need, but it's an */
/* overestimate in case the instrumented function uses any callee */
/* saved registers, they may be pushed to the stack much earlier. */
/* Also, on amd64 'push' puts 8 bytes on the stack even though */
/* our pointers are 4 bytes. */
# ifdef ARM32
/* Space for r4-r8, r10-r12, r14. */
# define NACL_GC_REG_STORAGE_SIZE 9
# else
# define NACL_GC_REG_STORAGE_SIZE 20
# endif
ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE];
# endif
#if defined(SN_TARGET_ORBIS)
# define ORBIS_GC_REG_STORAGE_SIZE 27
__uint64_t registers[ORBIS_GC_REG_STORAGE_SIZE];
#endif
};
GC_INNER void GC_stop_init(void);
EXTERN_C_END
#endif

View File

@@ -0,0 +1,195 @@
/*
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
* Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
* All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
#ifndef GC_PTHREAD_SUPPORT_H
#define GC_PTHREAD_SUPPORT_H
#include "private/gc_priv.h"
#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
#if defined(GC_DARWIN_THREADS)
# include "private/darwin_stop_world.h"
#else
# include "private/pthread_stop_world.h"
#endif
#ifdef THREAD_LOCAL_ALLOC
# include "thread_local_alloc.h"
#endif
#ifdef THREAD_SANITIZER
# include "dbg_mlc.h" /* for oh type */
#endif
EXTERN_C_BEGIN
/* We use the allocation lock to protect thread-related data structures. */
/* The set of all known threads. We intercept thread creation and */
/* joins. */
/* Protected by allocation/GC lock. */
/* Some of this should be declared volatile, but that's inconsistent */
/* with some library routine declarations. */
typedef struct GC_Thread_Rep {
# ifdef THREAD_SANITIZER
char dummy[sizeof(oh)]; /* A dummy field to avoid TSan false */
/* positive about the race between */
/* GC_has_other_debug_info and */
/* GC_suspend_handler_inner (which */
/* sets store_stop.stack_ptr). */
# endif
struct GC_Thread_Rep * next; /* More recently allocated threads */
/* with a given pthread id come */
/* first. (All but the first are */
/* guaranteed to be dead, but we may */
/* not yet have registered the join.) */
pthread_t id;
# ifdef USE_TKILL_ON_ANDROID
pid_t kernel_id;
# endif
/* Extra bookkeeping information the stopping code uses */
struct thread_stop_info stop_info;
# if defined(GC_ENABLE_SUSPEND_THREAD) && !defined(GC_DARWIN_THREADS) \
&& !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
volatile AO_t suspended_ext; /* Thread was suspended externally. */
# endif
unsigned char flags;
# define FINISHED 1 /* Thread has exited. */
# define DETACHED 2 /* Thread is treated as detached. */
/* Thread may really be detached, or */
/* it may have been explicitly */
/* registered, in which case we can */
/* deallocate its GC_Thread_Rep once */
/* it unregisters itself, since it */
/* may not return a GC pointer. */
# define MAIN_THREAD 4 /* True for the original thread only. */
# define DISABLED_GC 0x10 /* Collections are disabled while the */
/* thread is exiting. */
unsigned char thread_blocked;
/* Protected by GC lock. */
/* Treated as a boolean value. If set, */
/* thread will acquire GC lock before */
/* doing any pointer manipulations, and */
/* has set its SP value. Thus it does */
/* not need to be sent a signal to stop */
/* it. */
unsigned short finalizer_skipped;
unsigned char finalizer_nested;
/* Used by GC_check_finalizer_nested() */
/* to minimize the level of recursion */
/* when a client finalizer allocates */
/* memory (initially both are 0). */
ptr_t stack_end; /* Cold end of the stack (except for */
/* main thread). */
ptr_t altstack; /* The start of the alt-stack if there */
/* is one, NULL otherwise. */
word altstack_size; /* The size of the alt-stack if exists. */
ptr_t stack; /* The start and size of the normal */
/* stack (set by GC_register_altstack). */
word stack_size;
# if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
ptr_t topOfStack; /* Result of GC_FindTopOfStack(0); */
/* valid only if the thread is blocked; */
/* non-NULL value means already set. */
# endif
# ifdef IA64
ptr_t backing_store_end;
ptr_t backing_store_ptr;
# endif
struct GC_traced_stack_sect_s *traced_stack_sect;
/* Points to the "frame" data held in stack by */
/* the innermost GC_call_with_gc_active() of */
/* this thread. May be NULL. */
void * status; /* The value returned from the thread. */
/* Used only to avoid premature */
/* reclamation of any data it might */
/* reference. */
/* This is unfortunately also the */
/* reason we need to intercept join */
/* and detach. */
# ifdef THREAD_LOCAL_ALLOC
struct thread_local_freelists tlfs;
# endif
} * GC_thread;
#ifndef THREAD_TABLE_SZ
# define THREAD_TABLE_SZ 256 /* Power of 2 (for speed). */
#endif
#if CPP_WORDSZ == 64
# define THREAD_TABLE_INDEX(id) \
(int)(((((NUMERIC_THREAD_ID(id) >> 8) ^ NUMERIC_THREAD_ID(id)) >> 16) \
^ ((NUMERIC_THREAD_ID(id) >> 8) ^ NUMERIC_THREAD_ID(id))) \
% THREAD_TABLE_SZ)
#else
# define THREAD_TABLE_INDEX(id) \
(int)(((NUMERIC_THREAD_ID(id) >> 16) \
^ (NUMERIC_THREAD_ID(id) >> 8) \
^ NUMERIC_THREAD_ID(id)) % THREAD_TABLE_SZ)
#endif
GC_EXTERN volatile GC_thread GC_threads[THREAD_TABLE_SZ];
GC_EXTERN GC_bool GC_thr_initialized;
GC_INNER GC_thread GC_lookup_thread(pthread_t id);
GC_EXTERN GC_bool GC_in_thread_creation;
/* We may currently be in thread creation or destruction. */
/* Only set to TRUE while allocation lock is held. */
/* When set, it is OK to run GC from unknown thread. */
#ifdef NACL
GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
GC_INNER void GC_nacl_initialize_gc_thread(void);
GC_INNER void GC_nacl_shutdown_gc_thread(void);
#endif
#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
GC_INNER void GC_unblock_gc_signals(void);
#endif
#ifdef GC_PTHREAD_START_STANDALONE
# define GC_INNER_PTHRSTART /* empty */
#else
# define GC_INNER_PTHRSTART GC_INNER
#endif
GC_INNER_PTHRSTART void * GC_CALLBACK GC_inner_start_routine(
struct GC_stack_base *sb, void *arg);
GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
void *(**pstart)(void *),
void **pstart_arg,
struct GC_stack_base *sb, void *arg);
GC_INNER_PTHRSTART void GC_thread_exit_proc(void *);
EXTERN_C_END
#endif /* GC_PTHREADS && !GC_WIN32_THREADS */
#endif /* GC_PTHREAD_SUPPORT_H */

View File

@@ -0,0 +1,103 @@
/*
* This is a reimplementation of a subset of the pthread_getspecific/setspecific
* interface. This appears to outperform the standard linuxthreads one
* by a significant margin.
* The major restriction is that each thread may only make a single
* pthread_setspecific call on a single key. (The current data structure
* doesn't really require that. The restriction should be easily removable.)
* We don't currently support the destruction functions, though that
* could be done.
* We also currently assume that only one pthread_setspecific call
* can be executed at a time, though that assumption would be easy to remove
* by adding a lock.
*/
#include <errno.h>
EXTERN_C_BEGIN
/* Called during key creation or setspecific. */
/* For the GC we already hold lock. */
/* Currently allocated objects leak on thread exit. */
/* That's hard to fix, but OK if we allocate garbage */
/* collected memory. */
#define MALLOC_CLEAR(n) GC_INTERNAL_MALLOC(n, NORMAL)
#define TS_CACHE_SIZE 1024
#define CACHE_HASH(n) ((((n) >> 8) ^ (n)) & (TS_CACHE_SIZE - 1))
#define TS_HASH_SIZE 1024
#define HASH(p) \
((unsigned)((((word)(p)) >> 8) ^ (word)(p)) & (TS_HASH_SIZE - 1))
/* An entry describing a thread-specific value for a given thread. */
/* All such accessible structures preserve the invariant that if either */
/* thread is a valid pthread id or qtid is a valid "quick thread id" */
/* for a thread, then value holds the corresponding thread specific */
/* value. This invariant must be preserved at ALL times, since */
/* asynchronous reads are allowed. */
typedef struct thread_specific_entry {
volatile AO_t qtid; /* quick thread id, only for cache */
void * value;
struct thread_specific_entry *next;
pthread_t thread;
} tse;
/* We represent each thread-specific datum as two tables. The first is */
/* a cache, indexed by a "quick thread identifier". The "quick" thread */
/* identifier is an easy to compute value, which is guaranteed to */
/* determine the thread, though a thread may correspond to more than */
/* one value. We typically use the address of a page in the stack. */
/* The second is a hash table, indexed by pthread_self(). It is used */
/* only as a backup. */
/* Return the "quick thread id". Default version. Assumes page size, */
/* or at least thread stack separation, is at least 4K. */
/* Must be defined so that it never returns 0. (Page 0 can't really be */
/* part of any stack, since that would make 0 a valid stack pointer.) */
#define quick_thread_id() (((word)GC_approx_sp()) >> 12)
#define INVALID_QTID ((word)0)
#define INVALID_THREADID ((pthread_t)0)
union ptse_ao_u {
tse *p;
volatile AO_t ao;
};
typedef struct thread_specific_data {
tse * volatile cache[TS_CACHE_SIZE];
/* A faster index to the hash table */
union ptse_ao_u hash[TS_HASH_SIZE];
pthread_mutex_t lock;
} tsd;
typedef tsd * GC_key_t;
#define GC_key_create(key, d) GC_key_create_inner(key)
GC_INNER int GC_key_create_inner(tsd ** key_ptr);
GC_INNER int GC_setspecific(tsd * key, void * value);
#define GC_remove_specific(key) \
GC_remove_specific_after_fork(key, pthread_self())
GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t);
/* An internal version of getspecific that assumes a cache miss. */
GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
tse * volatile * cache_entry);
/* GC_INLINE is defined in gc_priv.h. */
GC_INLINE void * GC_getspecific(tsd * key)
{
word qtid = quick_thread_id();
tse * volatile * entry_ptr = &key->cache[CACHE_HASH(qtid)];
tse * entry = *entry_ptr; /* Must be loaded only once. */
GC_ASSERT(qtid != INVALID_QTID);
if (EXPECT(entry -> qtid == qtid, TRUE)) {
GC_ASSERT(entry -> thread == pthread_self());
return entry -> value;
}
return GC_slow_getspecific(key, qtid, entry_ptr);
}
EXTERN_C_END

View File

@@ -0,0 +1,206 @@
/*
* Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/* Included indirectly from a thread-library-specific file. */
/* This is the interface for thread-local allocation, whose */
/* implementation is mostly thread-library-independent. */
/* Here we describe only the interface that needs to be known */
/* and invoked from the thread support layer; the actual */
/* implementation also exports GC_malloc and friends, which */
/* are declared in gc.h. */
#ifndef GC_THREAD_LOCAL_ALLOC_H
#define GC_THREAD_LOCAL_ALLOC_H
#include "private/gc_priv.h"
#ifdef THREAD_LOCAL_ALLOC
#include "gc_inline.h"
#if defined(USE_HPUX_TLS)
# error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
#endif
#include <stdlib.h>
EXTERN_C_BEGIN
#if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) \
&& !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
&& !defined(USE_CUSTOM_SPECIFIC)
# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
# if defined(CYGWIN32) && GC_GNUC_PREREQ(4, 0)
# if defined(__clang__)
/* As of Cygwin clang3.5.2, thread-local storage is unsupported. */
# define USE_PTHREAD_SPECIFIC
# else
# define USE_COMPILER_TLS
# endif
# elif defined(__GNUC__) || defined(MSWINCE)
# define USE_WIN32_SPECIFIC
# else
# define USE_WIN32_COMPILER_TLS
# endif /* !GNU */
# elif (defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
&& GC_GNUC_PREREQ(3, 3) \
&& !(defined(__clang__) && defined(HOST_ANDROID))) \
|| (defined(FREEBSD) && defined(__GLIBC__) /* kFreeBSD */ \
&& GC_GNUC_PREREQ(4, 4)) \
|| (defined(HOST_ANDROID) && defined(ARM32) \
&& (GC_GNUC_PREREQ(4, 6) || GC_CLANG_PREREQ_FULL(3, 8, 256229)))
# define USE_COMPILER_TLS
# elif defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) \
|| defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
|| defined(GC_FREEBSD_THREADS) || defined(GC_NETBSD_THREADS) \
|| defined(GC_LINUX_THREADS) || defined(GC_HAIKU_THREADS) \
|| defined(GC_RTEMS_PTHREADS)
# define USE_PTHREAD_SPECIFIC
# elif defined(GC_HPUX_THREADS)
# ifdef __GNUC__
# define USE_PTHREAD_SPECIFIC
/* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work. */
# else
# define USE_COMPILER_TLS
# endif
# else
# define USE_CUSTOM_SPECIFIC /* Use our own. */
# endif
#endif
#ifndef THREAD_FREELISTS_KINDS
# ifdef ENABLE_DISCLAIM
# define THREAD_FREELISTS_KINDS (NORMAL+2)
# else
# define THREAD_FREELISTS_KINDS (NORMAL+1)
# endif
#endif /* !THREAD_FREELISTS_KINDS */
/* One of these should be declared as the tlfs field in the */
/* structure pointed to by a GC_thread. */
typedef struct thread_local_freelists {
void * _freelists[THREAD_FREELISTS_KINDS][TINY_FREELISTS];
# define ptrfree_freelists _freelists[PTRFREE]
# define normal_freelists _freelists[NORMAL]
/* Note: Preserve *_freelists names for some clients. */
# ifdef GC_GCJ_SUPPORT
void * gcj_freelists[TINY_FREELISTS];
# define ERROR_FL ((void *)(word)-1)
/* Value used for gcj_freelists[-1]; allocation is */
/* erroneous. */
# endif
/* Free lists contain either a pointer or a small count */
/* reflecting the number of granules allocated at that */
/* size. */
/* 0 ==> thread-local allocation in use, free list */
/* empty. */
/* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
/* too few objects of this size have been */
/* allocated by this thread. */
/* >= HBLKSIZE => pointer to nonempty free list. */
/* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
/* local alloc, equivalent to 0. */
# define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
/* Don't use local free lists for up to this much */
/* allocation. */
} *GC_tlfs;
#if defined(USE_PTHREAD_SPECIFIC)
# define GC_getspecific pthread_getspecific
# define GC_setspecific pthread_setspecific
# define GC_key_create pthread_key_create
# define GC_remove_specific(key) pthread_setspecific(key, NULL)
/* Explicitly delete the value to stop the TLS */
/* destructor from being called repeatedly. */
# define GC_remove_specific_after_fork(key, t) (void)0
/* Should not need any action. */
typedef pthread_key_t GC_key_t;
#elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
# define GC_getspecific(x) (x)
# define GC_setspecific(key, v) ((key) = (v), 0)
# define GC_key_create(key, d) 0
# define GC_remove_specific(key) /* No need for cleanup on exit. */
# define GC_remove_specific_after_fork(key, t) (void)0
typedef void * GC_key_t;
#elif defined(USE_WIN32_SPECIFIC)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
# endif
# define NOSERVICE
EXTERN_C_END
# include <windows.h>
EXTERN_C_BEGIN
# define GC_getspecific TlsGetValue
# define GC_setspecific(key, v) !TlsSetValue(key, v)
/* We assume 0 == success, msft does the opposite. */
# ifndef TLS_OUT_OF_INDEXES
/* this is currently missing in WinCE */
# define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
# endif
# define GC_key_create(key, d) \
((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
# define GC_remove_specific(key) /* No need for cleanup on exit. */
/* Need TlsFree on process exit/detach? */
# define GC_remove_specific_after_fork(key, t) (void)0
typedef DWORD GC_key_t;
#elif defined(USE_CUSTOM_SPECIFIC)
EXTERN_C_END
# include "private/specific.h"
EXTERN_C_BEGIN
#else
# error implement me
#endif
/* Each thread structure must be initialized. */
/* This call must be made from the new thread. */
/* Caller holds allocation lock. */
GC_INNER void GC_init_thread_local(GC_tlfs p);
/* Called when a thread is unregistered, or exits. */
/* We hold the allocator lock. */
GC_INNER void GC_destroy_thread_local(GC_tlfs p);
/* The thread support layer must arrange to mark thread-local */
/* free lists explicitly, since the link field is often */
/* invisible to the marker. It knows how to find all threads; */
/* we take care of an individual thread freelist structure. */
GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p);
#ifdef GC_ASSERTIONS
GC_bool GC_is_thread_tsd_valid(void *tsd);
void GC_check_tls_for(GC_tlfs p);
# if defined(USE_CUSTOM_SPECIFIC)
void GC_check_tsd_marks(tsd *key);
# endif
#endif /* GC_ASSERTIONS */
#ifndef GC_ATTR_TLS_FAST
# define GC_ATTR_TLS_FAST /* empty */
#endif
extern
#if defined(USE_COMPILER_TLS)
__thread GC_ATTR_TLS_FAST
#elif defined(USE_WIN32_COMPILER_TLS)
__declspec(thread) GC_ATTR_TLS_FAST
#endif
GC_key_t GC_thread_key;
/* This is set up by the thread_local_alloc implementation. No need */
/* for cleanup on thread exit. But the thread support layer makes sure */
/* that GC_thread_key is traced, if necessary. */
EXTERN_C_END
#endif /* THREAD_LOCAL_ALLOC */
#endif /* GC_THREAD_LOCAL_ALLOC_H */