[Local GC] Add async pinned handle methods to the handle interface (dotnet/coreclr...
authorSean Gillespie <segilles@microsoft.com>
Tue, 16 May 2017 17:19:36 +0000 (10:19 -0700)
committerSean Gillespie <segilles@microsoft.com>
Thu, 1 Jun 2017 17:20:00 +0000 (10:20 -0700)
* [Local GC] Add async pinned handle methods to the handle interface

* Add a callback to HandleAsyncPinnedHandles for handle enumeration

* Rename HandleAsyncPinnedHandles -> EnumerateAsyncPinnedHandles

* Introduce typedef for function pointer type

Commit migrated from https://github.com/dotnet/coreclr/commit/eb12b78102f2b54dc082caabcd1b59b42166509b

src/coreclr/src/gc/gchandletable.cpp
src/coreclr/src/gc/gchandletableimpl.h
src/coreclr/src/gc/gcinterface.h
src/coreclr/src/gc/handletable.cpp
src/coreclr/src/gc/handletablecore.cpp
src/coreclr/src/gc/handletablepriv.h
src/coreclr/src/gc/objecthandle.h
src/coreclr/src/vm/appdomain.cpp
src/coreclr/src/vm/nativeoverlapped.cpp

index ea02308..63f2f79 100644 (file)
@@ -56,6 +56,18 @@ OBJECTHANDLE GCHandleStore::CreateDependentHandle(Object* primary, Object* secon
     return handle;
 }
 
+void GCHandleStore::RelocateAsyncPinnedHandles(IGCHandleStore* pTarget)
+{
+    // assumption - the IGCHandleStore is an instance of GCHandleStore
+    GCHandleStore* other = static_cast<GCHandleStore*>(pTarget);
+    ::Ref_RelocateAsyncPinHandles(&_underlyingBucket, &other->_underlyingBucket);
+}
+
+bool GCHandleStore::EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context)
+{
+    return !!::Ref_HandleAsyncPinHandles(callback, context);
+}
+
 GCHandleStore::~GCHandleStore()
 {
     ::Ref_DestroyHandleTableBucket(&_underlyingBucket);
index a0a03ae..4be346f 100644 (file)
@@ -23,6 +23,10 @@ public:
 
     virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary);
 
+    virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget);
+
+    virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context);
+
     virtual ~GCHandleStore();
 
     HandleTableBucket _underlyingBucket;
index 3cea6a1..3eb332c 100644 (file)
@@ -399,6 +399,7 @@ typedef void (* record_surv_fn)(uint8_t* begin, uint8_t* end, ptrdiff_t reloc, v
 typedef void (* fq_walk_fn)(bool, void*);
 typedef void (* fq_scan_fn)(Object** ppObject, ScanContext *pSC, uint32_t dwFlags);
 typedef void (* handle_scan_fn)(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, bool isDependent);
+typedef bool (* async_pin_enum_fn)(Object* object, void* context);
 
 // Opaque type for tracking object pointers
 #ifndef DACCESS_COMPILE
@@ -426,6 +427,10 @@ public:
 
     virtual OBJECTHANDLE CreateDependentHandle(Object* primary, Object* secondary) = 0;
 
+    virtual void RelocateAsyncPinnedHandles(IGCHandleStore* pTarget) = 0;
+
+    virtual bool EnumerateAsyncPinnedHandles(async_pin_enum_fn callback, void* context) = 0;
+
     virtual ~IGCHandleStore() {};
 };
 
index 05137e4..da50483 100644 (file)
@@ -1286,9 +1286,9 @@ uint32_t HndCountAllHandles(BOOL fUseLocks)
     return uCount;
 }
 
