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 | Module Name: |
10 | |
11 | synchmanager.hpp |
12 | |
13 | Abstract: |
14 | Private header file for synchronization manager and |
15 | controllers implementation |
16 | |
17 | |
18 | |
19 | --*/ |
20 | #ifndef _SYNCHMANAGER_HPP_ |
21 | #define _SYNCHMANAGER_HPP_ |
22 | |
23 | #include "pal/synchobjects.hpp" |
24 | #include "pal/synchcache.hpp" |
25 | #include "pal/cs.hpp" |
26 | #include "pal/corunix.hpp" |
27 | #include "pal/thread.hpp" |
28 | #include "pal/procobj.hpp" |
29 | #include "pal/init.h" |
30 | #include "pal/process.h" |
31 | |
32 | #include <sys/types.h> |
33 | #include <unistd.h> |
34 | #if HAVE_KQUEUE |
35 | #include <sys/event.h> |
36 | #endif // HAVE_KQUEUE |
37 | #include "pal/dbgmsg.h" |
38 | |
39 | #ifdef _DEBUG |
40 | // #define SYNCH_OBJECT_VALIDATION |
41 | // #define SYNCH_STATISTICS |
42 | #endif |
43 | |
44 | #ifdef SYNCH_OBJECT_VALIDATION |
45 | #define VALIDATEOBJECT(obj) ((obj)->ValidateObject()) |
46 | #else |
47 | #define VALIDATEOBJECT(obj) |
48 | #endif |
49 | |
50 | namespace CorUnix |
51 | { |
52 | const DWORD WTLN_FLAG_OWNER_OBJECT_IS_SHARED = 1<<0; |
53 | const DWORD WTLN_FLAG_WAIT_ALL = 1<<1; |
54 | const DWORD WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS = 1<<2; |
55 | |
56 | #ifdef SYNCH_OBJECT_VALIDATION |
57 | const DWORD HeadSignature = 0x48454144; |
58 | const DWORD TailSignature = 0x5441494C; |
59 | const DWORD EmptySignature = 0xBAADF00D; |
60 | #endif |
61 | |
62 | enum THREAD_WAIT_STATE |
63 | { |
64 | TWS_ACTIVE, |
65 | TWS_WAITING, |
66 | TWS_ALERTABLE, |
67 | TWS_EARLYDEATH, |
68 | }; |
69 | |
70 | enum WaitCompletionState |
71 | { |
72 | WaitIsNotSatisfied, |
73 | WaitIsSatisfied, |
74 | WaitMayBeSatisfied |
75 | }; |
76 | |
77 | typedef union _SynchDataGenrPtr |
78 | { |
79 | SharedID shrid; |
80 | CSynchData * ptr; |
81 | } SynchDataGenrPtr; |
82 | |
83 | typedef union _WTLNodeGenrPtr |
84 | { |
85 | SharedID shrid; |
86 | struct _WaitingThreadsListNode * ptr; |
87 | } WTLNodeGenrPtr; |
88 | |
89 | typedef struct _WaitingThreadsListNode |
90 | { |
91 | #ifdef SYNCH_OBJECT_VALIDATION |
92 | DWORD dwDebugHeadSignature; |
93 | #endif |
94 | WTLNodeGenrPtr ptrNext; |
95 | WTLNodeGenrPtr ptrPrev; |
96 | SharedID shridSHRThis; |
97 | |
98 | // Data |
99 | DWORD dwThreadId; |
100 | DWORD dwProcessId; |
101 | DWORD dwObjIndex; |
102 | DWORD dwFlags; |
103 | |
104 | // Pointers to related objects |
105 | SharedID shridWaitingState; |
106 | SynchDataGenrPtr ptrOwnerObjSynchData; |
107 | struct _ThreadWaitInfo * ptwiWaitInfo; // valid only in the |
108 | // target process |
109 | #ifdef SYNCH_OBJECT_VALIDATION |
110 | _WaitingThreadsListNode(); |
111 | ~_WaitingThreadsListNode(); |
112 | void ValidateObject(void); |
113 | void ValidateEmptyObject(void); |
114 | void InvalidateObject(void); |
115 | |
116 | DWORD dwDebugTailSignature; |
117 | #endif |
118 | } WaitingThreadsListNode; |
119 | |
120 | typedef struct _DeferredSignalingListNode |
121 | { |
122 | LIST_ENTRY Link; |
123 | CPalThread * pthrTarget; |
124 | } DeferredSignalingListNode; |
125 | |
126 | typedef struct _OwnedObjectsListNode |
127 | { |
128 | LIST_ENTRY Link; |
129 | CSynchData * pPalObjSynchData; |
130 | } OwnedObjectsListNode; |
131 | |
132 | typedef struct _ThreadApcInfoNode |
133 | { |
134 | struct _ThreadApcInfoNode * pNext; |
135 | PAPCFUNC pfnAPC; |
136 | ULONG_PTR pAPCData; |
137 | } ThreadApcInfoNode; |
138 | |
139 | class CPalSynchronizationManager; // fwd declaration |
140 | class CProcProcessLocalData; // fwd declaration |
141 | |
142 | class CSynchData |
143 | { |
144 | #ifdef SYNCH_OBJECT_VALIDATION |
145 | DWORD m_dwDebugHeadSignature; |
146 | #endif |
147 | // NB: For perforformance purposes this class is supposed |
148 | // to have no virtual methods, and no destructor. |
149 | |
150 | WTLNodeGenrPtr m_ptrWTLHead; |
151 | WTLNodeGenrPtr m_ptrWTLTail; |
152 | ULONG m_ulcWaitingThreads; |
153 | SharedID m_shridThis; |
154 | ObjectDomain m_odObjectDomain; |
155 | PalObjectTypeId m_otiObjectTypeId; |
156 | LONG m_lRefCount; |
157 | LONG m_lSignalCount; |
158 | |
159 | // Ownership data |
160 | LONG m_lOwnershipCount; |
161 | DWORD m_dwOwnerPid; |
162 | DWORD m_dwOwnerTid; // used only by remote processes |
163 | // (thread ids may be recycled) |
164 | CPalThread * m_pOwnerThread; // valid only on the target process |
165 | OwnedObjectsListNode * m_poolnOwnedObjectListNode; |
166 | bool m_fAbandoned; |
167 | |
168 | #ifdef SYNCH_STATISTICS |
169 | ULONG m_lStatWaitCount; |
170 | ULONG m_lStatContentionCount; |
171 | #endif |
172 | |
173 | public: |
174 | CSynchData() |
175 | : m_ulcWaitingThreads(0), m_shridThis(NULL), m_lRefCount(1), |
176 | m_lSignalCount(0), m_lOwnershipCount(0), m_dwOwnerPid(0), |
177 | m_dwOwnerTid(0), m_pOwnerThread(NULL), |
178 | m_poolnOwnedObjectListNode(NULL), m_fAbandoned(false) |
179 | { |
180 | // m_ptrWTLHead, m_ptrWTLTail, m_odObjectDomain |
181 | // and m_otiObjectTypeId are initialized by |
182 | // CPalSynchronizationManager::AllocateObjectSynchData |
183 | #ifdef SYNCH_STATISTICS |
184 | m_lStatWaitCount = 0; |
185 | m_lStatContentionCount = 0; |
186 | #endif |
187 | #ifdef SYNCH_OBJECT_VALIDATION |
188 | ValidateEmptyObject(); |
189 | m_dwDebugHeadSignature = HeadSignature;; |
190 | m_dwDebugTailSignature = TailSignature; |
191 | #endif |
192 | } |
193 | |
194 | LONG AddRef() |
195 | { |
196 | return InterlockedIncrement(&m_lRefCount); |
197 | } |
198 | |
199 | LONG Release(CPalThread * pthrCurrent); |
200 | |
201 | bool CanWaiterWaitWithoutBlocking( |
202 | CPalThread * pWaiterThread, |
203 | bool * pfAbandoned); |
204 | |
205 | PAL_ERROR ReleaseWaiterWithoutBlocking( |
206 | CPalThread * pthrCurrent, |
207 | CPalThread * pthrTarget); |
208 | |
209 | void WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode, bool fPrioritize); |
210 | void SharedWaiterEnqueue(SharedID shridNewNode, bool fPrioritize); |
211 | |
212 | // Object Domain accessor methods |
213 | ObjectDomain GetObjectDomain(void) |
214 | { |
215 | return m_odObjectDomain; |
216 | } |
217 | void SetObjectDomain(ObjectDomain odObjectDomain) |
218 | { |
219 | m_odObjectDomain = odObjectDomain; |
220 | } |
221 | |
222 | // Object Type accessor methods |
223 | CObjectType * GetObjectType(void) |
224 | { |
225 | return CObjectType::GetObjectTypeById(m_otiObjectTypeId); |
226 | } |
227 | PalObjectTypeId GetObjectTypeId(void) |
228 | { |
229 | return m_otiObjectTypeId; |
230 | } |
231 | void SetObjectType(CObjectType * pot) |
232 | { |
233 | m_otiObjectTypeId = pot->GetId(); |
234 | } |
235 | void SetObjectType(PalObjectTypeId oti) |
236 | { |
237 | m_otiObjectTypeId = oti; |
238 | } |
239 | |
240 | // Object shared 'this' pointer accessor methods |
241 | SharedID GetSharedThis (void) |
242 | { |
243 | return m_shridThis; |
244 | } |
245 | void SetSharedThis (SharedID shridThis) |
246 | { |
247 | m_shridThis = shridThis; |
248 | } |
249 | |
250 | void Signal( |
251 | CPalThread * pthrCurrent, |
252 | LONG lSignalCount, |
253 | bool fWorkerThread); |
254 | |
255 | bool ReleaseFirstWaiter( |
256 | CPalThread * pthrCurrent, |
257 | bool * pfDelegated, |
258 | bool fWorkerThread); |
259 | |
260 | LONG ReleaseAllLocalWaiters( |
261 | CPalThread * pthrCurrent); |
262 | |
263 | WaitCompletionState IsRestOfWaitAllSatisfied( |
264 | WaitingThreadsListNode * pwtlnNode); |
265 | |
266 | // Object signal count accessor methods |
267 | LONG GetSignalCount(void) |
268 | { |
269 | _ASSERTE(m_lSignalCount >= 0); |
270 | return m_lSignalCount; |
271 | } |
272 | void SetSignalCount(LONG lSignalCount) |
273 | { |
274 | _ASSERTE(m_lSignalCount >= 0); |
275 | _ASSERTE(lSignalCount >= 0); |
276 | m_lSignalCount = lSignalCount; |
277 | } |
278 | LONG DecrementSignalCount(void) |
279 | { |
280 | _ASSERTE(m_lSignalCount > 0); |
281 | return --m_lSignalCount; |
282 | } |
283 | |
284 | // Object ownership accessor methods |
285 | void SetOwner(CPalThread * pOwnerThread); |
286 | void ResetOwnership(void); |
287 | PAL_ERROR AssignOwnershipToThread( |
288 | CPalThread * pthrCurrent, |
289 | CPalThread * pthrTarget); |
290 | DWORD GetOwnerProcessID(void) |
291 | { |
292 | return m_dwOwnerPid; |
293 | } |
294 | DWORD GetOwnerThreadID(void) |
295 | { |
296 | return m_dwOwnerTid; |
297 | } |
298 | CPalThread * GetOwnerThread(void) |
299 | { |
300 | return m_pOwnerThread; |
301 | } |
302 | OwnedObjectsListNode * GetOwnershipListNode(void) |
303 | { |
304 | return m_poolnOwnedObjectListNode; |
305 | } |
306 | void SetOwnershipListNode(OwnedObjectsListNode * pooln) |
307 | { |
308 | m_poolnOwnedObjectListNode = pooln; |
309 | } |
310 | |
311 | // Object ownership count accessor methods |
312 | LONG GetOwnershipCount(void) |
313 | { |
314 | return m_lOwnershipCount; |
315 | } |
316 | void SetOwnershipCount(LONG lOwnershipCount) |
317 | { |
318 | m_lOwnershipCount = lOwnershipCount; |
319 | } |
320 | |
321 | // Object abandoned flag accessor methods |
322 | void SetAbandoned(bool fAbandoned) |
323 | { m_fAbandoned = fAbandoned; } |
324 | bool IsAbandoned(void) { return m_fAbandoned; } |
325 | |
326 | void IncrementWaitingThreadCount(void) |
327 | { |
328 | m_ulcWaitingThreads += 1; |
329 | } |
330 | void DecrementWaitingThreadCount(void) |
331 | { |
332 | m_ulcWaitingThreads -= 1; |
333 | } |
334 | ULONG GetWaitingThreadCount(void) |
335 | { |
336 | return m_ulcWaitingThreads; |
337 | } |
338 | |
339 | |
340 | #ifdef SYNCH_STATISTICS |
341 | void IncrementStatWaitCount(void) |
342 | { |
343 | m_lStatWaitCount++; |
344 | } |
345 | LONG GetStatWaitCount(void) |
346 | { |
347 | return m_lStatWaitCount; |
348 | } |
349 | void IncrementStatContentionCount(void) |
350 | { |
351 | m_lStatContentionCount++; |
352 | } |
353 | LONG GetStatContentionCount(void) |
354 | { |
355 | return m_lStatContentionCount; |
356 | } |
357 | #endif |
358 | // |
359 | // Wating threads list access methods |
360 | // |
361 | WaitingThreadsListNode * GetWTLHeadPtr(void) |
362 | { |
363 | return m_ptrWTLHead.ptr; |
364 | } |
365 | WaitingThreadsListNode * GetWTLTailPtr(void) |
366 | { |
367 | return m_ptrWTLTail.ptr; |
368 | } |
369 | SharedID GetWTLHeadShmPtr(void) |
370 | { |
371 | return m_ptrWTLHead.shrid; |
372 | } |
373 | SharedID GetWTLTailShmPtr(void) |
374 | { |
375 | return m_ptrWTLTail.shrid; |
376 | } |
377 | void SetWTLHeadPtr(WaitingThreadsListNode * p) |
378 | { |
379 | m_ptrWTLHead.ptr = p; |
380 | } |
381 | void SetWTLTailPtr(WaitingThreadsListNode * p) |
382 | { |
383 | m_ptrWTLTail.ptr = p; |
384 | } |
385 | void SetWTLHeadShrPtr(SharedID shrid) |
386 | { |
387 | m_ptrWTLHead.shrid = shrid; |
388 | } |
389 | void SetWTLTailShrPtr(SharedID shrid) |
390 | { |
391 | m_ptrWTLTail.shrid = shrid; |
392 | } |
393 | #ifdef SYNCH_OBJECT_VALIDATION |
394 | ~CSynchData(); |
395 | void ValidateObject(bool fDestructor = false); |
396 | void ValidateEmptyObject(void); |
397 | void InvalidateObject(void); |
398 | |
399 | DWORD m_dwDebugTailSignature; |
400 | #endif |
401 | }; |
402 | |
403 | |
404 | class CSynchControllerBase |
405 | { |
406 | friend class CPalSynchronizationManager; |
407 | |
408 | // NB: For perforformance purposes this class is supposed |
409 | // to have no virtual methods, contructor and |
410 | // destructor |
411 | public: |
412 | enum ControllerType { WaitController, StateController }; |
413 | |
414 | protected: |
415 | CPalThread * m_pthrOwner; |
416 | ControllerType m_ctCtrlrType; |
417 | ObjectDomain m_odObjectDomain; |
418 | CObjectType * m_potObjectType; |
419 | CSynchData * m_psdSynchData; |
420 | WaitDomain m_wdWaitDomain; |
421 | |
422 | PAL_ERROR Init( |
423 | CPalThread * pthrCurrent, |
424 | ControllerType ctCtrlrType, |
425 | ObjectDomain odObjectDomain, |
426 | CObjectType *potObjectType, |
427 | CSynchData * psdSynchData, |
428 | WaitDomain wdWaitDomain); |
429 | |
430 | void Release(void); |
431 | |
432 | void SetSynchData(CSynchData * psdSynchData) |
433 | { |
434 | m_psdSynchData = psdSynchData; |
435 | } |
436 | CSynchData * GetSynchData() |
437 | { |
438 | return m_psdSynchData; |
439 | } |
440 | }; |
441 | |
442 | class CSynchWaitController : public CSynchControllerBase, |
443 | public ISynchWaitController |
444 | { |
445 | // Per-object-type specific data |
446 | // |
447 | // Process (otiProcess) |
448 | IPalObject *m_pProcessObject; // process that owns m_pProcLocalData, this is stored without a reference |
449 | CProcProcessLocalData * m_pProcLocalData; |
450 | |
451 | public: |
452 | CSynchWaitController() : m_pProcessObject(NULL), m_pProcLocalData(NULL) {} |
453 | virtual ~CSynchWaitController() = default; |
454 | |
455 | // |
456 | // ISynchWaitController methods |
457 | // |
458 | virtual PAL_ERROR CanThreadWaitWithoutBlocking( |
459 | bool * pfCanWaitWithoutBlocking, |
460 | bool * pfAbandoned); |
461 | |
462 | virtual PAL_ERROR ReleaseWaitingThreadWithoutBlocking(void); |
463 | |
464 | virtual PAL_ERROR RegisterWaitingThread( |
465 | WaitType wtWaitType, |
466 | DWORD dwIndex, |
467 | bool fAlertable, |
468 | bool fPrioritize); |
469 | |
470 | virtual void ReleaseController(void); |
471 | |
472 | CProcProcessLocalData * GetProcessLocalData(void); |
473 | |
474 | void SetProcessData(IPalObject* pProcessObject, CProcProcessLocalData * pProcLocalData); |
475 | }; |
476 | |
477 | class CSynchStateController : public CSynchControllerBase, |
478 | public ISynchStateController |
479 | { |
480 | public: |
481 | // NB: For perforformance purposes this class is supposed |
482 | // to have no constructor |
483 | virtual ~CSynchStateController() = default; |
484 | |
485 | // |
486 | // ISynchStateController methods |
487 | // |
488 | virtual PAL_ERROR GetSignalCount(LONG *plSignalCount); |
489 | virtual PAL_ERROR SetSignalCount(LONG lNewCount); |
490 | virtual PAL_ERROR IncrementSignalCount(LONG lAmountToIncrement); |
491 | virtual PAL_ERROR DecrementSignalCount(LONG lAmountToDecrement); |
492 | virtual PAL_ERROR SetOwner(CPalThread *pNewOwningThread); |
493 | virtual PAL_ERROR DecrementOwnershipCount(void); |
494 | virtual void ReleaseController(void); |
495 | }; |
496 | |
497 | class CPalSynchronizationManager : public IPalSynchronizationManager |
498 | { |
499 | friend class CPalSynchMgrController; |
500 | template <class T> friend T *CorUnix::InternalNew(); |
501 | |
502 | public: |
503 | // types |
504 | typedef CSynchCache<CSynchWaitController> CSynchWaitControllerCache; |
505 | typedef CSynchCache<CSynchStateController> CSynchStateControllerCache; |
506 | typedef CSynchCache<CSynchData> CSynchDataCache; |
507 | typedef CSHRSynchCache<CSynchData> CSHRSynchDataCache; |
508 | typedef CSynchCache<WaitingThreadsListNode> CWaitingThreadsListNodeCache; |
509 | typedef CSHRSynchCache<WaitingThreadsListNode> CSHRWaitingThreadsListNodeCache; |
510 | typedef CSynchCache<ThreadApcInfoNode> CThreadApcInfoNodeCache; |
511 | typedef CSynchCache<OwnedObjectsListNode> COwnedObjectsListNodeCache; |
512 | |
513 | private: |
514 | // types |
515 | enum InitStatus |
516 | { |
517 | SynchMgrStatusIdle, |
518 | SynchMgrStatusInitializing, |
519 | SynchMgrStatusRunning, |
520 | SynchMgrStatusShuttingDown, |
521 | SynchMgrStatusReadyForProcessShutDown, |
522 | SynchMgrStatusError |
523 | }; |
524 | enum SynchWorkerCmd |
525 | { |
526 | SynchWorkerCmdNop, |
527 | SynchWorkerCmdRemoteSignal, |
528 | SynchWorkerCmdDelegatedObjectSignaling, |
529 | SynchWorkerCmdShutdown, |
530 | SynchWorkerCmdTerminationRequest, |
531 | SynchWorkerCmdLast |
532 | }; |
533 | |
534 | typedef struct _MonitoredProcessesListNode |
535 | { |
536 | struct _MonitoredProcessesListNode * pNext; |
537 | LONG lRefCount; |
538 | CSynchData * psdSynchData; |
539 | DWORD dwPid; |
540 | DWORD dwExitCode; |
541 | bool fIsActualExitCode; |
542 | |
543 | // Object that owns pProcLocalData. This is stored, with a reference, to |
544 | // ensure that pProcLocalData is not deleted. |
545 | IPalObject *pProcessObject; |
546 | CProcProcessLocalData * pProcLocalData; |
547 | } MonitoredProcessesListNode; |
548 | |
549 | // constants |
550 | static const int CtrlrsCacheMaxSize = 256; |
551 | static const int SynchDataCacheMaxSize = 256; |
552 | static const int WTListNodeCacheMaxSize = 256; |
553 | static const int ApcInfoNodeCacheMaxSize = 32; |
554 | static const int OwnedObjectsListCacheMaxSize = 16; |
555 | static const int MaxWorkerConsecutiveEintrs = 128; |
556 | static const int MaxConsecutiveEagains = 128; |
557 | static const int WorkerThreadProcMonitoringTimeout = 250; // ms |
558 | static const int WorkerThreadShuttingDownTimeout = 1000; // ms |
559 | static const int WorkerCmdCompletionTimeout = 250; // ms |
560 | static const DWORD SecondNativeWaitTimeout = INFINITE; |
561 | static const DWORD WorkerThreadTerminationTimeout = 2000; // ms |
562 | |
563 | // static members |
564 | static CPalSynchronizationManager * s_pObjSynchMgr; |
565 | static Volatile<LONG> s_lInitStatus; |
566 | static CRITICAL_SECTION s_csSynchProcessLock; |
567 | static CRITICAL_SECTION s_csMonitoredProcessesLock; |
568 | |
569 | // members |
570 | DWORD m_dwWorkerThreadTid; |
571 | IPalObject * m_pipoThread; |
572 | CPalThread * m_pthrWorker; |
573 | int m_iProcessPipeRead; |
574 | int m_iProcessPipeWrite; |
575 | #if HAVE_KQUEUE |
576 | int m_iKQueue; |
577 | struct kevent m_keProcessPipeEvent; |
578 | #endif // HAVE_KQUEUE |
579 | |
580 | MonitoredProcessesListNode * m_pmplnMonitoredProcesses; |
581 | LONG m_lMonitoredProcessesCount; |
582 | MonitoredProcessesListNode * m_pmplnExitedNodes; |
583 | |
584 | // caches |
585 | CSynchWaitControllerCache m_cacheWaitCtrlrs; |
586 | CSynchStateControllerCache m_cacheStateCtrlrs; |
587 | CSynchDataCache m_cacheSynchData; |
588 | CSHRSynchDataCache m_cacheSHRSynchData; |
589 | CWaitingThreadsListNodeCache m_cacheWTListNodes; |
590 | CSHRWaitingThreadsListNodeCache m_cacheSHRWTListNodes; |
591 | CThreadApcInfoNodeCache m_cacheThreadApcInfoNodes; |
592 | COwnedObjectsListNodeCache m_cacheOwnedObjectsListNodes; |
593 | |
594 | // static methods |
595 | static PAL_ERROR Initialize(); |
596 | static DWORD PALAPI WorkerThread(LPVOID pArg); |
597 | |
598 | protected: |
599 | CPalSynchronizationManager(); |
600 | |
601 | PAL_ERROR GetSynchControllersForObjects( |
602 | CPalThread *pthrCurrent, |
603 | IPalObject *rgObjects[], |
604 | DWORD dwObjectCount, |
605 | void ** ppvControllers, |
606 | CSynchControllerBase::ControllerType ctCtrlrType); |
607 | |
608 | private: |
609 | static IPalSynchronizationManager * CreatePalSynchronizationManager(); |
610 | static PAL_ERROR StartWorker(CPalThread * pthrCurrent); |
611 | static PAL_ERROR PrepareForShutdown(void); |
612 | |
613 | public: |
614 | virtual ~CPalSynchronizationManager(); |
615 | |
616 | static CPalSynchronizationManager * GetInstance(void) |
617 | { |
618 | // No need here to check for NULL and in case create the |
619 | // singleton, since its creation is enforced by the PAL |
620 | // initialization code. |
621 | return s_pObjSynchMgr; |
622 | } |
623 | |
624 | // |
625 | // Inline utility methods |
626 | // |
627 | static void AcquireLocalSynchLock(CPalThread * pthrCurrent) |
628 | { |
629 | _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); |
630 | |
631 | if (1 == ++pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount) |
632 | { |
633 | InternalEnterCriticalSection(pthrCurrent, &s_csSynchProcessLock); |
634 | } |
635 | } |
636 | static void ReleaseLocalSynchLock(CPalThread * pthrCurrent) |
637 | { |
638 | _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); |
639 | if (0 == --pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount) |
640 | { |
641 | InternalLeaveCriticalSection(pthrCurrent, &s_csSynchProcessLock); |
642 | |
643 | #if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING |
644 | pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings(); |
645 | #endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING |
646 | } |
647 | } |
648 | static LONG ResetLocalSynchLock(CPalThread * pthrCurrent) |
649 | { |
650 | LONG lRet = pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount; |
651 | |
652 | _ASSERTE(0 <= lRet); |
653 | if (0 < lRet) |
654 | { |
655 | pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount = 0; |
656 | InternalLeaveCriticalSection(pthrCurrent, &s_csSynchProcessLock); |
657 | |
658 | #if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING |
659 | pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings(); |
660 | #endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING |
661 | } |
662 | return lRet; |
663 | } |
664 | static LONG GetLocalSynchLockCount(CPalThread * pthrCurrent) |
665 | { |
666 | _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); |
667 | return pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount; |
668 | } |
669 | |
670 | static void AcquireSharedSynchLock(CPalThread * pthrCurrent) |
671 | { |
672 | _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount); |
673 | _ASSERT_MSG(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount, |
674 | "The local synch lock should be acquired before grabbing the " |
675 | "shared one.\n" ); |
676 | if (1 == ++pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount) |
677 | { |
678 | SHMLock(); |
679 | } |
680 | } |
681 | static void ReleaseSharedSynchLock(CPalThread * pthrCurrent) |
682 | { |
683 | _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount); |
684 | if (0 == --pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount) |
685 | { |
686 | _ASSERT_MSG(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount, |
687 | "Final release of the shared synch lock while not holding the " |
688 | "local one. Local synch lock should always be acquired first and " |
689 | "released last.\n" ); |
690 | SHMRelease(); |
691 | } |
692 | } |
693 | static LONG ResetSharedSynchLock(CPalThread * pthrCurrent) |
694 | { |
695 | LONG lRet = pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount; |
696 | |
697 | _ASSERTE(0 <= lRet); |
698 | _ASSERTE(0 == lRet || |
699 | 0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); |
700 | if (0 < lRet) |
701 | { |
702 | pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount = 0; |
703 | SHMRelease(); |
704 | } |
705 | return lRet; |
706 | } |
707 | static LONG GetSharedSynchLockCount(CPalThread * pthrCurrent) |
708 | { |
709 | _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount); |
710 | _ASSERTE(0 == pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount || |
711 | 0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount); |
712 | return pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount; |
713 | } |
714 | |
715 | CSynchWaitController * CacheGetWaitCtrlr(CPalThread * pthrCurrent) |
716 | { |
717 | return m_cacheWaitCtrlrs.Get(pthrCurrent); |
718 | } |
719 | int CacheGetWaitCtrlr( |
720 | CPalThread * pthrCurrent, |
721 | int n, |
722 | CSynchWaitController * prgCtrlrs[]) |
723 | { |
724 | return m_cacheWaitCtrlrs.Get(pthrCurrent, n, prgCtrlrs); |
725 | } |
726 | void CacheAddWaitCtrlr( |
727 | CPalThread * pthrCurrent, |
728 | CSynchWaitController * pCtrlr) |
729 | { |
730 | m_cacheWaitCtrlrs.Add(pthrCurrent, pCtrlr); |
731 | } |
732 | CSynchStateController * CacheGetStateCtrlr(CPalThread * pthrCurrent) |
733 | { |
734 | return m_cacheStateCtrlrs.Get(pthrCurrent); |
735 | } |
736 | int CacheGetStateCtrlr( |
737 | CPalThread * pthrCurrent, |
738 | int n, |
739 | CSynchStateController * prgCtrlrs[]) |
740 | { |
741 | return m_cacheStateCtrlrs.Get(pthrCurrent, n, prgCtrlrs); |
742 | } |
743 | void CacheAddStateCtrlr( |
744 | CPalThread * pthrCurrent, |
745 | CSynchStateController * pCtrlr) |
746 | { |
747 | m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr); |
748 | } |
749 | |
750 | CSynchData * CacheGetLocalSynchData(CPalThread * pthrCurrent) |
751 | { |
752 | return m_cacheSynchData.Get(pthrCurrent); |
753 | } |
754 | void CacheAddLocalSynchData( |
755 | CPalThread * pthrCurrent, |
756 | CSynchData * psdSynchData) |
757 | { |
758 | m_cacheSynchData.Add(pthrCurrent, psdSynchData); |
759 | } |
760 | SharedID CacheGetSharedSynchData(CPalThread * pthrCurrent) |
761 | { |
762 | return m_cacheSHRSynchData.Get(pthrCurrent); |
763 | } |
764 | void CacheAddSharedSynchData( |
765 | CPalThread * pthrCurrent, |
766 | SharedID shridSData) |
767 | { |
768 | m_cacheSHRSynchData.Add(pthrCurrent, shridSData); |
769 | } |
770 | |
771 | WaitingThreadsListNode * CacheGetLocalWTListNode( |
772 | CPalThread * pthrCurrent) |
773 | { |
774 | return m_cacheWTListNodes.Get(pthrCurrent); |
775 | } |
776 | void CacheAddLocalWTListNode( |
777 | CPalThread * pthrCurrent, |
778 | WaitingThreadsListNode * pWTLNode) |
779 | { |
780 | m_cacheWTListNodes.Add(pthrCurrent, pWTLNode); |
781 | } |
782 | SharedID CacheGetSharedWTListNode(CPalThread * pthrCurrent) |
783 | { |
784 | return m_cacheSHRWTListNodes.Get(pthrCurrent); |
785 | } |
786 | void CacheAddSharedWTListNode( |
787 | CPalThread * pthrCurrent, |
788 | SharedID shridWTLNode) |
789 | { |
790 | m_cacheSHRWTListNodes.Add(pthrCurrent, shridWTLNode); |
791 | } |
792 | |
793 | ThreadApcInfoNode * CacheGetApcInfoNodes(CPalThread * pthrCurrent) |
794 | { |
795 | return m_cacheThreadApcInfoNodes.Get(pthrCurrent); |
796 | } |
797 | void CacheAddApcInfoNodes( |
798 | CPalThread * pthrCurrent, |
799 | ThreadApcInfoNode * pNode) |
800 | { |
801 | m_cacheThreadApcInfoNodes.Add(pthrCurrent, pNode); |
802 | } |
803 | |
804 | OwnedObjectsListNode * CacheGetOwnedObjsListNode( |
805 | CPalThread * pthrCurrent) |
806 | { |
807 | return m_cacheOwnedObjectsListNodes.Get(pthrCurrent); |
808 | } |
809 | void CacheAddOwnedObjsListNode( |
810 | CPalThread * pthrCurrent, |
811 | OwnedObjectsListNode * pNode) |
812 | { |
813 | m_cacheOwnedObjectsListNodes.Add(pthrCurrent, pNode); |
814 | } |
815 | |
816 | |
817 | // |
818 | // IPalSynchronizationManager methods |
819 | // |
820 | virtual PAL_ERROR BlockThread( |
821 | CPalThread *pthrCurrent, |
822 | DWORD dwTimeout, |
823 | bool fAlertable, |
824 | bool fIsSleep, |
825 | ThreadWakeupReason *ptwrWakeupReason, |
826 | DWORD *pdwSignaledObject); |
827 | |
828 | virtual PAL_ERROR AbandonObjectsOwnedByThread( |
829 | CPalThread *pthrCurrent, |
830 | CPalThread *pthrTarget); |
831 | |
832 | virtual PAL_ERROR GetSynchWaitControllersForObjects( |
833 | CPalThread *pthrCurrent, |
834 | IPalObject *rgObjects[], |
835 | DWORD dwObjectCount, |
836 | ISynchWaitController *rgControllers[]); |
837 | |
838 | virtual PAL_ERROR GetSynchStateControllersForObjects( |
839 | CPalThread *pthrCurrent, |
840 | IPalObject *rgObjects[], |
841 | DWORD dwObjectCount, |
842 | ISynchStateController *rgControllers[]); |
843 | |
844 | virtual PAL_ERROR AllocateObjectSynchData( |
845 | CObjectType *potObjectType, |
846 | ObjectDomain odObjectDomain, |
847 | VOID **ppvSynchData); |
848 | |
849 | virtual void FreeObjectSynchData( |
850 | CObjectType *potObjectType, |
851 | ObjectDomain odObjectDomain, |
852 | VOID *pvSynchData); |
853 | |
854 | virtual PAL_ERROR PromoteObjectSynchData( |
855 | CPalThread *pthrCurrent, |
856 | VOID *pvLocalSynchData, |
857 | VOID **ppvSharedSynchData); |
858 | |
859 | virtual PAL_ERROR CreateSynchStateController( |
860 | CPalThread *pthrCurrent, |
861 | CObjectType *potObjectType, |
862 | VOID *pvSynchData, |
863 | ObjectDomain odObjectDomain, |
864 | ISynchStateController **ppStateController); |
865 | |
866 | virtual PAL_ERROR CreateSynchWaitController( |
867 | CPalThread *pthrCurrent, |
868 | CObjectType *potObjectType, |
869 | VOID *pvSynchData, |
870 | ObjectDomain odObjectDomain, |
871 | ISynchWaitController **ppWaitController); |
872 | |
873 | virtual PAL_ERROR QueueUserAPC( |
874 | CPalThread * pthrCurrent, |
875 | CPalThread *pthrTarget, |
876 | PAPCFUNC pfnAPC, |
877 | ULONG_PTR uptrData); |
878 | |
879 | virtual PAL_ERROR SendTerminationRequestToWorkerThread(); |
880 | |
881 | virtual bool AreAPCsPending(CPalThread * pthrTarget); |
882 | |
883 | virtual PAL_ERROR DispatchPendingAPCs(CPalThread * pthrCurrent); |
884 | |
885 | virtual void AcquireProcessLock(CPalThread *pthrCurrent); |
886 | |
887 | virtual void ReleaseProcessLock(CPalThread *pthrCurrent); |
888 | |
889 | // |
890 | // Static helper methods |
891 | // |
892 | public: |
893 | static PAL_ERROR WakeUpLocalThread( |
894 | CPalThread * pthrCurrent, |
895 | CPalThread * pthrTarget, |
896 | ThreadWakeupReason twrWakeupReason, |
897 | DWORD dwObjectIndex); |
898 | |
899 | static PAL_ERROR SignalThreadCondition( |
900 | ThreadNativeWaitData * ptnwdNativeWaitData); |
901 | |
902 | static PAL_ERROR DeferThreadConditionSignaling( |
903 | CPalThread * pthrCurrent, |
904 | CPalThread * pthrTarget); |
905 | |
906 | static PAL_ERROR WakeUpRemoteThread( |
907 | SharedID shridWLNode); |
908 | |
909 | static PAL_ERROR DelegateSignalingToRemoteProcess( |
910 | CPalThread * pthrCurrent, |
911 | DWORD dwTargetProcessId, |
912 | SharedID shridSynchData); |
913 | |
914 | static PAL_ERROR SendMsgToRemoteWorker( |
915 | DWORD dwProcessId, |
916 | BYTE * pMsg, |
917 | int iMsgSize); |
918 | |
919 | static ThreadWaitInfo * GetThreadWaitInfo( |
920 | CPalThread * pthrCurrent); |
921 | |
922 | // |
923 | // The following methods must be called only by a Sync*Controller or |
924 | // while holding the required synchronization global locks |
925 | // |
926 | static void UnsignalRestOfLocalAwakeningWaitAll( |
927 | CPalThread * pthrCurrent, |
928 | CPalThread * pthrTarget, |
929 | WaitingThreadsListNode * pwtlnNode, |
930 | CSynchData * psdTgtObjectSynchData); |
931 | |
932 | static void MarkWaitForDelegatedObjectSignalingInProgress( |
933 | CPalThread * pthrCurrent, |
934 | WaitingThreadsListNode * pwtlnNode); |
935 | |
936 | static void UnmarkTWListForDelegatedObjectSignalingInProgress( |
937 | CSynchData * pTgtObjectSynchData); |
938 | |
939 | static PAL_ERROR ThreadNativeWait( |
940 | ThreadNativeWaitData * ptnwdNativeWaitData, |
941 | DWORD dwTimeout, |
942 | ThreadWakeupReason * ptwrWakeupReason, |
943 | DWORD * pdwSignaledObject); |
944 | |
945 | static void ThreadPrepareForShutdown(void); |
946 | |
947 | #ifndef CORECLR |
948 | static bool GetProcessPipeName( |
949 | LPSTR pDest, |
950 | int iDestSize, |
951 | DWORD dwPid); |
952 | #endif // !CORECLR |
953 | |
954 | // |
955 | // Non-static helper methods |
956 | // |
957 | private: |
958 | LONG DoMonitorProcesses(CPalThread * pthrCurrent); |
959 | |
960 | void DiscardMonitoredProcesses(CPalThread * pthrCurrent); |
961 | |
962 | PAL_ERROR ReadCmdFromProcessPipe( |
963 | int iPollTimeout, |
964 | SynchWorkerCmd * pswcWorkerCmd, |
965 | SharedID * pshridMarshaledData, |
966 | DWORD * pdwData); |
967 | |
968 | PAL_ERROR WakeUpLocalWorkerThread( |
969 | SynchWorkerCmd swcWorkerCmd); |
970 | |
971 | void DiscardAllPendingAPCs( |
972 | CPalThread * pthrCurrent, |
973 | CPalThread * pthrTarget); |
974 | |
975 | int ReadBytesFromProcessPipe( |
976 | int iTimeout, |
977 | BYTE * pRecvBuf, |
978 | LONG lBytes); |
979 | |
980 | bool CreateProcessPipe(); |
981 | |
982 | PAL_ERROR ShutdownProcessPipe(); |
983 | |
984 | public: |
985 | // |
986 | // The following methods must be called only by a Sync*Controller or |
987 | // while holding the required synchronization global locks |
988 | // |
989 | void UnRegisterWait( |
990 | CPalThread * pthrCurrent, |
991 | ThreadWaitInfo * ptwiWaitInfo, |
992 | bool fHaveSharedLock); |
993 | |
994 | PAL_ERROR RegisterProcessForMonitoring( |
995 | CPalThread * pthrCurrent, |
996 | CSynchData *psdSynchData, |
997 | IPalObject *pProcessObject, |
998 | CProcProcessLocalData * pProcLocalData); |
999 | |
1000 | PAL_ERROR UnRegisterProcessForMonitoring( |
1001 | CPalThread * pthrCurrent, |
1002 | CSynchData *psdSynchData, |
1003 | DWORD dwPid); |
1004 | |
1005 | // |
1006 | // Utility static methods, no lock required |
1007 | // |
1008 | static bool HasProcessExited( |
1009 | DWORD dwPid, |
1010 | DWORD * pdwExitCode, |
1011 | bool * pfIsActualExitCode); |
1012 | |
1013 | static bool InterlockedAwaken( |
1014 | DWORD *pWaitState, |
1015 | bool fAlertOnly); |
1016 | |
1017 | static PAL_ERROR GetAbsoluteTimeout( |
1018 | DWORD dwTimeout, |
1019 | struct timespec * ptsAbsTmo, |
1020 | BOOL fPreferMonotonicClock); |
1021 | }; |
1022 | } |
1023 | |
1024 | #endif // _SYNCHMANAGER_HPP_ |
1025 | |