Welcome to mirror list, hosted at ThFree Co, Russian Federation.

thread.h « Runtime « Native « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b2143c75d70f21b975aadef02654e62ac95e68d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include "forward_declarations.h"

struct gc_alloc_context;
class RuntimeInstance;
class ThreadStore;
class CLREventStatic;
class Thread;

// The offsets of some fields in the thread (in particular, m_pTransitionFrame) are known to the compiler and get 
// inlined into the code.  Let's make sure they don't change just because we enable/disable server GC in a particular
// runtime build.
#define KEEP_THREAD_LAYOUT_CONSTANT

#ifndef BIT64
# if defined(FEATURE_SVR_GC) || defined(KEEP_THREAD_LAYOUT_CONSTANT)
#  define SIZEOF_ALLOC_CONTEXT 40
# else
#  define SIZEOF_ALLOC_CONTEXT 28
# endif
#else // BIT64
# if defined(FEATURE_SVR_GC) || defined(KEEP_THREAD_LAYOUT_CONSTANT)
#  define SIZEOF_ALLOC_CONTEXT 56
# else
#  define SIZEOF_ALLOC_CONTEXT 40
# endif
#endif // BIT64

#define TOP_OF_STACK_MARKER ((PTR_VOID)(UIntNative)(IntNative)-1)

#define DYNAMIC_TYPE_TLS_OFFSET_FLAG 0x80000000


enum SyncRequestResult
{
    TryAgain,
    SuccessUnmanaged,
    SuccessManaged,
};

typedef DPTR(PAL_LIMITED_CONTEXT) PTR_PAL_LIMITED_CONTEXT;

struct ExInfo;
typedef DPTR(ExInfo) PTR_ExInfo;


// Also defined in ExceptionHandling.cs, layouts must match.
// When adding new fields to this struct, ensure they get properly initialized in the exception handling 
// assembly stubs
struct ExInfo
{

    PTR_ExInfo              m_pPrevExInfo;
    PTR_PAL_LIMITED_CONTEXT m_pExContext;
    PTR_Object              m_exception;  // actual object reference, specially reported by GcScanRootsWorker
    ExKind                  m_kind;
    UInt8                   m_passNumber;
    UInt32                  m_idxCurClause;
    StackFrameIterator      m_frameIter;
    volatile void*          m_notifyDebuggerSP;
};

struct ThreadBuffer
{
    UInt8                   m_rgbAllocContextBuffer[SIZEOF_ALLOC_CONTEXT];
    UInt32 volatile         m_ThreadStateFlags;                     // see Thread::ThreadStateFlags enum
#if DACCESS_COMPILE
    PTR_VOID                m_pTransitionFrame;
#else
    PTR_VOID volatile       m_pTransitionFrame;
#endif
    PTR_VOID                m_pHackPInvokeTunnel;                   // see Thread::EnablePreemptiveMode
    PTR_VOID                m_pCachedTransitionFrame;
    PTR_Thread              m_pNext;                                // used by ThreadStore's SList<Thread>
    HANDLE                  m_hPalThread;                           // WARNING: this may legitimately be INVALID_HANDLE_VALUE
    void **                 m_ppvHijackedReturnAddressLocation;
    void *                  m_pvHijackedReturnAddress;
#ifdef BIT64
    UIntNative              m_uHijackedReturnValueFlags;            // used on ARM64 only; however, ARM64 and AMD64 share field offsets
#endif // BIT64
    PTR_ExInfo              m_pExInfoStackHead;
    Object*                 m_threadAbortException;                 // ThreadAbortException instance -set only during thread abort
    PTR_VOID                m_pStackLow;
    PTR_VOID                m_pStackHigh;
    PTR_UInt8               m_pTEB;                                 // Pointer to OS TEB structure for this thread
    UInt64                  m_uPalThreadIdForLogging;               // @TODO: likely debug-only 
    EEThreadId              m_threadId;               
    PTR_VOID                m_pThreadStressLog;                     // pointer to head of thread's StressLogChunks
#ifdef FEATURE_GC_STRESS
    UInt32                  m_uRand;                                // current per-thread random number
#endif // FEATURE_GC_STRESS

    // Thread Statics Storage for dynamic types
    UInt32          m_numDynamicTypesTlsCells;
    PTR_PTR_UInt8   m_pDynamicTypesTlsCells;

#ifndef PROJECTN
    PTR_PTR_VOID    m_pThreadLocalModuleStatics;
    UInt32          m_numThreadLocalModuleStatics;
#endif // PROJECTN
};