-#ifndef FEATURE_REDHAWK
-BOOL  Ref_HandleAsyncPinHandles()
+BOOL  Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* context)
 {
+#ifndef FEATURE_REDHAWK
     CONTRACTL
     {
         NOTHROW;
@@ -1297,22 +1297,27 @@ BOOL  Ref_HandleAsyncPinHandles()
     }
     CONTRACTL_END;
 
+    AsyncPinCallbackContext callbackCtx(asyncPinCallback, context);
     HandleTableBucket *pBucket = g_HandleTableMap.pBuckets[0];
     BOOL result = FALSE;
     int limit = getNumberOfSlots();
     for (int n = 0; n < limit; n ++ )
     {
-        if (TableHandleAsyncPinHandles(Table(pBucket->pTable[n])))
+        if (TableHandleAsyncPinHandles(Table(pBucket->pTable[n]), callbackCtx))
         {
             result = TRUE;
         }
     }
 
     return result;
+#else
+    return true;
+#endif // !FEATURE_REDHAWK
 }
 
 void  Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget)
 {
+#ifndef FEATURE_REDHAWK
     CONTRACTL
     {
         NOTHROW;
@@ -1325,8 +1330,8 @@ void  Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket
     {
         TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]));
     }
-}
 #endif // !FEATURE_REDHAWK
+}
 
 /*--------------------------------------------------------------------------*/
 
index 228b8bf..a0ffb37 100644 (file)
@@ -908,7 +908,7 @@ void SegmentCompactAsyncPinHandles(TableSegment *pSegment, TableSegment **ppWork
 
 
 // Mark AsyncPinHandles ready to be cleaned when the marker job is processed
-BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment)
+BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment, const AsyncPinCallbackContext &callbackCtx)
 {
     CONTRACTL
     {
@@ -945,11 +945,10 @@ BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment)
             _UNCHECKED_OBJECTREF value = *pValue;
             if (!HndIsNullOrDestroyedHandle(value))
             {
-                _ASSERTE (value->GetMethodTable() == g_pOverlappedDataClass);
-                OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)value));
-                if (overlapped->GetAppDomainId() != DefaultADID && overlapped->HasCompleted())
+                // calls back into the VM using the callback given to
+                // Ref_HandleAsyncPinHandles
+                if (callbackCtx.Invoke((Object*)value))
                 {
-                    overlapped->HandleAsyncPinHandle();
                     result = TRUE;
                 }
             }
