75
78
MXUserStatsActionRec(MXUserHeader *header) // IN:
79
double contentionRatio;
81
80
MXUserRecLock *lock = (MXUserRecLock *) header;
84
* Dump the statistics for the specified lock.
87
MXUserDumpAcquisitionStats(&lock->acquisitionStats, header);
89
if (Atomic_ReadPtr(&lock->acquisitionHisto) != NULL) {
90
MXUserHistoDump(Atomic_ReadPtr(&lock->acquisitionHisto), header);
93
MXUserDumpBasicStats(&lock->heldStats, header);
95
if (Atomic_ReadPtr(&lock->heldHisto) != NULL) {
96
MXUserHistoDump(Atomic_ReadPtr(&lock->heldHisto), header);
100
* Has the lock gone "hot"? If so, implement the hot actions.
103
MXUserKitchen(&lock->acquisitionStats, &contentionRatio, &isHot, &doLog);
106
MXUserForceHisto(&lock->acquisitionHisto,
107
MXUSER_STAT_CLASS_ACQUISITION,
108
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
109
MXUSER_DEFAULT_HISTO_DECADES);
110
MXUserForceHisto(&lock->heldHisto,
111
MXUSER_STAT_CLASS_HELD,
112
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
113
MXUSER_DEFAULT_HISTO_DECADES);
116
Log("HOT LOCK (%s); contention ratio %f\n",
117
lock->header.name, contentionRatio);
81
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
86
double contentionRatio;
89
* Dump the statistics for the specified lock.
92
MXUserDumpAcquisitionStats(&stats->acquisitionStats, header);
94
if (Atomic_ReadPtr(&stats->acquisitionHisto) != NULL) {
95
MXUserHistoDump(Atomic_ReadPtr(&stats->acquisitionHisto), header);
98
MXUserDumpBasicStats(&stats->heldStats, header);
100
if (Atomic_ReadPtr(&stats->heldHisto) != NULL) {
101
MXUserHistoDump(Atomic_ReadPtr(&stats->heldHisto), header);
105
* Has the lock gone "hot"? If so, implement the hot actions.
108
MXUserKitchen(&stats->acquisitionStats, &contentionRatio, &isHot,
112
MXUserForceHisto(&stats->acquisitionHisto,
113
MXUSER_STAT_CLASS_ACQUISITION,
114
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
115
MXUSER_DEFAULT_HISTO_DECADES);
116
MXUserForceHisto(&stats->heldHisto,
117
MXUSER_STAT_CLASS_HELD,
118
MXUSER_DEFAULT_HISTO_MIN_VALUE_NS,
119
MXUSER_DEFAULT_HISTO_DECADES);
122
Log("HOT LOCK (%s); contention ratio %f\n",
123
lock->header.name, contentionRatio);
147
153
Warning("\tsignature 0x%X\n", lock->header.signature);
148
154
Warning("\tname %s\n", lock->header.name);
149
155
Warning("\trank 0x%X\n", lock->header.rank);
156
Warning("\tserial number %u\n", lock->header.serialNumber);
151
158
if (lock->vmmLock == NULL) {
159
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
152
161
Warning("\tcount %u\n", lock->recursiveLock.referenceCount);
154
#if defined(MXUSER_DEBUG)
155
Warning("\tcaller 0x%p\n", lock->recursiveLock.ownerRetAddr);
156
Warning("\tVThreadID %d\n", (int) lock->recursiveLock.portableThreadID);
164
Warning("\towner %u\n", lock->recursiveLock.nativeThreadID);
166
Warning("\towner 0x%p\n",
167
(void *)(uintptr_t)lock->recursiveLock.nativeThreadID);
170
if (stats && (stats->holder != NULL)) {
171
Warning("\tholder %p\n", stats->holder);
159
174
Warning("\tvmmLock 0x%p\n", lock->vmmLock);
165
180
*-----------------------------------------------------------------------------
167
* MXUser_CreateRecLock --
169
* Create a recursive lock.
182
* MXUser_ControlRecLock --
184
* Perform the specified command on the specified lock.
191
* Depends on the command, no?
193
*-----------------------------------------------------------------------------
197
MXUser_ControlRecLock(MXUserRecLock *lock, // IN/OUT:
198
uint32 command, // IN:
203
ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE));
206
case MXUSER_CONTROL_ACQUISITION_HISTO: {
207
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
209
if (stats && (lock->vmmLock == NULL)) {
213
va_start(a, command);
214
minValue = va_arg(a, uint64);
215
decades = va_arg(a, uint32);
218
MXUserForceHisto(&stats->acquisitionHisto,
219
MXUSER_STAT_CLASS_ACQUISITION, minValue, decades);
228
case MXUSER_CONTROL_HELD_HISTO: {
229
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
231
if (stats && (lock->vmmLock == NULL)) {
235
va_start(a, command);
236
minValue = va_arg(a, uint64);
237
decades = va_arg(a, uint32);
240
MXUserForceHisto(&stats->heldHisto, MXUSER_STAT_CLASS_HELD,
251
case MXUSER_CONTROL_ENABLE_STATS: {
252
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
254
if (LIKELY(stats == NULL)) {
257
stats = Util_SafeCalloc(1, sizeof(*stats));
259
MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
260
MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
262
before = (MXUserStats *) Atomic_ReadIfEqualWritePtr(&lock->statsMem,
270
lock->header.statsFunc = MXUserStatsActionRec;
286
*-----------------------------------------------------------------------------
288
* MXUserCreateRecLock --
290
* Create a recursive lock specifying if the lock must always be
171
293
* Only the owner (thread) of a recursive lock may recurse on it.
205
328
lock->vmmLock = NULL;
330
lock->header.signature = MXUSER_REC_SIGNATURE;
207
331
lock->header.name = properName;
208
lock->header.signature = MXUSER_REC_SIGNATURE;
209
332
lock->header.rank = rank;
333
lock->header.serialNumber = MXUserAllocSerialNumber();
210
334
lock->header.dumpFunc = MXUserDumpRecLock;
212
#if defined(MXUSER_STATS)
213
lock->header.statsFunc = MXUserStatsActionRec;
214
lock->header.identifier = MXUserAllocID();
336
if (beSilent || !MXUserStatsEnabled()) {
337
lock->header.statsFunc = NULL;
338
Atomic_WritePtr(&lock->statsMem, NULL);
340
MXUser_ControlRecLock(lock, MXUSER_CONTROL_ENABLE_STATS);
216
343
MXUserAddToList(&lock->header);
217
MXUserAcquisitionStatsSetUp(&lock->acquisitionStats);
218
MXUserBasicStatsSetUp(&lock->heldStats, MXUSER_STAT_CLASS_HELD);
226
350
*-----------------------------------------------------------------------------
352
* MXUser_CreateRecLockSilent --
354
* Create a recursive lock specifying if the lock must always be
355
* silent - never logging any messages. Silent locks will never
356
* produce any statistics, amongst the aspects of "silent".
358
* Only the owner (thread) of a recursive lock may recurse on it.
361
* NULL Creation failed
362
* !NULL Creation succeeded
367
*-----------------------------------------------------------------------------
371
MXUser_CreateRecLockSilent(const char *userName, // IN:
374
return MXUserCreateRecLock(userName, rank, TRUE);
378
*-----------------------------------------------------------------------------
380
* MXUser_CreateRecLock --
382
* Create a recursive lock.
384
* Only the owner (thread) of a recursive lock may recurse on it.
387
* NULL Creation failed
388
* !NULL Creation succeeded
393
*-----------------------------------------------------------------------------
397
MXUser_CreateRecLock(const char *userName, // IN:
400
return MXUserCreateRecLock(userName, rank, FALSE);
405
*-----------------------------------------------------------------------------
228
407
* MXUser_DestroyRecLock --
230
409
* Destroy a recursive lock.
232
411
* When the lock is bound to a MX lock, only the MXUser "wrapper" is
233
412
* freed. The caller is responsible for calling MX_DestroyLockRec() on
413
* the MX lock before calling this routine.
237
416
* Lock is destroyed. Don't use the pointer again.
258
439
MXRecLockDestroy(&lock->recursiveLock);
260
#if defined(MXUSER_STATS)
261
441
MXUserRemoveFromList(&lock->header);
262
MXUserAcquisitionStatsTearDown(&lock->acquisitionStats);
263
MXUserBasicStatsTearDown(&lock->heldStats);
264
MXUserHistoTearDown(Atomic_ReadPtr(&lock->acquisitionHisto));
265
MXUserHistoTearDown(Atomic_ReadPtr(&lock->heldHisto));
443
stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
446
MXUserAcquisitionStatsTearDown(&stats->acquisitionStats);
447
MXUserBasicStatsTearDown(&stats->heldStats);
448
MXUserHistoTearDown(Atomic_ReadPtr(&stats->acquisitionHisto));
449
MXUserHistoTearDown(Atomic_ReadPtr(&stats->heldHisto));
269
455
lock->header.signature = 0; // just in case...
270
free((void *) lock->header.name); // avoid const warnings
456
free(lock->header.name);
271
457
lock->header.name = NULL;
301
487
ASSERT(MXUserMX_LockRec);
302
488
(*MXUserMX_LockRec)(lock->vmmLock);
304
#if defined(MXUSER_STATS)
490
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
308
492
/* Rank checking is only done on the first acquisition */
309
493
MXUserAcquisitionTracking(&lock->header, TRUE);
311
#if defined(MXUSER_STATS)
312
begin = Hostinfo_SystemTimerNS();
317
MXRecLockAcquire(&lock->recursiveLock, GetReturnAddress());
319
#if defined(MXUSER_STATS)
320
if (MXRecLockCount(&lock->recursiveLock) == 1) {
322
VmTimeType value = Hostinfo_SystemTimerNS() - begin;
324
MXUserAcquisitionSample(&lock->acquisitionStats, contended, value);
326
histo = Atomic_ReadPtr(&lock->acquisitionHisto);
328
if (UNLIKELY(histo != NULL)) {
329
MXUserHistoSample(histo, value);
497
VmTimeType begin = Hostinfo_SystemTimerNS();
499
contended = MXRecLockAcquire(&lock->recursiveLock);
501
if (MXRecLockCount(&lock->recursiveLock) == 1) {
503
VmTimeType value = Hostinfo_SystemTimerNS() - begin;
505
MXUserAcquisitionSample(&stats->acquisitionStats, TRUE, contended,
508
stats->holder = GetReturnAddress();
510
histo = Atomic_ReadPtr(&stats->acquisitionHisto);
512
if (UNLIKELY(histo != NULL)) {
513
MXUserHistoSample(histo, value, stats->holder);
516
stats->holdStart = Hostinfo_SystemTimerNS();
332
lock->holdStart = Hostinfo_SystemTimerNS();
519
MXRecLockAcquire(&lock->recursiveLock);
361
547
ASSERT(MXUserMX_UnlockRec);
362
548
(*MXUserMX_UnlockRec)(lock->vmmLock);
364
#if defined(MXUSER_STATS)
365
if (MXRecLockCount(&lock->recursiveLock) == 1) {
366
VmTimeType value = Hostinfo_SystemTimerNS() - lock->holdStart;
367
MXUserHisto *histo = Atomic_ReadPtr(&lock->heldHisto);
369
MXUserBasicStatsSample(&lock->heldStats, value);
371
if (UNLIKELY(histo != NULL)) {
372
MXUserHistoSample(histo, value);
550
MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
553
if (MXRecLockCount(&lock->recursiveLock) == 1) {
554
VmTimeType value = Hostinfo_SystemTimerNS() - stats->holdStart;
555
MXUserHisto *histo = Atomic_ReadPtr(&stats->heldHisto);
557
MXUserBasicStatsSample(&stats->heldStats, value);
559
if (UNLIKELY(histo != NULL)) {
560
MXUserHistoSample(histo, value, stats->holder);
561
stats->holder = NULL;
377
566
if (!MXRecLockIsOwner(&lock->recursiveLock)) {
378
567
uint32 lockCount = MXRecLockCount(&lock->recursiveLock);
424
613
ASSERT(MXUserMX_TryLockRec);
425
614
success = (*MXUserMX_TryLockRec)(lock->vmmLock);
427
#if defined(MXUSER_STATS)
431
618
if (MXUserTryAcquireFail(lock->header.name)) {
435
#if defined(MXUSER_STATS)
436
begin = Hostinfo_SystemTimerNS();
439
success = MXRecLockTryAcquire(&lock->recursiveLock, GetReturnAddress());
622
success = MXRecLockTryAcquire(&lock->recursiveLock);
442
#if defined(MXUSER_STATS)
443
if (MXRecLockCount(&lock->recursiveLock) == 1) {
444
MXUserAcquisitionSample(&lock->acquisitionStats, FALSE,
445
Hostinfo_SystemTimerNS() - begin);
449
625
MXUserAcquisitionTracking(&lock->header, FALSE);
628
stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
631
MXUserAcquisitionSample(&stats->acquisitionStats, success,
492
675
*-----------------------------------------------------------------------------
494
* MXUser_ControlRecLock --
496
* Perform the specified command on the specified lock.
503
* Depends on the command, no?
505
*-----------------------------------------------------------------------------
509
MXUser_ControlRecLock(MXUserRecLock *lock, // IN/OUT:
510
uint32 command, // IN:
515
ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE));
516
ASSERT(lock->vmmLock == NULL); // only unbound locks
519
#if defined(MXUSER_STATS)
520
case MXUSER_CONTROL_ACQUISITION_HISTO: {
525
va_start(a, command);
526
minValue = va_arg(a, uint64);
527
decades = va_arg(a, uint32);
530
MXUserForceHisto(&lock->acquisitionHisto, MXUSER_STAT_CLASS_ACQUISITION,
537
case MXUSER_CONTROL_HELD_HISTO: {
542
va_start(a, command);
543
minValue = va_arg(a, uint64);
544
decades = va_arg(a, uint32);
547
MXUserForceHisto(&lock->heldHisto, MXUSER_STAT_CLASS_HELD,
564
*-----------------------------------------------------------------------------
566
677
* MXUser_CreateSingletonRecLock --
568
679
* Ensures that the specified backing object (Atomic_Ptr) contains a
591
702
lock = (MXUserRecLock *) Atomic_ReadPtr(lockStorage);
593
704
if (UNLIKELY(lock == NULL)) {
594
MXUserRecLock *before;
596
lock = MXUser_CreateRecLock(name, rank);
598
before = (MXUserRecLock *) Atomic_ReadIfEqualWritePtr(lockStorage, NULL,
602
MXUser_DestroyRecLock(lock);
705
MXUserRecLock *newLock = MXUser_CreateRecLock(name, rank);
707
lock = (MXUserRecLock *) Atomic_ReadIfEqualWritePtr(lockStorage, NULL,
711
MXUser_DestroyRecLock(newLock);
713
lock = (MXUserRecLock *) Atomic_ReadPtr(lockStorage);
676
786
* blocking and is reacquired before returning from this function.
679
* TRUE condVar was signalled
680
* FALSE timed out waiting for signal
792
* It is possible to return from this routine without the condtion
793
* variable having been signalled (spurious wake up); code accordingly!
685
795
*-----------------------------------------------------------------------------
689
799
MXUser_TimedWaitCondVarRecLock(MXUserRecLock *lock, // IN:
690
800
MXUserCondVar *condVar, // IN:
691
801
uint32 msecWait) // IN:
693
803
ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE));
694
804
ASSERT(lock->vmmLock == NULL); // only unbound locks
696
return MXUserWaitCondVar(&lock->header, &lock->recursiveLock, condVar,
806
MXUserWaitCondVar(&lock->header, &lock->recursiveLock, condVar, msecWait);
811
*-----------------------------------------------------------------------------
813
* MXUser_DumpRecLock --
815
* Dump a recursive lock.
823
*-----------------------------------------------------------------------------
827
MXUser_DumpRecLock(MXUserRecLock *lock) // IN:
829
ASSERT(lock && (lock->header.signature == MXUSER_REC_SIGNATURE));
831
MXUserDumpRecLock(&lock->header);
795
929
lock = Util_SafeCalloc(1, sizeof(*lock));
931
lock->header.signature = MXUSER_REC_SIGNATURE;
797
932
lock->header.name = Str_SafeAsprintf(NULL, "MX_%p", mutex);
799
lock->header.signature = MXUSER_REC_SIGNATURE;
800
933
lock->header.rank = rank;
934
lock->header.serialNumber = MXUserAllocSerialNumber();
801
935
lock->header.dumpFunc = NULL;
803
#if defined(MXUSER_STATS)
804
936
lock->header.statsFunc = NULL;
805
lock->header.identifier = MXUserAllocID();
938
Atomic_WritePtr(&lock->statsMem, NULL);
808
940
lock->vmmLock = mutex;