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 | // |
9 | /*============================================================ |
10 | ** |
11 | ** Header: Threads.inl |
12 | ** |
13 | ** Purpose: Implements Thread inline functions |
14 | ** |
15 | ** |
16 | ===========================================================*/ |
17 | #ifndef _THREADS_INL |
18 | #define _THREADS_INL |
19 | |
20 | #include "threads.h" |
21 | #include "appdomain.hpp" |
22 | #include "frames.h" |
23 | |
24 | #ifndef DACCESS_COMPILE |
25 | |
26 | #ifndef __llvm__ |
27 | EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo; |
28 | #else // !__llvm__ |
29 | EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo; |
30 | #endif // !__llvm__ |
31 | |
32 | EXTERN_C inline Thread* STDCALL GetThread() |
33 | { |
34 | return gCurrentThreadInfo.m_pThread; |
35 | } |
36 | |
37 | EXTERN_C inline AppDomain* STDCALL GetAppDomain() |
38 | { |
39 | return AppDomain::GetCurrentDomain(); |
40 | } |
41 | |
42 | #endif // !DACCESS_COMPILE |
43 | |
44 | inline void Thread::IncLockCount() |
45 | { |
46 | LIMITED_METHOD_CONTRACT; |
47 | _ASSERTE(GetThread() == this); |
48 | m_dwLockCount++; |
49 | _ASSERTE(m_dwLockCount != 0 || HasThreadStateNC(TSNC_UnbalancedLocks)); |
50 | } |
51 | |
52 | inline void Thread::DecLockCount() |
53 | { |
54 | LIMITED_METHOD_CONTRACT; |
55 | _ASSERTE(GetThread() == this); |
56 | _ASSERTE(m_dwLockCount > 0 || HasThreadStateNC(TSNC_UnbalancedLocks)); |
57 | m_dwLockCount--; |
58 | } |
59 | |
60 | inline |
61 | Frame* Thread::FindFrame(SIZE_T StackPointer) |
62 | { |
63 | Frame* pFrame = GetFrame(); |
64 | |
65 | while ((SIZE_T)pFrame < StackPointer) |
66 | { |
67 | pFrame = pFrame->Next(); |
68 | } |
69 | |
70 | return pFrame; |
71 | } |
72 | |
73 | inline void Thread::SetThrowable(OBJECTREF pThrowable DEBUG_ARG(ThreadExceptionState::SetThrowableErrorChecking stecFlags)) |
74 | { |
75 | WRAPPER_NO_CONTRACT; |
76 | |
77 | m_ExceptionState.SetThrowable(pThrowable DEBUG_ARG(stecFlags)); |
78 | } |
79 | |
80 | inline void Thread::SetKickOffDomainId(ADID ad) |
81 | { |
82 | CONTRACTL { |
83 | NOTHROW; |
84 | GC_NOTRIGGER; |
85 | SO_TOLERANT; |
86 | } |
87 | CONTRACTL_END; |
88 | |
89 | m_pKickOffDomainId = ad; |
90 | } |
91 | |
92 | |
93 | inline ADID Thread::GetKickOffDomainId() |
94 | { |
95 | CONTRACTL { |
96 | NOTHROW; |
97 | GC_NOTRIGGER; |
98 | SO_TOLERANT; |
99 | } |
100 | CONTRACTL_END; |
101 | |
102 | _ASSERTE(m_pKickOffDomainId.m_dwId != 0); |
103 | return m_pKickOffDomainId; |
104 | } |
105 | |
106 | // get the current notification (if any) from this thread |
107 | inline OBJECTHANDLE Thread::GetThreadCurrNotification() |
108 | { |
109 | CONTRACTL |
110 | { |
111 | SO_NOT_MAINLINE; |
112 | NOTHROW; |
113 | GC_NOTRIGGER; |
114 | SUPPORTS_DAC; |
115 | } |
116 | CONTRACTL_END; |
117 | |
118 | return m_hCurrNotification; |
119 | } |
120 | |
121 | // set the current notification (if any) from this thread |
122 | inline void Thread::SetThreadCurrNotification(OBJECTHANDLE handle) |
123 | { |
124 | CONTRACTL |
125 | { |
126 | SO_NOT_MAINLINE; |
127 | NOTHROW; |
128 | GC_NOTRIGGER; |
129 | } |
130 | CONTRACTL_END; |
131 | |
132 | m_hCurrNotification = handle; |
133 | } |
134 | |
135 | // clear the current notification (if any) from this thread |
136 | inline void Thread::ClearThreadCurrNotification() |
137 | { |
138 | CONTRACTL |
139 | { |
140 | SO_NOT_MAINLINE; |
141 | NOTHROW; |
142 | GC_NOTRIGGER; |
143 | } |
144 | CONTRACTL_END; |
145 | |
146 | m_hCurrNotification = NULL; |
147 | } |
148 | |
149 | |
150 | inline OBJECTREF Thread::GetExposedObjectRaw() |
151 | { |
152 | CONTRACTL { |
153 | NOTHROW; |
154 | GC_NOTRIGGER; |
155 | SO_TOLERANT; |
156 | SUPPORTS_DAC; |
157 | } |
158 | CONTRACTL_END; |
159 | |
160 | return ObjectFromHandle(m_ExposedObject); |
161 | } |
162 | |
163 | inline void Thread::FinishSOWork() |
164 | { |
165 | WRAPPER_NO_CONTRACT; |
166 | #ifdef FEATURE_STACK_PROBE |
167 | if (HasThreadStateNC(TSNC_SOWorkNeeded)) |
168 | { |
169 | ResetThreadStateNC(TSNC_SOWorkNeeded); |
170 | } |
171 | #else |
172 | _ASSERTE(!HasThreadStateNC(TSNC_SOWorkNeeded)); |
173 | #endif |
174 | } |
175 | |
176 | #ifdef FEATURE_COMINTEROP |
177 | inline void Thread::RevokeApartmentSpy() |
178 | { |
179 | LIMITED_METHOD_CONTRACT; |
180 | |
181 | if (m_fInitializeSpyRegistered) |
182 | { |
183 | VERIFY(SUCCEEDED(CoRevokeInitializeSpy(m_uliInitializeSpyCookie))); |
184 | m_fInitializeSpyRegistered = false; |
185 | } |
186 | } |
187 | |
188 | inline LPVOID Thread::GetLastSTACtxCookie(BOOL *pfNAContext) |
189 | { |
190 | LIMITED_METHOD_CONTRACT; |
191 | *pfNAContext = ((UINT_PTR)m_pLastSTACtxCookie & 1); |
192 | return (LPVOID)((UINT_PTR)m_pLastSTACtxCookie & ~1); |
193 | } |
194 | |
195 | inline void Thread::SetLastSTACtxCookie(LPVOID pCtxCookie, BOOL fNAContext) |
196 | { |
197 | LIMITED_METHOD_CONTRACT; |
198 | if (fNAContext) |
199 | { |
200 | // The ctx cookie is an interface pointer so we can steal the lowest bit |
201 | // to mark whether the context is known to be Neutral Apartment or not. |
202 | m_pLastSTACtxCookie = (LPVOID)((UINT_PTR)pCtxCookie | 1); |
203 | } |
204 | else |
205 | { |
206 | m_pLastSTACtxCookie = pCtxCookie; |
207 | } |
208 | } |
209 | #endif // FEATURE_COMINTEROP |
210 | |
211 | inline bool Thread::IsGCSpecial() |
212 | { |
213 | LIMITED_METHOD_CONTRACT; |
214 | return m_fGCSpecial; |
215 | } |
216 | |
217 | inline void Thread::SetGCSpecial(bool fGCSpecial) |
218 | { |
219 | LIMITED_METHOD_CONTRACT; |
220 | m_fGCSpecial = fGCSpecial; |
221 | } |
222 | |
223 | #endif |
224 |