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 synchcontrollers.cpp
12
13Abstract:
14 Implementation of Synchronization Controllers and related objects
15
16
17
18--*/
19
20#include "pal/dbgmsg.h"
21
22SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first
23
24#include "synchmanager.hpp"
25
26#include <sys/types.h>
27#include <sys/time.h>
28#include <sys/stat.h>
29#include <unistd.h>
30#include <sched.h>
31#include <errno.h>
32#include <limits.h>
33
34namespace CorUnix
35{
36#ifdef SYNCH_STATISTICS
37 LONG g_rglStatWaitCount[ObjectTypeIdCount] = { 0 };
38 LONG g_rglStatContentionCount[ObjectTypeIdCount] = { 0 };
39#endif // SYNCH_STATISTICS
40 ////////////////////////////
41 // //
42 // CSynchControllerBase //
43 // //
44 ////////////////////////////
45
46 /*++
47 Method:
48 CSynchControllerBase::Init
49
50 Initializes a generic controller
51 --*/
52 PAL_ERROR CSynchControllerBase::Init(
53 CPalThread * pthrCurrent,
54 ControllerType ctCtrlrType,
55 ObjectDomain odObjectDomain,
56 CObjectType *potObjectType,
57 CSynchData * psdSynchData,
58 WaitDomain wdWaitDomain)
59 {
60 VALIDATEOBJECT(psdSynchData);
61
62 _ASSERTE(InternalGetCurrentThread() == pthrCurrent);
63
64 // Initialize internal controller data
65 m_pthrOwner = pthrCurrent;
66 m_ctCtrlrType = ctCtrlrType;
67 m_odObjectDomain = odObjectDomain;
68 m_potObjectType = potObjectType;
69 m_psdSynchData = psdSynchData;
70 m_wdWaitDomain = wdWaitDomain;
71
72 // Add reference to target synch data
73 m_psdSynchData->AddRef();
74
75 // Acquire lock implied by the controller
76 CPalSynchronizationManager::AcquireLocalSynchLock(m_pthrOwner);
77 if (LocalWait != m_wdWaitDomain)
78 {
79 CPalSynchronizationManager::AcquireSharedSynchLock(m_pthrOwner);
80 }
81
82 return NO_ERROR;
83 }
84
85 /*++
86 Method:
87 CSynchControllerBase::Release
88
89 Releases a generic controller a return it to the appropriate cache
90 --*/
91 void CSynchControllerBase::Release()
92 {
93 VALIDATEOBJECT(m_psdSynchData);
94
95#ifdef _DEBUG
96 ThreadWaitInfo * ptwiWaitInfo =
97 CPalSynchronizationManager::GetThreadWaitInfo(m_pthrOwner);
98#endif // _DEBUG
99
100 CPalSynchronizationManager * pSynchManager =
101 CPalSynchronizationManager::GetInstance();
102
103 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
104 _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner);
105
106 // Release reference to target synch data
107 m_psdSynchData->Release(m_pthrOwner);
108
109 // Release lock implied by the controller
110 if (LocalWait != m_wdWaitDomain)
111 {
112 CPalSynchronizationManager::ReleaseSharedSynchLock(m_pthrOwner);
113 }
114 CPalSynchronizationManager::ReleaseLocalSynchLock(m_pthrOwner);
115
116 // Return controller to the appropriate cache
117 if (WaitController == m_ctCtrlrType)
118 {
119 // The cast here must be static_cast and not reinterpet_cast.
120 // In fact in general static_cast<CSynchWaitController*>(this) is
121 // equal to this-sizeof(void*), given that CSynchWaitController
122 // has a virtual table, while CSynchControllerBase doesn't.
123 pSynchManager->CacheAddWaitCtrlr(m_pthrOwner,
124 static_cast<CSynchWaitController*>(this));
125 }
126 else
127 {
128 // The cast here must be static_cast and not reinterpet_cast
129 pSynchManager->CacheAddStateCtrlr(m_pthrOwner,
130 static_cast<CSynchStateController*>(this));
131 }
132 }
133
134 ////////////////////////////
135 // //
136 // CSynchWaitController //
137 // //
138 ////////////////////////////
139
140 /*++
141 Method:
142 CSynchWaitController::CanThreadWaitWithoutBlocking
143
144 Returns whether or not the thread owning this controller can
145 wait on the target object without blocking (i.e. the objet is
146 signaled)
147 --*/
148 PAL_ERROR CSynchWaitController::CanThreadWaitWithoutBlocking(
149 bool * pfCanWaitWithoutBlocking,
150 bool * pfAbandoned)
151 {
152 VALIDATEOBJECT(m_psdSynchData);
153
154 bool fRetVal = false;
155
156 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
157 _ASSERTE(NULL != pfCanWaitWithoutBlocking);
158 _ASSERTE(NULL != pfAbandoned);
159
160 fRetVal = m_psdSynchData->CanWaiterWaitWithoutBlocking(m_pthrOwner, pfAbandoned);
161
162 if(!fRetVal && otiProcess == m_psdSynchData->GetObjectTypeId())
163 {
164 // Note: if the target object is a process, here we need to check
165 // whether or not it has already exited. In fact, since currently
166 // we do not monitor a process status as long as there is no
167 // thread waiting on it, in general if the process already exited
168 // the process object is likely not to be signaled yet, therefore
169 // the above CanWaiterWaitWithoutBlocking call probably returned
170 // false, and, without the check below, that would cause the
171 // current thread to eventually go to sleep for a short time
172 // (until the worker thread notifies that the waited process has
173 // indeed exited), while it would not be necessary.
174 // As side effect that would cause a WaitForSingleObject with zero
175 // timeout to always return WAIT_TIMEOUT, even though the target
176 // process already exited. WaitForSingleObject with zero timeout
177 // is a common way to probe whether or not a process has already
178 // exited, and it is supposed to return WAIT_OBJECT_0 if the
179 // process exited, and WAIT_TIMEOUT if it is still active.
180 // In order to support this feature we need to check at this time
181 // whether or not the process has already exited.
182
183 CProcProcessLocalData * pProcLocalData = GetProcessLocalData();
184 DWORD dwExitCode = 0;
185 bool fIsActualExitCode = false;
186
187 _ASSERT_MSG(NULL != pProcLocalData,
188 "Process synch data pointer is missing\n");
189
190 if (NULL != pProcLocalData &&
191 CPalSynchronizationManager::HasProcessExited(pProcLocalData->dwProcessId,
192 &dwExitCode,
193 &fIsActualExitCode))
194 {
195 TRACE("Process pid=%u exited with %s exitcode=%u\n",
196 pProcLocalData->dwProcessId,
197 fIsActualExitCode ? "actual" : "guessed",
198 dwExitCode);
199
200 // Store the exit code in the process local data
201 if (fIsActualExitCode)
202 {
203 pProcLocalData->dwExitCode = dwExitCode;
204 }
205
206 // Set process status to PS_DONE
207 pProcLocalData->ps = PS_DONE;
208
209 // Set signal count
210 m_psdSynchData->SetSignalCount(1);
211
212 // Releasing all local waiters
213 // (see comments in DoMonitorProcesses)
214 m_psdSynchData->ReleaseAllLocalWaiters(m_pthrOwner);
215
216 fRetVal = true;
217 }
218 }
219
220 *pfCanWaitWithoutBlocking = fRetVal;
221 return NO_ERROR;
222 }
223
224 /*++
225 Method:
226 CSynchWaitController::ReleaseWaitingThreadWithoutBlocking
227
228 Performs all the steps needed to be done by the controller's owner
229 thread in order to wait on the target object without blocking
230 (e.g. modifying the object signal count accordingly with its
231 thread release semantics)
232 This method should be called only after having received positive
233 response from CanThreadWaitWithoutBlocking called on the same
234 controller.
235 --*/
236 PAL_ERROR CSynchWaitController::ReleaseWaitingThreadWithoutBlocking()
237 {
238 VALIDATEOBJECT(m_psdSynchData);
239
240 PAL_ERROR palErr = NO_ERROR;
241
242 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
243
244 palErr = m_psdSynchData->ReleaseWaiterWithoutBlocking(m_pthrOwner, m_pthrOwner);
245
246#ifdef SYNCH_STATISTICS
247 if (NO_ERROR == palErr)
248 {
249 m_psdSynchData->IncrementStatWaitCount();
250 }
251#endif
252 return palErr;
253 }
254
255 /*++
256 Method:
257 CSynchWaitController::RegisterWaitingThread
258
259 Registers the controller's owner thread for waiting on the target
260 object
261 --*/
262 PAL_ERROR CSynchWaitController::RegisterWaitingThread(
263 WaitType wtWaitType,
264 DWORD dwIndex,
265 bool fAlertable,
266 bool fPrioritize)
267 {
268 VALIDATEOBJECT(m_psdSynchData);
269
270 PAL_ERROR palErr = NO_ERROR;
271 WaitingThreadsListNode * pwtlnNewNode = NULL;
272 SharedID shridNewNode = NULL;
273 ThreadWaitInfo * ptwiWaitInfo;
274 DWORD * pdwWaitState;
275 bool fSharedObject = (SharedObject == m_odObjectDomain);
276 bool fEarlyDeath = false;
277 bool fSynchDataRefd = false;
278 CPalSynchronizationManager * pSynchManager =
279 CPalSynchronizationManager::GetInstance();
280
281 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
282
283 ptwiWaitInfo = CPalSynchronizationManager::GetThreadWaitInfo(
284 m_pthrOwner);
285
286 _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner);
287
288 pdwWaitState = SharedIDToTypePointer(DWORD,
289 m_pthrOwner->synchronizationInfo.m_shridWaitAwakened);
290
291 if (fSharedObject)
292 {
293 shridNewNode = pSynchManager->CacheGetSharedWTListNode(m_pthrOwner);
294 pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
295 }
296 else
297 {
298 pwtlnNewNode = pSynchManager->CacheGetLocalWTListNode(m_pthrOwner);
299 }
300
301 if (!pwtlnNewNode)
302 {
303 if (fSharedObject && (NULL != shridNewNode))
304 {
305 ASSERT("Bad Shared Memory ptr %p\n", shridNewNode);
306 palErr = ERROR_INTERNAL_ERROR;
307 }
308 else
309 {
310 ERROR("Out of memory\n");
311 palErr = ERROR_NOT_ENOUGH_MEMORY;
312 }
313 goto RWT_exit;
314 }
315
316 if (ptwiWaitInfo->lObjCount >= MAXIMUM_WAIT_OBJECTS)
317 {
318 ASSERT("Too many objects");
319 palErr = ERROR_INTERNAL_ERROR;
320 goto RWT_exit;
321 }
322
323 if (0 == ptwiWaitInfo->lObjCount)
324 {
325 ptwiWaitInfo->wtWaitType = wtWaitType;
326 ptwiWaitInfo->wdWaitDomain = m_wdWaitDomain;
327 }
328 else
329 {
330 _ASSERT_MSG(wtWaitType == ptwiWaitInfo->wtWaitType,
331 "Conflicting wait types in wait registration\n");
332
333 if (m_wdWaitDomain != ptwiWaitInfo->wdWaitDomain)
334 {
335 ptwiWaitInfo->wdWaitDomain = MixedWait;
336 }
337 }
338
339 pwtlnNewNode->shridSHRThis = NULL;
340 pwtlnNewNode->ptwiWaitInfo = ptwiWaitInfo;
341 pwtlnNewNode->dwObjIndex = dwIndex;
342 pwtlnNewNode->dwProcessId = gPID;
343 pwtlnNewNode->dwThreadId = m_pthrOwner->GetThreadId();
344 pwtlnNewNode->dwFlags = (MultipleObjectsWaitAll == wtWaitType) ?
345 WTLN_FLAG_WAIT_ALL : 0;
346 pwtlnNewNode->shridWaitingState = m_pthrOwner->synchronizationInfo.m_shridWaitAwakened;
347 if (fSharedObject)
348 {
349 pwtlnNewNode->dwFlags |= WTLN_FLAG_OWNER_OBJECT_IS_SHARED;
350 pwtlnNewNode->shridSHRThis = shridNewNode;
351 pwtlnNewNode->ptrOwnerObjSynchData.shrid = m_psdSynchData->GetSharedThis();
352 }
353 else
354 {
355 pwtlnNewNode->ptrOwnerObjSynchData.ptr = m_psdSynchData;
356 }
357
358 // AddRef the synch data (will be released in UnregisterWait)
359 m_psdSynchData->AddRef();
360 fSynchDataRefd = true;
361
362 ptwiWaitInfo->rgpWTLNodes[ptwiWaitInfo->lObjCount] = pwtlnNewNode;
363
364 if(otiProcess == m_psdSynchData->GetObjectTypeId())
365 {
366 CProcProcessLocalData * pProcLocalData = GetProcessLocalData();
367
368 if (NULL == pProcLocalData)
369 {
370 // Process local data pointer not set in the controller.
371 // This pointer is set in CSynchWaitController only when the
372 // wait controller for the object is created by calling
373 // GetSynchWaitControllersForObjects
374 ASSERT("Process synch data pointer is missing\n");
375 palErr = ERROR_INTERNAL_ERROR;
376 goto RWT_exit;
377 }
378
379 palErr = pSynchManager->RegisterProcessForMonitoring(m_pthrOwner,
380 m_psdSynchData,
381 m_pProcessObject,
382 pProcLocalData);
383 if (NO_ERROR != palErr)
384 {
385 goto RWT_exit;
386 }
387 }
388
389 if (0 == ptwiWaitInfo->lObjCount)
390 {
391 DWORD dwWaitState;
392
393 // Setting the thread in wait state
394 dwWaitState = (DWORD)(fAlertable ? TWS_ALERTABLE: TWS_WAITING);
395
396 TRACE("Switching my wait state [%p] from TWS_ACTIVE to %u \n",
397 pdwWaitState, dwWaitState);
398
399 dwWaitState = InterlockedCompareExchange(
400 (LONG *)pdwWaitState, (LONG)dwWaitState, TWS_ACTIVE);
401 if ((DWORD)TWS_ACTIVE != dwWaitState)
402 {
403 if ((DWORD)TWS_EARLYDEATH == dwWaitState)
404 {
405 // Process is terminating, this thread will soon be
406 // suspended (by SuspendOtherThreads).
407 WARN("Thread is about to get suspended by "
408 "TerminateProcess\n");
409
410 fEarlyDeath = true;
411 palErr = WAIT_FAILED;
412 }
413 else
414 {
415 ASSERT("Unexpected thread wait state %d\n", dwWaitState);
416 palErr = ERROR_INTERNAL_ERROR;
417 }
418 goto RWT_exit;
419 }
420 }
421
422 // Add new node to queue
423 if (fSharedObject)
424 {
425 m_psdSynchData->SharedWaiterEnqueue(shridNewNode, fPrioritize);
426 ptwiWaitInfo->lSharedObjCount += 1;
427 }
428 else
429 {
430 m_psdSynchData->WaiterEnqueue(pwtlnNewNode, fPrioritize);
431 }
432
433 // Succeeded: update object count
434 ptwiWaitInfo->lObjCount++;
435
436 RWT_exit:
437 if (palErr != NO_ERROR)
438 {
439 // Unregister any partial wait registration
440 pSynchManager->UnRegisterWait(m_pthrOwner, ptwiWaitInfo, fSharedObject);
441
442 if (fSynchDataRefd)
443 {
444 m_psdSynchData->Release(m_pthrOwner);
445 }
446 if ((fSharedObject) && (NULL != shridNewNode))
447 {
448 pSynchManager->CacheAddSharedWTListNode(m_pthrOwner, shridNewNode);
449 }
450 else if (NULL != pwtlnNewNode)
451 {
452 pSynchManager->CacheAddLocalWTListNode(m_pthrOwner, pwtlnNewNode);
453 }
454
455 if (fEarlyDeath)
456 {
457 // Early death detected, i.e. the process is about to exit.
458 // We need to completely release the synch lock(s) before
459 // going to sleep
460 LONG lLocalSynchLockCount;
461 LONG lSharedSynchLockCount;
462
463 lSharedSynchLockCount = CPalSynchronizationManager::ResetSharedSynchLock(m_pthrOwner);
464 lLocalSynchLockCount = CPalSynchronizationManager::ResetLocalSynchLock(m_pthrOwner);
465
466 _ASSERTE(0 < lLocalSynchLockCount);
467
468 // Sleep for ever
469 CPalSynchronizationManager::ThreadPrepareForShutdown();
470 }
471 }
472#ifdef SYNCH_STATISTICS
473 else
474 {
475 m_psdSynchData->IncrementStatWaitCount();
476 m_psdSynchData->IncrementStatContentionCount();
477 }
478#endif
479 return palErr;
480 }
481
482 /*++
483 Method:
484 CSynchWaitController::ReleaseController
485
486 Releases the current controller
487 --*/
488 void CSynchWaitController::ReleaseController()
489 {
490 VALIDATEOBJECT(m_psdSynchData);
491
492 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
493
494 Release();
495 }
496
497 /*++
498 Method:
499 CSynchWaitController::GetProcessLocalData
500
501 Accessor Get method for process local data of the target object
502 --*/
503 CProcProcessLocalData * CSynchWaitController::GetProcessLocalData()
504 {
505 VALIDATEOBJECT(m_psdSynchData);
506
507 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
508 _ASSERT_MSG(NULL != m_pProcLocalData,
509 "Pointer to process local data not yet initialized\n");
510
511 return m_pProcLocalData;
512 }
513
514 /*++
515 Method:
516 CSynchWaitController::SetProcessData
517
518 Accessor Set method for process local data of the target object
519 --*/
520 void CSynchWaitController::SetProcessData(IPalObject* pProcessObject, CProcProcessLocalData * pProcLocalData)
521 {
522 VALIDATEOBJECT(m_psdSynchData);
523
524 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
525 _ASSERT_MSG(m_pProcessObject == nullptr, "SetProcessData should not be called more than once");
526 _ASSERT_MSG(pProcessObject != nullptr && pProcessObject->GetObjectType()->GetId() == otiProcess, "Invalid process object passed to SetProcessData");
527
528 m_pProcessObject = pProcessObject;
529 m_pProcLocalData = pProcLocalData;
530 }
531
532 /////////////////////////////
533 // //
534 // CSynchStateController //
535 // //
536 /////////////////////////////
537
538 /*++
539 Method:
540 CSynchStateController::GetSignalCount
541
542 Returns the current signal count of the target object
543 --*/
544 PAL_ERROR CSynchStateController::GetSignalCount(LONG *plSignalCount)
545 {
546 VALIDATEOBJECT(m_psdSynchData);
547
548 PAL_ERROR palErr = NO_ERROR;
549 LONG lCount = m_psdSynchData->GetSignalCount();
550
551 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
552 _ASSERTE(NULL != plSignalCount);
553 _ASSERT_MSG(0 <= lCount,
554 "Internal error: negative signal count [signal count=%d]",
555 lCount);
556
557 *plSignalCount = lCount;
558 return palErr;
559 }
560
561 /*++
562 Method:
563 CSynchStateController::SetSignalCount
564
565 Sets the signal count of the target object, possibly triggering
566 waiting threads awakening.
567 --*/
568 PAL_ERROR CSynchStateController::SetSignalCount(LONG lNewCount)
569 {
570 VALIDATEOBJECT(m_psdSynchData);
571
572 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
573 _ASSERTE(lNewCount >= 0);
574
575 m_psdSynchData->Signal(m_pthrOwner, lNewCount, false);
576
577 return NO_ERROR;
578 }
579
580 /*++
581 Method:
582 CSynchStateController::IncrementSignalCount
583
584 Increments the signal count of the target object, possibly triggering
585 waiting threads awakening.
586 --*/
587 PAL_ERROR CSynchStateController::IncrementSignalCount(
588 LONG lAmountToIncrement)
589 {
590 VALIDATEOBJECT(m_psdSynchData);
591
592 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
593 _ASSERTE(lAmountToIncrement > 0);
594
595 LONG lOldCount = m_psdSynchData->GetSignalCount();
596 LONG lNewCount = lOldCount + lAmountToIncrement;
597
598 _ASSERT_MSG(lNewCount > lOldCount,
599 "Signal count increment %d would make current signal count %d to "
600 "wrap around\n", lAmountToIncrement, lOldCount);
601
602 m_psdSynchData->Signal(m_pthrOwner, lNewCount, false);
603
604 return NO_ERROR;
605 }
606
607 /*++
608 Method:
609 CSynchStateController::DecrementSignalCount
610
611 Decrements the signal count of the target object.
612 --*/
613 PAL_ERROR CSynchStateController::DecrementSignalCount(
614 LONG lAmountToDecrement)
615 {
616 VALIDATEOBJECT(m_psdSynchData);
617
618 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
619 _ASSERTE(lAmountToDecrement > 0);
620
621 PAL_ERROR palErr = NO_ERROR;
622 LONG lCount = m_psdSynchData->GetSignalCount();
623 _ASSERTE(lAmountToDecrement <= lCount);
624
625 m_psdSynchData->SetSignalCount(lCount - lAmountToDecrement);
626
627 return palErr;
628 }
629
630 /*++
631 Method:
632 CSynchStateController::SetOwner
633
634 Sets the owner of the target object and initializes the ownership
635 count to 1 (for objects with tracked ownership).
636 --*/
637 PAL_ERROR CSynchStateController::SetOwner(CPalThread * pNewOwningThread)
638 {
639 VALIDATEOBJECT(m_psdSynchData);
640
641 PAL_ERROR palErr = NO_ERROR;
642
643 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
644 _ASSERTE(NULL != pNewOwningThread);
645 _ASSERT_MSG(CObjectType::OwnershipTracked ==
646 m_potObjectType->GetOwnershipSemantics(),
647 "SetOwner called on an object without OwnershipTracked "
648 "semantics\n");
649
650 if (0 != m_psdSynchData->GetOwnershipCount())
651 {
652 ASSERT("Ownership count should be zero at this time\n");
653 palErr = ERROR_INTERNAL_ERROR;
654 goto SO_exit;
655 }
656
657 palErr = m_psdSynchData->AssignOwnershipToThread(m_pthrOwner,
658 pNewOwningThread);
659
660 _ASSERT_MSG(0 == m_psdSynchData->GetOwnershipCount() ||
661 0 == m_psdSynchData->GetSignalCount(),
662 "Conflicting values for SignalCount [%d] and "
663 "OwnershipCount [%d]\n",
664 m_psdSynchData->GetOwnershipCount(),
665 m_psdSynchData->GetSignalCount());
666
667 SO_exit:
668 return palErr;
669 }
670
671 /*++
672 Method:
673 CSynchStateController::DecrementOwnershipCount
674
675 Decrements the ownership count of the target object possibly triggering
676 waiting threads awakening (for objects with tracked ownership).
677 --*/
678 PAL_ERROR CSynchStateController::DecrementOwnershipCount()
679 {
680 VALIDATEOBJECT(m_psdSynchData);
681
682 PAL_ERROR palErr = NO_ERROR;
683 LONG lOwnershipCount = m_psdSynchData->GetOwnershipCount();
684
685 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
686 _ASSERT_MSG(CObjectType::OwnershipTracked ==
687 m_potObjectType->GetOwnershipSemantics(),
688 "Trying to decrement ownership count on an object with "
689 "ownership semantics other than OwnershipTracked\n");
690 _ASSERT_MSG(0 <= lOwnershipCount,
691 "Operation would make ownership count negative - object "
692 "should be owned at this time [ownership count=%d]\n",
693 lOwnershipCount);
694
695 if ( (1 > lOwnershipCount) ||
696 (m_psdSynchData->GetOwnerProcessID() != gPID) ||
697 (m_psdSynchData->GetOwnerThread() != m_pthrOwner) )
698 {
699 palErr = ERROR_NOT_OWNER;
700 goto DOC_exit;
701 }
702
703 lOwnershipCount--;
704 m_psdSynchData->SetOwnershipCount(lOwnershipCount);
705
706 if (0 == lOwnershipCount)
707 {
708 CPalSynchronizationManager * pSynchManager =
709 CPalSynchronizationManager::GetInstance();
710 OwnedObjectsListNode * pooln =
711 m_psdSynchData->GetOwnershipListNode();
712
713 _ASSERT_MSG(NULL != pooln,
714 "Null ownership node pointer in SynchData with ownership "
715 "semantics\n");
716 _ASSERT_MSG(m_psdSynchData == pooln->pPalObjSynchData,
717 "Corrupted ownership node\n");
718
719 // Object has been released
720 // Remove it from list of owned objs for current thread
721 m_pthrOwner->synchronizationInfo.RemoveObjectFromOwnedList(pooln);
722
723 // Release SynchData reference count implied by the ownership
724 // list node
725 m_psdSynchData->Release(m_pthrOwner);
726
727 // Return node to the cache
728 pSynchManager->CacheAddOwnedObjsListNode(m_pthrOwner, pooln);
729
730 // Reset ownership
731 m_psdSynchData->ResetOwnership();
732
733 // Signal it and trigger waiter thread awakening
734 m_psdSynchData->Signal(m_pthrOwner, 1, false);
735 }
736
737 DOC_exit:
738 return palErr;
739 }
740
741 /*++
742 Method:
743 CSynchStateController::ReleaseController
744
745 Releases the controller.
746 --*/
747 void CSynchStateController::ReleaseController(void)
748 {
749 VALIDATEOBJECT(m_psdSynchData);
750
751 _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
752
753 Release();
754 }
755
756 //////////////////
757 // //
758 // CSynchData //
759 // //
760 //////////////////
761
762 /*++
763 Method:
764 CSynchData::Release
765
766 Decremnt the reference count of the target synchdata and retrurns
767 it to the appropriate cache if the reference count reaches zero.
768 --*/
769 LONG CSynchData::Release(CPalThread * pthrCurrent)
770 {
771 VALIDATEOBJECT(this);
772
773 LONG lCount = InterlockedDecrement(&m_lRefCount);
774
775 _ASSERT_MSG(0 <= lCount,
776 "CSynchData %p with negative reference count [%d]\n",
777 this, lCount);
778
779 if (0 == lCount)
780 {
781 CPalSynchronizationManager * pSynchManager =
782 CPalSynchronizationManager::GetInstance();
783 bool fSharedObject = (SharedObject == m_odObjectDomain);
784
785 _ASSERT_MSG((fSharedObject && (NULL == m_ptrWTLHead.shrid)) ||
786 (!fSharedObject && (NULL == m_ptrWTLHead.ptr)),
787 "Final Release on CSynchData with threads still in "
788 "the waiting list\n");
789
790 TRACE("Disposing %s waitable object with SynchData @ "
791 "{shrid=%p, p=%p}\n",
792 (SharedObject == m_odObjectDomain) ? "shared" : "local",
793 (PVOID)m_shridThis, this);
794
795
796#ifdef SYNCH_STATISTICS
797 LONG lStatWaitCount = GetStatWaitCount();
798 LONG lStatContentionCount = GetStatContentionCount();
799 LONG lCount, lNewCount;
800
801 TRACE("Statistical data for SynchData of otiType=%u @ %p: WaitCount=%d "
802 "ContentionCount=%d\n", m_otiObjectTypeId, this, lStatWaitCount,
803 lStatContentionCount);
804
805 do {
806 lCount = g_rglStatWaitCount[m_otiObjectTypeId];
807 lNewCount = lCount + lStatWaitCount;
808 lNewCount = InterlockedCompareExchange(&(g_rglStatWaitCount[m_otiObjectTypeId]),
809 lNewCount, lCount);
810 } while (lCount != lNewCount);
811
812 lStatWaitCount = lNewCount;
813
814 do {
815 lCount = g_rglStatContentionCount[m_otiObjectTypeId];
816 lNewCount = lCount + lStatContentionCount;
817 lNewCount = InterlockedCompareExchange(&(g_rglStatContentionCount[m_otiObjectTypeId]),
818 lNewCount, lCount);
819 } while (lCount != lNewCount);
820
821 lStatContentionCount = lNewCount;
822
823 TRACE("Total current statistical data for otiType=%u objects: WaitCount=%d "
824 "ContentionCount=%d\n", m_otiObjectTypeId, lStatWaitCount,
825 lStatContentionCount);
826#endif // SYNCH_STATISTICS
827
828 if (fSharedObject)
829 {
830 pSynchManager->CacheAddSharedSynchData(pthrCurrent, m_shridThis);
831 }
832 else
833 {
834 pSynchManager->CacheAddLocalSynchData(pthrCurrent, this);
835 }
836 }
837
838 return lCount;
839 }
840
841 /*++
842 Method:
843 CSynchData::ReleaseWaiterWithoutBlocking
844
845 Performs all the steps needed to be done by the target thread in order
846 to wait without blocking on the object associated with the current
847 SynchData (e.g. modifying the object signal count accordingly with its
848 thread release semantics)
849
850 Note: this method must be called while holding the appropriate
851 synchronization locks (the local process synch lock if the target
852 object is local, both local and shared one if the object is shared).
853 --*/
854 PAL_ERROR CSynchData::ReleaseWaiterWithoutBlocking(
855 CPalThread * pthrCurrent,
856 CPalThread * pthrTarget)
857 {
858 VALIDATEOBJECT(this);
859
860 PAL_ERROR palErr = NO_ERROR;
861 CObjectType * potObjectType = GetObjectType();
862#ifdef _DEBUG
863 CObjectType::SignalingSemantics ssSignalingSemantics =
864 potObjectType->GetSignalingSemantics();
865#endif // _DEBUG
866 CObjectType::OwnershipSemantics osOwnershipSemantics =
867 potObjectType->GetOwnershipSemantics();
868 CObjectType::ThreadReleaseSemantics trsThreadReleaseSemantics =
869 potObjectType->GetThreadReleaseSemantics();
870 bool fReenteringObjWithOwnership = false;
871
872 _ASSERT_MSG(CObjectType::SignalingNotApplicable != ssSignalingSemantics,
873 "Signaling not applicable");
874 _ASSERT_MSG(CObjectType::ThreadReleaseNotApplicable !=
875 trsThreadReleaseSemantics,
876 "Thread releasing not applicable");
877 _ASSERT_MSG(CObjectType::SingleTransitionObject != ssSignalingSemantics ||
878 (CObjectType::ThreadReleaseHasNoSideEffects ==
879 trsThreadReleaseSemantics &&
880 CObjectType::NoOwner == osOwnershipSemantics),
881 "Conflicting object synchronization attributes "
882 "[SignalingSemantics=%u OwnershipSemantics=%u "
883 "ThreadReleaseSemantics=%u]\n", ssSignalingSemantics,
884 osOwnershipSemantics, trsThreadReleaseSemantics);
885
886 if (CObjectType::OwnershipTracked == osOwnershipSemantics &&
887 0 < GetOwnershipCount())
888 {
889 // We are rentering an object with ownership: we need to skip
890 // the object unsignaling
891 fReenteringObjWithOwnership = true;
892 }
893
894 if (!fReenteringObjWithOwnership &&
895 CObjectType::ThreadReleaseAltersSignalCount == trsThreadReleaseSemantics)
896 {
897 _ASSERT_MSG(0 < GetSignalCount(),
898 "Internal error: operation would make signal count "
899 "negative - object should be signaled at this time "
900 "[signal count=%d]", GetSignalCount());
901 _ASSERT_MSG(CObjectType::OwnershipTracked != osOwnershipSemantics ||
902 1 == GetSignalCount(),
903 "Ownable objects cannot have signal count greater "
904 "than zero [current SignalCount=%d]\n",
905 GetSignalCount());
906
907 // Unsignal the object
908 DecrementSignalCount();
909 }
910
911 if (CObjectType::OwnershipTracked == osOwnershipSemantics)
912 {
913 _ASSERT_MSG(0 == GetOwnershipCount() || 0 == GetSignalCount(),
914 "OwnershipCount and SignalCount with conflicting "
915 "values\n");
916
917 // Take ownership or increment ownership count.
918 // We do this after the object unsignaling to minimize possibilities
919 // of having both SignalCount and OwnershipCount greater than zero
920 // (see comment in AssignOwnershipToThread)
921 palErr = AssignOwnershipToThread(pthrCurrent, pthrTarget);
922
923 if (NO_ERROR != palErr)
924 {
925 ERROR("AssignOwnershipToThread failed with error %u; "
926 "ownership data on object with SynchData {shrid=%p p=%p} "
927 "may be corrupted\n", palErr, (void *)m_shridThis, this);
928 }
929 }
930
931#ifdef SYNCH_STATISTICS
932 if (NO_ERROR == palErr)
933 {
934 IncrementStatWaitCount();
935 }
936#endif
937 return palErr;
938
939 }
940
941 /*++
942 Method:
943 CSynchData::CanWaiterWaitWithoutBlocking
944
945 Returns whether or not the waiter thread can wait on the target object
946 without blocking (i.e. the objet is signaled)
947
948 Note: this method must be called while holding the appropriate
949 synchronization locks (the local process synch lock if the target
950 object is local, both local and shared one if the object is shared).
951 --*/
952 bool CSynchData::CanWaiterWaitWithoutBlocking(
953 CPalThread * pWaiterThread,
954 bool * pfAbandoned)
955 {
956 VALIDATEOBJECT(this);
957
958 bool fRetVal = (0 < GetSignalCount());
959 bool fAbandoned = false;
960 bool fOwnershipTracked = (CObjectType::OwnershipTracked ==
961 GetObjectType()->GetOwnershipSemantics());
962 if (fRetVal)
963 {
964 // Object signaled: thread can wait without blocking
965 if (fOwnershipTracked)
966 {
967 fAbandoned = IsAbandoned();
968 }
969
970 goto CWWWB_exit;
971 }
972
973 // Object not signaled: thread can wait without blocking only if the
974 // object is an ownable one, and it is owned by the current thread
975 if (fOwnershipTracked)
976 {
977 _ASSERT_MSG(0 < GetSignalCount() || 0 < GetOwnershipCount(),
978 "Objects with ownership must be either signaled or "
979 "owned by a thread\n");
980
981 if ((GetOwnerProcessID() == gPID) &&
982 (GetOwnerThread() == pWaiterThread) )
983 {
984 fRetVal = true;
985 goto CWWWB_exit;
986 }
987 }
988
989 CWWWB_exit:
990 *pfAbandoned = fAbandoned;
991 return fRetVal;
992 }
993
994 /*++
995 Method:
996 CSynchData::Signal
997
998 Sets the signal count of the object owning the target SynchData,
999 possibly triggering awakening of waiting threads.
1000
1001 Note: this method must be called while holding the appropriate
1002 synchronization locks (the local process synch lock if the target
1003 object is local, both local and shared one if the object is shared).
1004 --*/
1005 void CSynchData::Signal(
1006 CPalThread * pthrCurrent,
1007 LONG lSignalCount,
1008 bool fWorkerThread)
1009 {
1010 VALIDATEOBJECT(this);
1011
1012 bool fThreadReleased = false;
1013 bool fDelegatedSignaling = false;
1014 bool fReleaseAltersSignalCount =
1015 (CObjectType::ThreadReleaseAltersSignalCount ==
1016 GetObjectType()->GetThreadReleaseSemantics());
1017
1018 _ASSERTE(0 <= lSignalCount);
1019
1020 // Preset the signal count to the new value, so that it can be used
1021 // by ReleaseFirstWaiter when delegating signaling to another process
1022 m_lSignalCount = lSignalCount;
1023
1024 while (m_lSignalCount > 0)
1025 {
1026 fThreadReleased = ReleaseFirstWaiter(pthrCurrent,
1027 &fDelegatedSignaling,
1028 fWorkerThread);
1029 if (!fThreadReleased)
1030 {
1031 // No more threads to release: break out of the loop
1032 // keeping the current signal count
1033 break;
1034 }
1035 if (fReleaseAltersSignalCount)
1036 {
1037 // Adjust signal count
1038 m_lSignalCount--;
1039 }
1040 if (fDelegatedSignaling)
1041 {
1042 // Object signaling has been delegated
1043 m_lSignalCount = 0;
1044 }
1045 }
1046
1047 _ASSERT_MSG(CObjectType::OwnershipTracked !=
1048 GetObjectType()->GetOwnershipSemantics() ||
1049 0 == GetOwnershipCount() || 0 == GetSignalCount(),
1050 "Conflicting values for SignalCount [%d] and "
1051 "OwnershipCount [%d]\n",
1052 GetOwnershipCount(), GetSignalCount());
1053
1054 _ASSERT_MSG(otiMutex != m_otiObjectTypeId || m_lSignalCount <= 1,
1055 "Mutex with invalid singal count\n");
1056
1057 return;
1058 }
1059
1060 /*++
1061 Method:
1062 CSynchData::ReleaseFirstWaiter
1063
1064 Releases the first thread from the front of the list of waiting threads
1065 whose wait is fully satisfied, possibly triggering remote awakening (if
1066 the target thread lives in a different process) or object signaling
1067 delegation (if the target thread lives in a different processing and it
1068 is blocked on a wait-all).
1069
1070 Note: this method must be called while holding the appropriate
1071 synchronization locks (the local process synch lock if the target
1072 object is local, both local and shared one if the object is shared).
1073 --*/
1074 bool CSynchData::ReleaseFirstWaiter(
1075 CPalThread * pthrCurrent,
1076 bool * pfDelegated,
1077 bool fWorkerThread)
1078 {
1079 PAL_ERROR palErr = NO_ERROR;
1080 bool fSharedSynchLock = false;
1081 bool fSharedObject = (SharedObject == GetObjectDomain());
1082 bool fThreadAwakened = false;
1083 bool fDelegatedSignaling = false;
1084 DWORD * pdwWaitState;
1085 DWORD dwObjIdx;
1086 SharedID shridItem = NULL, shridNextItem = NULL;
1087 WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem;
1088 DWORD dwPid = gPID;
1089 CPalSynchronizationManager * pSynchManager =
1090 CPalSynchronizationManager::GetInstance();
1091
1092 VALIDATEOBJECT(this);
1093
1094 *pfDelegated = false;
1095
1096 if (fSharedObject)
1097 {
1098 shridItem = GetWTLHeadShmPtr();
1099 pwtlnItem = SharedIDToTypePointer(WaitingThreadsListNode, shridItem);
1100 }
1101 else
1102 {
1103 pwtlnItem = GetWTLHeadPtr();
1104 }
1105
1106 while (pwtlnItem)
1107 {
1108 VALIDATEOBJECT(pwtlnItem);
1109
1110 WaitCompletionState wcsWaitCompletionState;
1111 bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags));
1112 pdwWaitState = SharedIDToTypePointer(DWORD,
1113 pwtlnItem->shridWaitingState);
1114
1115 if (fSharedObject)
1116 {
1117 shridNextItem = pwtlnItem->ptrNext.shrid;
1118 pwtlnNextItem = SharedIDToTypePointer(WaitingThreadsListNode,
1119 shridNextItem);
1120 }
1121 else
1122 {
1123 pwtlnNextItem = pwtlnItem->ptrNext.ptr;
1124 }
1125
1126 if (fWaitAll)
1127 {
1128 // Wait All: we need to find out whether the wait is satisfied,
1129 // or it is not, or if that cannot be determined from within
1130 // this process (WaitMayBeSatisfied); in this case we need to
1131 // delegate the object signaling to the process hosting the
1132 // thread that owns the current target WaitingThreadsListNode
1133
1134 // If the target object is local (fSharedObject == false)
1135 // we're probably not holding the shared lock.
1136 // If the wait is not a LocalWait, it involves at least one
1137 // shared object. If that is the case, at this time we need
1138 // to grab the shared lock. In fact IsRestOfWaitAllSatisfied
1139 // and UnsignalRestOfLocalAwakeningWaitAll must be called
1140 // atomically to prevent that another thread living
1141 // in a different process could race with us stealing the
1142 // signaling from one of the objects involved in the wait-all.
1143 //
1144 // Note: pwtlnItem->ptwiWaitInfo is valid only if the target
1145 // wait originates in the current process. Anyway in the
1146 // following 'if' we don't need to check that since we are
1147 // already making sure that the object is local (!fSharedObject).
1148 // If a wait involves at least one object local to this process,
1149 // it can only be a wait performed by a thread in the current
1150 // process, therefore pwtlnItem->ptwiWaitInfo is valid.
1151
1152 _ASSERTE(fSharedObject || pwtlnItem->dwProcessId == gPID);
1153
1154 if (!fSharedSynchLock && !fSharedObject &&
1155 LocalWait != pwtlnItem->ptwiWaitInfo->wdWaitDomain)
1156 {
1157 CPalSynchronizationManager::AcquireSharedSynchLock(pthrCurrent);
1158 fSharedSynchLock = true;
1159 }
1160
1161 // First check if the current target node is already marked for
1162 // wait all check in progress, and in case skip it by setting
1163 // wcsWaitCompletionState to WaitIsNotSatisfied
1164 bool fMarkedForDelegatedObjectSingalingInProgress =
1165 (0 != (WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS & pwtlnItem->dwFlags));
1166
1167 wcsWaitCompletionState =
1168 fMarkedForDelegatedObjectSingalingInProgress ? WaitIsNotSatisfied :
1169 IsRestOfWaitAllSatisfied(pwtlnItem);
1170 }
1171 else
1172 {
1173 // Normal Wait: the wait is satisfied by definition
1174 wcsWaitCompletionState = WaitIsSatisfied;
1175 }
1176
1177 if (WaitIsSatisfied == wcsWaitCompletionState)
1178 {
1179 //
1180 // Target wait is satisfied
1181 //
1182 TRACE("Trying to switch wait state [%p] from WAIT/ALERTABLE "
1183 "to ACTIVE for thread=%u\n",
1184 pdwWaitState, pwtlnItem->dwThreadId);
1185
1186 if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState, FALSE))
1187 {
1188 TRACE("Succeeded switching wait state [%p] from WAIT/ALERTABLE "
1189 "to TWS_ACTIVE for trhead=%u\n",
1190 pdwWaitState, pwtlnItem->dwThreadId);
1191
1192 dwObjIdx = pwtlnItem->dwObjIndex;
1193
1194 if (dwPid == pwtlnItem->dwProcessId)
1195 {
1196 ///////////////////////////
1197 //
1198 // Local Thread Awakening
1199 //
1200 ///////////////////////////
1201 ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo;
1202 bool fAbandoned = false;
1203
1204 if (CObjectType::OwnershipTracked ==
1205 GetObjectType()->GetOwnershipSemantics())
1206 {
1207 // Get the abandoned status before resetting it by
1208 // assigning ownership to target thread
1209 fAbandoned = IsAbandoned();
1210
1211 // Assign ownership to target thread
1212 // Note: This will cause both ownership count and
1213 // signal count to be greater than zero at the
1214 // same time; the signal count will be anyway
1215 // decremented immediately by the caller
1216 // CsynchData::Signal
1217 palErr = AssignOwnershipToThread(pthrCurrent,
1218 ptwiWaitInfo->pthrOwner);
1219 if (NO_ERROR != palErr)
1220 {
1221 ERROR("Synch Worker: AssignOwnershipToThread "
1222 "failed with error %u; ownership data on "
1223 "object with SynchData %p may be "
1224 "corrupted\n", palErr, this);
1225 }
1226 }
1227
1228 if (fWaitAll)
1229 {
1230 // Wait all satisfied: unsignal other objects
1231 // involved in the wait
1232 CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
1233 pthrCurrent,
1234 ptwiWaitInfo->pthrOwner,
1235 pwtlnItem,
1236 this);
1237 }
1238
1239 TRACE("Unregistering wait for thread %u and waking it up "
1240 "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId,
1241 pdwWaitState);
1242
1243 // Unregister the wait
1244 pSynchManager->UnRegisterWait(pthrCurrent,
1245 ptwiWaitInfo,
1246 fSharedObject || fSharedSynchLock);
1247
1248 // After UnRegisterWait pwtlnItem is invalid
1249 pwtlnItem = NULL;
1250
1251 palErr = CPalSynchronizationManager::WakeUpLocalThread(
1252 pthrCurrent,
1253 ptwiWaitInfo->pthrOwner,
1254 fAbandoned ? MutexAbondoned : WaitSucceeded,
1255 dwObjIdx);
1256
1257 if (NO_ERROR != palErr)
1258 {
1259 ERROR("Failed to wakeup local thread %#x: "
1260 "object signaling may be "
1261 "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId());
1262 }
1263 }
1264 else
1265 {
1266 ///////////////////////////
1267 //
1268 // Remote Thread Awakening
1269 //
1270 ///////////////////////////
1271
1272 // Note: if we are here, this cannot be a wait-all
1273 _ASSERT_MSG(!fWaitAll,
1274 "Control should never reach this point if "
1275 "target wait is a wait-all\n");
1276
1277 // Wake up remote thread
1278 palErr = CPalSynchronizationManager::WakeUpRemoteThread(shridItem);
1279
1280 if (NO_ERROR != palErr)
1281 {
1282 ERROR("Failed to dispatch remote awakening cmd to "
1283 "worker thread in process pid=%d to wake up"
1284 "thread tid=%#x; object signaling may be "
1285 "lost\n", pwtlnItem->dwProcessId,
1286 pwtlnItem->dwThreadId);
1287 }
1288 }
1289
1290 // A thread has been awakened
1291 fThreadAwakened = true;
1292
1293 // break out of the while loop
1294 break;
1295 }
1296 }
1297 else if (WaitMayBeSatisfied == wcsWaitCompletionState)
1298 {
1299 //////////////////////////////////////////
1300 //
1301 // Wait All with remote thread awakening
1302 //
1303 //////////////////////////////////////////
1304
1305 //
1306 // We need to transfer the object signaling to the process
1307 // hosting the target waiter thread
1308 //
1309
1310 _ASSERT_MSG(fWaitAll,
1311 "IsRestOfWaitAllSatisfied() apparently "
1312 "returned -1 on a normal (non wait all) "
1313 "wait\n");
1314 _ASSERT_MSG(fSharedObject,
1315 "About to delegate object signaling to a remote "
1316 "process, but the signaled object is actually "
1317 "local\n");
1318
1319 // Delegate object signaling to target process
1320 palErr = CPalSynchronizationManager::DelegateSignalingToRemoteProcess(
1321 pthrCurrent,
1322 pwtlnItem->dwProcessId,
1323 pwtlnItem->ptrOwnerObjSynchData.shrid);
1324
1325 TRACE("Delegating object signaling for SynchData shrid=%p\n",
1326 (VOID *)pwtlnItem->ptrOwnerObjSynchData.shrid);
1327
1328 if (NO_ERROR == palErr)
1329 {
1330 // A remote thread will be awakened
1331 // This will also cause the object to be unsignaled by the
1332 // code calling ReleaseFirstWaiter before releasing the
1333 // synch locks, so no other WaitForMultipleObjects
1334 // involving the target object may race stealing this
1335 // particuklar object signaling
1336 fThreadAwakened = true;
1337
1338 fDelegatedSignaling = true;
1339
1340 // break out of the while loop
1341 break;
1342 }
1343 else
1344 {
1345 ERROR("Failed to delegate object signaling to remote "
1346 "process %d. Looking for another waiter.\n",
1347 pwtlnItem->dwProcessId);
1348
1349 // Go on: a different target waiter will be selected
1350 }
1351 }
1352
1353 if (fWorkerThread && fWaitAll && (dwPid == pwtlnItem->dwProcessId))
1354 {
1355 // Mark the target wait for object signaling
1356 CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress(
1357 pthrCurrent,
1358 pwtlnItem);
1359 }
1360
1361 // Go to the next item
1362 shridItem = shridNextItem;
1363 pwtlnItem = pwtlnNextItem;
1364 }
1365
1366 if (fDelegatedSignaling)
1367 {
1368 *pfDelegated = true;
1369 }
1370 else if (fWorkerThread)
1371 {
1372 // Reset 'delegated object signaling in progress' flags
1373 CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress(
1374 this);
1375 }
1376
1377 if (fSharedSynchLock)
1378 {
1379 CPalSynchronizationManager::ReleaseSharedSynchLock(pthrCurrent);
1380 }
1381 return fThreadAwakened;
1382 }
1383
1384 /*++
1385 Method:
1386 CSynchData::Signal
1387
1388 Releases all the threads waiting on this object and living in the current
1389 process.
1390
1391 Note: this method must be called while holding the appropriate
1392 synchronization locks (the local process synch lock if the target
1393 object is local, both local and shared one if the object is shared).
1394 --*/
1395 LONG CSynchData::ReleaseAllLocalWaiters(
1396 CPalThread * pthrCurrent)
1397 {
1398 PAL_ERROR palErr = NO_ERROR;
1399 LONG lAwakenedCount = 0;
1400 bool fSharedSynchLock = false;
1401 bool fSharedObject = (SharedObject == GetObjectDomain());
1402 DWORD * pdwWaitState;
1403 DWORD dwObjIdx;
1404 SharedID shridItem = NULL, shridNextItem = NULL;
1405 WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem;
1406 DWORD dwPid = gPID;
1407 CPalSynchronizationManager * pSynchManager =
1408 CPalSynchronizationManager::GetInstance();
1409
1410 VALIDATEOBJECT(this);
1411
1412 if (fSharedObject)
1413 {
1414 shridItem = GetWTLHeadShmPtr();
1415 pwtlnItem = SharedIDToTypePointer(WaitingThreadsListNode, shridItem);
1416 }
1417 else
1418 {
1419 pwtlnItem = GetWTLHeadPtr();
1420 }
1421
1422 while (pwtlnItem)
1423 {
1424 VALIDATEOBJECT(pwtlnItem);
1425
1426 bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags));
1427 pdwWaitState = SharedIDToTypePointer(DWORD,
1428 pwtlnItem->shridWaitingState);
1429
1430 if (fSharedObject)
1431 {
1432 shridNextItem = pwtlnItem->ptrNext.shrid;
1433 pwtlnNextItem = SharedIDToTypePointer(WaitingThreadsListNode,
1434 shridNextItem);
1435 }
1436 else
1437 {
1438 pwtlnNextItem = pwtlnItem->ptrNext.ptr;
1439 }
1440
1441 // See note in similar spot in ReleaseFirstWaiter
1442
1443 _ASSERTE(fSharedObject || pwtlnItem->dwProcessId == gPID);
1444
1445 if (!fSharedSynchLock && !fSharedObject &&
1446 LocalWait != pwtlnItem->ptwiWaitInfo->wdWaitDomain)
1447 {
1448 CPalSynchronizationManager::AcquireSharedSynchLock(pthrCurrent);
1449 fSharedSynchLock = true;
1450 }
1451
1452 if( dwPid == pwtlnItem->dwProcessId &&
1453 (!fWaitAll || WaitIsSatisfied == IsRestOfWaitAllSatisfied(pwtlnItem)) )
1454 {
1455 //
1456 // Target wait is satisfied
1457 //
1458 TRACE("Trying to switch wait state [%p] from WAIT/ALERTABLE "
1459 "to ACTIVE for thread=%u\n",
1460 pdwWaitState, pwtlnItem->dwThreadId);
1461
1462 if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState, FALSE))
1463 {
1464 TRACE("Succeeded switching wait state [%p] from WAIT/ALERTABLE "
1465 "to TWS_ACTIVE for trhead=%u\n",
1466 pdwWaitState, pwtlnItem->dwThreadId);
1467
1468 dwObjIdx = pwtlnItem->dwObjIndex;
1469
1470 ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo;
1471 bool fAbandoned = false;
1472
1473 if (CObjectType::OwnershipTracked ==
1474 GetObjectType()->GetOwnershipSemantics())
1475 {
1476 // Get the abandoned status before resetting it by
1477 // assigning ownership to target thread
1478 fAbandoned = IsAbandoned();
1479
1480 // Assign ownership to target thread
1481 palErr = AssignOwnershipToThread(pthrCurrent,
1482 ptwiWaitInfo->pthrOwner);
1483 if (NO_ERROR != palErr)
1484 {
1485 ERROR("Synch Worker: AssignOwnershipToThread "
1486 "failed with error %u; ownership data on "
1487 "object with SynchData %p may be "
1488 "corrupted\n", palErr, this);
1489 }
1490 }
1491
1492 if (fWaitAll)
1493 {
1494 // Wait all satisfied: unsignal other objects
1495 // involved in the wait
1496 CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
1497 pthrCurrent,
1498 ptwiWaitInfo->pthrOwner,
1499 pwtlnItem,
1500 this);
1501 }
1502
1503 TRACE("Unregistering wait for thread %u and waking it up "
1504 "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId,
1505 pdwWaitState);
1506
1507 // Unregister the wait
1508 pSynchManager->UnRegisterWait(pthrCurrent,
1509 ptwiWaitInfo,
1510 fSharedObject || fSharedSynchLock);
1511
1512 // After UnRegisterWait pwtlnItem is invalid
1513 pwtlnItem = NULL;
1514
1515 palErr = CPalSynchronizationManager::WakeUpLocalThread(
1516 pthrCurrent,
1517 ptwiWaitInfo->pthrOwner,
1518 fAbandoned ? MutexAbondoned : WaitSucceeded,
1519 dwObjIdx);
1520
1521 if (NO_ERROR != palErr)
1522 {
1523 ERROR("Failed to wakeup local thread %#x: "
1524 "object signaling may be "
1525 "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId());
1526 }
1527 else
1528 {
1529 // A thread has been awakened
1530 lAwakenedCount++;
1531 }
1532 }
1533 }
1534
1535 // Go to the next item
1536 shridItem = shridNextItem;
1537 pwtlnItem = pwtlnNextItem;
1538 }
1539
1540 if (fSharedSynchLock)
1541 {
1542 CPalSynchronizationManager::ReleaseSharedSynchLock(pthrCurrent);
1543 }
1544 return lAwakenedCount;
1545 }
1546
1547 /*++
1548 Method:
1549 CSynchData::IsRestOfWaitAllSatisfied
1550
1551 Returns whether or not the current wait-all operation is fully satisfied,
1552 assuming the current target object as signaled (i.e. whether or not all the
1553 involved object, except the current one, are signaled).
1554 It returns:
1555 - WaitIsNotSatisfied if the wait-all is not fully satisfied.
1556 - WaitIsSatisfied if the wait-all is fully satisfied.
1557 - WaitMayBeSatisfied if the target thread lives in a different process and
1558 therefore the wait may involve objects local to the remote process, and
1559 as result is generally not possible to say whther or not the wait-all is
1560 fully satisfied from the current process.
1561
1562 Note: this method must be called while holding the synchronization locks
1563 appropriate to all the objects involved in the wait-all. If any
1564 of the objects is shared, the caller must own both local and
1565 shared synch locks; if no shared object is involved in the wait,
1566 only the local synch lock is needed.
1567 --*/
1568 WaitCompletionState CSynchData::IsRestOfWaitAllSatisfied(
1569 WaitingThreadsListNode * pwtlnNode)
1570 {
1571 int iSignaledOrOwnedObjCount = 0;
1572 int iTgtCount = 0;
1573 int i;
1574 WaitCompletionState wcsWaitCompletionState = WaitIsNotSatisfied;
1575 CSynchData * psdSynchDataItem = NULL;
1576 ThreadWaitInfo * ptwiWaitInfo = NULL;
1577
1578 VALIDATEOBJECT(this);
1579 VALIDATEOBJECT(pwtlnNode);
1580
1581 _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags),
1582 "IsRestOfWaitAllSatisfied() called on a normal "
1583 "(non wait all) wait");
1584 _ASSERT_MSG((SharedObject == GetObjectDomain()) ==
1585 (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNode->dwFlags)),
1586 "WTLN_FLAG_OWNER_OBJECT_IS_SHARED in WaitingThreadsListNode "
1587 "not consistent with target object's domain\n");
1588
1589 if(gPID != pwtlnNode->dwProcessId)
1590 {
1591 ////////////////////////////
1592 //
1593 // Remote Thread Awakening
1594 //
1595 ////////////////////////////
1596
1597 // Cannot determine whether or not the wait all is satisfied from
1598 // this process
1599 wcsWaitCompletionState = WaitMayBeSatisfied;
1600 goto IROWAS_exit;
1601 }
1602
1603 ///////////////////////////
1604 //
1605 // Local Thread Awakening
1606 //
1607 ///////////////////////////
1608
1609 ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
1610
1611 iTgtCount = ptwiWaitInfo->lObjCount;
1612 for (i=0; i < iTgtCount; i++)
1613 {
1614 WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
1615 bool fRetVal;
1616 bool fIsAbandoned;
1617
1618 VALIDATEOBJECT(pwtlnItem);
1619
1620 if (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnItem->dwFlags))
1621 {
1622 psdSynchDataItem = SharedIDToTypePointer(CSynchData,
1623 pwtlnItem->ptrOwnerObjSynchData.shrid);
1624 }
1625 else
1626 {
1627 psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr;
1628 }
1629
1630 VALIDATEOBJECT(psdSynchDataItem);
1631
1632 if (pwtlnItem == pwtlnNode)
1633 {
1634 _ASSERT_MSG (this == psdSynchDataItem,
1635 "pwtlnNode and pwtlnItem match, but this "
1636 "and psdSynchDataItem don't\n");
1637
1638 // The target object (the one related to pwtlnNode) is counted as
1639 // signaled/owned without checking it (also if it is not, as
1640 // it normally happens when this method is called)
1641 iSignaledOrOwnedObjCount++;
1642 continue;
1643 }
1644
1645 fRetVal = psdSynchDataItem->CanWaiterWaitWithoutBlocking(
1646 ptwiWaitInfo->pthrOwner,
1647 &fIsAbandoned);
1648
1649 if (fRetVal)
1650 {
1651 iSignaledOrOwnedObjCount++;
1652 }
1653 else
1654 {
1655 break;
1656 }
1657 }
1658
1659 if (iSignaledOrOwnedObjCount < iTgtCount)
1660 {
1661 wcsWaitCompletionState = WaitIsNotSatisfied;
1662 }
1663 else
1664 {
1665 wcsWaitCompletionState = WaitIsSatisfied;
1666 }
1667
1668 IROWAS_exit:
1669 TRACE("IsRestOfWaitAllSatisfied() returning %u \n", wcsWaitCompletionState);
1670
1671 return wcsWaitCompletionState;
1672 }
1673
1674
1675 /*++
1676 Method:
1677 CSynchData::SetOwner
1678
1679 Blindly sets the thread whose CPalThread is passed as argument, as the
1680 owner of the current object.
1681 WARNING: this method discards any previous ownership data and does not
1682 update the list of the object owned by the owner thread.
1683
1684 Note: this method must be called while holding the appropriate
1685 synchronization locks (the local process synch lock if the target
1686 object is local, both local and shared one if the object is shared).
1687 --*/
1688 void CSynchData::SetOwner(CPalThread * pOwnerThread)
1689 {
1690 VALIDATEOBJECT(this);
1691
1692 m_dwOwnerPid = gPID;
1693 m_dwOwnerTid = pOwnerThread->GetThreadId();
1694 m_pOwnerThread = pOwnerThread;
1695 }
1696
1697 /*++
1698 Method:
1699 CSynchData::ResetOwnership
1700
1701 Resets current object's ownership data
1702
1703 Note: this method must be called while holding the appropriate
1704 synchronization locks (the local process synch lock if the target
1705 object is local, both local and shared one if the object is shared).
1706 --*/
1707 void CSynchData::ResetOwnership()
1708 {
1709 VALIDATEOBJECT(this);
1710
1711 m_lOwnershipCount = 0;
1712 m_dwOwnerPid = 0;
1713 m_dwOwnerTid = 0;
1714 m_pOwnerThread = NULL;
1715 m_poolnOwnedObjectListNode = NULL;
1716 }
1717
1718 /*++
1719 Method:
1720 CSynchData::AssignOwnershipToThread
1721
1722 Assigns thw ownership of the current object to the target thread, performing
1723 all the operations neede to mantain the correct status of ownership data,
1724 also handling recursive object ownership acquisition
1725
1726 Note: this method must be called while holding the appropriate
1727 synchronization locks (the local process synch lock if the target
1728 object is local, both local and shared one if the object is shared).
1729 --*/
1730 PAL_ERROR CSynchData::AssignOwnershipToThread(
1731 CPalThread * pthrCurrent,
1732 CPalThread * pthrTarget)
1733 {
1734 // Note: when this method is called by ReleaseFirstWaiter there is
1735 // a small time window in which both SignalCount and
1736 // OwnershipCount can be greater than zero (which normally
1737 // is illegal). Anyway that is fine since ReleaseFirstWaiter
1738 // will restore the value right after, and such situation
1739 // takes place while holding synchroniztion locks, so no
1740 // other thread/process can access the object.
1741
1742 PAL_ERROR palErr = NO_ERROR;
1743
1744 _ASSERT_MSG(CObjectType::OwnershipTracked ==
1745 GetObjectType()->GetOwnershipSemantics(),
1746 "AssignOwnershipToThread called on a non-ownable "
1747 "CSynchData [this=%p OwnershipSemantics=%u]\n", this,
1748 GetObjectType()->GetOwnershipSemantics());
1749
1750
1751 if (0 < m_lOwnershipCount)
1752 {
1753 //
1754 // Object already owned, incrementing ownership count
1755 //
1756 _ASSERT_MSG(0 == GetSignalCount(),
1757 "Conflicting OwnershipCount and SignalCount values\n");
1758
1759 _ASSERT_MSG(pthrTarget == m_pOwnerThread && gPID == m_dwOwnerPid,
1760 "Attempting to assign ownership of CSynchData %p to "
1761 "thread {pid=%#x tid=%#x} while it is currently owned "
1762 "by thread {pid=%#x tid=%#x}\n", this,
1763 gPID, pthrTarget->GetThreadId(),
1764 m_dwOwnerPid, m_pOwnerThread->GetThreadId());
1765
1766 m_lOwnershipCount++;
1767
1768 TRACE("Incrementing ownership count for object with "
1769 "SynchData %p owned by thread %#x [new count=%d]\n",
1770 this, pthrTarget->GetThreadId(), m_lOwnershipCount);
1771 }
1772 else
1773 {
1774 //
1775 // Acquiring currently not owned object
1776 //
1777 CPalSynchronizationManager * pSynchManager =
1778 CPalSynchronizationManager::GetInstance();
1779 OwnedObjectsListNode * pooln;
1780
1781 pooln = pSynchManager->CacheGetOwnedObjsListNode(pthrCurrent);
1782 if (NULL == pooln)
1783 {
1784 ERROR("Out of memory while acquiring mutex ownership");
1785 // In this case we bail out. It will result in no
1786 // thread being awakend, which may cause deadlock,
1787 // but it is anyway better than corrupting the
1788 // ownership list
1789 palErr = ERROR_NOT_ENOUGH_MEMORY;
1790 goto AOTT_exit;
1791 }
1792
1793 TRACE("Assigning ownable object with SynchData %p to "
1794 "thread %#x\n",
1795 this, pthrTarget->GetThreadId());
1796
1797 // Set ownership data
1798 SetOwner(pthrTarget);
1799 SetOwnershipListNode(pooln);
1800 SetOwnershipCount(1);
1801 SetAbandoned(false);
1802
1803 // Add object to list of owned objs for current thread
1804 pooln->pPalObjSynchData = this;
1805 AddRef();
1806 pthrTarget->synchronizationInfo.AddObjectToOwnedList(pooln);
1807 }
1808
1809 AOTT_exit:
1810 return palErr;
1811 }
1812
1813 /*++
1814 Method:
1815 CSynchData::WaiterEnqueue
1816
1817 Adds the WaitingThreadsListNode passed as argument at the end of the
1818 list of WaitingThreadsListNode for the current object, representing
1819 the threads waiting on the current object. The target SynchData is
1820 assumed to be local to the current process
1821
1822 Note: this method must be called while holding the local process
1823 synchronization lock.
1824 --*/
1825 void CSynchData::WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode, bool fPrioritize)
1826 {
1827 VALIDATEOBJECT(this);
1828 VALIDATEOBJECT(pwtlnNewNode);
1829
1830 _ASSERT_MSG(ProcessLocalObject == GetObjectDomain(),
1831 "Trying to enqueue a WaitingThreadsListNode as local "
1832 "on a shared object\n");
1833 _ASSERT_MSG(0 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
1834 "Trying to add a WaitingThreadsListNode marked as shared "
1835 "as it was a local one\n");
1836
1837 if (!fPrioritize)
1838 {
1839 // Enqueue normally to the end of the queue
1840 WaitingThreadsListNode * pwtlnCurrLast = m_ptrWTLTail.ptr;
1841
1842 pwtlnNewNode->ptrNext.ptr = NULL;
1843 if (NULL == pwtlnCurrLast)
1844 {
1845 _ASSERT_MSG(NULL == m_ptrWTLHead.ptr,
1846 "Corrupted waiting list on local CSynchData @ %p\n",
1847 this);
1848
1849 pwtlnNewNode->ptrPrev.ptr = NULL;
1850 m_ptrWTLHead.ptr = pwtlnNewNode;
1851 m_ptrWTLTail.ptr = pwtlnNewNode;
1852 }
1853 else
1854 {
1855 VALIDATEOBJECT(pwtlnCurrLast);
1856
1857 pwtlnNewNode->ptrPrev.ptr = pwtlnCurrLast;
1858 pwtlnCurrLast->ptrNext.ptr = pwtlnNewNode;
1859 m_ptrWTLTail.ptr = pwtlnNewNode;
1860 }
1861 }
1862 else
1863 {
1864 // The wait is prioritized, enqueue to the beginning of the queue
1865 WaitingThreadsListNode * pwtlnCurrFirst = m_ptrWTLHead.ptr;
1866
1867 pwtlnNewNode->ptrPrev.ptr = NULL;
1868 if (NULL == pwtlnCurrFirst)
1869 {
1870 _ASSERT_MSG(NULL == m_ptrWTLTail.ptr,
1871 "Corrupted waiting list on local CSynchData @ %p\n",
1872 this);
1873
1874 pwtlnNewNode->ptrNext.ptr = NULL;
1875 m_ptrWTLHead.ptr = pwtlnNewNode;
1876 m_ptrWTLTail.ptr = pwtlnNewNode;
1877 }
1878 else
1879 {
1880 VALIDATEOBJECT(pwtlnCurrFirst);
1881
1882 pwtlnNewNode->ptrNext.ptr = pwtlnCurrFirst;
1883 pwtlnCurrFirst->ptrPrev.ptr = pwtlnNewNode;
1884 m_ptrWTLHead.ptr = pwtlnNewNode;
1885 }
1886 }
1887
1888 m_ulcWaitingThreads += 1;
1889
1890 return;
1891 }
1892
1893 /*++
1894 Method:
1895 CSynchData::SharedWaiterEnqueue
1896
1897 Adds the WaitingThreadsListNode passed as argument at the end of the
1898 list of WaitingThreadsListNode for the current object, representing
1899 the threads waiting on the current object. The target SynchData is
1900 assumed to be shared among processes
1901
1902 Note: this method must be called while holding both local and shared
1903 synchronization locks.
1904 --*/
1905 void CSynchData::SharedWaiterEnqueue(SharedID shridNewNode, bool fPrioritize)
1906 {
1907 VALIDATEOBJECT(this);
1908
1909 _ASSERT_MSG(SharedObject == GetObjectDomain(),
1910 "Trying to enqueue a WaitingThreadsListNode as shared "
1911 "on a local object\n");
1912
1913 if (!fPrioritize)
1914 {
1915 // Enqueue normally to the end of the queue
1916 SharedID shridCurrLast;
1917 WaitingThreadsListNode * pwtlnCurrLast, * pwtlnNewNode;
1918
1919 shridCurrLast = m_ptrWTLTail.shrid;
1920 pwtlnCurrLast = SharedIDToTypePointer(WaitingThreadsListNode, shridCurrLast);
1921 pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
1922
1923 _ASSERT_MSG(1 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
1924 "Trying to add a WaitingThreadsListNode marked as local "
1925 "as it was a shared one\n");
1926
1927 VALIDATEOBJECT(pwtlnNewNode);
1928
1929 pwtlnNewNode->ptrNext.shrid = NULL;
1930 if (NULL == pwtlnCurrLast)
1931 {
1932 _ASSERT_MSG(NULL == m_ptrWTLHead.shrid,
1933 "Corrupted waiting list on shared CSynchData at "
1934 "{shrid=%p, p=%p}\n", m_shridThis, this);
1935
1936 pwtlnNewNode->ptrPrev.shrid = NULL;
1937 m_ptrWTLHead.shrid = shridNewNode;
1938 m_ptrWTLTail.shrid = shridNewNode;
1939 }
1940 else
1941 {
1942 VALIDATEOBJECT(pwtlnCurrLast);
1943
1944 pwtlnNewNode->ptrPrev.shrid = shridCurrLast;
1945 pwtlnCurrLast->ptrNext.shrid = shridNewNode;
1946 m_ptrWTLTail.shrid = shridNewNode;
1947 }
1948 }
1949 else
1950 {
1951 // The wait is prioritized, enqueue to the beginning of the queue
1952 SharedID shridCurrFirst;
1953 WaitingThreadsListNode * pwtlnCurrFirst, * pwtlnNewNode;
1954
1955 shridCurrFirst = m_ptrWTLHead.shrid;
1956 pwtlnCurrFirst = SharedIDToTypePointer(WaitingThreadsListNode, shridCurrFirst);
1957 pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
1958
1959 _ASSERT_MSG(1 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
1960 "Trying to add a WaitingThreadsListNode marked as local "
1961 "as it was a shared one\n");
1962
1963 VALIDATEOBJECT(pwtlnNewNode);
1964
1965 pwtlnNewNode->ptrPrev.shrid = NULL;
1966 if (NULL == pwtlnCurrFirst)
1967 {
1968 _ASSERT_MSG(NULL == m_ptrWTLTail.shrid,
1969 "Corrupted waiting list on shared CSynchData at "
1970 "{shrid=%p, p=%p}\n", m_shridThis, this);
1971
1972 pwtlnNewNode->ptrNext.shrid = NULL;
1973 m_ptrWTLHead.shrid = shridNewNode;
1974 m_ptrWTLTail.shrid = shridNewNode;
1975 }
1976 else
1977 {
1978 VALIDATEOBJECT(pwtlnCurrFirst);
1979
1980 pwtlnNewNode->ptrNext.shrid = shridCurrFirst;
1981 pwtlnCurrFirst->ptrPrev.shrid = shridNewNode;
1982 m_ptrWTLHead.shrid = shridNewNode;
1983 }
1984 }
1985
1986 m_ulcWaitingThreads += 1;
1987
1988 return;
1989 }
1990
1991#ifdef SYNCH_OBJECT_VALIDATION
1992 CSynchData::~CSynchData()
1993 {
1994 ValidateObject(true);
1995 InvalidateObject();
1996 }
1997 /*++
1998 Method:
1999 CSynchData::ValidateObject
2000
2001 Makes sure that the signature at the beginning and at the end of the
2002 current object are those of a currently alive object (i.e. the object
2003 has been constructed and does not appear to have been overwritten)
2004 --*/
2005 void CSynchData::ValidateObject(bool fDestructor)
2006 {
2007 TRACE("Verifying in-use CSynchData @ %p\n", this);
2008 _ASSERT_MSG(HeadSignature == m_dwDebugHeadSignature,
2009 "CSynchData header signature corruption [p=%p]", this);
2010 _ASSERT_MSG(TailSignature == m_dwDebugTailSignature,
2011 "CSynchData trailer signature corruption [p=%p]", this);
2012 _ASSERT_MSG((fDestructor && 0 == m_lRefCount) ||
2013 (!fDestructor && 0 < m_lRefCount),
2014 "CSynchData %p with NULL reference count\n", this);
2015 }
2016 /*++
2017 Method:
2018 CSynchData::ValidateEmptyObject
2019
2020 Makes sure that the signature at the beginning and at the end of the
2021 current object are not those of a currently alive object (i.e. the
2022 object has not yet been constructed or it has alread been destructed)
2023 --*/
2024 void CSynchData::ValidateEmptyObject()
2025 {
2026 TRACE("Verifying empty CSynchData @ %p\n", this);
2027 _ASSERT_MSG(HeadSignature != m_dwDebugHeadSignature,
2028 "CSynchData header previously signed [p=%p]", this);
2029 _ASSERT_MSG(TailSignature != m_dwDebugTailSignature,
2030 "CSynchData trailer previously signed [p=%p]", this);
2031 }
2032 /*++
2033 Method:
2034 CSynchData::InvalidateObject
2035
2036 Turns signatures from alive object to destructed object
2037 --*/
2038 void CSynchData::InvalidateObject()
2039 {
2040 TRACE("Invalidating CSynchData @ %p\n", this);
2041 m_dwDebugHeadSignature = EmptySignature;
2042 m_dwDebugTailSignature = EmptySignature;
2043 }
2044#endif // SYNCH_OBJECT_VALIDATION
2045}
2046
2047