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 | // |
30 | FCIMPL3(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 | } |
92 | FCIMPLEND |
93 | |
94 | FCIMPL1(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 | } |
154 | FCIMPLEND |
155 | |
156 | FCIMPL1(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 | } |
169 | FCIMPLEND |
170 | |
171 | FCIMPL1(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 | } |
179 | FCIMPLEND |
180 | |