summaryrefslogtreecommitdiff
path: root/src/gc
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2017-04-27 16:54:50 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2017-04-27 16:54:50 +0900
commit5b975f8233e8c8d17b215372f89ca713b45d6a0b (patch)
tree0267bcc331458a01f4c26fafd28110a72273beb3 /src/gc
parenta56e30c8d33048216567753d9d3fefc2152af8ac (diff)
downloadcoreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.tar.gz
coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.tar.bz2
coreclr-5b975f8233e8c8d17b215372f89ca713b45d6a0b.zip
Imported Upstream version 2.0.0.11599upstream/2.0.0.11599
Diffstat (limited to 'src/gc')
-rw-r--r--src/gc/env/gcenv.os.h80
-rw-r--r--src/gc/gc.cpp52
-rw-r--r--src/gc/gc.h6
-rw-r--r--src/gc/gccommon.cpp12
-rw-r--r--src/gc/gcee.cpp11
-rw-r--r--src/gc/gchandletable.cpp128
-rw-r--r--src/gc/gchandletableimpl.h43
-rw-r--r--src/gc/gcimpl.h7
-rw-r--r--src/gc/gcinterface.h50
-rw-r--r--src/gc/gcpriv.h28
-rw-r--r--src/gc/handletable.cpp12
-rw-r--r--src/gc/handletable.inl21
-rw-r--r--src/gc/handletablecore.cpp38
-rw-r--r--src/gc/handletablescan.cpp4
-rw-r--r--src/gc/objecthandle.cpp138
-rw-r--r--src/gc/objecthandle.h24
-rw-r--r--src/gc/sample/GCSample.cpp8
-rw-r--r--src/gc/unix/CMakeLists.txt1
-rw-r--r--src/gc/unix/config.h.in4
-rw-r--r--src/gc/unix/configure.cmake17
-rw-r--r--src/gc/unix/events.cpp323
-rw-r--r--src/gc/unix/gcenv.unix.cpp41
-rw-r--r--src/gc/unix/globals.h30
-rw-r--r--src/gc/windows/gcenv.windows.cpp142
24 files changed, 938 insertions, 282 deletions
diff --git a/src/gc/env/gcenv.os.h b/src/gc/env/gcenv.os.h
index 6a126f29ed..d3e40ac4ff 100644
--- a/src/gc/env/gcenv.os.h
+++ b/src/gc/env/gcenv.os.h
@@ -47,6 +47,86 @@ struct GCThreadAffinity
int Processor;
};
+// An event is a synchronization object whose state can be set and reset
+// indicating that an event has occured. It is used pervasively throughout
+// the GC.
+//
+// Note that GCEvent deliberately leaks its contents by not having a non-trivial destructor.
+// This is by design; since all uses of GCEvent have static lifetime, their destructors
+// are run on process exit, potentially concurrently with other threads that may still be
+// operating on the static event. To avoid these sorts of unsafety, GCEvent chooses to
+// not have a destructor at all. The cost of this is leaking a small amount of memory, but
+// this is not a problem since a majority of the uses of GCEvent are static. See CoreCLR#11111
+// for more details on the hazards of static destructors.
+class GCEvent {
+private:
+ class Impl;
+ Impl *m_impl;
+
+public:
+ // Constructs a new uninitialized event.
+ GCEvent();
+
+ // Closes the event. Attempting to use the event past calling CloseEvent
+ // is a logic error.
+ void CloseEvent();
+
+ // "Sets" the event, indicating that a particular event has occured. May
+ // wake up other threads waiting on this event. Depending on whether or
+ // not this event is an auto-reset event, the state of the event may
+ // or may not be automatically reset after Set is called.
+ void Set();
+
+ // Resets the event, resetting it back to a non-signalled state. Auto-reset
+ // events automatically reset once the event is set, while manual-reset
+ // events do not reset until Reset is called. It is a no-op to call Reset
+ // on an auto-reset event.
+ void Reset();
+
+ // Waits for some period of time for this event to be signalled. The
+ // period of time may be infinite (if the timeout argument is INFINITE) or
+ // it may be a specified period of time, in milliseconds.
+ // Returns:
+ // One of three values, depending on how why this thread was awoken:
+ // WAIT_OBJECT_0 - This event was signalled and woke up this thread.
+ // WAIT_TIMEOUT - The timeout interval expired without this event being signalled.
+ // WAIT_FAILED - The wait failed.
+ uint32_t Wait(uint32_t timeout, bool alertable);
+
+ // Determines whether or not this event is valid.
+ // Returns:
+ // true if this event is invalid (i.e. it has not yet been initialized or
+ // has already been closed), false otherwise
+ bool IsValid() const
+ {
+ return m_impl != nullptr;
+ }
+
+ // Initializes this event to be a host-aware manual reset event with the
+ // given initial state.
+ // Returns:
+ // true if the initialization succeeded, false if it did not
+ bool CreateManualEventNoThrow(bool initialState);
+
+ // Initializes this event to be a host-aware auto-resetting event with the
+ // given initial state.
+ // Returns:
+ // true if the initialization succeeded, false if it did not
+ bool CreateAutoEventNoThrow(bool initialState);
+
+ // Initializes this event to be a host-unaware manual reset event with the
+ // given initial state.
+ // Returns:
+ // true if the initialization succeeded, false if it did not
+ bool CreateOSManualEventNoThrow(bool initialState);
+
+ // Initializes this event to be a host-unaware auto-resetting event with the
+ // given initial state.
+ // Returns:
+ // true if the initialization succeeded, false if it did not
+ bool CreateOSAutoEventNoThrow(bool initialState);
+};
+
// GC thread function prototype
typedef void (*GCThreadFunction)(void* param);
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index ecc13e38fd..08de1facb2 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -621,7 +621,7 @@ enum gc_join_flavor
#define first_thread_arrived 2
struct join_structure
{
- CLREvent joined_event[3]; // the last event in the array is only used for first_thread_arrived.
+ GCEvent joined_event[3]; // the last event in the array is only used for first_thread_arrived.
VOLATILE(int32_t) join_lock;
VOLATILE(int32_t) r_join_lock;
VOLATILE(int32_t) join_restart;
@@ -1201,8 +1201,8 @@ class recursive_gc_sync
static VOLATILE(BOOL) gc_background_running; //initial state FALSE
static VOLATILE(int32_t) foreground_count; // initial state 0;
static VOLATILE(uint32_t) foreground_gate; // initial state FALSE;
- static CLREvent foreground_complete;//Auto Reset
- static CLREvent foreground_allowed;//Auto Reset
+ static GCEvent foreground_complete;//Auto Reset
+ static GCEvent foreground_allowed;//Auto Reset
public:
static void begin_background();
static void end_background();
@@ -1218,8 +1218,8 @@ VOLATILE(int32_t) recursive_gc_sync::foreground_request_count = 0;//initial stat
VOLATILE(int32_t) recursive_gc_sync::foreground_count = 0; // initial state 0;
VOLATILE(BOOL) recursive_gc_sync::gc_background_running = FALSE; //initial state FALSE
VOLATILE(uint32_t) recursive_gc_sync::foreground_gate = 0;
-CLREvent recursive_gc_sync::foreground_complete;//Auto Reset
-CLREvent recursive_gc_sync::foreground_allowed;//Manual Reset
+GCEvent recursive_gc_sync::foreground_complete;//Auto Reset
+GCEvent recursive_gc_sync::foreground_allowed;//Manual Reset
BOOL recursive_gc_sync::init ()
{
@@ -2308,7 +2308,7 @@ sorted_table* gc_heap::seg_table;
#endif //!SEG_MAPPING_TABLE || FEATURE_BASICFREEZE
#ifdef MULTIPLE_HEAPS
-CLREvent gc_heap::ee_suspend_event;
+GCEvent gc_heap::ee_suspend_event;
size_t gc_heap::min_balance_threshold = 0;
#endif //MULTIPLE_HEAPS
@@ -2316,7 +2316,7 @@ VOLATILE(BOOL) gc_heap::gc_started;
#ifdef MULTIPLE_HEAPS
-CLREvent gc_heap::gc_start_event;
+GCEvent gc_heap::gc_start_event;
bool gc_heap::gc_thread_no_affinitize_p = false;
@@ -2385,13 +2385,13 @@ uint64_t gc_heap::total_physical_mem;
uint64_t gc_heap::entry_available_physical_mem;
#ifdef BACKGROUND_GC
-CLREvent gc_heap::bgc_start_event;
+GCEvent gc_heap::bgc_start_event;
gc_mechanisms gc_heap::saved_bgc_settings;
-CLREvent gc_heap::background_gc_done_event;
+GCEvent gc_heap::background_gc_done_event;
-CLREvent gc_heap::ee_proceed_event;
+GCEvent gc_heap::ee_proceed_event;
bool gc_heap::gc_can_use_concurrent = false;
@@ -2403,7 +2403,7 @@ BOOL gc_heap::dont_restart_ee_p = FALSE;
BOOL gc_heap::keep_bgc_threads_p = FALSE;
-CLREvent gc_heap::bgc_threads_sync_event;
+GCEvent gc_heap::bgc_threads_sync_event;
BOOL gc_heap::do_ephemeral_gc_p = FALSE;
@@ -2589,7 +2589,7 @@ BOOL gc_heap::bgc_thread_running;
CLRCriticalSection gc_heap::bgc_threads_timeout_cs;
-CLREvent gc_heap::gc_lh_block_event;
+GCEvent gc_heap::gc_lh_block_event;
#endif //BACKGROUND_GC
@@ -2685,9 +2685,9 @@ int gc_heap::loh_pinned_queue_decay = LOH_PIN_DECAY;
#endif //FEATURE_LOH_COMPACTION
-CLREvent gc_heap::full_gc_approach_event;
+GCEvent gc_heap::full_gc_approach_event;
-CLREvent gc_heap::full_gc_end_event;
+GCEvent gc_heap::full_gc_end_event;
uint32_t gc_heap::fgn_maxgen_percent = 0;
@@ -5151,7 +5151,6 @@ void gc_heap::destroy_thread_support ()
}
}
-#if !defined(FEATURE_PAL)
void set_thread_group_affinity_for_heap(int heap_number, GCThreadAffinity* affinity)
{
affinity->Group = GCThreadAffinity::None;
@@ -5231,7 +5230,6 @@ void set_thread_affinity_mask_for_heap(int heap_number, GCThreadAffinity* affini
}
}
}
-#endif // !FEATURE_PAL
bool gc_heap::create_gc_thread ()
{
@@ -5241,7 +5239,6 @@ bool gc_heap::create_gc_thread ()
affinity.Group = GCThreadAffinity::None;
affinity.Processor = GCThreadAffinity::None;
-#if !defined(FEATURE_PAL)
if (!gc_thread_no_affinitize_p)
{
// We are about to set affinity for GC threads. It is a good place to set up NUMA and
@@ -5252,7 +5249,6 @@ bool gc_heap::create_gc_thread ()
else
set_thread_affinity_mask_for_heap(heap_number, &affinity);
}
-#endif // !FEATURE_PAL
return GCToOSInterface::CreateThread(gc_thread_stub, this, &affinity);
}
@@ -9266,12 +9262,10 @@ void gc_heap::delete_heap_segment (heap_segment* seg, BOOL consider_hoarding)
void gc_heap::reset_heap_segment_pages (heap_segment* seg)
{
-#ifndef FEATURE_PAL // No MEM_RESET support in PAL VirtualAlloc
size_t page_start = align_on_page ((size_t)heap_segment_allocated (seg));
size_t size = (size_t)heap_segment_committed (seg) - page_start;
if (size != 0)
GCToOSInterface::VirtualReset((void*)page_start, size, false /* unlock */);
-#endif //!FEATURE_PAL
}
void gc_heap::decommit_heap_segment_pages (heap_segment* seg,
@@ -10312,7 +10306,7 @@ gc_heap::loh_state_info gc_heap::last_loh_states[max_saved_loh_states];
VOLATILE(int32_t) gc_heap::gc_done_event_lock;
VOLATILE(bool) gc_heap::gc_done_event_set;
-CLREvent gc_heap::gc_done_event;
+GCEvent gc_heap::gc_done_event;
#endif //!MULTIPLE_HEAPS
VOLATILE(bool) gc_heap::internal_gc_done;
@@ -11741,7 +11735,7 @@ void gc_heap::send_full_gc_notification (int gen_num, BOOL due_to_alloc_p)
}
}
-wait_full_gc_status gc_heap::full_gc_wait (CLREvent *event, int time_out_ms)
+wait_full_gc_status gc_heap::full_gc_wait (GCEvent *event, int time_out_ms)
{
if (fgn_maxgen_percent == 0)
{
@@ -20362,7 +20356,7 @@ size_t gc_heap::update_brick_table (uint8_t* tree, size_t current_brick,
dprintf (3, ("tree: %Ix, current b: %Ix, x: %Ix, plug_end: %Ix",
tree, current_brick, x, plug_end));
- if (tree > 0)
+ if (tree != NULL)
{
dprintf (3, ("b- %Ix->%Ix pointing to tree %Ix",
current_brick, (size_t)(tree - brick_address (current_brick)), tree));
@@ -30809,7 +30803,6 @@ CObjectHeader* gc_heap::allocate_large_object (size_t jsize, int64_t& alloc_byte
void reset_memory (uint8_t* o, size_t sizeo)
{
-#ifndef FEATURE_PAL
if (sizeo > 128 * 1024)
{
// We cannot reset the memory for the useful part of a free object.
@@ -30824,7 +30817,6 @@ void reset_memory (uint8_t* o, size_t sizeo)
reset_mm_p = GCToOSInterface::VirtualReset((void*)page_start, size, true /* unlock */);
}
}
-#endif //!FEATURE_PAL
}
void gc_heap::reset_large_object (uint8_t* o)
@@ -32417,7 +32409,7 @@ void gc_heap::descr_generations (BOOL begin_gc_p)
VOLATILE(BOOL) GCHeap::GcInProgress = FALSE;
//GCTODO
//CMCSafeLock* GCHeap::fGcLock;
-CLREvent *GCHeap::WaitForGCEvent = NULL;
+GCEvent *GCHeap::WaitForGCEvent = NULL;
//GCTODO
#ifdef TRACE_GC
unsigned int GCHeap::GcDuration;
@@ -33691,7 +33683,7 @@ HRESULT GCHeap::Initialize ()
gc_heap::youngest_gen_desired_th = gc_heap::mem_one_percent;
#endif // BIT64
- WaitForGCEvent = new (nothrow) CLREvent;
+ WaitForGCEvent = new (nothrow) GCEvent;
if (!WaitForGCEvent)
{
@@ -33891,7 +33883,7 @@ bool GCHeap::IsHeapPointer (void* vpObject, bool small_heap_only)
STATIC_CONTRACT_SO_TOLERANT;
// removed STATIC_CONTRACT_CAN_TAKE_LOCK here because find_segment
- // no longer calls CLREvent::Wait which eventually takes a lock.
+ // no longer calls GCEvent::Wait which eventually takes a lock.
uint8_t* object = (uint8_t*) vpObject;
#ifndef FEATURE_BASICFREEZE
@@ -34226,7 +34218,7 @@ bool GCHeap::StressHeap(gc_alloc_context * context)
if (g_pConfig->AppDomainLeaks() && str->SetAppDomainNoThrow())
{
#endif
- StoreObjectInHandle(m_StressObjs[i], ObjectToOBJECTREF(str));
+ HndAssignHandle(m_StressObjs[i], ObjectToOBJECTREF(str));
#if CHECK_APP_DOMAIN_LEAKS
}
#endif
@@ -34259,7 +34251,7 @@ bool GCHeap::StressHeap(gc_alloc_context * context)
{
// Let the string itself become garbage.
// will be realloced next time around
- StoreObjectInHandle(m_StressObjs[m_CurStressObj], 0);
+ HndAssignHandle(m_StressObjs[m_CurStressObj], 0);
}
}
}
diff --git a/src/gc/gc.h b/src/gc/gc.h
index a661c311ab..07ae6c916c 100644
--- a/src/gc/gc.h
+++ b/src/gc/gc.h
@@ -115,7 +115,7 @@ extern "C" GCHeapType g_gc_heap_type;
extern "C" uint32_t g_max_generation;
extern "C" MethodTable* g_gc_pFreeObjectMethodTable;
-::IGCHandleTable* CreateGCHandleTable();
+::IGCHandleManager* CreateGCHandleManager();
namespace WKS {
::IGCHeapInternal* CreateGCHeap();
@@ -260,8 +260,8 @@ void updateGCShadow(Object** ptr, Object* val);
// The single GC heap instance, shared with the VM.
extern IGCHeapInternal* g_theGCHeap;
-// The single GC handle table instance, shared with the VM.
-extern IGCHandleTable* g_theGCHandleTable;
+// The single GC handle manager instance, shared with the VM.
+extern IGCHandleManager* g_theGCHandleManager;
#ifndef DACCESS_COMPILE
inline bool IsGCInProgress(bool bConsiderGCStart = false)
diff --git a/src/gc/gccommon.cpp b/src/gc/gccommon.cpp
index f931597667..4950809cda 100644
--- a/src/gc/gccommon.cpp
+++ b/src/gc/gccommon.cpp
@@ -15,7 +15,7 @@
#include "gc.h"
IGCHeapInternal* g_theGCHeap;
-IGCHandleTable* g_theGCHandleTable;
+IGCHandleManager* g_theGCHandleManager;
#ifdef FEATURE_STANDALONE_GC
IGCToCLR* g_theGCToCLR;
@@ -143,7 +143,7 @@ namespace SVR
extern void PopulateDacVars(GcDacVars* dacVars);
}
-bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleTable** gcHandleTable, GcDacVars* gcDacVars)
+bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleManager** gcHandleManager, GcDacVars* gcDacVars)
{
LIMITED_METHOD_CONTRACT;
@@ -151,10 +151,10 @@ bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleTa
assert(gcDacVars != nullptr);
assert(gcHeap != nullptr);
- assert(gcHandleTable != nullptr);
+ assert(gcHandleManager != nullptr);
- IGCHandleTable* handleTable = CreateGCHandleTable();
- if (handleTable == nullptr)
+ IGCHandleManager* handleManager = CreateGCHandleManager();
+ if (handleManager == nullptr)
{
return false;
}
@@ -192,7 +192,7 @@ bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleTa
assert(clrToGC == nullptr);
#endif
- *gcHandleTable = handleTable;
+ *gcHandleManager = handleManager;
*gcHeap = heap;
return true;
}
diff --git a/src/gc/gcee.cpp b/src/gc/gcee.cpp
index 889f940973..0404058cde 100644
--- a/src/gc/gcee.cpp
+++ b/src/gc/gcee.cpp
@@ -428,9 +428,14 @@ void GCHeap::SetGCInProgress(bool fInProgress)
GcInProgress = fInProgress;
}
-CLREvent * GCHeap::GetWaitForGCEvent()
+void GCHeap::SetWaitForGCEvent()
{
- return WaitForGCEvent;
+ WaitForGCEvent->Set();
+}
+
+void GCHeap::ResetWaitForGCEvent()
+{
+ WaitForGCEvent->Reset();
}
void GCHeap::WaitUntilConcurrentGCComplete()
@@ -520,7 +525,7 @@ void gc_heap::fire_etw_pin_object_event (uint8_t* object, uint8_t** ppObject)
}
#endif // FEATURE_EVENT_TRACE
-uint32_t gc_heap::user_thread_wait (CLREvent *event, BOOL no_mode_change, int time_out_ms)
+uint32_t gc_heap::user_thread_wait (GCEvent *event, BOOL no_mode_change, int time_out_ms)
{
Thread* pCurThread = NULL;
bool mode = false;
diff --git a/src/gc/gchandletable.cpp b/src/gc/gchandletable.cpp
index 82ab269861..52fede6299 100644
--- a/src/gc/gchandletable.cpp
+++ b/src/gc/gchandletable.cpp
@@ -8,104 +8,146 @@
#include "gchandletableimpl.h"
#include "objecthandle.h"
-IGCHandleTable* CreateGCHandleTable()
+GCHandleStore* g_gcGlobalHandleStore;
+
+IGCHandleManager* CreateGCHandleManager()
{
- return new(nothrow) GCHandleTable();
+ return new (nothrow) GCHandleManager();
}
-bool GCHandleTable::Initialize()
+void GCHandleStore::Uproot()
{
- return Ref_Initialize();
+ Ref_RemoveHandleTableBucket(&_underlyingBucket);
}
-void GCHandleTable::Shutdown()
+bool GCHandleStore::ContainsHandle(OBJECTHANDLE handle)
{
- Ref_Shutdown();
+ return _underlyingBucket.Contains(handle);
}
-void* GCHandleTable::GetGlobalHandleStore()
+OBJECTHANDLE GCHandleStore::CreateHandleOfType(Object* object, int type)
{
- return (void*)g_HandleTableMap.pBuckets[0];
+ HHANDLETABLE handletable = _underlyingBucket.pTable[GetCurrentThreadHomeHeapNumber()];
+ return ::HndCreateHandle(handletable, type, ObjectToOBJECTREF(object));
}
-void* GCHandleTable::CreateHandleStore(void* context)
+OBJECTHANDLE GCHandleStore::CreateHandleOfType(Object* object, int type, int heapToAffinitizeTo)
{
-#ifndef FEATURE_REDHAWK
- return (void*)::Ref_CreateHandleTableBucket(ADIndex((DWORD)(uintptr_t)context));
-#else
- assert("CreateHandleStore is not implemented when FEATURE_REDHAWK is defined!");
- return nullptr;
-#endif
+ HHANDLETABLE handletable = _underlyingBucket.pTable[heapToAffinitizeTo];
+ return ::HndCreateHandle(handletable, type, ObjectToOBJECTREF(object));
}
-void* GCHandleTable::GetHandleContext(OBJECTHANDLE handle)
+OBJECTHANDLE GCHandleStore::CreateHandleWithExtraInfo(Object* object, int type, void* pExtraInfo)
{
- return (void*)((uintptr_t)::HndGetHandleTableADIndex(::HndGetHandleTable(handle)).m_dwIndex);
+ HHANDLETABLE handletable = _underlyingBucket.pTable[GetCurrentThreadHomeHeapNumber()];
+ return ::HndCreateHandle(handletable, type, ObjectToOBJECTREF(object), reinterpret_cast<uintptr_t>(pExtraInfo));
}
-void GCHandleTable::DestroyHandleStore(void* store)
+OBJECTHANDLE GCHandleStore::CreateDependentHandle(Object* primary, Object* secondary)
{
- Ref_DestroyHandleTableBucket((HandleTableBucket*) store);
+ HHANDLETABLE handletable = _underlyingBucket.pTable[GetCurrentThreadHomeHeapNumber()];
+ OBJECTHANDLE handle = ::HndCreateHandle(handletable, HNDTYPE_DEPENDENT, ObjectToOBJECTREF(primary));
+ if (!handle)
+ {
+ return nullptr;
+ }
+
+ ::SetDependentHandleSecondary(handle, ObjectToOBJECTREF(secondary));
+ return handle;
}
-void GCHandleTable::UprootHandleStore(void* store)
+GCHandleStore::~GCHandleStore()
{
- Ref_RemoveHandleTableBucket((HandleTableBucket*) store);
+ ::Ref_DestroyHandleTableBucket(&_underlyingBucket);
}
-bool GCHandleTable::ContainsHandle(void* store, OBJECTHANDLE handle)
+bool GCHandleManager::Initialize()
{
- return ((HandleTableBucket*)store)->Contains(handle);
+ return Ref_Initialize();
}
-OBJECTHANDLE GCHandleTable::CreateHandleOfType(void* store, Object* object, int type)
+void GCHandleManager::Shutdown()
{
- HHANDLETABLE handletable = ((HandleTableBucket*)store)->pTable[GetCurrentThreadHomeHeapNumber()];
- return ::HndCreateHandle(handletable, type, ObjectToOBJECTREF(object));
+ if (g_gcGlobalHandleStore != nullptr)
+ {
+ DestroyHandleStore(g_gcGlobalHandleStore);
+ }
+
+ ::Ref_Shutdown();
}
-OBJECTHANDLE GCHandleTable::CreateHandleOfType(void* store, Object* object, int type, int heapToAffinitizeTo)
+IGCHandleStore* GCHandleManager::GetGlobalHandleStore()
{
- HHANDLETABLE handletable = ((HandleTableBucket*)store)->pTable[heapToAffinitizeTo];
- return ::HndCreateHandle(handletable, type, ObjectToOBJECTREF(object));
+ return g_gcGlobalHandleStore;
}
-OBJECTHANDLE GCHandleTable::CreateGlobalHandleOfType(Object* object, int type)
+IGCHandleStore* GCHandleManager::CreateHandleStore(void* context)
{
- return ::HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], type, ObjectToOBJECTREF(object));
+#ifndef FEATURE_REDHAWK
+ GCHandleStore* store = new (nothrow) GCHandleStore();
+ if (store == nullptr)
+ return nullptr;
+
+ bool success = ::Ref_InitializeHandleTableBucket(&store->_underlyingBucket, context);
+ if (!success)
+ {
+ delete store;
+ return nullptr;
+ }
+
+ return store;
+#else
+ assert("CreateHandleStore is not implemented when FEATURE_REDHAWK is defined!");
+ return nullptr;
+#endif
}
-OBJECTHANDLE GCHandleTable::CreateHandleWithExtraInfo(void* store, Object* object, int type, void* pExtraInfo)
+void GCHandleManager::DestroyHandleStore(IGCHandleStore* store)
{
- HHANDLETABLE handletable = ((HandleTableBucket*)store)->pTable[GetCurrentThreadHomeHeapNumber()];
- return ::HndCreateHandle(handletable, type, ObjectToOBJECTREF(object), reinterpret_cast<uintptr_t>(pExtraInfo));
+ delete store;
}
-OBJECTHANDLE GCHandleTable::CreateDependentHandle(void* store, Object* primary, Object* secondary)
+void* GCHandleManager::GetHandleContext(OBJECTHANDLE handle)
{
- HHANDLETABLE handletable = ((HandleTableBucket*)store)->pTable[GetCurrentThreadHomeHeapNumber()];
- OBJECTHANDLE handle = ::HndCreateHandle(handletable, HNDTYPE_DEPENDENT, ObjectToOBJECTREF(primary));
- ::SetDependentHandleSecondary(handle, ObjectToOBJECTREF(secondary));
+ return (void*)((uintptr_t)::HndGetHandleTableADIndex(::HndGetHandleTable(handle)).m_dwIndex);
+}
- return handle;
+OBJECTHANDLE GCHandleManager::CreateGlobalHandleOfType(Object* object, int type)
+{
+ return ::HndCreateHandle(g_HandleTableMap.pBuckets[0]->pTable[GetCurrentThreadHomeHeapNumber()], type, ObjectToOBJECTREF(object));
}
-OBJECTHANDLE GCHandleTable::CreateDuplicateHandle(OBJECTHANDLE handle)
+OBJECTHANDLE GCHandleManager::CreateDuplicateHandle(OBJECTHANDLE handle)
{
return ::HndCreateHandle(HndGetHandleTable(handle), HNDTYPE_DEFAULT, ::HndFetchHandle(handle));
}
-void GCHandleTable::DestroyHandleOfType(OBJECTHANDLE handle, int type)
+void GCHandleManager::DestroyHandleOfType(OBJECTHANDLE handle, int type)
{
::HndDestroyHandle(::HndGetHandleTable(handle), type, handle);
}
-void GCHandleTable::DestroyHandleOfUnknownType(OBJECTHANDLE handle)
+void GCHandleManager::DestroyHandleOfUnknownType(OBJECTHANDLE handle)
{
::HndDestroyHandleOfUnknownType(::HndGetHandleTable(handle), handle);
}
-void* GCHandleTable::GetExtraInfoFromHandle(OBJECTHANDLE handle)
+void* GCHandleManager::GetExtraInfoFromHandle(OBJECTHANDLE handle)
{
return (void*)::HndGetHandleExtraInfo(handle);
}
+
+void GCHandleManager::StoreObjectInHandle(OBJECTHANDLE handle, Object* object)
+{
+ ::HndAssignHandle(handle, ObjectToOBJECTREF(object));
+}
+
+bool GCHandleManager::StoreObjectInHandleIfNull(OBJECTHANDLE handle, Object* object)
+{
+ return !!::HndFirstAssignHandle(handle, ObjectToOBJECTREF(object));
+}
+
+Object* GCHandleManager::InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE handle, Object* object, Object* comparandObject)
+{
+ return (Object*)::HndInterlockedCompareExchangeHandle(handle, ObjectToOBJECTREF(object), ObjectToOBJECTREF(comparandObject));
+}
diff --git a/src/gc/gchandletableimpl.h b/src/gc/gchandletableimpl.h
index af20f52e54..01c1c130ed 100644
--- a/src/gc/gchandletableimpl.h
+++ b/src/gc/gchandletableimpl.h
@@ -6,33 +6,44 @@
#define GCHANDLETABLE_H_
#include "gcinterface.h"
+#include "objecthandle.h"
-class GCHandleTable : public IGCHandleTable
+class GCHandleStore : public IGCHandleStore
{
public:
- virtual bool Initialize();
+ virtual void Uproot();
- virtual void Shutdown();
+ virtual bool ContainsHandle(OBJECTHANDLE handle);
- virtual void* GetGlobalHandleStore();
+ virtual OBJECTHANDLE CreateHandleOfType(Object* object, int type);
- virtual void* CreateHandleStore(void* context);
+ virtual OBJECTHANDLE CreateHandleOfType(Object* object, int type, int heapToAffinitizeTo);
- virtual void* GetHandleContext(OBJECTHANDLE handle);
+ virtual OBJECTHANDLE CreateHandleWithExtraInfo(Object* object, int type, void* pExtraInfo);
- virtual void DestroyHandleStore(void* store);
+ virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary);
- virtual void UprootHandleStore(void* store);
+ virtual ~GCHandleStore();
- virtual bool ContainsHandle(void* store, OBJECTHANDLE handle);
+ HandleTableBucket _underlyingBucket;
+};
- virtual OBJECTHANDLE CreateHandleOfType(void* store, Object* object, int type);
+extern GCHandleStore* g_gcGlobalHandleStore;
- virtual OBJECTHANDLE CreateHandleOfType(void* store, Object* object, int type, int heapToAffinitizeTo);
+class GCHandleManager : public IGCHandleManager
+{
+public:
+ virtual bool Initialize();
- virtual OBJECTHANDLE CreateHandleWithExtraInfo(void* store, Object* object, int type, void* pExtraInfo);
+ virtual void Shutdown();
- virtual OBJECTHANDLE CreateDependentHandle(void* store, Object* primary, Object* secondary);
+ virtual void* GetHandleContext(OBJECTHANDLE handle);
+
+ virtual IGCHandleStore* GetGlobalHandleStore();
+
+ virtual IGCHandleStore* CreateHandleStore(void* context);
+
+ virtual void DestroyHandleStore(IGCHandleStore* store);
virtual OBJECTHANDLE CreateGlobalHandleOfType(Object* object, int type);
@@ -43,6 +54,12 @@ public:
virtual void DestroyHandleOfUnknownType(OBJECTHANDLE handle);
virtual void* GetExtraInfoFromHandle(OBJECTHANDLE handle);
+
+ virtual void StoreObjectInHandle(OBJECTHANDLE handle, Object* object);
+
+ virtual bool StoreObjectInHandleIfNull(OBJECTHANDLE handle, Object* object);
+
+ virtual Object* InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE handle, Object* object, Object* comparandObject);
};
#endif // GCHANDLETABLE_H_
diff --git a/src/gc/gcimpl.h b/src/gc/gcimpl.h
index 2a51d477b0..8ac16c5107 100644
--- a/src/gc/gcimpl.h
+++ b/src/gc/gcimpl.h
@@ -6,8 +6,6 @@
#ifndef GCIMPL_H_
#define GCIMPL_H_
-#define CLREvent CLREventStatic
-
#ifdef SERVER_GC
#define MULTIPLE_HEAPS 1
#endif // SERVER_GC
@@ -93,7 +91,8 @@ public:
bool RuntimeStructuresValid();
- CLREvent * GetWaitForGCEvent();
+ void SetWaitForGCEvent();
+ void ResetWaitForGCEvent();
HRESULT Initialize ();
@@ -242,7 +241,7 @@ public: // FIX
void TemporaryDisableConcurrentGC();
bool IsConcurrentGCEnabled();
- PER_HEAP_ISOLATED CLREvent *WaitForGCEvent; // used for syncing w/GC
+ PER_HEAP_ISOLATED GCEvent *WaitForGCEvent; // used for syncing w/GC
PER_HEAP_ISOLATED CFinalize* m_Finalize;
diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h
index cac2ba7114..552a8caec8 100644
--- a/src/gc/gcinterface.h
+++ b/src/gc/gcinterface.h
@@ -169,12 +169,12 @@ struct segment_info
class Object;
class IGCHeap;
-class IGCHandleTable;
+class IGCHandleManager;
// Initializes the garbage collector. Should only be called
// once, during EE startup. Returns true if the initialization
// was successful, false otherwise.
-bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleTable** gcHandleTable, GcDacVars* gcDacVars);
+bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleManager** gcHandleTable, GcDacVars* gcDacVars);
// The runtime needs to know whether we're using workstation or server GC
// long before the GCHeap is created. This function sets the type of
@@ -402,32 +402,38 @@ typedef struct OBJECTHANDLE__* OBJECTHANDLE;
typedef uintptr_t OBJECTHANDLE;
#endif
-class IGCHandleTable {
+class IGCHandleStore {
public:
- virtual bool Initialize() = 0;
+ virtual void Uproot() = 0;
- virtual void Shutdown() = 0;
+ virtual bool ContainsHandle(OBJECTHANDLE handle) = 0;
- virtual void* GetHandleContext(OBJECTHANDLE handle) = 0;
+ virtual OBJECTHANDLE CreateHandleOfType(Object* object, int type) = 0;
+
+ virtual OBJECTHANDLE CreateHandleOfType(Object* object, int type, int heapToAffinitizeTo) = 0;
- virtual void* GetGlobalHandleStore() = 0;
+ virtual OBJECTHANDLE CreateHandleWithExtraInfo(Object* object, int type, void* pExtraInfo) = 0;
- virtual void* CreateHandleStore(void* context) = 0;
+ virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary) = 0;
- virtual void DestroyHandleStore(void* store) = 0;
+ virtual ~IGCHandleStore() {};
+};
+
+class IGCHandleManager {
+public:
- virtual void UprootHandleStore(void* store) = 0;
+ virtual bool Initialize() = 0;
- virtual bool ContainsHandle(void* store, OBJECTHANDLE handle) = 0;
+ virtual void Shutdown() = 0;
- virtual OBJECTHANDLE CreateHandleOfType(void* store, Object* object, int type) = 0;
+ virtual void* GetHandleContext(OBJECTHANDLE handle) = 0;
- virtual OBJECTHANDLE CreateHandleOfType(void* store, Object* object, int type, int heapToAffinitizeTo) = 0;
+ virtual IGCHandleStore* GetGlobalHandleStore() = 0;
- virtual OBJECTHANDLE CreateHandleWithExtraInfo(void* store, Object* object, int type, void* pExtraInfo) = 0;
+ virtual IGCHandleStore* CreateHandleStore(void* context) = 0;
- virtual OBJECTHANDLE CreateDependentHandle(void* store, Object* primary, Object* secondary) = 0;
+ virtual void DestroyHandleStore(IGCHandleStore* store) = 0;
virtual OBJECTHANDLE CreateGlobalHandleOfType(Object* object, int type) = 0;
@@ -438,6 +444,12 @@ public:
virtual void DestroyHandleOfUnknownType(OBJECTHANDLE handle) = 0;
virtual void* GetExtraInfoFromHandle(OBJECTHANDLE handle) = 0;
+
+ virtual void StoreObjectInHandle(OBJECTHANDLE handle, Object* object) = 0;
+
+ virtual bool StoreObjectInHandleIfNull(OBJECTHANDLE handle, Object* object) = 0;
+
+ virtual Object* InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE handle, Object* object, Object* comparandObject) = 0;
};
// IGCHeap is the interface that the VM will use when interacting with the GC.
@@ -687,9 +699,11 @@ public:
// background GC as the BGC threads also need to walk LOH.
virtual void PublishObject(uint8_t* obj) = 0;
- // Gets the event that suspended threads will use to wait for the
- // end of a GC.
- virtual CLREventStatic* GetWaitForGCEvent() = 0;
+ // Signals the WaitForGCEvent event, indicating that a GC has completed.
+ virtual void SetWaitForGCEvent() = 0;
+
+ // Resets the state of the WaitForGCEvent back to an unsignalled state.
+ virtual void ResetWaitForGCEvent() = 0;
/*
===========================================================================
diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h
index 108045cd37..a2ec64b614 100644
--- a/src/gc/gcpriv.h
+++ b/src/gc/gcpriv.h
@@ -197,8 +197,6 @@ void GCLogConfig (const char *fmt, ... );
//Please leave these definitions intact.
-#define CLREvent CLREventStatic
-
// hosted api
#ifdef memcpy
#undef memcpy
@@ -2766,7 +2764,7 @@ public:
BOOL dont_restart_ee_p;
PER_HEAP_ISOLATED
- CLREvent bgc_start_event;
+ GCEvent bgc_start_event;
#endif //BACKGROUND_GC
// The variables in this block are known to the DAC and must come first
@@ -2833,9 +2831,9 @@ public:
PER_HEAP
#ifndef MULTIPLE_HEAPS
- CLREvent gc_done_event;
+ GCEvent gc_done_event;
#else // MULTIPLE_HEAPS
- CLREvent gc_done_event;
+ GCEvent gc_done_event;
#endif // MULTIPLE_HEAPS
PER_HEAP
@@ -2890,10 +2888,10 @@ public:
// notification feature which is only enabled if concurrent
// GC is disabled.
PER_HEAP_ISOLATED
- CLREvent full_gc_approach_event;
+ GCEvent full_gc_approach_event;
PER_HEAP_ISOLATED
- CLREvent full_gc_end_event;
+ GCEvent full_gc_end_event;
// Full GC Notification percentages.
PER_HEAP_ISOLATED
@@ -2913,9 +2911,9 @@ public:
PER_HEAP
size_t fgn_last_alloc;
- static uint32_t user_thread_wait (CLREvent *event, BOOL no_mode_change, int time_out_ms=INFINITE);
+ static uint32_t user_thread_wait (GCEvent *event, BOOL no_mode_change, int time_out_ms=INFINITE);
- static wait_full_gc_status full_gc_wait (CLREvent *event, int time_out_ms);
+ static wait_full_gc_status full_gc_wait (GCEvent *event, int time_out_ms);
PER_HEAP
uint8_t* demotion_low;
@@ -2943,10 +2941,10 @@ public:
bool gc_thread_no_affinitize_p;
PER_HEAP_ISOLATED
- CLREvent gc_start_event;
+ GCEvent gc_start_event;
PER_HEAP_ISOLATED
- CLREvent ee_suspend_event;
+ GCEvent ee_suspend_event;
PER_HEAP
heap_segment* new_heap_segment;
@@ -3133,7 +3131,7 @@ protected:
// we need to create them on the thread that called
// SuspendEE which is heap 0.
PER_HEAP_ISOLATED
- CLREvent bgc_threads_sync_event;
+ GCEvent bgc_threads_sync_event;
PER_HEAP
Thread* bgc_thread;
@@ -3142,13 +3140,13 @@ protected:
CLRCriticalSection bgc_threads_timeout_cs;
PER_HEAP_ISOLATED
- CLREvent background_gc_done_event;
+ GCEvent background_gc_done_event;
PER_HEAP_ISOLATED
- CLREvent ee_proceed_event;
+ GCEvent ee_proceed_event;
PER_HEAP
- CLREvent gc_lh_block_event;
+ GCEvent gc_lh_block_event;
PER_HEAP_ISOLATED
bool gc_can_use_concurrent;
diff --git a/src/gc/handletable.cpp b/src/gc/handletable.cpp
index eee181959f..05137e4d68 100644
--- a/src/gc/handletable.cpp
+++ b/src/gc/handletable.cpp
@@ -285,12 +285,7 @@ OBJECTHANDLE HndCreateHandle(HHANDLETABLE hTable, uint32_t uType, OBJECTREF obje
{
CONTRACTL
{
-#ifdef FEATURE_REDHAWK
- // Redhawk returns NULL on failure.
NOTHROW;
-#else
- THROWS;
-#endif
GC_NOTRIGGER;
if (object != NULL)
{
@@ -308,8 +303,7 @@ OBJECTHANDLE HndCreateHandle(HHANDLETABLE hTable, uint32_t uType, OBJECTREF obje
if (g_pConfig->ShouldInjectFault(INJECTFAULT_HANDLETABLE))
{
FAULT_NOT_FATAL();
- char *a = new char;
- delete a;
+ return NULL;
}
#endif // _DEBUG && !FEATURE_REDHAWK
@@ -331,11 +325,7 @@ OBJECTHANDLE HndCreateHandle(HHANDLETABLE hTable, uint32_t uType, OBJECTREF obje
// did the allocation succeed?
if (!handle)
{
-#ifdef FEATURE_REDHAWK
return NULL;
-#else
- ThrowOutOfMemory();
-#endif
}
#ifdef DEBUG_DestroyedHandleValue
diff --git a/src/gc/handletable.inl b/src/gc/handletable.inl
index ae815c129b..752a7b01ae 100644
--- a/src/gc/handletable.inl
+++ b/src/gc/handletable.inl
@@ -22,13 +22,6 @@ inline void HndAssignHandle(OBJECTHANDLE handle, OBJECTREF objref)
// sanity
_ASSERTE(handle);
-#ifdef _DEBUG_IMPL
- // handle should not be in unloaded domain
- ValidateAppDomainForHandle(handle);
-
- // Make sure the objref is valid before it is assigned to a handle
- ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
-#endif
// unwrap the objectref we were given
_UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
@@ -49,13 +42,6 @@ inline void* HndInterlockedCompareExchangeHandle(OBJECTHANDLE handle, OBJECTREF
// sanity
_ASSERTE(handle);
-#ifdef _DEBUG_IMPL
- // handle should not be in unloaded domain
- ValidateAppDomainForHandle(handle);
-
- // Make sure the objref is valid before it is assigned to a handle
- ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
-#endif
// unwrap the objectref we were given
_UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
_UNCHECKED_OBJECTREF oldValue = OBJECTREF_TO_UNCHECKED_OBJECTREF(oldObjref);
@@ -88,13 +74,6 @@ inline BOOL HndFirstAssignHandle(OBJECTHANDLE handle, OBJECTREF objref)
// sanity
_ASSERTE(handle);
-#ifdef _DEBUG_IMPL
- // handle should not be in unloaded domain
- ValidateAppDomainForHandle(handle);
-
- // Make sure the objref is valid before it is assigned to a handle
- ValidateAssignObjrefForHandle(objref, HndGetHandleTableADIndex(HndGetHandleTable(handle)));
-#endif
// unwrap the objectref we were given
_UNCHECKED_OBJECTREF value = OBJECTREF_TO_UNCHECKED_OBJECTREF(objref);
_UNCHECKED_OBJECTREF null = NULL;
diff --git a/src/gc/handletablecore.cpp b/src/gc/handletablecore.cpp
index 5776c26ace..00ab6a24b9 100644
--- a/src/gc/handletablecore.cpp
+++ b/src/gc/handletablecore.cpp
@@ -961,12 +961,12 @@ BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment)
}
// Replace an async pin handle with one from default domain
-void SegmentRelocateAsyncPinHandles (TableSegment *pSegment, HandleTable *pTargetTable)
+bool SegmentRelocateAsyncPinHandles (TableSegment *pSegment, HandleTable *pTargetTable)
{
CONTRACTL
{
GC_NOTRIGGER;
- THROWS;
+ NOTHROW;
MODE_COOPERATIVE;
}
CONTRACTL_END;
@@ -975,7 +975,7 @@ void SegmentRelocateAsyncPinHandles (TableSegment *pSegment, HandleTable *pTarge
if (uBlock == BLOCK_INVALID)
{
// There is no pinning handles.
- return;
+ return true;
}
for (uBlock = 0; uBlock < pSegment->bEmptyLine; uBlock ++)
{
@@ -1003,12 +1003,21 @@ void SegmentRelocateAsyncPinHandles (TableSegment *pSegment, HandleTable *pTarge
overlapped->m_userObject = NULL;
}
BashMTForPinnedObject(ObjectToOBJECTREF(value));
- overlapped->m_pinSelf = CreateAsyncPinningHandle((HHANDLETABLE)pTargetTable,ObjectToOBJECTREF(value));
+
+ overlapped->m_pinSelf = HndCreateHandle((HHANDLETABLE)pTargetTable, HNDTYPE_ASYNCPINNED, ObjectToOBJECTREF(value));
+ if (!overlapped->m_pinSelf)
+ {
+ // failed to allocate a new handle - callers have to handle this.
+ return false;
+ }
+
*pValue = NULL;
}
pValue ++;
} while (pValue != pLast);
}
+
+ return true;
}
// Mark all non-pending AsyncPinHandle ready for cleanup.
@@ -1067,6 +1076,7 @@ void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable
BOOL fGotException = FALSE;
TableSegment *pSegment = pTable->pSegmentList;
+ bool wasSuccessful = true;
#ifdef _DEBUG
// on debug builds, execute the OOM path 10% of the time.
@@ -1075,21 +1085,18 @@ void TableRelocateAsyncPinHandles(HandleTable *pTable, HandleTable *pTargetTable
#endif
// Step 1: replace pinning handles with ones from default domain
- EX_TRY
+ while (pSegment)
{
- while (pSegment)
+ wasSuccessful = wasSuccessful && SegmentRelocateAsyncPinHandles (pSegment, pTargetTable);
+ if (!wasSuccessful)
{
- SegmentRelocateAsyncPinHandles (pSegment, pTargetTable);
- pSegment = pSegment->pNextSegment;
+ break;
}
+
+ pSegment = pSegment->pNextSegment;
}
- EX_CATCH
- {
- fGotException = TRUE;
- }
- EX_END_CATCH(SwallowAllExceptions);
- if (!fGotException)
+ if (wasSuccessful)
{
return;
}
@@ -2719,9 +2726,8 @@ void TableFreeBulkUnpreparedHandles(HandleTable *pTable, uint32_t uType, const O
{
CONTRACTL
{
- THROWS;
+ NOTHROW;
WRAPPER(GC_TRIGGERS);
- INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
diff --git a/src/gc/handletablescan.cpp b/src/gc/handletablescan.cpp
index 86ce62d5b1..967aca5095 100644
--- a/src/gc/handletablescan.cpp
+++ b/src/gc/handletablescan.cpp
@@ -949,7 +949,7 @@ static void VerifyObjectAndAge(_UNCHECKED_OBJECTREF *pValue, _UNCHECKED_OBJECTRE
if (minAge >= GEN_MAX_AGE || (minAge > thisAge && thisAge < static_cast<int>(g_theGCHeap->GetMaxGeneration())))
{
_ASSERTE(!"Fatal Error in HandleTable.");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
+ GCToEEInterface::HandleFatalError(COR_E_EXECUTIONENGINE);
}
}
@@ -1423,7 +1423,7 @@ PTR_TableSegment CALLBACK StandardSegmentIterator(PTR_HandleTable pTable, PTR_Ta
{
CONTRACTL
{
- WRAPPER(THROWS);
+ WRAPPER(NOTHROW);
WRAPPER(GC_TRIGGERS);
FORBID_FAULT;
SUPPORTS_DAC;
diff --git a/src/gc/objecthandle.cpp b/src/gc/objecthandle.cpp
index 5df53baad5..dd43ec23d5 100644
--- a/src/gc/objecthandle.cpp
+++ b/src/gc/objecthandle.cpp
@@ -19,6 +19,8 @@
#include "objecthandle.h"
#include "handletablepriv.h"
+#include "gchandletableimpl.h"
+
#ifdef FEATURE_COMINTEROP
#include "comcallablewrapper.h"
#endif // FEATURE_COMINTEROP
@@ -627,54 +629,62 @@ bool Ref_Initialize()
if (pBuckets == NULL)
return false;
- ZeroMemory(pBuckets,
- INITIAL_HANDLE_TABLE_ARRAY_SIZE * sizeof (HandleTableBucket *));
+ ZeroMemory(pBuckets, INITIAL_HANDLE_TABLE_ARRAY_SIZE * sizeof (HandleTableBucket *));
- // Crate the first bucket
- HandleTableBucket * pBucket = new (nothrow) HandleTableBucket;
- if (pBucket != NULL)
+ g_gcGlobalHandleStore = new (nothrow) GCHandleStore();
+ if (g_gcGlobalHandleStore == NULL)
{
- pBucket->HandleTableIndex = 0;
-
- int n_slots = getNumberOfSlots();
-
- HandleTableBucketHolder bucketHolder(pBucket, n_slots);
+ delete[] pBuckets;
+ return false;
+ }
- // create the handle table set for the first bucket
- pBucket->pTable = new (nothrow) HHANDLETABLE[n_slots];
- if (pBucket->pTable == NULL)
- goto CleanupAndFail;
+ // Initialize the bucket in the global handle store
+ HandleTableBucket* pBucket = &g_gcGlobalHandleStore->_underlyingBucket;
- ZeroMemory(pBucket->pTable,
- n_slots * sizeof(HHANDLETABLE));
- for (int uCPUindex = 0; uCPUindex < n_slots; uCPUindex++)
- {
- pBucket->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags), ADIndex(1));
- if (pBucket->pTable[uCPUindex] == NULL)
- goto CleanupAndFail;
+ pBucket->HandleTableIndex = 0;
- HndSetHandleTableIndex(pBucket->pTable[uCPUindex], 0);
- }
+ int n_slots = getNumberOfSlots();
- pBuckets[0] = pBucket;
- bucketHolder.SuppressRelease();
+ HandleTableBucketHolder bucketHolder(pBucket, n_slots);
- g_HandleTableMap.pBuckets = pBuckets;
- g_HandleTableMap.dwMaxIndex = INITIAL_HANDLE_TABLE_ARRAY_SIZE;
- g_HandleTableMap.pNext = NULL;
+ // create the handle table set for the first bucket
+ pBucket->pTable = new (nothrow) HHANDLETABLE[n_slots];
+ if (pBucket->pTable == NULL)
+ goto CleanupAndFail;
- // Allocate contexts used during dependent handle promotion scanning. There's one of these for every GC
- // heap since they're scanned in parallel.
- g_pDependentHandleContexts = new (nothrow) DhContext[n_slots];
- if (g_pDependentHandleContexts == NULL)
+ ZeroMemory(pBucket->pTable,
+ n_slots * sizeof(HHANDLETABLE));
+ for (int uCPUindex = 0; uCPUindex < n_slots; uCPUindex++)
+ {
+ pBucket->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags), ADIndex(1));
+ if (pBucket->pTable[uCPUindex] == NULL)
goto CleanupAndFail;
- return true;
+ HndSetHandleTableIndex(pBucket->pTable[uCPUindex], 0);
}
+ pBuckets[0] = pBucket;
+ bucketHolder.SuppressRelease();
+
+ g_HandleTableMap.pBuckets = pBuckets;
+ g_HandleTableMap.dwMaxIndex = INITIAL_HANDLE_TABLE_ARRAY_SIZE;
+ g_HandleTableMap.pNext = NULL;
+
+ // Allocate contexts used during dependent handle promotion scanning. There's one of these for every GC
+ // heap since they're scanned in parallel.
+ g_pDependentHandleContexts = new (nothrow) DhContext[n_slots];
+ if (g_pDependentHandleContexts == NULL)
+ goto CleanupAndFail;
+
+ return true;
+
CleanupAndFail:
if (pBuckets != NULL)
delete[] pBuckets;
+
+ if (g_gcGlobalHandleStore != NULL)
+ delete g_gcGlobalHandleStore;
+
return false;
}
@@ -694,9 +704,6 @@ void Ref_Shutdown()
// don't destroy any of the indexed handle tables; they should
// be destroyed externally.
- // destroy the global handle table bucket tables
- Ref_DestroyHandleTableBucket(g_HandleTableMap.pBuckets[0]);
-
// destroy the handle table bucket array
HandleTableMap *walk = &g_HandleTableMap;
while (walk) {
@@ -714,26 +721,37 @@ void Ref_Shutdown()
}
#ifndef FEATURE_REDHAWK
-// ATTENTION: interface changed
-// Note: this function called only from AppDomain::Init()
-HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex)
+HandleTableBucket* Ref_CreateHandleTableBucket(void* context)
+{
+ HandleTableBucket* result = new (nothrow) HandleTableBucket();
+ if (result == nullptr)
+ return nullptr;
+
+ if (!Ref_InitializeHandleTableBucket(result, context))
+ {
+ delete result;
+ return nullptr;
+ }
+
+ return result;
+}
+
+bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket, void* context)
{
CONTRACTL
{
- THROWS;
+ NOTHROW;
WRAPPER(GC_TRIGGERS);
- INJECT_FAULT(COMPlusThrowOM());
+ INJECT_FAULT(return false);
}
CONTRACTL_END;
- HandleTableBucket *result = NULL;
- HandleTableMap *walk;
-
- walk = &g_HandleTableMap;
+ HandleTableBucket *result = bucket;
+ HandleTableMap *walk = &g_HandleTableMap;
+
HandleTableMap *last = NULL;
uint32_t offset = 0;
- result = new HandleTableBucket;
result->pTable = NULL;
// create handle table set for the bucket
@@ -741,13 +759,18 @@ HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex)
HandleTableBucketHolder bucketHolder(result, n_slots);
- result->pTable = new HHANDLETABLE [ n_slots ];
- ZeroMemory(result->pTable, n_slots * sizeof (HHANDLETABLE));
+ result->pTable = new (nothrow) HHANDLETABLE[n_slots];
+ if (!result->pTable)
+ {
+ return false;
+ }
+
+ ZeroMemory(result->pTable, n_slots * sizeof(HHANDLETABLE));
for (int uCPUindex=0; uCPUindex < n_slots; uCPUindex++) {
- result->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags), uADIndex);
+ result->pTable[uCPUindex] = HndCreateHandleTable(s_rgTypeFlags, _countof(s_rgTypeFlags), ADIndex((DWORD)(uintptr_t)context));
if (!result->pTable[uCPUindex])
- COMPlusThrowOM();
+ return false;
}
for (;;) {
@@ -762,7 +785,7 @@ HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex)
if (Interlocked::CompareExchangePointer(&walk->pBuckets[i], result, NULL) == 0) {
// Get a free slot.
bucketHolder.SuppressRelease();
- return result;
+ return true;
}
}
}
@@ -774,9 +797,18 @@ HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex)
// No free slot.
// Let's create a new node
NewHolder<HandleTableMap> newMap;
- newMap = new HandleTableMap;
+ newMap = new (nothrow) HandleTableMap;
+ if (!newMap)
+ {
+ return false;
+ }
+
+ newMap->pBuckets = new (nothrow) HandleTableBucket * [ INITIAL_HANDLE_TABLE_ARRAY_SIZE ];
+ if (!newMap->pBuckets)
+ {
+ return false;
+ }
- newMap->pBuckets = new HandleTableBucket * [ INITIAL_HANDLE_TABLE_ARRAY_SIZE ];
newMap.SuppressRelease();
newMap->dwMaxIndex = last->dwMaxIndex + INITIAL_HANDLE_TABLE_ARRAY_SIZE;
diff --git a/src/gc/objecthandle.h b/src/gc/objecthandle.h
index d3e45f8659..b3e4b58a1c 100644
--- a/src/gc/objecthandle.h
+++ b/src/gc/objecthandle.h
@@ -21,16 +21,6 @@
#include <weakreference.h>
#endif // FEATURE_COMINTEROP
-/*
- * Convenience macros for accessing handles. StoreFirstObjectInHandle is like
- * StoreObjectInHandle, except it only succeeds if transitioning from NULL to
- * non-NULL. In other words, if this handle is being initialized for the first
- * time.
- */
-#define StoreObjectInHandle(handle, object) HndAssignHandle(handle, object)
-#define InterlockedCompareExchangeObjectInHandle(handle, object, oldObj) HndInterlockedCompareExchangeHandle(handle, object, oldObj)
-#define StoreFirstObjectInHandle(handle, object) HndFirstAssignHandle(handle, object)
-
typedef DPTR(struct HandleTableMap) PTR_HandleTableMap;
typedef DPTR(struct HandleTableBucket) PTR_HandleTableBucket;
typedef DPTR(PTR_HandleTableBucket) PTR_PTR_HandleTableBucket;
@@ -90,23 +80,13 @@ void GCHandleValidatePinnedObject(OBJECTREF obj);
int GetCurrentThreadHomeHeapNumber();
-inline void ResetOBJECTHANDLE(OBJECTHANDLE handle)
-{
- WRAPPER_NO_CONTRACT;
-
- StoreObjectInHandle(handle, NULL);
-}
-
-#ifndef FEATURE_REDHAWK
-typedef Holder<OBJECTHANDLE,DoNothing<OBJECTHANDLE>,ResetOBJECTHANDLE> ObjectInHandleHolder;
-#endif
-
/*
* Table maintenance routines
*/
bool Ref_Initialize();
void Ref_Shutdown();
-HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex);
+HandleTableBucket* Ref_CreateHandleTableBucket(void* context);
+bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket, void* context);
BOOL Ref_HandleAsyncPinHandles();
void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget);
void Ref_RemoveHandleTableBucket(HandleTableBucket *pBucket);
diff --git a/src/gc/sample/GCSample.cpp b/src/gc/sample/GCSample.cpp
index 2914ee1665..0a771b7e91 100644
--- a/src/gc/sample/GCSample.cpp
+++ b/src/gc/sample/GCSample.cpp
@@ -130,8 +130,8 @@ int __cdecl main(int argc, char* argv[])
//
GcDacVars dacVars;
IGCHeap *pGCHeap;
- IGCHandleTable *pGCHandleTable;
- if (!InitializeGarbageCollector(nullptr, &pGCHeap, &pGCHandleTable, &dacVars))
+ IGCHandleManager *pGCHandleManager;
+ if (!InitializeGarbageCollector(nullptr, &pGCHeap, &pGCHandleManager, &dacVars))
{
return -1;
}
@@ -140,9 +140,9 @@ int __cdecl main(int argc, char* argv[])
return -1;
//
- // Initialize handle table
+ // Initialize handle manager
//
- if (!pGCHandleTable->Initialize())
+ if (!pGCHandleManager->Initialize())
return -1;
//
diff --git a/src/gc/unix/CMakeLists.txt b/src/gc/unix/CMakeLists.txt
index 3e1aa5ad19..10258108c6 100644
--- a/src/gc/unix/CMakeLists.txt
+++ b/src/gc/unix/CMakeLists.txt
@@ -6,6 +6,7 @@ include(configure.cmake)
set(GC_PAL_SOURCES
gcenv.unix.cpp
+ events.cpp
cgroup.cpp)
add_library(gc_unix STATIC ${GC_PAL_SOURCES} ${VERSION_FILE_PATH})
diff --git a/src/gc/unix/config.h.in b/src/gc/unix/config.h.in
index 7578c74c05..21980a7d08 100644
--- a/src/gc/unix/config.h.in
+++ b/src/gc/unix/config.h.in
@@ -10,5 +10,7 @@
#cmakedefine01 HAVE_PTHREAD_THREADID_NP
#cmakedefine01 HAVE_PTHREAD_GETTHREADID_NP
#cmakedefine01 HAVE_SCHED_GETCPU
+#cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK
+#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
-#endif // __CONFIG_H__ \ No newline at end of file
+#endif // __CONFIG_H__
diff --git a/src/gc/unix/configure.cmake b/src/gc/unix/configure.cmake
index 6e1e8fe27d..5f2bdbd8b3 100644
--- a/src/gc/unix/configure.cmake
+++ b/src/gc/unix/configure.cmake
@@ -37,4 +37,19 @@ check_cxx_source_runs("
}
" HAVE_SCHED_GETCPU)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) \ No newline at end of file
+check_library_exists(pthread pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK)
+
+check_cxx_source_runs("
+ #include <stdlib.h>
+ #include <mach/mach_time.h>
+ int main()
+ {
+ int ret;
+ mach_timebase_info_data_t timebaseInfo;
+ ret = mach_timebase_info(&timebaseInfo);
+ mach_absolute_time();
+ exit(ret);
+ }
+ " HAVE_MACH_ABSOLUTE_TIME)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
diff --git a/src/gc/unix/events.cpp b/src/gc/unix/events.cpp
new file mode 100644
index 0000000000..7c665f4aaa
--- /dev/null
+++ b/src/gc/unix/events.cpp
@@ -0,0 +1,323 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <cstdint>
+#include <cstddef>
+#include <cassert>
+#include <memory>
+#include <mutex>
+#include <pthread.h>
+#include <errno.h>
+#include "config.h"
+
+#ifndef __out_z
+#define __out_z
+#endif // __out_z
+
+#include "gcenv.structs.h"
+#include "gcenv.base.h"
+#include "gcenv.os.h"
+#include "globals.h"
+
+#if HAVE_MACH_ABSOLUTE_TIME
+mach_timebase_info_data_t g_TimebaseInfo;
+#endif // MACH_ABSOLUTE_TIME
+
+namespace
+{
+
+#if HAVE_PTHREAD_CONDATTR_SETCLOCK
+void TimeSpecAdd(timespec* time, uint32_t milliseconds)
+{
+ uint64_t nsec = time->tv_nsec + (uint64_t)milliseconds * tccMilliSecondsToNanoSeconds;
+ if (nsec >= tccSecondsToNanoSeconds)
+ {
+ time->tv_sec += nsec / tccSecondsToNanoSeconds;
+ nsec %= tccSecondsToNanoSeconds;
+ }
+
+ time->tv_nsec = nsec;
+}
+#endif // HAVE_PTHREAD_CONDATTR_SETCLOCK
+
+#if HAVE_MACH_ABSOLUTE_TIME
+// Convert nanoseconds to the timespec structure
+// Parameters:
+// nanoseconds - time in nanoseconds to convert
+// t - the target timespec structure
+void NanosecondsToTimeSpec(uint64_t nanoseconds, timespec* t)
+{
+ t->tv_sec = nanoseconds / tccSecondsToNanoSeconds;
+ t->tv_nsec = nanoseconds % tccSecondsToNanoSeconds;
+}
+#endif // HAVE_PTHREAD_CONDATTR_SETCLOCK
+
+} // anonymous namespace
+
+class GCEvent::Impl
+{
+ pthread_cond_t m_condition;
+ pthread_mutex_t m_mutex;
+ bool m_manualReset;
+ bool m_state;
+ bool m_isValid;
+
+public:
+
+ Impl(bool manualReset, bool initialState)
+ : m_manualReset(manualReset),
+ m_state(initialState),
+ m_isValid(false)
+ {
+ }
+
+ bool Initialize()
+ {
+ pthread_condattr_t attrs;
+ int st = pthread_condattr_init(&attrs);
+ if (st != 0)
+ {
+ assert(!"Failed to initialize UnixEvent condition attribute");
+ return false;
+ }
+
+ // TODO(segilles) implement this for CoreCLR
+ //PthreadCondAttrHolder attrsHolder(&attrs);
+
+#if HAVE_PTHREAD_CONDATTR_SETCLOCK && !HAVE_MACH_ABSOLUTE_TIME
+ // Ensure that the pthread_cond_timedwait will use CLOCK_MONOTONIC
+ st = pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+ if (st != 0)
+ {
+ assert(!"Failed to set UnixEvent condition variable wait clock");
+ return false;
+ }
+#endif // HAVE_PTHREAD_CONDATTR_SETCLOCK && !HAVE_MACH_ABSOLUTE_TIME
+
+ st = pthread_mutex_init(&m_mutex, NULL);
+ if (st != 0)
+ {
+ assert(!"Failed to initialize UnixEvent mutex");
+ return false;
+ }
+
+ st = pthread_cond_init(&m_condition, &attrs);
+ if (st != 0)
+ {
+ assert(!"Failed to initialize UnixEvent condition variable");
+
+ st = pthread_mutex_destroy(&m_mutex);
+ assert(st == 0 && "Failed to destroy UnixEvent mutex");
+ return false;
+ }
+
+ m_isValid = true;
+
+ return true;
+ }
+
+ void CloseEvent()
+ {
+ if (m_isValid)
+ {
+ int st = pthread_mutex_destroy(&m_mutex);
+ assert(st == 0 && "Failed to destroy UnixEvent mutex");
+
+ st = pthread_cond_destroy(&m_condition);
+ assert(st == 0 && "Failed to destroy UnixEvent condition variable");
+ }
+ }
+
+ uint32_t Wait(uint32_t milliseconds, bool alertable)
+ {
+ UNREFERENCED_PARAMETER(alertable);
+
+ timespec endTime;
+#if HAVE_MACH_ABSOLUTE_TIME
+ uint64_t endMachTime;
+ if (milliseconds != INFINITE)
+ {
+ uint64_t nanoseconds = (uint64_t)milliseconds * tccMilliSecondsToNanoSeconds;
+ NanosecondsToTimeSpec(nanoseconds, &endTime);
+ endMachTime = mach_absolute_time() + nanoseconds * g_TimebaseInfo.denom / g_TimebaseInfo.numer;
+ }
+#elif HAVE_PTHREAD_CONDATTR_SETCLOCK
+ if (milliseconds != INFINITE)
+ {
+ clock_gettime(CLOCK_MONOTONIC, &endTime);
+ TimeSpecAdd(&endTime, milliseconds);
+ }
+#else
+#error Don't know how to perfom timed wait on this platform
+#endif
+
+ int st = 0;
+
+ pthread_mutex_lock(&m_mutex);
+ while (!m_state)
+ {
+ if (milliseconds == INFINITE)
+ {
+ st = pthread_cond_wait(&m_condition, &m_mutex);
+ }
+ else
+ {
+#if HAVE_MACH_ABSOLUTE_TIME
+ // Since OSX doesn't support CLOCK_MONOTONIC, we use relative variant of the
+ // timed wait and we need to handle spurious wakeups properly.
+ st = pthread_cond_timedwait_relative_np(&m_condition, &m_mutex, &endTime);
+ if ((st == 0) && !m_state)
+ {
+ uint64_t machTime = mach_absolute_time();
+ if (machTime < endMachTime)
+ {
+ // The wake up was spurious, recalculate the relative endTime
+ uint64_t remainingNanoseconds = (endMachTime - machTime) * g_TimebaseInfo.numer / g_TimebaseInfo.denom;
+ NanosecondsToTimeSpec(remainingNanoseconds, &endTime);
+ }
+ else
+ {
+ // Although the timed wait didn't report a timeout, time calculated from the
+ // mach time shows we have already reached the end time. It can happen if
+ // the wait was spuriously woken up right before the timeout.
+ st = ETIMEDOUT;
+ }
+ }
+#else // HAVE_MACH_ABSOLUTE_TIME
+ st = pthread_cond_timedwait(&m_condition, &m_mutex, &endTime);
+#endif // HAVE_MACH_ABSOLUTE_TIME
+ // Verify that if the wait timed out, the event was not set
+ assert((st != ETIMEDOUT) || !m_state);
+ }
+
+ if (st != 0)
+ {
+ // wait failed or timed out
+ break;
+ }
+ }
+
+ if ((st == 0) && !m_manualReset)
+ {
+ // Clear the state for auto-reset events so that only one waiter gets released
+ m_state = false;
+ }
+
+ pthread_mutex_unlock(&m_mutex);
+
+ uint32_t waitStatus;
+
+ if (st == 0)
+ {
+ waitStatus = WAIT_OBJECT_0;
+ }
+ else if (st == ETIMEDOUT)
+ {
+ waitStatus = WAIT_TIMEOUT;
+ }
+ else
+ {
+ waitStatus = WAIT_FAILED;
+ }
+
+ return waitStatus;
+ }
+
+ void Set()
+ {
+ pthread_mutex_lock(&m_mutex);
+ m_state = true;
+ pthread_mutex_unlock(&m_mutex);
+
+ // Unblock all threads waiting for the condition variable
+ pthread_cond_broadcast(&m_condition);
+ }
+
+ void Reset()
+ {
+ pthread_mutex_lock(&m_mutex);
+ m_state = false;
+ pthread_mutex_unlock(&m_mutex);
+ }
+};
+
+GCEvent::GCEvent()
+ : m_impl(nullptr)
+{
+}
+
+void GCEvent::CloseEvent()
+{
+ assert(m_impl != nullptr);
+ m_impl->CloseEvent();
+}
+
+void GCEvent::Set()
+{
+ assert(m_impl != nullptr);
+ m_impl->Set();
+}
+
+void GCEvent::Reset()
+{
+ assert(m_impl != nullptr);
+ m_impl->Reset();
+}
+
+uint32_t GCEvent::Wait(uint32_t timeout, bool alertable)
+{
+ assert(m_impl != nullptr);
+ return m_impl->Wait(timeout, alertable);
+}
+
+bool GCEvent::CreateAutoEventNoThrow(bool initialState)
+{
+ // This implementation of GCEvent makes no distinction between
+ // host-aware and non-host-aware events (since there will be no host).
+ return CreateOSAutoEventNoThrow(initialState);
+}
+
+bool GCEvent::CreateManualEventNoThrow(bool initialState)
+{
+ // This implementation of GCEvent makes no distinction between
+ // host-aware and non-host-aware events (since there will be no host).
+ return CreateOSManualEventNoThrow(initialState);
+}
+
+bool GCEvent::CreateOSAutoEventNoThrow(bool initialState)
+{
+ assert(m_impl == nullptr);
+ std::unique_ptr<GCEvent::Impl> event(new (std::nothrow) GCEvent::Impl(false, initialState));
+ if (!event)
+ {
+ return false;
+ }
+
+ if (!event->Initialize())
+ {
+ return false;
+ }
+
+ m_impl = event.release();
+ return true;
+}
+
+bool GCEvent::CreateOSManualEventNoThrow(bool initialState)
+{
+ assert(m_impl == nullptr);
+ std::unique_ptr<GCEvent::Impl> event(new (std::nothrow) GCEvent::Impl(true, initialState));
+ if (!event)
+ {
+ return false;
+ }
+
+ if (!event->Initialize())
+ {
+ return false;
+ }
+
+ m_impl = event.release();
+ return true;
+}
+
diff --git a/src/gc/unix/gcenv.unix.cpp b/src/gc/unix/gcenv.unix.cpp
index 45489c69a7..5fc63f47d3 100644
--- a/src/gc/unix/gcenv.unix.cpp
+++ b/src/gc/unix/gcenv.unix.cpp
@@ -36,13 +36,13 @@ static_assert(sizeof(uint64_t) == 8, "unsigned long isn't 8 bytes");
#error "A GC-private implementation of GCToOSInterface should only be used with FEATURE_STANDALONE_GC"
#endif // FEATURE_STANDALONE_GC
-#ifdef HAVE_SYS_TIME_H
+#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#error "sys/time.h required by GC PAL for the time being"
#endif // HAVE_SYS_TIME_
-#ifdef HAVE_SYS_MMAN_H
+#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
#else
#error "sys/mman.h required by GC PAL"
@@ -56,18 +56,7 @@ static_assert(sizeof(uint64_t) == 8, "unsigned long isn't 8 bytes");
#include <sched.h> // sched_yield
#include <errno.h>
#include <unistd.h> // sysconf
-
-// The number of milliseconds in a second.
-static const int tccSecondsToMilliSeconds = 1000;
-
-// The number of microseconds in a second.
-static const int tccSecondsToMicroSeconds = 1000000;
-
-// The number of microseconds in a millisecond.
-static const int tccMilliSecondsToMicroSeconds = 1000;
-
-// The number of nanoseconds in a millisecond.
-static const int tccMilliSecondsToNanoSeconds = 1000000;
+#include "globals.h"
// The cachced number of logical CPUs observed.
static uint32_t g_logicalCpuCount = 0;
@@ -117,6 +106,14 @@ bool GCToOSInterface::Initialize()
return false;
}
+#if HAVE_MACH_ABSOLUTE_TIME
+ kern_return_t machRet;
+ if ((machRet = mach_timebase_info(&g_TimebaseInfo)) != KERN_SUCCESS)
+ {
+ return false;
+ }
+#endif // HAVE_MACH_ABSOLUTE_TIME
+
return true;
}
@@ -348,8 +345,20 @@ bool GCToOSInterface::VirtualDecommit(void* address, size_t size)
// true if it has succeeded, false if it has failed
bool GCToOSInterface::VirtualReset(void * address, size_t size, bool unlock)
{
- // TODO(CoreCLR#1259) pipe to madvise?
- return false;
+ int st;
+#if HAVE_MADV_FREE
+ // Try to use MADV_FREE if supported. It tells the kernel that the application doesn't
+ // need the pages in the range. Freeing the pages can be delayed until a memory pressure
+ // occurs.
+ st = madvise(address, size, MADV_FREE);
+ if (st != 0)
+#endif
+ {
+ // In case the MADV_FREE is not supported, use MADV_DONTNEED
+ st = madvise(address, size, MADV_DONTNEED);
+ }
+
+ return (st == 0);
}
// Check if the OS supports write watching
diff --git a/src/gc/unix/globals.h b/src/gc/unix/globals.h
new file mode 100644
index 0000000000..bc3dc49918
--- /dev/null
+++ b/src/gc/unix/globals.h
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __GLOBALS_H__
+#define __GLOBALS_H__
+
+#if HAVE_MACH_ABSOLUTE_TIME
+#include <mach/mach_time.h>
+#endif // HAVE_MACH_ABSOLUTE_TIME
+
+const int tccSecondsToMilliSeconds = 1000;
+
+// The number of microseconds in a second.
+const int tccSecondsToMicroSeconds = 1000000;
+
+// The number of nanoseconds in a second.
+const int tccSecondsToNanoSeconds = 1000000000;
+
+// The number of microseconds in a millisecond.
+const int tccMilliSecondsToMicroSeconds = 1000;
+
+// The number of nanoseconds in a millisecond.
+const int tccMilliSecondsToNanoSeconds = 1000000;
+
+#if HAVE_MACH_ABSOLUTE_TIME
+extern mach_timebase_info_data_t g_TimebaseInfo;
+#endif // HAVE_MACH_ABSOLUTE_TIME
+
+#endif // __GLOBALS_H__
diff --git a/src/gc/windows/gcenv.windows.cpp b/src/gc/windows/gcenv.windows.cpp
index 30232bfb09..3749f06a68 100644
--- a/src/gc/windows/gcenv.windows.cpp
+++ b/src/gc/windows/gcenv.windows.cpp
@@ -626,3 +626,145 @@ void CLRCriticalSection::Leave()
{
::LeaveCriticalSection(&m_cs);
}
+
+// WindowsEvent is an implementation of GCEvent that forwards
+// directly to Win32 APIs.
+class GCEvent::Impl
+{
+private:
+ HANDLE m_hEvent;
+
+public:
+ Impl() : m_hEvent(INVALID_HANDLE_VALUE) {}
+
+ bool IsValid() const
+ {
+ return m_hEvent != INVALID_HANDLE_VALUE;
+ }
+
+ void Set()
+ {
+ assert(IsValid());
+ BOOL result = SetEvent(m_hEvent);
+ assert(result && "SetEvent failed");
+ }
+
+ void Reset()
+ {
+ assert(IsValid());
+ BOOL result = ResetEvent(m_hEvent);
+ assert(result && "ResetEvent failed");
+ }
+
+ uint32_t Wait(uint32_t timeout, bool alertable)
+ {
+ UNREFERENCED_PARAMETER(alertable);
+ assert(IsValid());
+
+ return WaitForSingleObject(m_hEvent, timeout);
+ }
+
+ void CloseEvent()
+ {
+ assert(IsValid());
+ BOOL result = CloseHandle(m_hEvent);
+ assert(result && "CloseHandle failed");
+ m_hEvent = INVALID_HANDLE_VALUE;
+ }
+
+ bool CreateAutoEvent(bool initialState)
+ {
+ m_hEvent = CreateEvent(nullptr, false, initialState, nullptr);
+ return IsValid();
+ }
+
+ bool CreateManualEvent(bool initialState)
+ {
+ m_hEvent = CreateEvent(nullptr, true, initialState, nullptr);
+ return IsValid();
+ }
+};
+
+GCEvent::GCEvent()
+ : m_impl(nullptr)
+{
+}
+
+void GCEvent::CloseEvent()
+{
+ assert(m_impl != nullptr);
+ m_impl->CloseEvent();
+}
+
+void GCEvent::Set()
+{
+ assert(m_impl != nullptr);
+ m_impl->Set();
+}
+
+void GCEvent::Reset()
+{
+ assert(m_impl != nullptr);
+ m_impl->Reset();
+}
+
+uint32_t GCEvent::Wait(uint32_t timeout, bool alertable)
+{
+ assert(m_impl != nullptr);
+ return m_impl->Wait(timeout, alertable);
+}
+
+bool GCEvent::CreateAutoEventNoThrow(bool initialState)
+{
+ // [DESKTOP TODO] The difference between events and OS events is
+ // whether or not the hosting API is made aware of them. When (if)
+ // we implement hosting support for Local GC, we will need to be
+ // aware of the host here.
+ return CreateOSAutoEventNoThrow(initialState);
+}
+
+bool GCEvent::CreateManualEventNoThrow(bool initialState)
+{
+ // [DESKTOP TODO] The difference between events and OS events is
+ // whether or not the hosting API is made aware of them. When (if)
+ // we implement hosting support for Local GC, we will need to be
+ // aware of the host here.
+ return CreateOSManualEventNoThrow(initialState);
+}
+
+bool GCEvent::CreateOSAutoEventNoThrow(bool initialState)
+{
+ assert(m_impl == nullptr);
+ std::unique_ptr<GCEvent::Impl> event(new (std::nothrow) GCEvent::Impl());
+ if (!event)
+ {
+ return false;
+ }
+
+ if (!event->CreateAutoEvent(initialState))
+ {
+ return false;
+ }
+
+ m_impl = event.release();
+ return true;
+}
+
+bool GCEvent::CreateOSManualEventNoThrow(bool initialState)
+{
+ assert(m_impl == nullptr);
+ std::unique_ptr<GCEvent::Impl> event(new (std::nothrow) GCEvent::Impl());
+ if (!event)
+ {
+ return false;
+ }
+
+ if (!event->CreateManualEvent(initialState))
+ {
+ return false;
+ }
+
+ m_impl = event.release();
+ return true;
+}
+