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);
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;
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
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() {};
};
return uCount;
}
-#ifndef FEATURE_REDHAWK
-BOOL Ref_HandleAsyncPinHandles()
+BOOL Ref_HandleAsyncPinHandles(async_pin_enum_fn asyncPinCallback, void* context)
{
+#ifndef FEATURE_REDHAWK
CONTRACTL
{
NOTHROW;
}
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;
{
TableRelocateAsyncPinHandles(Table(pSource->pTable[n]), Table(pTarget->pTable[n]));
}
-}
#endif // !FEATURE_REDHAWK
+}
/*--------------------------------------------------------------------------*/
// Mark AsyncPinHandles ready to be cleaned when the marker job is processed
-BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment)
+BOOL SegmentHandleAsyncPinHandles (TableSegment *pSegment, const AsyncPinCallbackContext &callbackCtx)
{
CONTRACTL
{
_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;
}
}
// 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
{
while (pSegment)
{
- if (SegmentHandleAsyncPinHandles (pSegment))
+ if (SegmentHandleAsyncPinHandles (pSegment, callbackCtx))
{
result = TRUE;
}
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);
+ }
+};
+
/*---------------------------------------------------------------------------*/
* 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
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);
}
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();
}
}
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
if (FastInterlockExchange((LONG*)&s_CleanupInProgress, TRUE) == FALSE)
{
{
- BOOL HasJob = Ref_HandleAsyncPinHandles();
+ BOOL HasJob = HandleAsyncPinHandles();
if (!HasJob)
{
s_CleanupInProgress = FALSE;
GCX_COOP();
s_CleanupFreeHandle = TRUE;
- Ref_HandleAsyncPinHandles();
+ HandleAsyncPinHandles();
s_CleanupFreeHandle = FALSE;
s_CleanupInProgress = FALSE;