struct ReversePInvokeFrame
{
    void*   m_savedPInvokeTransitionFrame;
    Thread* m_savedThread;
};

class Thread : private ThreadBuffer
{
    friend class AsmOffsets;
    friend struct DefaultSListTraits<Thread>;
    friend class ThreadStore;
    IN_DAC(friend class ClrDataAccess;)

public:
    enum ThreadStateFlags
    {
        TSF_Unknown             = 0x00000000,       // Threads are created in this state
        TSF_Attached            = 0x00000001,       // Thread was inited by first U->M transition on this thread
        TSF_Detached            = 0x00000002,       // Thread was detached by DllMain
        TSF_SuppressGcStress    = 0x00000008,       // Do not allow gc stress on this thread, used in DllMain
                                                    // ...and on the Finalizer thread
        TSF_DoNotTriggerGc      = 0x00000010,       // Do not allow hijacking of this thread, also intended to
                                                    // ...be checked during allocations in debug builds.
        TSF_IsGcSpecialThread   = 0x00000020,       // Set to indicate a GC worker thread used for background GC
#ifdef FEATURE_GC_STRESS
        TSF_IsRandSeedSet       = 0x00000040,       // set to indicate the random number generator for GCStress was inited
#endif // FEATURE_GC_STRESS
    };
private:

    void Construct();

    void SetState(ThreadStateFlags flags);
    void ClearState(ThreadStateFlags flags);
    bool IsStateSet(ThreadStateFlags flags);

    static UInt32_BOOL HijackCallback(HANDLE hThread, PAL_LIMITED_CONTEXT* pThreadContext, void* pCallbackContext);
    bool InternalHijack(PAL_LIMITED_CONTEXT * pSuspendCtx, void * pvHijackTargets[]);

    bool CacheTransitionFrameForSuspend();
    void ResetCachedTransitionFrame();
    void CrossThreadUnhijack();
    void UnhijackWorker();
    void EnsureRuntimeInitialized();
#ifdef _DEBUG
    bool DebugIsSuspended();
#endif

    // 
    // SyncState members
    //
    PTR_VOID    GetTransitionFrame();

    void GcScanRootsWorker(void * pfnEnumCallback, void * pvCallbackData, StackFrameIterator & sfIter);

public:


    void Destroy();

    bool                IsInitialized();

    gc_alloc_context *  GetAllocContext();  // @TODO: I would prefer to not expose this in this way

#ifndef DACCESS_COMPILE
    UInt64              GetPalThreadIdForLogging();
    bool                IsCurrentThread();

    void                GcScanRoots(void * pfnEnumCallback, void * pvCallbackData);
#else
    typedef void GcScanRootsCallbackFunc(PTR_RtuObjectRef ppObject, void* token, UInt32 flags);
    bool GcScanRoots(GcScanRootsCallbackFunc * pfnCallback, void * token, PTR_PAL_LIMITED_CONTEXT pInitialContext);
#endif

    bool                Hijack();
    void                Unhijack();
#ifdef FEATURE_GC_STRESS
    static void         HijackForGcStress(PAL_LIMITED_CONTEXT * pSuspendCtx);
#endif // FEATURE_GC_STRESS
    bool                IsHijacked();
    void *              GetHijackedReturnAddress();
    void *              GetUnhijackedReturnAddress(void** ppvReturnAddressLocation);
    bool                DangerousCrossThreadIsHijacked();

    bool                IsSuppressGcStressSet();
    void                SetSuppressGcStress();
    void                ClearSuppressGcStress();
    bool                IsWithinStackBounds(PTR_VOID p);

    void                GetStackBounds(PTR_VOID * ppStackLow, PTR_VOID * ppStackHigh);

    PTR_UInt8           AllocateThreadLocalStorageForDynamicType(UInt32 uTlsTypeOffset, UInt32 tlsStorageSize, UInt32 numTlsCells);
    // mrt100 Debugger (dac) has dependencies on the GetThreadLocalStorageForDynamicType method.
    PTR_UInt8           GetThreadLocalStorageForDynamicType(UInt32 uTlsTypeOffset);
    PTR_UInt8           GetThreadLocalStorage(UInt32 uTlsIndex, UInt32 uTlsStartOffset);
    PTR_UInt8           GetTEB();

