summaryrefslogtreecommitdiff
path: root/src/vm/nativeoverlapped.cpp
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2018-06-09 13:39:58 -0700
committerGitHub <noreply@github.com>2018-06-09 13:39:58 -0700
commit911d332c523848023e3c6564788b72b7f419fca1 (patch)
treeae979e6b048630ed0393983d14bde5d43942459f /src/vm/nativeoverlapped.cpp
parent618f9c2d18e88566ac61f93529bac58123c50cba (diff)
downloadcoreclr-911d332c523848023e3c6564788b72b7f419fca1.tar.gz
coreclr-911d332c523848023e3c6564788b72b7f419fca1.tar.bz2
coreclr-911d332c523848023e3c6564788b72b7f419fca1.zip
Avoid NativeOverlapped pinning by allocating unmanaged memory for it (#18360)
It makes PinnableBufferCache unnecessary
Diffstat (limited to 'src/vm/nativeoverlapped.cpp')
-rw-r--r--src/vm/nativeoverlapped.cpp407
1 files changed, 23 insertions, 384 deletions
diff --git a/src/vm/nativeoverlapped.cpp b/src/vm/nativeoverlapped.cpp
index 6f053ea267..94e61c63fd 100644
--- a/src/vm/nativeoverlapped.cpp
+++ b/src/vm/nativeoverlapped.cpp
@@ -22,11 +22,6 @@
#include "comthreadpool.h"
#include "marshalnative.h"
-LONG OverlappedDataObject::s_CleanupRequestCount = 0;
-BOOL OverlappedDataObject::s_CleanupInProgress = FALSE;
-BOOL OverlappedDataObject::s_GCDetectsCleanup = FALSE;
-BOOL OverlappedDataObject::s_CleanupFreeHandle = FALSE;
-
//
//The function is called from managed code to quicly check if a packet is available.
//This is a perf-critical function. Even helper method frames are not created. We fall
@@ -38,7 +33,6 @@ FCIMPL3(void, CheckVMForIOPacket, LPOVERLAPPED* lpOverlapped, DWORD* errorCode,
#ifndef FEATURE_PAL
Thread *pThread = GetThread();
- DWORD adid = pThread->GetDomain()->GetId().m_dwId;
size_t key=0;
_ASSERTE(pThread);
@@ -46,7 +40,7 @@ FCIMPL3(void, CheckVMForIOPacket, LPOVERLAPPED* lpOverlapped, DWORD* errorCode,
//Poll and wait if GC is in progress, to avoid blocking GC for too long.
FC_GC_POLL();
- *lpOverlapped = ThreadpoolMgr::CompletionPortDispatchWorkWithinAppDomain(pThread, errorCode, numBytes, &key, adid);
+ *lpOverlapped = ThreadpoolMgr::CompletionPortDispatchWorkWithinAppDomain(pThread, errorCode, numBytes, &key, DefaultADID);
if(*lpOverlapped == NULL)
{
return;
@@ -54,17 +48,10 @@ FCIMPL3(void, CheckVMForIOPacket, LPOVERLAPPED* lpOverlapped, DWORD* errorCode,
OVERLAPPEDDATAREF overlapped = ObjectToOVERLAPPEDDATAREF(OverlappedDataObject::GetOverlapped(*lpOverlapped));
- _ASSERTE(overlapped->GetAppDomainId() == adid);
-
- if(overlapped->m_iocb == NULL)
+ if (overlapped->m_callback == NULL)
{
- // no user delegate to callback
- _ASSERTE((overlapped->m_iocbHelper == NULL) || !"This is benign, but should be optimized");
-
- {
- //We're not initialized yet, go back to the Vm, and process the packet there.
- ThreadpoolMgr::StoreOverlappedInfoInThread(pThread, *errorCode, *numBytes, key, *lpOverlapped);
- }
+ //We're not initialized yet, go back to the Vm, and process the packet there.
+ ThreadpoolMgr::StoreOverlappedInfoInThread(pThread, *errorCode, *numBytes, key, *lpOverlapped);
*lpOverlapped = NULL;
return;
@@ -94,7 +81,7 @@ FCIMPL3(void, CheckVMForIOPacket, LPOVERLAPPED* lpOverlapped, DWORD* errorCode,
// if this will be "dispatched" to the managed callback fire the IODequeue event:
if (*lpOverlapped != NULL && ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadPoolIODequeue))
- FireEtwThreadPoolIODequeue(*lpOverlapped, (BYTE*)(*lpOverlapped) - offsetof(OverlappedDataObject, Internal), GetClrInstanceId());
+ FireEtwThreadPoolIODequeue(*lpOverlapped, OverlappedDataObject::GetOverlapped(*lpOverlapped), GetClrInstanceId());
#else // !FEATURE_PAL
*lpOverlapped = NULL;
@@ -104,17 +91,17 @@ FCIMPL3(void, CheckVMForIOPacket, LPOVERLAPPED* lpOverlapped, DWORD* errorCode,
}
FCIMPLEND
-FCIMPL1(void*, AllocateNativeOverlapped, OverlappedDataObject* overlappedUNSAFE)
+FCIMPL1(LPOVERLAPPED, AllocateNativeOverlapped, OverlappedDataObject* overlappedUNSAFE)
{
FCALL_CONTRACT;
+ LPOVERLAPPED lpOverlapped;
+
OVERLAPPEDDATAREF overlapped = ObjectToOVERLAPPEDDATAREF(overlappedUNSAFE);
OBJECTREF userObject = overlapped->m_userObject;
HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_NONE, overlapped, userObject);
- AsyncPinningHandleHolder handle;
-
if (g_pOverlappedDataClass == NULL)
{
g_pOverlappedDataClass = MscorlibBinder::GetClass(CLASS__OVERLAPPEDDATA);
@@ -126,11 +113,9 @@ FCIMPL1(void*, AllocateNativeOverlapped, OverlappedDataObject* overlappedUNSAFE)
CONSISTENCY_CHECK(overlapped->GetMethodTable() == g_pOverlappedDataClass);
- overlapped->m_AppDomainId = GetAppDomain()->GetId().m_dwId;
-
if (userObject != NULL)
{
- if (overlapped->m_isArray == 1)
+ if (userObject->GetMethodTable() == g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT]->GetMethodTable())
{
BASEARRAYREF asArray = (BASEARRAYREF) userObject;
OBJECTREF *pObj = (OBJECTREF*)(asArray->GetDataPtr());
@@ -140,33 +125,32 @@ FCIMPL1(void*, AllocateNativeOverlapped, OverlappedDataObject* overlappedUNSAFE)
{
ValidatePinnedObject(pObj[i]);
}
- for (i = 0; i < num; i ++)
- {
- asArray = (BASEARRAYREF) userObject;
- AddMTForPinHandle(pObj[i]);
- }
}
else
{
ValidatePinnedObject(userObject);
- AddMTForPinHandle(userObject);
}
-
}
- handle = GetAppDomain()->CreateTypedHandle(overlapped, HNDTYPE_ASYNCPINNED);
+ NewHolder<NATIVEOVERLAPPED_AND_HANDLE> overlappedHolder(new NATIVEOVERLAPPED_AND_HANDLE());
+ overlappedHolder->m_handle = GetAppDomain()->CreateTypedHandle(overlapped, HNDTYPE_ASYNCPINNED);
+ lpOverlapped = &(overlappedHolder.Extract()->m_overlapped);
+ lpOverlapped->Internal = 0;
+ lpOverlapped->InternalHigh = 0;
+ lpOverlapped->Offset = overlapped->m_offsetLow;
+ lpOverlapped->OffsetHigh = overlapped->m_offsetHigh;
+ lpOverlapped->hEvent = (HANDLE)overlapped->m_eventHandle;
- handle.SuppressRelease();
- overlapped->m_pinSelf = handle;
+ overlapped->m_pNativeOverlapped = lpOverlapped;
HELPER_METHOD_FRAME_END();
LOG((LF_INTEROP, LL_INFO10000, "In AllocNativeOperlapped thread 0x%x\n", GetThread()));
if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadPoolIODequeue))
- FireEtwThreadPoolIOPack(&overlapped->Internal, overlappedUNSAFE, GetClrInstanceId());
+ FireEtwThreadPoolIOPack(lpOverlapped, overlappedUNSAFE, GetClrInstanceId());
- return &overlapped->Internal;
+ return lpOverlapped;
}
FCIMPLEND
@@ -176,28 +160,11 @@ FCIMPL1(void, FreeNativeOverlapped, LPOVERLAPPED lpOverlapped)
HELPER_METHOD_FRAME_BEGIN_0();
- OVERLAPPEDDATAREF overlapped = ObjectToOVERLAPPEDDATAREF(OverlappedDataObject::GetOverlapped(lpOverlapped));
- CONSISTENCY_CHECK(g_pOverlappedDataClass && (overlapped->GetMethodTable() == g_pOverlappedDataClass));
+ CONSISTENCY_CHECK(g_pOverlappedDataClass && (OverlappedDataObject::GetOverlapped(lpOverlapped)->GetMethodTable() == g_pOverlappedDataClass));
- // We don't want to call HasCompleted in the default domain, because we don't have
- // overlapped handle support.
- if ((!overlapped->HasCompleted ()))
- {
-#ifdef MDA_SUPPORTED
- MdaOverlappedFreeError *pFreeError = MDA_GET_ASSISTANT(OverlappedFreeError);
- if (pFreeError)
- {
- pFreeError->ReportError((LPVOID) OVERLAPPEDDATAREFToObject(overlapped));
-
- // If we entered ReportError then our overlapped OBJECTREF became technically invalid,
- // since a gc can be triggered. That causes an assert from FreeAsyncPinHandles() below.
- // (I say technically because the object is pinned and won't really move)
- overlapped = ObjectToOVERLAPPEDDATAREF(OverlappedDataObject::GetOverlapped(lpOverlapped));
- }
-#endif // MDA_SUPPORTED
- }
+ DestroyAsyncPinningHandle(((NATIVEOVERLAPPED_AND_HANDLE*)lpOverlapped)->m_handle);
+ delete lpOverlapped;
- overlapped->FreeAsyncPinHandles();
HELPER_METHOD_FRAME_END();
}
FCIMPLEND
@@ -211,331 +178,3 @@ FCIMPL1(OverlappedDataObject*, GetOverlappedFromNative, LPOVERLAPPED lpOverlappe
return OverlappedDataObject::GetOverlapped(lpOverlapped);
}
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
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- // This cannot throw or return error, and cannot force SO because it is called
- // from CCLRIoCompletionManager::OnComplete which probes.
- CONTRACT_VIOLATION(SOToleranceViolation);
-
- CONSISTENCY_CHECK(g_pOverlappedDataClass && (this->GetMethodTable() == g_pOverlappedDataClass));
-
- _ASSERTE(GetThread() != NULL);
-
- if (m_pinSelf)
- {
- OBJECTHANDLE h = m_pinSelf;
- if (FastInterlockCompareExchangePointer(&m_pinSelf, static_cast<OBJECTHANDLE>(NULL), h) == h)
- {
- DestroyAsyncPinningHandle(h);
- }
- }
-
- EventHandle = 0;
-}
-
-
-void OverlappedDataObject::StartCleanup()
-{
- CONTRACTL
- {
- NOTHROW;
- if (GetThread()) {MODE_COOPERATIVE;} else {DISABLED(MODE_COOPERATIVE);}
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- if (s_CleanupRequestCount == 0)
- {
- return;
- }
-
- LONG curCount = s_CleanupRequestCount;
- if (FastInterlockExchange((LONG*)&s_CleanupInProgress, TRUE) == FALSE)
- {
- {
- BOOL HasJob = HandleAsyncPinHandles();
- if (!HasJob)
- {
- s_CleanupInProgress = FALSE;
- FastInterlockExchangeAdd (&s_CleanupRequestCount, -curCount);
- return;
- }
- }
-
- if (!ThreadpoolMgr::DrainCompletionPortQueue())
- {
- s_CleanupInProgress = FALSE;
- }
- else
- {
- FastInterlockExchangeAdd (&s_CleanupRequestCount, -curCount);
- }
- }
-}
-
-
-void OverlappedDataObject::FinishCleanup(bool wasDrained)
-{
- WRAPPER_NO_CONTRACT;
-
- if (wasDrained)
- {
- GCX_COOP();
-
- s_CleanupFreeHandle = TRUE;
- HandleAsyncPinHandles();
- s_CleanupFreeHandle = FALSE;
-
- s_CleanupInProgress = FALSE;
- if (s_CleanupRequestCount > 0)
- {
- StartCleanup();
- }
- }
- else
- {
- s_CleanupInProgress = FALSE;
- }
-}
-
-
-void OverlappedDataObject::HandleAsyncPinHandle()
-{
- WRAPPER_NO_CONTRACT;
-
- _ASSERTE (s_CleanupInProgress);
- if (m_toBeCleaned || !ThreadpoolMgr::IsCompletionPortInitialized())
- {
- OBJECTHANDLE h = m_pinSelf;
- if (h)
- {
- if (FastInterlockCompareExchangePointer(&m_pinSelf, (OBJECTHANDLE)NULL, h) == h)
- {
- DestroyAsyncPinningHandle(h);
- }
- }
- }
- else if (!s_CleanupFreeHandle)
- {
- m_toBeCleaned = 1;
- }
-}
-
-
-// A hash table to track size of objects that may be moved to default domain
-typedef EEHashTable<size_t, EEPtrHashTableHelper<size_t>, FALSE> EEHashTableOfMT;
-EEHashTableOfMT *s_pPinHandleTable;
-
-CrstStatic s_PinHandleTableCrst;
-
-void InitializePinHandleTable()
-{
- WRAPPER_NO_CONTRACT;
-
- s_PinHandleTableCrst.Init(CrstPinHandle);
- LockOwner lock = {&s_PinHandleTableCrst, IsOwnerOfCrst};
- s_pPinHandleTable = new EEHashTableOfMT();
- s_pPinHandleTable->Init(10, &lock);
-}
-
-// We can not fail due to OOM when we move an object to default domain during AD unload.
-// If we may need a dummy MethodTable later, we allocate the MethodTable here.
-void AddMTForPinHandle(OBJECTREF obj)
-{
- CONTRACTL
- {
- THROWS;
- WRAPPER(GC_TRIGGERS);
- }
- CONTRACTL_END;
-
- if (obj == NULL)
- {
- return;
- }
-
- _ASSERTE (g_pOverlappedDataClass != NULL);
-
- SSIZE_T size = 0;
- MethodTable *pMT = obj->GetMethodTable();
-
- if (pMT->GetLoaderModule()->IsSystem())
- {
- return;
- }
-
- if (pMT->IsArray())
- {
-#ifdef _DEBUG
- BASEARRAYREF asArray = (BASEARRAYREF) obj;
- TypeHandle th = asArray->GetArrayElementTypeHandle();
- _ASSERTE (!th.IsTypeDesc());
- MethodTable *pElemMT = th.AsMethodTable();
- _ASSERTE (pElemMT->IsValueType() && pElemMT->IsBlittable());
- _ASSERTE (!pElemMT->GetLoaderModule()->IsSystem());
-#endif
-
- // Create an ArrayMethodTable that has the same element size
- // Use negative number for arrays of structs - it assumes that
- // the maximum type base size is less than 2GB.
- size = - (SSIZE_T)pMT->GetComponentSize();
- _ASSERTE(size < 0);
- }
- else
- {
- size = pMT->GetBaseSize();
- _ASSERTE(size >= 0);
- }
-
- HashDatum data;
- if (s_pPinHandleTable->GetValue(size, &data) == FALSE)
- {
- CrstHolder csh(&s_PinHandleTableCrst);
- if (s_pPinHandleTable->GetValue(size, &data) == FALSE)
- {
- // We do not need to include GCDescr here, since this
- // methodtable does not contain pointers.
- BYTE *buffer = new BYTE[sizeof(MethodTable)];
- memset (buffer, 0, sizeof(MethodTable));
- MethodTable *pNewMT = (MethodTable *)buffer;
- NewArrayHolder<BYTE> pMTHolder(buffer);
- pNewMT->SetIsAsyncPinType();
- if (size >= 0)
- {
- pNewMT->SetBaseSize(static_cast<DWORD>(size));
- }
- else
- {
- pNewMT->SetBaseSize(ARRAYBASE_BASESIZE);
- pNewMT->SetComponentSize(static_cast<WORD>(-size));
- }
- s_pPinHandleTable->InsertValue(size, (HashDatum)pNewMT);
- pMTHolder.SuppressRelease();
- }
- }
-}
-
-// We need to ensure that the MethodTable of an object is valid in default domain when the object
-// is move to default domain duing AD unload.
-void BashMTForPinnedObject(OBJECTREF obj)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- NOTHROW;
- }
- CONTRACTL_END;
-
- if (obj == NULL)
- {
- return;
- }
-
- ADIndex adIndx = obj->GetAppDomainIndex();
- ADIndex defaultAdIndx = SystemDomain::System()->DefaultDomain()->GetIndex();
- if (adIndx.m_dwIndex != 0 && adIndx != defaultAdIndx)
- {
- obj->GetHeader()->ResetAppDomainIndexNoFailure(defaultAdIndx);
- }
- SSIZE_T size = 0;
- MethodTable *pMT = obj->GetMethodTable();
-
- if (pMT == g_pOverlappedDataClass)
- {
- // Managed Overlapped
- OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(obj);
- overlapped->m_asyncResult = NULL;
- overlapped->m_iocb = NULL;
- overlapped->m_iocbHelper = NULL;
- overlapped->m_overlapped = NULL;
-
- if (overlapped->m_userObject != NULL)
- {
- if (overlapped->m_isArray == 1)
- {
- BASEARRAYREF asArray = (BASEARRAYREF) (overlapped->m_userObject);
- OBJECTREF *pObj = (OBJECTREF*)asArray->GetDataPtr (TRUE);
- SIZE_T num = asArray->GetNumComponents();
- for (SIZE_T i = 0; i < num; i ++)
- {
- BashMTForPinnedObject(pObj[i]);
- }
- }
- else
- {
- BashMTForPinnedObject(overlapped->m_userObject);
- }
- }
- STRESS_LOG1 (LF_APPDOMAIN | LF_GC, LL_INFO100, "OverlappedData %p:MT is bashed\n", OBJECTREFToObject (overlapped));
- return;
- }
-
- if (pMT->GetLoaderModule()->IsSystem())
- {
- return;
- }
-
- if (pMT->IsArray())
- {
-#ifdef _DEBUG
- BASEARRAYREF asArray = (BASEARRAYREF) obj;
- TypeHandle th = asArray->GetArrayElementTypeHandle();
- _ASSERTE (!th.IsTypeDesc());
- MethodTable *pElemMT = th.AsMethodTable();
- _ASSERTE (pElemMT->IsValueType() && pElemMT->IsBlittable());
- _ASSERTE (!pElemMT->GetLoaderModule()->IsSystem());
-#endif
-
- // Create an ArrayMethodTable that has the same element size
- size = - (SSIZE_T)pMT->GetComponentSize();
- }
- else
- {
- _ASSERTE (pMT->IsBlittable());
- size = pMT->GetBaseSize();
- }
-
- HashDatum data = NULL;
- BOOL fRet;
- fRet = s_pPinHandleTable->GetValue(size, &data);
- _ASSERTE(fRet);
- PREFIX_ASSUME(data != NULL);
- obj->SetMethodTable((MethodTable*)data);
-}