@@ -1024,7 +1023,7 @@ bool SegmentRelocateAsyncPinHandles (TableSegment *pSegment, HandleTable *pTarge
 // We will queue a marker Overlapped to io completion port.  We use the marker
 // to make sure that all iocompletion jobs before this marker have been processed.
 // After that we can free the async pinned handles.
-BOOL TableHandleAsyncPinHandles(HandleTable *pTable)
+BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackContext &callbackCtx)
 {
     CONTRACTL
     {
@@ -1043,7 +1042,7 @@ BOOL TableHandleAsyncPinHandles(HandleTable *pTable)
 
     while (pSegment)
     {
-        if (SegmentHandleAsyncPinHandles (pSegment))
+        if (SegmentHandleAsyncPinHandles (pSegment, callbackCtx))
         {
             result = TRUE;
         }
index 59c08ca..cda1cb0 100644 (file)
@@ -341,6 +341,37 @@ struct HandleTypeCache
     int32_t lFreeIndex;
 };
 
+/*
+ * Async pin EE callback context, used to call back tot he EE when enumerating
+ * over async pinned handles.
+ */
+class AsyncPinCallbackContext
+{
+private:
+    async_pin_enum_fn m_callback;
+    void* m_context;
+
+public:
+    /*
+     * Constructs a new AsyncPinCallbackContext from a callback and a context,
+     * which will be passed to the callback as its second parameter every time
+     * it is invoked.
+     */
+    AsyncPinCallbackContext(async_pin_enum_fn callback, void* context)
+        : m_callback(callback), m_context(context)
+    {}
+
+    /*
+     * Invokes the callback with the given argument, returning the callback's
+     * result.'
+     */
+    bool Invoke(Object* argument) const
+    {
+        assert(m_callback != nullptr);
+        return m_callback(argument, m_context);
+    }
+};
+
 
 /*---------------------------------------------------------------------------*/
 
@@ -759,7 +790,7 @@ void SegmentFree(TableSegment *pSegment);
  * Mark ready for all non-pending OverlappedData that get moved to default domain.
  *
  */
-BOOL TableHandleAsyncPinHandles(HandleTable *pTable);
+BOOL TableHandleAsyncPinHandles(HandleTable *pTable, const AsyncPinCallbackContext& callbackCtx);
 
 /*
  * TableRelocateAsyncPinHandles
index b3e4b58..6ae75b4 100644 (file)
@@ -87,7 +87,7 @@ bool Ref_Initialize();
 void Ref_Shutdown();
 HandleTableBucket* Ref_CreateHandleTableBucket(void* context);
 bool Ref_InitializeHandleTableBucket(HandleTableBucket* bucket, void* context);
-BOOL Ref_HandleAsyncPinHandles();
+BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn callback, void* context);
 void Ref_RelocateAsyncPinHandles(HandleTableBucket *pSource, HandleTableBucket *pTarget);
 void Ref_RemoveHandleTableBucket(HandleTableBucket *pBucket);
 void Ref_DestroyHandleTableBucket(HandleTableBucket *pBucket);
index 7468f0b..56b5aa1 100644 (file)
@@ -9084,18 +9084,16 @@ void AppDomain::HandleAsyncPinHandles()
     }
     CONTRACTL_END;
 
-    // TODO: Temporarily casting stuff here until Ref_RelocateAsyncPinHandles is moved to the interface.
-    HandleTableBucket *pBucket = (HandleTableBucket*)m_handleStore;
+    IGCHandleStore *pBucket = m_handleStore;
 
     // IO completion port picks IO job using FIFO.  Here is how we know which AsyncPinHandle can be freed.
     // 1. We mark all non-pending AsyncPinHandle with READYTOCLEAN.
     // 2. We queue a dump Overlapped to the IO completion as a marker.
     // 3. When the Overlapped is picked up by completion port, we wait until all previous IO jobs are processed.
     // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN.
-    HandleTableBucket *pBucketInDefault = (HandleTableBucket*)SystemDomain::System()->DefaultDomain()->m_handleStore;
+    IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore;
 
-    // TODO: When this function is moved to the interface it will take void*s
-    Ref_RelocateAsyncPinHandles(pBucket, pBucketInDefault);
+    pBucket->RelocateAsyncPinnedHandles(pBucketInDefault);
 
     OverlappedDataObject::RequestCleanup();
 }
index 3a77c52..027af31 100644 (file)
@@ -211,6 +211,33 @@ FCIMPL1(OverlappedDataObject*, GetOverlappedFromNative, LPOVERLAPPED lpOverlappe
 }
 FCIMPLEND
 
+namespace
+{
+
+// Sets up an enumeration of all async pinned handles, such that all enumerated
+// async pinned handles are processed by calling HandleAsyncPinHandle on the
+// underlying overlapped instance.
+BOOL HandleAsyncPinHandles()
+{
+    auto callback = [](Object* value, void*) 
+    {
+        _ASSERTE (value->GetMethodTable() == g_pOverlappedDataClass);
+        OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF(value));
+        if (overlapped->GetAppDomainId() != DefaultADID && overlapped->HasCompleted())
+        {
+            overlapped->HandleAsyncPinHandle();
+            return true;
+        }
+
+        return false;
+    };
+
+    IGCHandleManager* mgr = GCHandleUtilities::GetGCHandleManager();
+    return mgr->GetGlobalHandleStore()->EnumerateAsyncPinnedHandles(callback, nullptr);
+}
+
+} // anonymous namespace
+
 void OverlappedDataObject::FreeAsyncPinHandles()
 {
     CONTRACTL
@@ -262,7 +289,7 @@ void OverlappedDataObject::StartCleanup()
     if (FastInterlockExchange((LONG*)&s_CleanupInProgress, TRUE) == FALSE)
     {
         {
-            BOOL HasJob = Ref_HandleAsyncPinHandles();
+            BOOL HasJob = HandleAsyncPinHandles();
             if (!HasJob)
             {
                 s_CleanupInProgress = FALSE;
@@ -292,7 +319,7 @@ void OverlappedDataObject::FinishCleanup(bool wasDrained)
         GCX_COOP();
 
         s_CleanupFreeHandle = TRUE;
-        Ref_HandleAsyncPinHandles();
+        HandleAsyncPinHandles();
         s_CleanupFreeHandle = FALSE;
 
         s_CleanupInProgress = FALSE;