import gc6.1alpha5
This commit is contained in:
+75
-21
@@ -43,6 +43,11 @@
|
||||
#if defined(IRIX_THREADS)
|
||||
# define GC_IRIX_THREADS
|
||||
#endif
|
||||
#if defined(DGUX_THREADS)
|
||||
# if !defined(GC_DGUX386_THREADS)
|
||||
# define GC_DGUX386_THREADS
|
||||
# endif
|
||||
#endif
|
||||
#if defined(HPUX_THREADS)
|
||||
# define GC_HPUX_THREADS
|
||||
#endif
|
||||
@@ -68,13 +73,19 @@
|
||||
/* depend on this were previously included. */
|
||||
#endif
|
||||
|
||||
#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
|
||||
# define _POSIX4A_DRAFT10_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
|
||||
# define GC_SOLARIS_THREADS
|
||||
#endif
|
||||
|
||||
# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
|
||||
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
|
||||
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
|
||||
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
|
||||
defined(GC_DGUX386_THREADS) || \
|
||||
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
|
||||
# define GC_PTHREADS
|
||||
# endif
|
||||
|
||||
@@ -86,7 +97,7 @@
|
||||
typedef long ptrdiff_t; /* ptrdiff_t is not defined */
|
||||
# endif
|
||||
|
||||
#if defined(__MINGW32__) && defined(GC_WIN32_THREADS)
|
||||
#if defined(__MINGW32__) && defined(_DLL) && !defined(GC_NOT_DLL)
|
||||
# ifdef GC_BUILD
|
||||
# define GC_API __declspec(dllexport)
|
||||
# else
|
||||
@@ -154,7 +165,7 @@ GC_API int GC_parallel; /* GC is parallelized for performance on */
|
||||
/* Env variable GC_NPROC is set to > 1, or */
|
||||
/* GC_NPROC is not set and this is an MP. */
|
||||
/* If GC_parallel is set, incremental */
|
||||
/* collection is aonly partially functional, */
|
||||
/* collection is only partially functional, */
|
||||
/* and may not be desirable. */
|
||||
|
||||
|
||||
@@ -296,7 +307,29 @@ GC_API int GC_dont_precollect; /* Don't collect as part of */
|
||||
/* Interferes with blacklisting. */
|
||||
/* Wizards only. */
|
||||
|
||||
GC_API unsigned long GC_time_limit;
|
||||
/* If incremental collection is enabled, */
|
||||
/* We try to terminate collections */
|
||||
/* after this many milliseconds. Not a */
|
||||
/* hard time bound. Setting this to */
|
||||
/* GC_TIME_UNLIMITED will essentially */
|
||||
/* disable incremental collection while */
|
||||
/* leaving generational collection */
|
||||
/* enabled. */
|
||||
# define GC_TIME_UNLIMITED 999999
|
||||
/* Setting GC_time_limit to this value */
|
||||
/* will disable the "pause time exceeded"*/
|
||||
/* tests. */
|
||||
|
||||
/* Public procedures */
|
||||
|
||||
/* Initialize the collector. This is only required when using thread-local
|
||||
* allocation, since unlike the regular allocation routines, GC_local_malloc
|
||||
* is not self-initializing. If you use GC_local_malloc you should arrange
|
||||
* to call this somehow (e.g. from a constructor) before doing any allocation.
|
||||
*/
|
||||
GC_API void GC_init GC_PROTO((void));
|
||||
|
||||
/*
|
||||
* general purpose allocation routines, with roughly malloc calling conv.
|
||||
* The atomic versions promise that no relevant pointers are contained
|
||||
@@ -452,9 +485,23 @@ GC_API size_t GC_get_total_bytes GC_PROTO((void));
|
||||
/* Don't use in leak finding mode. */
|
||||
/* Ignored if GC_dont_gc is true. */
|
||||
/* Only the generational piece of this is */
|
||||
/* functional if GC_parallel is TRUE. */
|
||||
/* functional if GC_parallel is TRUE */
|
||||
/* or if GC_time_limit is GC_TIME_UNLIMITED. */
|
||||
/* Causes GC_local_gcj_malloc() to revert to */
|
||||
/* locked allocation. Must be called */
|
||||
/* before any GC_local_gcj_malloc() calls. */
|
||||
GC_API void GC_enable_incremental GC_PROTO((void));
|
||||
|
||||
/* Does incremental mode write-protect pages? Returns zero or */
|
||||
/* more of the following, or'ed together: */
|
||||
#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objs. */
|
||||
#define GC_PROTECTS_PTRFREE_HEAP 2
|
||||
#define GC_PROTECTS_STATIC_DATA 4 /* Curently never. */
|
||||
#define GC_PROTECTS_STACK 8 /* Probably impractical. */
|
||||
|
||||
#define GC_PROTECTS_NONE 0
|
||||
GC_API int GC_incremental_protection_needs GC_PROTO((void));
|
||||
|
||||
/* Perform some garbage collection work, if appropriate. */
|
||||
/* Return 0 if there is no more work to be done. */
|
||||
/* Typically performs an amount of work corresponding roughly */
|
||||
@@ -841,9 +888,23 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
|
||||
|
||||
#endif /* THREADS && !SRC_M3 */
|
||||
|
||||
#if defined(GC_WIN32_THREADS) && defined(_WIN32_WCE)
|
||||
#if defined(GC_WIN32_THREADS)
|
||||
# include <windows.h>
|
||||
# include <winbase.h>
|
||||
|
||||
/*
|
||||
* All threads must be created using GC_CreateThread, so that they will be
|
||||
* recorded in the thread table. For backwards compatibility, this is not
|
||||
* technically true if the GC is built as a dynamic library, since it can
|
||||
* and does then use DllMain to keep track of thread creations. But new code
|
||||
* should be built to call GC_CreateThread.
|
||||
*/
|
||||
HANDLE WINAPI GC_CreateThread(
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
|
||||
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
|
||||
|
||||
# if defined(_WIN32_WCE)
|
||||
/*
|
||||
* win32_threads.c implements the real WinMain, which will start a new thread
|
||||
* to call GC_WinMain after initializing the garbage collector.
|
||||
@@ -854,21 +915,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
|
||||
LPWSTR lpCmdLine,
|
||||
int nCmdShow );
|
||||
|
||||
/*
|
||||
* All threads must be created using GC_CreateThread, so that they will be
|
||||
* recorded in the thread table.
|
||||
*/
|
||||
HANDLE WINAPI GC_CreateThread(
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
|
||||
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
|
||||
# ifndef GC_BUILD
|
||||
# define WinMain GC_WinMain
|
||||
# define CreateThread GC_CreateThread
|
||||
# endif
|
||||
# endif /* defined(_WIN32_WCE) */
|
||||
|
||||
# ifndef GC_BUILD
|
||||
# define WinMain GC_WinMain
|
||||
# define CreateThread GC_CreateThread
|
||||
# endif
|
||||
|
||||
#endif
|
||||
#endif /* defined(GC_WIN32_THREADS) */
|
||||
|
||||
/*
|
||||
* If you are planning on putting
|
||||
@@ -880,9 +933,10 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
|
||||
# define GC_INIT() { extern end, etext; \
|
||||
GC_noop(&end, &etext); }
|
||||
#else
|
||||
# if defined(__CYGWIN32__) && defined(GC_USE_DLL)
|
||||
# if defined(__CYGWIN32__) && defined(GC_USE_DLL) || defined (_AIX)
|
||||
/*
|
||||
* Similarly gnu-win32 DLLs need explicit initialization
|
||||
* Similarly gnu-win32 DLLs need explicit initialization from
|
||||
* the main program, as does AIX.
|
||||
*/
|
||||
# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
|
||||
# else
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 1996-1997
|
||||
* Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Silicon Graphics makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* Copyright (c) 2002
|
||||
* Hewlett-Packard Company
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Hewlett-Packard Company makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This implements standard-conforming allocators that interact with
|
||||
* the garbage collector. Gc_alloctor<T> allocates garbage-collectable
|
||||
* objects of type T. Traceable_allocator<T> allocates objects that
|
||||
* are not temselves garbage collected, but are scanned by the
|
||||
* collector for pointers to collectable objects. Traceable_alloc
|
||||
* should be used for explicitly managed STL containers that may
|
||||
* point to collectable objects.
|
||||
*
|
||||
* This code was derived from an earlier version of the GNU C++ standard
|
||||
* library, which itself was derived from the SGI STL implementation.
|
||||
*/
|
||||
|
||||
#include "gc.h" // For size_t
|
||||
|
||||
/* First some helpers to allow us to dispatch on whether or not a type
|
||||
* is known to be pointerfree.
|
||||
* These are private, except that the client may invoke the
|
||||
* GC_DECLARE_PTRFREE macro.
|
||||
*/
|
||||
|
||||
struct GC_true_type {};
|
||||
struct GC_false_type {};
|
||||
|
||||
template <class GC_tp>
|
||||
struct GC_type_traits {
|
||||
GC_false_type GC_is_ptr_free;
|
||||
};
|
||||
|
||||
# define GC_DECLARE_PTRFREE(T) \
|
||||
template<> struct GC_type_traits<T> { GC_true_type GC_is_ptr_free; }
|
||||
|
||||
GC_DECLARE_PTRFREE(signed char);
|
||||
GC_DECLARE_PTRFREE(unsigned char);
|
||||
GC_DECLARE_PTRFREE(signed short);
|
||||
GC_DECLARE_PTRFREE(unsigned short);
|
||||
GC_DECLARE_PTRFREE(signed int);
|
||||
GC_DECLARE_PTRFREE(unsigned int);
|
||||
GC_DECLARE_PTRFREE(signed long);
|
||||
GC_DECLARE_PTRFREE(unsigned long);
|
||||
GC_DECLARE_PTRFREE(float);
|
||||
GC_DECLARE_PTRFREE(double);
|
||||
/* The client may want to add others. */
|
||||
|
||||
// In the following GC_Tp is GC_true_type iff we are allocating a
|
||||
// pointerfree object.
|
||||
template <class GC_Tp>
|
||||
inline void * GC_selective_alloc(size_t n, GC_Tp) {
|
||||
return GC_MALLOC(n);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type) {
|
||||
return GC_MALLOC_ATOMIC(n);
|
||||
}
|
||||
|
||||
/* Now the public gc_allocator<T> class:
|
||||
*/
|
||||
template <class GC_Tp>
|
||||
class gc_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1> struct rebind {
|
||||
typedef gc_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
gc_allocator() {}
|
||||
# ifndef _MSC_VER
|
||||
// I'm not sure why this is needed here in addition to the following.
|
||||
// The standard specifies it for the standard allocator, but VC++ rejects
|
||||
// it. -HB
|
||||
gc_allocator(const gc_allocator&) throw() {}
|
||||
# endif
|
||||
template <class GC_Tp1> gc_allocator(const gc_allocator<GC_Tp1>&) throw() {}
|
||||
~gc_allocator() throw() {}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0) {
|
||||
GC_type_traits<GC_Tp> traits;
|
||||
return static_cast<GC_Tp *>
|
||||
(GC_selective_alloc(GC_n * sizeof(GC_Tp),
|
||||
traits.GC_is_ptr_free));
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_n)
|
||||
{ GC_FREE(__p); }
|
||||
|
||||
size_type max_size() const throw()
|
||||
{ return size_t(-1) / sizeof(GC_Tp); }
|
||||
|
||||
void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class gc_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1> struct rebind {
|
||||
typedef gc_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const gc_allocator<GC_T1>&, const gc_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const gc_allocator<GC_T1>&, const gc_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* And the public traceable_allocator class.
|
||||
*/
|
||||
|
||||
// Note that we currently don't specialize the pointer-free case, since a
|
||||
// pointer-free traceable container doesn't make that much sense,
|
||||
// though it could become an issue due to abstraction boundaries.
|
||||
template <class GC_Tp>
|
||||
class traceable_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef GC_Tp* pointer;
|
||||
typedef const GC_Tp* const_pointer;
|
||||
typedef GC_Tp& reference;
|
||||
typedef const GC_Tp& const_reference;
|
||||
typedef GC_Tp value_type;
|
||||
|
||||
template <class GC_Tp1> struct rebind {
|
||||
typedef traceable_allocator<GC_Tp1> other;
|
||||
};
|
||||
|
||||
traceable_allocator() throw() {}
|
||||
# ifndef _MSC_VER
|
||||
traceable_allocator(const traceable_allocator&) throw() {}
|
||||
# endif
|
||||
template <class GC_Tp1> traceable_allocator
|
||||
(const traceable_allocator<GC_Tp1>&) throw() {}
|
||||
~traceable_allocator() throw() {}
|
||||
|
||||
pointer address(reference GC_x) const { return &GC_x; }
|
||||
const_pointer address(const_reference GC_x) const { return &GC_x; }
|
||||
|
||||
// GC_n is permitted to be 0. The C++ standard says nothing about what
|
||||
// the return value is when GC_n == 0.
|
||||
GC_Tp* allocate(size_type GC_n, const void* = 0) {
|
||||
return static_cast<GC_Tp*>(GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp)));
|
||||
}
|
||||
|
||||
// __p is not permitted to be a null pointer.
|
||||
void deallocate(pointer __p, size_type GC_n)
|
||||
{ GC_FREE(__p); }
|
||||
|
||||
size_type max_size() const throw()
|
||||
{ return size_t(-1) / sizeof(GC_Tp); }
|
||||
|
||||
void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); }
|
||||
void destroy(pointer __p) { __p->~GC_Tp(); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class traceable_allocator<void> {
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
typedef void value_type;
|
||||
|
||||
template <class GC_Tp1> struct rebind {
|
||||
typedef traceable_allocator<GC_Tp1> other;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator==(const traceable_allocator<GC_T1>&, const traceable_allocator<GC_T2>&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class GC_T1, class GC_T2>
|
||||
inline bool operator!=(const traceable_allocator<GC_T1>&, const traceable_allocator<GC_T2>&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
+26
-30
@@ -159,12 +159,18 @@ enum GCPlacement {UseGC,
|
||||
class gc {public:
|
||||
inline void* operator new( size_t size );
|
||||
inline void* operator new( size_t size, GCPlacement gcp );
|
||||
inline void* operator new( size_t size, void *p );
|
||||
/* Must be redefined here, since the other overloadings */
|
||||
/* hide the global definition. */
|
||||
inline void operator delete( void* obj );
|
||||
inline void operator delete( void*, void* );
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
inline void* operator new[]( size_t size );
|
||||
inline void* operator new[]( size_t size, GCPlacement gcp );
|
||||
inline void* operator new[]( size_t size, void *p );
|
||||
inline void operator delete[]( void* obj );
|
||||
inline void gc::operator delete[]( void*, void* );
|
||||
#endif /* GC_OPERATOR_NEW_ARRAY */
|
||||
};
|
||||
/*
|
||||
@@ -211,7 +217,6 @@ inline void* operator new(
|
||||
classes derived from "gc_cleanup" or containing members derived
|
||||
from "gc_cleanup". */
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/** This ensures that the system default operator new[] doesn't get
|
||||
@@ -220,42 +225,24 @@ inline void* operator new(
|
||||
* There seems to be really redirect new in this environment without
|
||||
* including this everywhere.
|
||||
*/
|
||||
inline void *operator new[]( size_t size )
|
||||
{
|
||||
return GC_MALLOC_UNCOLLECTABLE( size );
|
||||
}
|
||||
void *operator new[]( size_t size );
|
||||
|
||||
void operator delete[](void* obj);
|
||||
|
||||
inline void operator delete[](void* obj)
|
||||
{
|
||||
GC_FREE(obj);
|
||||
};
|
||||
void* operator new( size_t size);
|
||||
|
||||
inline void* operator new( size_t size)
|
||||
{
|
||||
return GC_MALLOC_UNCOLLECTABLE( size);
|
||||
};
|
||||
void operator delete(void* obj);
|
||||
|
||||
inline void operator delete(void* obj)
|
||||
{
|
||||
GC_FREE(obj);
|
||||
};
|
||||
|
||||
|
||||
// This new operator is used by VC++ in case of Debug builds !
|
||||
inline void* operator new( size_t size,
|
||||
// This new operator is used by VC++ in case of Debug builds !
|
||||
void* operator new( size_t size,
|
||||
int ,//nBlockUse,
|
||||
const char * szFileName,
|
||||
int nLine
|
||||
) {
|
||||
# ifndef GC_DEBUG
|
||||
return GC_malloc_uncollectable( size );
|
||||
# else
|
||||
return GC_debug_malloc_uncollectable(size, szFileName, nLine);
|
||||
# endif
|
||||
}
|
||||
|
||||
int nLine );
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
|
||||
inline void* operator new[](
|
||||
size_t size,
|
||||
GCPlacement gcp,
|
||||
@@ -283,9 +270,13 @@ inline void* gc::operator new( size_t size, GCPlacement gcp ) {
|
||||
else
|
||||
return GC_MALLOC_UNCOLLECTABLE( size );}
|
||||
|
||||
inline void* gc::operator new( size_t size, void *p ) {
|
||||
return p;}
|
||||
|
||||
inline void gc::operator delete( void* obj ) {
|
||||
GC_FREE( obj );}
|
||||
|
||||
inline void gc::operator delete( void*, void* ) {}
|
||||
|
||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||
|
||||
@@ -295,8 +286,13 @@ inline void* gc::operator new[]( size_t size ) {
|
||||
inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
|
||||
return gc::operator new( size, gcp );}
|
||||
|
||||
inline void* gc::operator new[]( size_t size, void *p ) {
|
||||
return p;}
|
||||
|
||||
inline void gc::operator delete[]( void* obj ) {
|
||||
gc::operator delete( obj );}
|
||||
|
||||
inline void gc::operator delete[]( void*, void* ) {}
|
||||
|
||||
#endif /* GC_OPERATOR_NEW_ARRAY */
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
* -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
|
||||
*
|
||||
* The debugging allocators use standard, not thread-local allocation.
|
||||
*
|
||||
* These routines normally require an explicit call to GC_init(), though
|
||||
* that may be done from a constructor function.
|
||||
*/
|
||||
|
||||
#ifndef GC_LOCAL_ALLOC_H
|
||||
|
||||
@@ -115,16 +115,24 @@ typedef struct {
|
||||
|
||||
#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. */
|
||||
# define DEBUG_BYTES (sizeof (oh) + sizeof (word) - EXTRA_BYTES)
|
||||
/* For uncollectable objects, the extra byte is not added. */
|
||||
# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
|
||||
# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
|
||||
#endif
|
||||
#define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh))
|
||||
|
||||
/* 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 may be called with or without the allocation */
|
||||
/* lock. */
|
||||
/* PRINT_CALL_CHAIN prints the call chain stored in an object */
|
||||
/* to stderr. It requires that we do not hold the lock. */
|
||||
#ifdef SAVE_CALL_CHAIN
|
||||
# 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)
|
||||
|
||||
@@ -70,7 +70,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */
|
||||
#define ADVANCE(p, hhdr, source) \
|
||||
{ \
|
||||
hdr * new_hdr = GC_invalid_header; \
|
||||
p = GC_FIND_START(p, hhdr, &new_hdr, (word)source); \
|
||||
p = GC_find_start(p, hhdr, &new_hdr); \
|
||||
hhdr = new_hdr; \
|
||||
}
|
||||
|
||||
|
||||
@@ -145,15 +145,15 @@
|
||||
# if defined(POWERPC)
|
||||
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
||||
int oldval;
|
||||
int temp = 1; // locked value
|
||||
int temp = 1; /* locked value */
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1:\tlwarx %0,0,%3\n" // load and reserve
|
||||
"\tcmpwi %0, 0\n" // if load is
|
||||
"\tbne 2f\n" // non-zero, return already set
|
||||
"\tstwcx. %2,0,%1\n" // else store conditional
|
||||
"\tbne- 1b\n" // retry if lost reservation
|
||||
"2:\t\n" // oldval is zero if we set
|
||||
"1:\tlwarx %0,0,%3\n" /* load and reserve */
|
||||
"\tcmpwi %0, 0\n" /* if load is */
|
||||
"\tbne 2f\n" /* non-zero, return already set */
|
||||
"\tstwcx. %2,0,%1\n" /* else store conditional */
|
||||
"\tbne- 1b\n" /* retry if lost reservation */
|
||||
"2:\t\n" /* oldval is zero if we set */
|
||||
: "=&r"(oldval), "=p"(addr)
|
||||
: "r"(temp), "1"(addr)
|
||||
: "memory");
|
||||
@@ -161,7 +161,7 @@
|
||||
}
|
||||
# define GC_TEST_AND_SET_DEFINED
|
||||
inline static void GC_clear(volatile unsigned int *addr) {
|
||||
__asm__ __volatile__("eieio" ::: "memory");
|
||||
__asm__ __volatile__("eieio" : : : "memory");
|
||||
*(addr) = 0;
|
||||
}
|
||||
# define GC_CLEAR_DEFINED
|
||||
@@ -219,11 +219,19 @@
|
||||
# define GC_TEST_AND_SET_DEFINED
|
||||
# endif
|
||||
# ifdef MIPS
|
||||
# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|
||||
# ifdef LINUX
|
||||
# include <sys/tas.h>
|
||||
# define GC_test_and_set(addr) _test_and_set((int *) addr,1)
|
||||
# define GC_TEST_AND_SET_DEFINED
|
||||
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|
||||
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
|
||||
# define GC_test_and_set(addr, v) test_and_set(addr,v)
|
||||
# ifdef __GNUC__
|
||||
# define GC_test_and_set(addr) _test_and_set(addr,1)
|
||||
# else
|
||||
# define GC_test_and_set(addr) test_and_set(addr,1)
|
||||
# endif
|
||||
# else
|
||||
# define GC_test_and_set(addr, v) __test_and_set(addr,v)
|
||||
# define GC_test_and_set(addr) __test_and_set(addr,1)
|
||||
# define GC_clear(addr) __lock_release(addr);
|
||||
# define GC_CLEAR_DEFINED
|
||||
# endif
|
||||
@@ -262,7 +270,7 @@
|
||||
# endif
|
||||
|
||||
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||
&& !defined(GC_IRIX_THREADS)
|
||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
|
||||
# define NO_THREAD (pthread_t)(-1)
|
||||
# include <pthread.h>
|
||||
# if defined(PARALLEL_MARK)
|
||||
@@ -431,7 +439,7 @@
|
||||
# define NO_THREAD (pthread_t)(-1)
|
||||
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
|
||||
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
|
||||
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); }
|
||||
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
|
||||
# define UNLOCK() GC_clear(&GC_allocate_lock);
|
||||
extern VOLATILE GC_bool GC_collecting;
|
||||
# define ENTER_GC() \
|
||||
@@ -440,11 +448,18 @@
|
||||
}
|
||||
# define EXIT_GC() GC_collecting = 0;
|
||||
# endif /* GC_IRIX_THREADS */
|
||||
# ifdef GC_WIN32_THREADS
|
||||
# include <windows.h>
|
||||
GC_API CRITICAL_SECTION GC_allocate_ml;
|
||||
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
|
||||
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
|
||||
# if defined(GC_WIN32_THREADS)
|
||||
# if defined(GC_PTHREADS)
|
||||
# include <pthread.h>
|
||||
extern pthread_mutex_t GC_allocate_ml;
|
||||
# define LOCK() pthread_mutex_lock(&GC_allocate_ml)
|
||||
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
|
||||
# else
|
||||
# include <windows.h>
|
||||
GC_API CRITICAL_SECTION GC_allocate_ml;
|
||||
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
|
||||
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
|
||||
# endif
|
||||
# endif
|
||||
# ifndef SET_LOCK_HOLDER
|
||||
# define SET_LOCK_HOLDER()
|
||||
|
||||
@@ -137,7 +137,7 @@ extern mse * GC_mark_stack;
|
||||
#ifdef __STDC__
|
||||
# ifdef PRINT_BLACK_LIST
|
||||
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p,
|
||||
ptr_t source);
|
||||
word source);
|
||||
# else
|
||||
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
|
||||
# endif
|
||||
@@ -145,7 +145,7 @@ extern mse * GC_mark_stack;
|
||||
ptr_t GC_find_start();
|
||||
#endif
|
||||
|
||||
mse * GC_signal_mark_stack_overflow();
|
||||
mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
|
||||
|
||||
# ifdef GATHERSTATS
|
||||
# define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz)
|
||||
@@ -174,14 +174,6 @@ mse * GC_signal_mark_stack_overflow();
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef PRINT_BLACK_LIST
|
||||
# define GC_FIND_START(current, hhdr, new_hdr_p, source) \
|
||||
GC_find_start(current, hhdr, new_hdr_p, source)
|
||||
#else
|
||||
# define GC_FIND_START(current, hhdr, new_hdr_p, source) \
|
||||
GC_find_start(current, hhdr, new_hdr_p)
|
||||
#endif
|
||||
|
||||
/* Push the contents of current onto the mark stack if it is a valid */
|
||||
/* ptr to a currently unmarked object. Mark it. */
|
||||
/* If we assumed a standard-conforming compiler, we could probably */
|
||||
@@ -195,8 +187,7 @@ mse * GC_signal_mark_stack_overflow();
|
||||
GET_HDR(my_current, my_hhdr); \
|
||||
if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
|
||||
hdr * new_hdr = GC_invalid_header; \
|
||||
my_current = GC_FIND_START(my_current, my_hhdr, \
|
||||
&new_hdr, (word)source); \
|
||||
my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \
|
||||
my_hhdr = new_hdr; \
|
||||
} \
|
||||
PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
|
||||
@@ -236,7 +227,6 @@ exit_label: ; \
|
||||
# define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \
|
||||
{ \
|
||||
register word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(displ); \
|
||||
register word mark_word = *mark_word_addr; \
|
||||
\
|
||||
OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(displ), \
|
||||
exit_label); \
|
||||
|
||||
+53
-103
@@ -30,6 +30,12 @@
|
||||
# define BSD_TIME
|
||||
#endif
|
||||
|
||||
#ifdef DGUX
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif /* DGUX */
|
||||
|
||||
#ifdef BSD_TIME
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
@@ -44,10 +50,6 @@
|
||||
# include "../gc_mark.h"
|
||||
# endif
|
||||
|
||||
# ifndef GCCONFIG_H
|
||||
# include "gcconfig.h"
|
||||
# endif
|
||||
|
||||
typedef GC_word word;
|
||||
typedef GC_signed_word signed_word;
|
||||
|
||||
@@ -60,6 +62,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
||||
/* Preferably identical to caddr_t, if it */
|
||||
/* exists. */
|
||||
|
||||
# ifndef GCCONFIG_H
|
||||
# include "gcconfig.h"
|
||||
# endif
|
||||
|
||||
# ifndef HEADERS_H
|
||||
# include "gc_hdrs.h"
|
||||
# endif
|
||||
@@ -205,6 +211,11 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
||||
/* odd numbered words to have mark bits. */
|
||||
#endif
|
||||
|
||||
#if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE)
|
||||
/* GCJ's Hashtable synchronization code requires 64-bit alignment. */
|
||||
# define ALIGN_DOUBLE
|
||||
#endif
|
||||
|
||||
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
|
||||
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
|
||||
# define MERGE_SIZES
|
||||
@@ -249,20 +260,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
||||
|
||||
#ifdef SAVE_CALL_CHAIN
|
||||
|
||||
/*
|
||||
* Number of frames and arguments to save in objects allocated by
|
||||
* debugging allocator.
|
||||
*/
|
||||
# ifndef SAVE_CALL_COUNT
|
||||
# define NFRAMES 6 /* Number of frames to save. Even for */
|
||||
/* alignment reasons. */
|
||||
# else
|
||||
# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
|
||||
# endif
|
||||
# define NARGS 2 /* Mumber of arguments to save for each call. */
|
||||
|
||||
# define NEED_CALLINFO
|
||||
|
||||
/* Fill in the pc and argument information for up to NFRAMES of my */
|
||||
/* callers. Ignore my frame and my callers frame. */
|
||||
struct callinfo;
|
||||
@@ -270,14 +267,6 @@ void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||
|
||||
void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||
|
||||
#else
|
||||
|
||||
# ifdef GC_ADD_CALLER
|
||||
# define NFRAMES 1
|
||||
# define NARGS 0
|
||||
# define NEED_CALLINFO
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NEED_CALLINFO
|
||||
@@ -376,68 +365,6 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||
# define BZERO(x,n) bzero((char *)(x),(int)(n))
|
||||
# endif
|
||||
|
||||
/* HBLKSIZE aligned allocation. 0 is taken to mean failure */
|
||||
/* space is assumed to be cleared. */
|
||||
/* In the case os USE_MMAP, the argument must also be a */
|
||||
/* physical page size. */
|
||||
/* GET_MEM is currently not assumed to retrieve 0 filled space, */
|
||||
/* though we should perhaps take advantage of the case in which */
|
||||
/* does. */
|
||||
struct hblk; /* See below. */
|
||||
# ifdef PCR
|
||||
char * real_malloc();
|
||||
# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
|
||||
+ GC_page_size-1)
|
||||
# else
|
||||
# ifdef OS2
|
||||
void * os2_alloc(size_t bytes);
|
||||
# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
|
||||
+ GC_page_size) \
|
||||
+ GC_page_size-1)
|
||||
# else
|
||||
# if defined(NEXT) || defined(MACOSX) || defined(DOS4GW) || \
|
||||
(defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
|
||||
(defined(SUNOS5) && !defined(USE_MMAP))
|
||||
# define GET_MEM(bytes) HBLKPTR((size_t) \
|
||||
calloc(1, (size_t)bytes + GC_page_size) \
|
||||
+ GC_page_size-1)
|
||||
# else
|
||||
# ifdef MSWIN32
|
||||
extern ptr_t GC_win32_get_mem();
|
||||
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
|
||||
# else
|
||||
# ifdef MACOS
|
||||
# if defined(USE_TEMPORARY_MEMORY)
|
||||
extern Ptr GC_MacTemporaryNewPtr(size_t size,
|
||||
Boolean clearMemory);
|
||||
# define GET_MEM(bytes) HBLKPTR( \
|
||||
GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
|
||||
+ GC_page_size-1)
|
||||
# else
|
||||
# define GET_MEM(bytes) HBLKPTR( \
|
||||
NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
|
||||
# endif
|
||||
# else
|
||||
# ifdef MSWINCE
|
||||
extern ptr_t GC_wince_get_mem();
|
||||
# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
|
||||
# else
|
||||
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
|
||||
extern void *GC_amiga_get_mem(size_t size);
|
||||
define GET_MEM(bytes) HBLKPTR((size_t) \
|
||||
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
|
||||
+ GC_page_size-1)
|
||||
# else
|
||||
extern ptr_t GC_unix_get_mem();
|
||||
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* Delay any interrupts or signals that may abort this thread. Data */
|
||||
/* structures are in a consistent state outside this pair of calls. */
|
||||
/* ANSI C allows both to be empty (though the standard isn't very */
|
||||
@@ -502,7 +429,7 @@ struct hblk; /* See below. */
|
||||
# ifdef SMALL_CONFIG
|
||||
# define ABORT(msg) abort();
|
||||
# else
|
||||
GC_API void GC_abort();
|
||||
GC_API void GC_abort GC_PROTO((GC_CONST char * msg));
|
||||
# define ABORT(msg) GC_abort(msg);
|
||||
# endif
|
||||
# endif
|
||||
@@ -515,7 +442,7 @@ struct hblk; /* See below. */
|
||||
# endif
|
||||
|
||||
/* Print warning message, e.g. almost out of memory. */
|
||||
# define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg))
|
||||
# define WARN(msg,arg) (*GC_current_warn_proc)("GC Warning: " msg, (GC_word)(arg))
|
||||
extern GC_warn_proc GC_current_warn_proc;
|
||||
|
||||
/* Get environment entry */
|
||||
@@ -788,12 +715,11 @@ struct hblkhdr {
|
||||
# define BODY_SZ (HBLKSIZE/sizeof(word))
|
||||
|
||||
struct hblk {
|
||||
# if 0 /* DISCARDWORDS no longer supported */
|
||||
word garbage[DISCARD_WORDS];
|
||||
# endif
|
||||
word hb_body[BODY_SZ];
|
||||
};
|
||||
|
||||
# define HBLK_IS_FREE(hdr) ((hdr) -> hb_map == GC_invalid_map)
|
||||
|
||||
# define OBJ_SZ_TO_BLOCKS(sz) \
|
||||
divHBLKSZ(WORDS_TO_BYTES(sz) + HBLKSIZE-1)
|
||||
/* Size of block (in units of HBLKSIZE) needed to hold objects of */
|
||||
@@ -914,6 +840,10 @@ struct _GC_arrays {
|
||||
word _mem_freed;
|
||||
/* Number of explicitly deallocated words of memory */
|
||||
/* since last collection. */
|
||||
word _finalizer_mem_freed;
|
||||
/* Words of memory explicitly deallocated while */
|
||||
/* finalizers were running. Used to approximate mem. */
|
||||
/* explicitly deallocated by finalizers. */
|
||||
ptr_t _scratch_end_ptr;
|
||||
ptr_t _scratch_last_end_ptr;
|
||||
/* Used by headers.c, and can easily appear to point to */
|
||||
@@ -1084,6 +1014,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
|
||||
# define GC_words_finalized GC_arrays._words_finalized
|
||||
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
|
||||
# define GC_mem_freed GC_arrays._mem_freed
|
||||
# define GC_finalizer_mem_freed GC_arrays._finalizer_mem_freed
|
||||
# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
|
||||
# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
|
||||
# define GC_mark_procs GC_arrays._mark_procs
|
||||
@@ -1218,17 +1149,19 @@ extern struct hblk * GC_hblkfreelist[];
|
||||
/* header structure associated with */
|
||||
/* block. */
|
||||
|
||||
extern GC_bool GC_is_initialized; /* GC_init() has been run. */
|
||||
|
||||
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
|
||||
/* the heap. */
|
||||
|
||||
#ifndef SMALL_CONFIG
|
||||
extern GC_bool GC_incremental;
|
||||
/* Using incremental/generational collection. */
|
||||
# define TRUE_INCREMENTAL \
|
||||
(GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
|
||||
/* True incremental, not just generational, mode */
|
||||
#else
|
||||
# define GC_incremental FALSE
|
||||
/* Hopefully allow optimizer to remove some code. */
|
||||
# define TRUE_INCREMENTAL FALSE
|
||||
#endif
|
||||
|
||||
extern GC_bool GC_dirty_maintained;
|
||||
@@ -1240,7 +1173,12 @@ extern word GC_root_size; /* Total size of registered root sections */
|
||||
|
||||
extern GC_bool GC_debugging_started; /* GC_debug_malloc has been called. */
|
||||
|
||||
|
||||
extern long GC_large_alloc_warn_interval;
|
||||
/* Interval between unsuppressed warnings. */
|
||||
|
||||
extern long GC_large_alloc_warn_suppressed;
|
||||
/* Number of warnings suppressed so far. */
|
||||
|
||||
/* Operations */
|
||||
# ifndef abs
|
||||
# define abs(x) ((x) < 0? (-(x)) : (x))
|
||||
@@ -1630,7 +1568,8 @@ GC_bool GC_collect_or_expand GC_PROTO(( \
|
||||
/* blocks available. Should be called */
|
||||
/* until the blocks are available or */
|
||||
/* until it fails by returning FALSE. */
|
||||
GC_API void GC_init GC_PROTO((void)); /* Initialize collector. */
|
||||
|
||||
extern GC_bool GC_is_initialized; /* GC_init() has been run. */
|
||||
|
||||
#if defined(MSWIN32) || defined(MSWINCE)
|
||||
void GC_deinit GC_PROTO((void));
|
||||
@@ -1712,8 +1651,11 @@ void GC_print_obj GC_PROTO((ptr_t p));
|
||||
/* description of the object to stderr. */
|
||||
extern void (*GC_check_heap) GC_PROTO((void));
|
||||
/* Check that all objects in the heap with */
|
||||
/* debugging info are intact. Print */
|
||||
/* descriptions of any that are not. */
|
||||
/* debugging info are intact. */
|
||||
/* Add any that are not to GC_smashed list. */
|
||||
extern void (*GC_print_all_smashed) GC_PROTO((void));
|
||||
/* Print GC_smashed if it's not empty. */
|
||||
/* Clear GC_smashed list. */
|
||||
extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p));
|
||||
/* If possible print s followed by a more */
|
||||
/* detailed description of the object */
|
||||
@@ -1767,8 +1709,12 @@ GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h));
|
||||
void GC_is_fresh GC_PROTO((struct hblk *h, word n));
|
||||
/* Assert the region currently contains no */
|
||||
/* valid pointers. */
|
||||
void GC_write_hint GC_PROTO((struct hblk *h));
|
||||
/* h is about to be written. */
|
||||
void GC_remove_protection GC_PROTO((struct hblk *h, word nblocks,
|
||||
GC_bool pointerfree));
|
||||
/* h is about to be writteni or allocated. Ensure */
|
||||
/* that it's not write protected by the virtual */
|
||||
/* dirty bit implementation. */
|
||||
|
||||
void GC_dirty_init GC_PROTO((void));
|
||||
|
||||
/* Slow/general mark bit manipulation: */
|
||||
@@ -1915,7 +1861,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
|
||||
/* in Linux glibc, but it's not exported.) Thus we continue to use */
|
||||
/* the same hard-coded signals we've always used. */
|
||||
# if !defined(SIG_SUSPEND)
|
||||
# if defined(GC_LINUX_THREADS)
|
||||
# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
|
||||
# if defined(SPARC) && !defined(SIGPWR)
|
||||
/* SPARC/Linux doesn't properly define SIGPWR in <signal.h>.
|
||||
* It is aliased to SIGLOST in asm/signal.h, though. */
|
||||
@@ -1925,7 +1871,11 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
|
||||
# define SIG_SUSPEND SIGPWR
|
||||
# endif
|
||||
# else /* !GC_LINUX_THREADS */
|
||||
# define SIG_SUSPEND _SIGRTMIN + 6
|
||||
# if defined(_SIGRTMIN)
|
||||
# define SIG_SUSPEND _SIGRTMIN + 6
|
||||
# else
|
||||
# define SIG_SUSPEND SIGRTMIN + 6
|
||||
# endif
|
||||
# endif
|
||||
# endif /* !SIG_SUSPEND */
|
||||
|
||||
|
||||
+422
-188
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,8 @@
|
||||
# define DETACHED 2 /* Thread is intended to be detached. */
|
||||
# define CLIENT_OWNS_STACK 4
|
||||
/* Stack was supplied by client. */
|
||||
# define SUSPENDED 8 /* Currently suspended. */
|
||||
# define SUSPNDED 8 /* Currently suspended. */
|
||||
/* SUSPENDED is used insystem header. */
|
||||
ptr_t stack;
|
||||
size_t stack_size;
|
||||
cond_t join_cv;
|
||||
|
||||
@@ -27,16 +27,22 @@
|
||||
#define TS_HASH_SIZE 1024
|
||||
#define HASH(n) (((((long)n) >> 8) ^ (long)n) & (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 tread 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 {
|
||||
unsigned long qtid; /* quick thread id, only for cache */
|
||||
void * value;
|
||||
pthread_t thread;
|
||||
struct thread_specific_entry *next;
|
||||
pthread_t thread;
|
||||
} tse;
|
||||
|
||||
|
||||
/* We represent each thread-specific datum as two tables. The first is */
|
||||
/* a cache, index by a "quick thread identifier". The "quick" thread */
|
||||
/* 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. */
|
||||
@@ -45,12 +51,15 @@ typedef struct thread_specific_entry {
|
||||
|
||||
/* Return the "quick thread id". Default version. Assumes page size, */
|
||||
/* or at least thread stack separation, is at least 4K. */
|
||||
static __inline__ long quick_thread_id() {
|
||||
/* 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.)*/
|
||||
static __inline__ unsigned long quick_thread_id() {
|
||||
int dummy;
|
||||
return (long)(&dummy) >> 12;
|
||||
return (unsigned long)(&dummy) >> 12;
|
||||
}
|
||||
|
||||
#define INVALID_QTID ((unsigned long)(-1))
|
||||
#define INVALID_QTID ((unsigned long)0)
|
||||
#define INVALID_THREADID ((pthread_t)0)
|
||||
|
||||
typedef struct thread_specific_data {
|
||||
tse * volatile cache[TS_CACHE_SIZE];
|
||||
@@ -76,7 +85,10 @@ static __inline__ void * PREFIXED(getspecific) (tsd * key) {
|
||||
unsigned hash_val = CACHE_HASH(qtid);
|
||||
tse * volatile * entry_ptr = key -> cache + hash_val;
|
||||
tse * entry = *entry_ptr; /* Must be loaded only once. */
|
||||
if (entry -> qtid == qtid) return entry -> value;
|
||||
if (entry -> qtid == qtid) {
|
||||
GC_ASSERT(entry -> thread == pthread_self());
|
||||
return entry -> value;
|
||||
}
|
||||
return PREFIXED(slow_getspecific) (key, qtid, entry_ptr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user