1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6/*============================================================
7**
8** Header: COMNativeOverlapped.h
9**
10** Purpose: Native methods for allocating and freeing NativeOverlapped
11**
12
13**
14===========================================================*/
15#include "common.h"
16#include "fcall.h"
17#include "nativeoverlapped.h"
18#include "corhost.h"
19#include "win32threadpool.h"
20#include "mdaassistants.h"
21#include "comsynchronizable.h"
22#include "comthreadpool.h"
23#include "marshalnative.h"
24
25//
26//The function is called from managed code to quicly check if a packet is available.
27//This is a perf-critical function. Even helper method frames are not created. We fall
28//back to the VM to do heavy weight operations like creating a new CP thread.
29//
30FCIMPL3(void, CheckVMForIOPacket, LPOVERLAPPED* lpOverlapped, DWORD* errorCode, DWORD* numBytes)
31{
32 FCALL_CONTRACT;
33
34#ifndef FEATURE_PAL
35 Thread *pThread = GetThread();
36 size_t key=0;
37
38 _ASSERTE(pThread);
39
40 //Poll and wait if GC is in progress, to avoid blocking GC for too long.
41 FC_GC_POLL();
42
43 *lpOverlapped = ThreadpoolMgr::CompletionPortDispatchWorkWithinAppDomain(pThread, errorCode, numBytes, &key, DefaultADID);
44 if(*lpOverlapped == NULL)
45 {
46 return;
47 }
48
49 OVERLAPPEDDATAREF overlapped = ObjectToOVERLAPPEDDATAREF(OverlappedDataObject::GetOverlapped(*lpOverlapped));
50
51 if (overlapped->m_callback == NULL)
52 {
53 //We're not initialized yet, go back to the Vm, and process the packet there.
54 ThreadpoolMgr::StoreOverlappedInfoInThread(pThread, *errorCode, *numBytes, key, *lpOverlapped);
55
56 *lpOverlapped = NULL;
57 return;
58 }
59 else
60 {
61 if(!pThread->IsRealThreadPoolResetNeeded())
62 {
63 pThread->ResetManagedThreadObjectInCoopMode(ThreadNative::PRIORITY_NORMAL);
64 pThread->InternalReset(TRUE, FALSE, FALSE);
65 if(ThreadpoolMgr::ShouldGrowCompletionPortThreadpool(ThreadpoolMgr::CPThreadCounter.DangerousGetDirtyCounts()))
66 {
67 //We may have to create a CP thread, go back to the Vm, and process the packet there.
68 ThreadpoolMgr::StoreOverlappedInfoInThread(pThread, *errorCode, *numBytes, key, *lpOverlapped);
69 *lpOverlapped = NULL;
70 }
71 }
72 else
73 {
74 //A more complete reset is needed (due to change in priority etc), go back to the VM,
75 //and process the packet there.
76
77 ThreadpoolMgr::StoreOverlappedInfoInThread(pThread, *errorCode, *numBytes, key, *lpOverlapped);
78 *lpOverlapped = NULL;
79 }
80 }
81
82 // if this will be "dispatched" to the managed callback fire the IODequeue event:
83 if (*lpOverlapped != NULL && ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadPoolIODequeue))
84 FireEtwThreadPoolIODequeue(*lpOverlapped, OverlappedDataObject::GetOverlapped(*lpOverlapped), GetClrInstanceId());
85
86#else // !FEATURE_PAL
87 *lpOverlapped = NULL;
88#endif // !FEATURE_PAL
89
90 return;
91}
92FCIMPLEND
93
94FCIMPL1(LPOVERLAPPED, AllocateNativeOverlapped, OverlappedDataObject* overlappedUNSAFE)
95{
96 FCALL_CONTRACT;
97
98 LPOVERLAPPED lpOverlapped;
99
100 OVERLAPPEDDATAREF overlapped = ObjectToOVERLAPPEDDATAREF(overlappedUNSAFE);
101 OBJECTREF userObject = overlapped->m_userObject;
102
103 HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_NONE, overlapped, userObject);
104
105 if (g_pOverlappedDataClass == NULL)
106 {
107 g_pOverlappedDataClass = MscorlibBinder::GetClass(CLASS__OVERLAPPEDDATA);
108 // We have optimization to avoid creating event if IO is in default domain. This depends on default domain
109 // can not be unloaded.
110 _ASSERTE(SystemDomain::System()->DefaultDomain()->GetId().m_dwId == DefaultADID);
111 }
112
113 CONSISTENCY_CHECK(overlapped->GetMethodTable() == g_pOverlappedDataClass);
114
115 if (userObject != NULL)
116 {
117 if (userObject->GetMethodTable() == g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT]->GetMethodTable())
118 {
119 BASEARRAYREF asArray = (BASEARRAYREF) userObject;
120 OBJECTREF *pObj = (OBJECTREF*)(asArray->GetDataPtr());
121 SIZE_T num = asArray->GetNumComponents();
122 SIZE_T i;
123 for (i = 0; i < num; i ++)
124 {
125 ValidatePinnedObject(pObj[i]);
126 }
127 }
128 else
129 {
130 ValidatePinnedObject(userObject);
131 }
132 }
133
134 NewHolder<NATIVEOVERLAPPED_AND_HANDLE> overlappedHolder(new NATIVEOVERLAPPED_AND_HANDLE());
135 overlappedHolder->m_handle = GetAppDomain()->CreateTypedHandle(overlapped, HNDTYPE_ASYNCPINNED);
136 lpOverlapped = &(overlappedHolder.Extract()->m_overlapped);
137
138 lpOverlapped->Internal = 0;
139 lpOverlapped->InternalHigh = 0;
140 lpOverlapped->Offset = overlapped->m_offsetLow;
141 lpOverlapped->OffsetHigh = overlapped->m_offsetHigh;
142 lpOverlapped->hEvent = (HANDLE)overlapped->m_eventHandle;
143
144 overlapped->m_pNativeOverlapped = lpOverlapped;
145
146 HELPER_METHOD_FRAME_END();
147 LOG((LF_INTEROP, LL_INFO10000, "In AllocNativeOperlapped thread 0x%x\n", GetThread()));
148
149 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ThreadPoolIODequeue))
150 FireEtwThreadPoolIOPack(lpOverlapped, overlappedUNSAFE, GetClrInstanceId());
151
152 return lpOverlapped;
153}
154FCIMPLEND
155
156FCIMPL1(void, FreeNativeOverlapped, LPOVERLAPPED lpOverlapped)
157{
158 FCALL_CONTRACT;
159
160 HELPER_METHOD_FRAME_BEGIN_0();
161
162 CONSISTENCY_CHECK(g_pOverlappedDataClass && (OverlappedDataObject::GetOverlapped(lpOverlapped)->GetMethodTable() == g_pOverlappedDataClass));
163
164 DestroyAsyncPinningHandle(((NATIVEOVERLAPPED_AND_HANDLE*)lpOverlapped)->m_handle);
165 delete lpOverlapped;
166
167 HELPER_METHOD_FRAME_END();
168}
169FCIMPLEND
170
171FCIMPL1(OverlappedDataObject*, GetOverlappedFromNative, LPOVERLAPPED lpOverlapped)
172{
173 FCALL_CONTRACT;
174
175 CONSISTENCY_CHECK(g_pOverlappedDataClass && (OverlappedDataObject::GetOverlapped(lpOverlapped)->GetMethodTable() == g_pOverlappedDataClass));
176
177 return OverlappedDataObject::GetOverlapped(lpOverlapped);
178}
179FCIMPLEND
180