281
291
MXUserStatsActionRW(MXUserHeader *header) // IN:
285
double contentionRatio;
287
293
MXUserRWLock *lock = (MXUserRWLock *) header;
290
* Dump the statistics for the specified lock.
293
MXUserDumpAcquisitionStats(&lock->acquisitionStats, header);
295
if (Atomic_ReadPtr(&lock->acquisitionHisto) != NULL) {
296
MXUserHistoDump(Atomic_ReadPtr(&lock->acquisitionHisto), header);
299
MXUserDumpBasicStats(&lock->heldStats, header);
301
if (Atomic_ReadPtr(&lock->heldHisto) != NULL) {
302
MXUserHistoDump(Atomic_ReadPtr(&lock->heldHisto), header);
306
* Has the lock gone "hot"? If so, implement the hot actions.
307
* Allow the read and write statistics to go independently hot.
310
MXUserKitchen(&lock->acquisitionStats, &contentionRatio, &isHot, &doLog);
313
MXUserForceHisto(&lock->acquisitionHisto,
314
MXUSER_STAT_CLASS_ACQUISITION,
315
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
316
MXUSER_DEFAULT_HISTO_DECADES);
317
MXUserForceHisto(&lock->heldHisto,
318
MXUSER_STAT_CLASS_HELD,
319
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
320
MXUSER_DEFAULT_HISTO_DECADES);
323
Log("HOT LOCK (%s); contention ratio %f\n",
324
lock->header.name, contentionRatio);
294
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
299
double contentionRatio;
302
* Dump the statistics for the specified lock.
305
MXUserDumpAcquisitionStats(&stats->acquisitionStats, header);
307
if (Atomic_ReadPtr(&stats->acquisitionHisto) != NULL) {
308
MXUserHistoDump(Atomic_ReadPtr(&stats->acquisitionHisto), header);
311
MXUserDumpBasicStats(&stats->heldStats, header);
313
if (Atomic_ReadPtr(&stats->heldHisto) != NULL) {
314
MXUserHistoDump(Atomic_ReadPtr(&stats->heldHisto), header);
318
* Has the lock gone "hot"? If so, implement the hot actions.
319
* Allow the read and write statistics to go independently hot.
322
MXUserKitchen(&stats->acquisitionStats, &contentionRatio, &isHot,
326
MXUserForceHisto(&stats->acquisitionHisto,
327
MXUSER_STAT_CLASS_ACQUISITION,
328
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
329
MXUSER_DEFAULT_HISTO_DECADES);
330
MXUserForceHisto(&stats->heldHisto,
331
MXUSER_STAT_CLASS_HELD,
332
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
333
MXUSER_DEFAULT_HISTO_DECADES);
336
Log("HOT LOCK (%s); contention ratio %f\n",
337
lock->header.name, contentionRatio);
354
367
Warning("\tsignature 0x%X\n", lock->header.signature);
355
368
Warning("\tname %s\n", lock->header.name);
356
369
Warning("\trank 0x%X\n", lock->header.rank);
370
Warning("\tserial number %u\n", lock->header.serialNumber);
358
372
if (LIKELY(lock->useNative)) {
359
373
Warning("\tnativeLock 0x%p\n", &lock->nativeLock);
361
375
Warning("\tcount %u\n", lock->recursiveLock.referenceCount);
363
#if defined(MXUSER_DEBUG)
364
Warning("\tcaller 0x%p\n", lock->recursiveLock.ownerRetAddr);
365
Warning("\tVThreadID %d\n", (int) lock->recursiveLock.portableThreadID);
369
378
Warning("\tholderCount %d\n", Atomic_Read(&lock->holderCount));
374
383
*-----------------------------------------------------------------------------
385
* MXUser_ControlRWLock --
387
* Perform the specified command on the specified lock.
394
* Depends on the command, no?
396
*-----------------------------------------------------------------------------
400
MXUser_ControlRWLock(MXUserRWLock *lock, // IN/OUT:
401
uint32 command, // IN:
406
ASSERT(lock && (lock->header.signature == MXUSER_RW_SIGNATURE));
409
case MXUSER_CONTROL_ACQUISITION_HISTO: {
410
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
417
va_start(a, command);
418
minValue = va_arg(a, uint64);
419
decades = va_arg(a, uint32);
422
MXUserForceHisto(&stats->acquisitionHisto,
423
MXUSER_STAT_CLASS_ACQUISITION, minValue, decades);
433
case MXUSER_CONTROL_HELD_HISTO: {
434
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
441
va_start(a, command);
442
minValue = va_arg(a, uint64);
443
decades = va_arg(a, uint32);
446
MXUserForceHisto(&stats->heldHisto, MXUSER_STAT_CLASS_HELD,
457
case MXUSER_CONTROL_ENABLE_STATS: {
458
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
460
if (LIKELY(stats == NULL)) {
463
stats = Util_SafeCalloc(1, sizeof(*stats));
465
MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
466
MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
468
before = (MXUserStats *) Atomic_ReadIfEqualWritePtr(&lock->statsMem,
476
lock->header.statsFunc = MXUserStatsActionRW;
492
*-----------------------------------------------------------------------------
376
494
* MXUser_CreateRWLock --
378
496
* Create a read/write lock.
418
530
properName = Util_SafeStrdup(userName);
533
lock->header.signature = MXUSER_RW_SIGNATURE;
534
lock->header.name = properName;
535
lock->header.rank = rank;
536
lock->header.serialNumber = MXUserAllocSerialNumber();
537
lock->header.dumpFunc = MXUserDumpRWLock;
422
540
* Always attempt to use native locks when they are available. If, for some
423
541
* reason, a native lock should be available but isn't, fall back to using
427
545
lock->useNative = useNative && MXUserNativeRWInit(&lock->nativeLock);
429
if (lock->useNative) {
430
#if defined(MXUSER_STATS)
431
/* stats builds need an internal recursive lock for data integrity */
433
lockInited = MXRecLockInit(&lock->recursiveLock);
436
MXUserNativeRWDestroy(&lock->nativeLock);
442
lockInited = MXRecLockInit(&lock->recursiveLock);
547
lockInited = MXRecLockInit(&lock->recursiveLock);
445
549
if (LIKELY(lockInited)) {
446
550
lock->holderTable = HashTable_Alloc(256,
447
551
HASH_INT_KEY | HASH_FLAG_ATOMIC,
448
552
MXUserFreeHashEntry);
450
lock->header.name = properName;
451
lock->header.signature = MXUSER_RW_SIGNATURE;
452
lock->header.rank = rank;
453
lock->header.dumpFunc = MXUserDumpRWLock;
455
#if defined(MXUSER_STATS)
456
lock->header.statsFunc = MXUserStatsActionRW;
457
lock->header.identifier = MXUserAllocID();
554
if (MXUserStatsEnabled()) {
555
MXUser_ControlRWLock(lock, MXUSER_CONTROL_ENABLE_STATS);
557
lock->header.statsFunc = NULL;
558
Atomic_WritePtr(&lock->statsMem, NULL);
459
561
MXUserAddToList(&lock->header);
460
MXUserAcquisitionStatsSetUp(&lock->acquisitionStats);
461
MXUserBasicStatsSetUp(&lock->heldStats, MXUSER_STAT_CLASS_HELD);
563
if (lock->useNative) {
564
MXUserNativeRWDestroy(&lock->nativeLock);
464
567
free(properName);
505
610
MXUserDumpAndPanic(&lock->header, "%s: Internal error (%d)\n",
506
611
__FUNCTION__, err);
509
#if defined(MXUSER_STATS)
510
MXRecLockDestroy(&lock->recursiveLock);
513
MXRecLockDestroy(&lock->recursiveLock);
516
#if defined(MXUSER_STATS)
615
MXRecLockDestroy(&lock->recursiveLock);
517
617
MXUserRemoveFromList(&lock->header);
518
MXUserAcquisitionStatsTearDown(&lock->acquisitionStats);
519
MXUserBasicStatsTearDown(&lock->heldStats);
520
MXUserHistoTearDown(Atomic_ReadPtr(&lock->acquisitionHisto));
521
MXUserHistoTearDown(Atomic_ReadPtr(&lock->heldHisto));
524
HashTable_Free(lock->holderTable);
619
stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
622
MXUserAcquisitionStatsTearDown(&stats->acquisitionStats);
623
MXUserBasicStatsTearDown(&stats->heldStats);
624
MXUserHistoTearDown(Atomic_ReadPtr(&stats->acquisitionHisto));
625
MXUserHistoTearDown(Atomic_ReadPtr(&stats->heldHisto));
630
HashTable_FreeUnsafe(lock->holderTable);
525
631
lock->header.signature = 0; // just in case...
526
free((void *) lock->header.name); // avoid const warnings
632
free(lock->header.name);
527
633
lock->header.name = NULL;
551
657
MXUserGetHolderContext(MXUserRWLock *lock) // IN:
553
659
HolderContext *result;
554
VThreadID tid = VThread_CurID();
660
void *threadID = MXUserGetNativeTID();
556
662
ASSERT(lock->holderTable);
558
if (!HashTable_Lookup(lock->holderTable, (void *) (uintptr_t) tid,
559
(void **) &result)) {
664
if (!HashTable_Lookup(lock->holderTable, threadID, (void **) &result)) {
560
665
HolderContext *newContext = Util_SafeMalloc(sizeof(HolderContext));
562
#if defined(MXUSER_STATS)
563
667
newContext->holdStart = 0;
668
newContext->holder = NULL;
566
669
newContext->state = RW_UNLOCKED;
568
result = HashTable_LookupOrInsert(lock->holderTable,
569
(void *) (uintptr_t) tid,
671
result = HashTable_LookupOrInsert(lock->holderTable, threadID,
570
672
(void *) newContext);
572
674
if (result != newContext) {
626
#if defined(MXUSER_STATS)
627
begin = Hostinfo_SystemTimerNS();
630
contended = lock->useNative ? MXUserNativeRWAcquire(&lock->nativeLock,
632
MXRecLockAcquire(&lock->recursiveLock,
634
if (UNLIKELY(err != 0)) {
635
MXUserDumpAndPanic(&lock->header, "%s: Error %d: contended %d\n",
636
__FUNCTION__, err, contended);
639
#if defined(MXUSER_STATS)
640
value = Hostinfo_SystemTimerNS() - begin;
642
/* The statistics are not atomically safe so protect them when necessary */
643
if (forRead && lock->useNative) {
644
MXRecLockAcquire(&lock->recursiveLock, GetReturnAddress());
647
MXUserAcquisitionSample(&lock->acquisitionStats, contended, value);
649
histo = Atomic_ReadPtr(&lock->acquisitionHisto);
651
if (UNLIKELY(histo != NULL)) {
652
MXUserHistoSample(histo, value);
655
if (forRead && lock->useNative) {
656
MXRecLockRelease(&lock->recursiveLock);
723
stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
726
VmTimeType begin = Hostinfo_SystemTimerNS();
730
contended = lock->useNative ? MXUserNativeRWAcquire(&lock->nativeLock,
732
MXRecLockAcquire(&lock->recursiveLock);
734
value = Hostinfo_SystemTimerNS() - begin;
736
if (UNLIKELY(err != 0)) {
737
MXUserDumpAndPanic(&lock->header, "%s: Error %d: contended %d\n",
738
__FUNCTION__, err, contended);
742
* The statistics are not atomically safe so protect them when
746
if (forRead && lock->useNative) {
747
MXRecLockAcquire(&lock->recursiveLock);
750
MXUserAcquisitionSample(&stats->acquisitionStats, TRUE, contended,
753
histo = Atomic_ReadPtr(&stats->acquisitionHisto);
755
if (UNLIKELY(histo != NULL)) {
756
MXUserHistoSample(histo, value, GetReturnAddress());
759
if (forRead && lock->useNative) {
760
MXRecLockRelease(&lock->recursiveLock);
763
if (LIKELY(lock->useNative)) {
764
MXUserNativeRWAcquire(&lock->nativeLock, forRead, &err);
766
MXRecLockAcquire(&lock->recursiveLock);
660
770
if (!forRead || !lock->useNative) {
661
771
ASSERT(Atomic_Read(&lock->holderCount) == 0);
783
893
MXUser_ReleaseRWLock(MXUserRWLock *lock) // IN/OUT:
785
896
HolderContext *myContext;
787
#if defined(MXUSER_STATS)
788
VmTimeType holdEnd = Hostinfo_SystemTimerNS();
793
898
ASSERT(lock && (lock->header.signature == MXUSER_RW_SIGNATURE));
795
900
myContext = MXUserGetHolderContext(lock);
902
stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
905
VmTimeType duration = Hostinfo_SystemTimerNS() - myContext->holdStart;
909
* The statistics are not always atomically safe so protect them
913
if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
914
MXRecLockAcquire(&lock->recursiveLock);
917
MXUserBasicStatsSample(&stats->heldStats, duration);
919
histo = Atomic_ReadPtr(&stats->heldHisto);
921
if (UNLIKELY(histo != NULL)) {
922
MXUserHistoSample(histo, duration, myContext->holder);
923
myContext->holder = NULL;
926
if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
927
MXRecLockRelease(&lock->recursiveLock);
797
931
if (UNLIKELY(myContext->state == RW_UNLOCKED)) {
798
932
uint32 lockCount = Atomic_Read(&lock->holderCount);
803
937
lockCount == 0 ? "unacquired" : "acquired");
806
#if defined(MXUSER_STATS)
807
duration = holdEnd - myContext->holdStart;
809
/* The statistics are not atomically safe so protect them when necessary */
810
if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
811
MXRecLockAcquire(&lock->recursiveLock, GetReturnAddress());
814
MXUserBasicStatsSample(&lock->heldStats, duration);
816
histo = Atomic_ReadPtr(&lock->heldHisto);
818
if (UNLIKELY(histo != NULL)) {
819
MXUserHistoSample(histo, duration);
822
if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
823
MXRecLockRelease(&lock->recursiveLock);
827
940
MXUserReleaseTracking(&lock->header);
829
942
Atomic_Dec(&lock->holderCount);
831
944
if (LIKELY(lock->useNative)) {
832
int err = MXUserNativeRWRelease(&lock->nativeLock, myContext->state);
945
int err = MXUserNativeRWRelease(&lock->nativeLock,
946
myContext->state == RW_LOCKED_FOR_READ);
834
948
if (UNLIKELY(err != 0)) {
835
949
MXUserDumpAndPanic(&lock->header, "%s: Internal error (%d)\n",
875
989
lock = (MXUserRWLock *) Atomic_ReadPtr(lockStorage);
877
991
if (UNLIKELY(lock == NULL)) {
878
MXUserRWLock *before;
880
lock = MXUser_CreateRWLock(name, rank);
882
before = (MXUserRWLock *) Atomic_ReadIfEqualWritePtr(lockStorage, NULL,
886
MXUser_DestroyRWLock(lock);
992
MXUserRWLock *newLock = MXUser_CreateRWLock(name, rank);
994
lock = (MXUserRWLock *) Atomic_ReadIfEqualWritePtr(lockStorage, NULL,
998
MXUser_DestroyRWLock(newLock);
1000
lock = (MXUserRWLock *) Atomic_ReadPtr(lockStorage);