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
9Module Name:
10
11 synchmanager.hpp
12
13Abstract:
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
50namespace 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