    void                PushExInfo(ExInfo * pExInfo);
    void                ValidateExInfoPop(ExInfo * pExInfo, void * limitSP);
    void                ValidateExInfoStack();
    bool                IsDoNotTriggerGcSet();
    void                SetDoNotTriggerGc();
    void                ClearDoNotTriggerGc();

    bool                IsDetached();
    void                SetDetached();

    PTR_VOID            GetThreadStressLog() const;
#ifndef DACCESS_COMPILE
    void                SetThreadStressLog(void * ptsl);
#endif // DACCESS_COMPILE
#ifdef FEATURE_GC_STRESS
    void                SetRandomSeed(UInt32 seed);
    UInt32              NextRand();
    bool                IsRandInited();
#endif // FEATURE_GC_STRESS
    PTR_ExInfo          GetCurExInfo();

    bool                IsCurrentThreadInCooperativeMode();

    PTR_VOID            GetTransitionFrameForStackTrace();
    void *              GetCurrentThreadPInvokeReturnAddress();

    static bool         IsHijackTarget(void * address);

    //
    // The set of operations used to support unmanaged code running in cooperative mode
    //
    void                EnablePreemptiveMode();
    void                DisablePreemptiveMode();

    // Set the m_pHackPInvokeTunnel field for GC allocation helpers that setup transition frame 
    // in assembly code. Do not use anywhere else.
    void                SetCurrentThreadPInvokeTunnelForGcAlloc(void * pTransitionFrame);

    // Setup the m_pHackPInvokeTunnel field for GC helpers entered via regular PInvoke.
    // Do not use anywhere else.
    void                SetupHackPInvokeTunnel();

    //
    // GC support APIs - do not use except from GC itself
    //
    void SetGCSpecial(bool isGCSpecial);
    bool IsGCSpecial();
    bool CatchAtSafePoint();

    //
    // Managed/unmanaged interop transitions support APIs
    //
    void WaitForSuspend();
    void WaitForGC(void * pTransitionFrame);

    void ReversePInvokeAttachOrTrapThread(ReversePInvokeFrame * pFrame);

    bool InlineTryFastReversePInvoke(ReversePInvokeFrame * pFrame);
    void InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame);

    void InlinePInvoke(PInvokeTransitionFrame * pFrame);
    void InlinePInvokeReturn(PInvokeTransitionFrame * pFrame);

    Object * GetThreadAbortException();
    void SetThreadAbortException(Object *exception);

#ifndef PROJECTN
    Object* GetThreadStaticStorageForModule(UInt32 moduleIndex);
    Boolean SetThreadStaticStorageForModule(Object * pStorage, UInt32 moduleIndex);
#endif // PROJECTN
};

#ifndef GCENV_INCLUDED
typedef DPTR(Object) PTR_Object;
typedef DPTR(PTR_Object) PTR_PTR_Object;
#endif // !GCENV_INCLUDED
#ifdef DACCESS_COMPILE

// The DAC uses DebuggerEnumGcRefContext in place of a GCCONTEXT when doing reference
// enumeration. The GC passes through additional data in the ScanContext which the debugger
// neither has nor needs. While we could refactor the GC code to make an interface
// with less coupling, that might affect perf or make integration messier. Instead
// we use some typedefs so DAC and runtime can get strong yet distinct types.


// Ideally we wouldn't need this wrapper, but PromoteCarefully needs access to the
// thread and a promotion field. We aren't assuming the user's token will have this data.
struct DacScanCallbackData
{
    Thread* thread_under_crawl;               // the thread being scanned
    bool promotion;                           // are we emulating the GC promote phase or relocate phase?
                                              // different references are reported for each
    void* token;                              // the callback data passed to GCScanRoots
    void* pfnUserCallback;                    // the callback passed in to GcScanRoots
    uintptr_t stack_limit;                    // Lowest point on the thread stack that the scanning logic is permitted to read
};

typedef DacScanCallbackData EnumGcRefScanContext;
typedef void EnumGcRefCallbackFunc(PTR_PTR_Object, EnumGcRefScanContext* callbackData, UInt32 flags);

#else // DACCESS_COMPILE
#ifndef GCENV_INCLUDED
struct ScanContext;
typedef void promote_func(PTR_PTR_Object, ScanContext*, unsigned);
#endif // !GCENV_INCLUDED
typedef promote_func EnumGcRefCallbackFunc;
typedef ScanContext  EnumGcRefScanContext;

#endif // DACCESS_COMPILE