~n-muench/open-vm-tools/devel

« back to all changes in this revision

Viewing changes to lib/lock/ulRW.c

  • Committer: Nate Muench
  • Date: 2011-05-05 00:27:16 UTC
  • Revision ID: nowiwilldestroyabydos@gmail.com-20110505002716-f87n4uvh2hg3crrk
Merge with Natty, Enable shared folders

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#endif
22
22
 
23
23
#include "vmware.h"
 
24
#include "vm_basic_asm.h"
24
25
#include "str.h"
25
26
#include "util.h"
26
27
#include "hashTable.h"
30
31
 
31
32
#define MXUSER_RW_SIGNATURE 0x57524B4C // 'LKRW' in memory
32
33
 
 
34
static void
 
35
MXUserFreeHashEntry(void *data)  // IN:
 
36
{
 
37
   free(data);
 
38
}
 
39
 
33
40
 
34
41
/*
35
42
 * Environment specific implementations of portable read-write locks.
88
95
                                    GetProcAddress(kernel32,
89
96
                                                   "ReleaseSRWLockExclusive");
90
97
 
 
98
         COMPILER_MEM_BARRIER();
 
99
 
91
100
         result = ((pInitializeSRWLock != NULL) &&
92
101
                   (pAcquireSRWLockShared != NULL) &&
93
102
                   (pReleaseSRWLockShared != NULL) &&
94
103
                   (pAcquireSRWLockExclusive != NULL) &&
95
104
                   (pReleaseSRWLockExclusive != NULL));
 
105
 
 
106
         COMPILER_MEM_BARRIER();
96
107
      } else {
97
108
         result = FALSE;
98
109
      }
232
243
} HolderState;
233
244
 
234
245
typedef struct {
235
 
#if defined(MXUSER_STATS)
236
 
   VmTimeType   holdStart;
237
 
#endif
238
 
 
239
 
   HolderState  state;
 
246
   HolderState   state;
 
247
   void         *holder;
 
248
   VmTimeType    holdStart;
240
249
} HolderContext;
241
250
 
 
251
typedef struct {
 
252
   MXUserAcquisitionStats  acquisitionStats;
 
253
   Atomic_Ptr              acquisitionHisto;
 
254
 
 
255
   MXUserBasicStats        heldStats;
 
256
   Atomic_Ptr              heldHisto;
 
257
} MXUserStats;
 
258
 
242
259
struct MXUserRWLock
243
260
{
244
261
   MXUserHeader    header;
250
267
   Atomic_uint32   holderCount;
251
268
   HashTable      *holderTable;
252
269
 
253
 
#if defined(MXUSER_STATS)
254
 
   MXUserAcquisitionStats  acquisitionStats;
255
 
   Atomic_Ptr              acquisitionHisto;
256
 
 
257
 
   MXUserBasicStats        heldStats;
258
 
   Atomic_Ptr              heldHisto;
259
 
#endif
 
270
   Atomic_Ptr      statsMem;
260
271
};
261
272
 
262
273
 
263
 
#if defined(MXUSER_STATS)
264
274
/*
265
275
 *-----------------------------------------------------------------------------
266
276
 *
280
290
static void
281
291
MXUserStatsActionRW(MXUserHeader *header)  // IN:
282
292
{
283
 
   Bool isHot;
284
 
   Bool doLog;
285
 
   double contentionRatio;
286
 
 
287
293
   MXUserRWLock *lock = (MXUserRWLock *) header;
288
 
 
289
 
   /*
290
 
    * Dump the statistics for the specified lock.
291
 
    */
292
 
 
293
 
   MXUserDumpAcquisitionStats(&lock->acquisitionStats, header);
294
 
 
295
 
   if (Atomic_ReadPtr(&lock->acquisitionHisto) != NULL) {
296
 
      MXUserHistoDump(Atomic_ReadPtr(&lock->acquisitionHisto), header);
297
 
   }
298
 
 
299
 
   MXUserDumpBasicStats(&lock->heldStats, header);
300
 
 
301
 
   if (Atomic_ReadPtr(&lock->heldHisto) != NULL) {
302
 
      MXUserHistoDump(Atomic_ReadPtr(&lock->heldHisto), header);
303
 
   }
304
 
 
305
 
   /*
306
 
    * Has the lock gone "hot"? If so, implement the hot actions.
307
 
    * Allow the read and write statistics to go independently hot.
308
 
    */
309
 
 
310
 
   MXUserKitchen(&lock->acquisitionStats, &contentionRatio, &isHot, &doLog);
311
 
 
312
 
   if (isHot) {
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);
321
 
 
322
 
      if (doLog) {
323
 
         Log("HOT LOCK (%s); contention ratio %f\n",
324
 
             lock->header.name, contentionRatio);
 
294
   MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
295
 
 
296
   if (stats) {
 
297
      Bool isHot;
 
298
      Bool doLog;
 
299
      double contentionRatio;
 
300
 
 
301
      /*
 
302
       * Dump the statistics for the specified lock.
 
303
       */
 
304
 
 
305
      MXUserDumpAcquisitionStats(&stats->acquisitionStats, header);
 
306
 
 
307
      if (Atomic_ReadPtr(&stats->acquisitionHisto) != NULL) {
 
308
         MXUserHistoDump(Atomic_ReadPtr(&stats->acquisitionHisto), header);
 
309
      }
 
310
 
 
311
      MXUserDumpBasicStats(&stats->heldStats, header);
 
312
 
 
313
      if (Atomic_ReadPtr(&stats->heldHisto) != NULL) {
 
314
         MXUserHistoDump(Atomic_ReadPtr(&stats->heldHisto), header);
 
315
      }
 
316
 
 
317
      /*
 
318
       * Has the lock gone "hot"? If so, implement the hot actions.
 
319
       * Allow the read and write statistics to go independently hot.
 
320
       */
 
321
 
 
322
      MXUserKitchen(&stats->acquisitionStats, &contentionRatio, &isHot,
 
323
                    &doLog);
 
324
 
 
325
      if (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);
 
334
 
 
335
         if (doLog) {
 
336
            Log("HOT LOCK (%s); contention ratio %f\n",
 
337
                lock->header.name, contentionRatio);
 
338
         }
325
339
      }
326
340
   }
327
341
}
328
 
#endif
329
342
 
330
343
 
331
344
/*
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);
357
371
 
358
372
   if (LIKELY(lock->useNative)) {
359
373
      Warning("\tnativeLock 0x%p\n", &lock->nativeLock);
360
374
   } else {
361
375
      Warning("\tcount %u\n", lock->recursiveLock.referenceCount);
362
 
 
363
 
#if defined(MXUSER_DEBUG)
364
 
      Warning("\tcaller 0x%p\n", lock->recursiveLock.ownerRetAddr);
365
 
      Warning("\tVThreadID %d\n", (int) lock->recursiveLock.portableThreadID);
366
 
#endif
367
376
   }
368
377
 
369
378
   Warning("\tholderCount %d\n", Atomic_Read(&lock->holderCount));
373
382
/*
374
383
 *-----------------------------------------------------------------------------
375
384
 *
 
385
 * MXUser_ControlRWLock --
 
386
 *
 
387
 *      Perform the specified command on the specified lock.
 
388
 *
 
389
 * Results:
 
390
 *      TRUE    succeeded
 
391
 *      FALSE   failed
 
392
 *
 
393
 * Side effects:
 
394
 *      Depends on the command, no?
 
395
 *
 
396
 *-----------------------------------------------------------------------------
 
397
 */
 
398
 
 
399
Bool
 
400
MXUser_ControlRWLock(MXUserRWLock *lock,  // IN/OUT:
 
401
                     uint32 command,      // IN:
 
402
                     ...)                 // IN:
 
403
{
 
404
   Bool result;
 
405
 
 
406
   ASSERT(lock && (lock->header.signature == MXUSER_RW_SIGNATURE));
 
407
 
 
408
   switch (command) {
 
409
   case MXUSER_CONTROL_ACQUISITION_HISTO: {
 
410
      MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
411
 
 
412
      if (stats) {
 
413
         va_list a;
 
414
         uint64 minValue;
 
415
         uint32 decades;
 
416
 
 
417
         va_start(a, command);
 
418
         minValue = va_arg(a, uint64);
 
419
         decades = va_arg(a, uint32);
 
420
         va_end(a);
 
421
 
 
422
         MXUserForceHisto(&stats->acquisitionHisto,
 
423
                          MXUSER_STAT_CLASS_ACQUISITION, minValue, decades);
 
424
 
 
425
         result = TRUE;
 
426
      } else {
 
427
         result = FALSE;
 
428
      }
 
429
 
 
430
      break;
 
431
   }
 
432
 
 
433
   case MXUSER_CONTROL_HELD_HISTO: {
 
434
      MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
435
 
 
436
      if (stats) {
 
437
         va_list a;
 
438
         uint32 minValue;
 
439
         uint32 decades;
 
440
 
 
441
         va_start(a, command);
 
442
         minValue = va_arg(a, uint64);
 
443
         decades = va_arg(a, uint32);
 
444
         va_end(a);
 
445
 
 
446
         MXUserForceHisto(&stats->heldHisto, MXUSER_STAT_CLASS_HELD,
 
447
                          minValue, decades);
 
448
 
 
449
         result = TRUE;
 
450
      } else {
 
451
         result = FALSE;
 
452
      }
 
453
 
 
454
      break;
 
455
   }
 
456
 
 
457
   case MXUSER_CONTROL_ENABLE_STATS: {
 
458
      MXUserStats *stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
459
 
 
460
      if (LIKELY(stats == NULL)) {
 
461
         MXUserStats *before;
 
462
 
 
463
         stats = Util_SafeCalloc(1, sizeof(*stats));
 
464
 
 
465
         MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
 
466
         MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
 
467
 
 
468
         before = (MXUserStats *) Atomic_ReadIfEqualWritePtr(&lock->statsMem,
 
469
                                                             NULL,
 
470
                                                             (void *) stats);
 
471
 
 
472
         if (before) {
 
473
            free(stats);
 
474
         }
 
475
 
 
476
         lock->header.statsFunc = MXUserStatsActionRW;
 
477
      }
 
478
 
 
479
      result = TRUE;
 
480
      break;
 
481
   }
 
482
 
 
483
   default:
 
484
      result = FALSE;
 
485
   }
 
486
 
 
487
   return result;
 
488
}
 
489
 
 
490
 
 
491
/*
 
492
 *-----------------------------------------------------------------------------
 
493
 *
376
494
 * MXUser_CreateRWLock --
377
495
 *
378
496
 *      Create a read/write lock.
390
508
 *-----------------------------------------------------------------------------
391
509
 */
392
510
 
393
 
static void
394
 
MXUserFreeHashEntry(void *data)  // IN:
395
 
{
396
 
   free(data);
397
 
}
398
 
 
399
511
MXUserRWLock *
400
512
MXUser_CreateRWLock(const char *userName,  // IN:
401
513
                    MX_Rank rank)          // IN:
418
530
      properName = Util_SafeStrdup(userName);
419
531
   }
420
532
 
 
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;
 
538
 
421
539
   /*
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
426
544
 
427
545
   lock->useNative = useNative && MXUserNativeRWInit(&lock->nativeLock);
428
546
 
429
 
   if (lock->useNative) {
430
 
#if defined(MXUSER_STATS)
431
 
      /* stats builds need an internal recursive lock for data integrity */
432
 
 
433
 
      lockInited = MXRecLockInit(&lock->recursiveLock);
434
 
 
435
 
      if (!lockInited) {
436
 
         MXUserNativeRWDestroy(&lock->nativeLock);
437
 
      }
438
 
#else
439
 
      lockInited = TRUE;
440
 
#endif
441
 
   } else {
442
 
      lockInited = MXRecLockInit(&lock->recursiveLock);
443
 
   }
 
547
   lockInited = MXRecLockInit(&lock->recursiveLock);
444
548
 
445
549
   if (LIKELY(lockInited)) {
446
550
      lock->holderTable = HashTable_Alloc(256,
447
551
                                          HASH_INT_KEY | HASH_FLAG_ATOMIC,
448
552
                                          MXUserFreeHashEntry);
449
553
 
450
 
      lock->header.name = properName;
451
 
      lock->header.signature = MXUSER_RW_SIGNATURE;
452
 
      lock->header.rank = rank;
453
 
      lock->header.dumpFunc = MXUserDumpRWLock;
454
 
 
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);
 
556
      } else {
 
557
         lock->header.statsFunc = NULL;
 
558
         Atomic_WritePtr(&lock->statsMem, NULL);
 
559
      }
458
560
 
459
561
      MXUserAddToList(&lock->header);
460
 
      MXUserAcquisitionStatsSetUp(&lock->acquisitionStats);
461
 
      MXUserBasicStatsSetUp(&lock->heldStats, MXUSER_STAT_CLASS_HELD);
462
 
#endif
463
562
   } else {
 
563
      if (lock->useNative) {
 
564
         MXUserNativeRWDestroy(&lock->nativeLock);
 
565
      }
 
566
 
464
567
      free(properName);
465
568
      free(lock);
466
569
      lock = NULL;
490
593
MXUser_DestroyRWLock(MXUserRWLock *lock)  // IN:
491
594
{
492
595
   if (LIKELY(lock != NULL)) {
 
596
      MXUserStats *stats;
 
597
 
493
598
      ASSERT(lock->header.signature == MXUSER_RW_SIGNATURE);
494
599
 
495
600
      if (Atomic_Read(&lock->holderCount) != 0) {
505
610
            MXUserDumpAndPanic(&lock->header, "%s: Internal error (%d)\n",
506
611
                               __FUNCTION__, err);
507
612
         }
508
 
 
509
 
#if defined(MXUSER_STATS)
510
 
         MXRecLockDestroy(&lock->recursiveLock);  
511
 
#endif
512
 
      } else {
513
 
         MXRecLockDestroy(&lock->recursiveLock);  
514
613
      }
515
614
 
516
 
#if defined(MXUSER_STATS)
 
615
      MXRecLockDestroy(&lock->recursiveLock);  
 
616
 
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));
522
 
#endif
523
 
 
524
 
      HashTable_Free(lock->holderTable);
 
618
 
 
619
      stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
620
 
 
621
      if (stats) {
 
622
         MXUserAcquisitionStatsTearDown(&stats->acquisitionStats);
 
623
         MXUserBasicStatsTearDown(&stats->heldStats);
 
624
         MXUserHistoTearDown(Atomic_ReadPtr(&stats->acquisitionHisto));
 
625
         MXUserHistoTearDown(Atomic_ReadPtr(&stats->heldHisto));
 
626
 
 
627
         free(stats);
 
628
      }
 
629
 
 
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;
528
634
      free(lock);
529
635
   }
551
657
MXUserGetHolderContext(MXUserRWLock *lock)  // IN:
552
658
{
553
659
   HolderContext *result;
554
 
   VThreadID tid = VThread_CurID();
 
660
   void *threadID = MXUserGetNativeTID();
555
661
 
556
662
   ASSERT(lock->holderTable);
557
663
 
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));
561
666
 
562
 
#if defined(MXUSER_STATS)
563
667
      newContext->holdStart = 0;
564
 
#endif
565
 
 
 
668
      newContext->holder = NULL;
566
669
      newContext->state = RW_UNLOCKED;
567
670
 
568
 
      result = HashTable_LookupOrInsert(lock->holderTable,
569
 
                                        (void *) (uintptr_t) tid,
 
671
      result = HashTable_LookupOrInsert(lock->holderTable, threadID,
570
672
                                        (void *) newContext);
571
673
 
572
674
      if (result != newContext) {
600
702
{
601
703
   int err = 0;
602
704
   Bool contended;
 
705
   MXUserStats *stats;
603
706
   HolderContext *myContext;
604
707
 
605
 
#if defined(MXUSER_STATS)
606
 
   VmTimeType begin;
607
 
   VmTimeType value;
608
 
   MXUserHisto *histo;
609
 
#endif
610
 
 
611
708
   ASSERT(lock && (lock->header.signature == MXUSER_RW_SIGNATURE));
612
709
 
613
710
   MXUserAcquisitionTracking(&lock->header, TRUE);
623
720
                                                                   "Write");
624
721
   }
625
722
 
626
 
#if defined(MXUSER_STATS)
627
 
   begin = Hostinfo_SystemTimerNS();
628
 
#endif
629
 
 
630
 
   contended = lock->useNative ? MXUserNativeRWAcquire(&lock->nativeLock,
631
 
                                                       forRead, &err) :
632
 
                                 MXRecLockAcquire(&lock->recursiveLock,
633
 
                                                  GetReturnAddress());
634
 
   if (UNLIKELY(err != 0)) {
635
 
      MXUserDumpAndPanic(&lock->header, "%s: Error %d: contended %d\n",
636
 
                         __FUNCTION__, err, contended);
637
 
   }
638
 
 
639
 
#if defined(MXUSER_STATS)
640
 
   value = Hostinfo_SystemTimerNS() - begin;
641
 
 
642
 
   /* The statistics are not atomically safe so protect them when necessary */
643
 
   if (forRead && lock->useNative) {
644
 
      MXRecLockAcquire(&lock->recursiveLock, GetReturnAddress());
645
 
   }
646
 
 
647
 
   MXUserAcquisitionSample(&lock->acquisitionStats, contended, value);
648
 
 
649
 
   histo = Atomic_ReadPtr(&lock->acquisitionHisto);
650
 
 
651
 
   if (UNLIKELY(histo != NULL)) {
652
 
      MXUserHistoSample(histo, value);
653
 
   }
654
 
 
655
 
   if (forRead && lock->useNative) {
656
 
      MXRecLockRelease(&lock->recursiveLock);
657
 
   }
658
 
#endif
 
723
   stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
724
 
 
725
   if (stats) {
 
726
      VmTimeType begin = Hostinfo_SystemTimerNS();
 
727
      VmTimeType value;
 
728
      MXUserHisto *histo;
 
729
 
 
730
      contended = lock->useNative ? MXUserNativeRWAcquire(&lock->nativeLock,
 
731
                                                          forRead, &err) :
 
732
                                    MXRecLockAcquire(&lock->recursiveLock);
 
733
 
 
734
      value = Hostinfo_SystemTimerNS() - begin;
 
735
 
 
736
      if (UNLIKELY(err != 0)) {
 
737
         MXUserDumpAndPanic(&lock->header, "%s: Error %d: contended %d\n",
 
738
                            __FUNCTION__, err, contended);
 
739
      }
 
740
 
 
741
      /*
 
742
       * The statistics are not atomically safe so protect them when
 
743
       * necessary
 
744
       */
 
745
 
 
746
      if (forRead && lock->useNative) {
 
747
         MXRecLockAcquire(&lock->recursiveLock);
 
748
      }
 
749
 
 
750
      MXUserAcquisitionSample(&stats->acquisitionStats, TRUE, contended,
 
751
                              value);
 
752
 
 
753
      histo = Atomic_ReadPtr(&stats->acquisitionHisto);
 
754
 
 
755
      if (UNLIKELY(histo != NULL)) {
 
756
         MXUserHistoSample(histo, value, GetReturnAddress());
 
757
      }
 
758
 
 
759
      if (forRead && lock->useNative) {
 
760
         MXRecLockRelease(&lock->recursiveLock);
 
761
      }
 
762
   } else {
 
763
      if (LIKELY(lock->useNative)) {
 
764
         MXUserNativeRWAcquire(&lock->nativeLock, forRead, &err);
 
765
      } else {
 
766
         MXRecLockAcquire(&lock->recursiveLock);
 
767
      }
 
768
   }
659
769
 
660
770
   if (!forRead || !lock->useNative) {
661
771
      ASSERT(Atomic_Read(&lock->holderCount) == 0);
664
774
   Atomic_Inc(&lock->holderCount);
665
775
   myContext->state = forRead ? RW_LOCKED_FOR_READ : RW_LOCKED_FOR_WRITE;
666
776
 
667
 
#if defined(MXUSER_STATS)
668
 
   myContext->holdStart = Hostinfo_SystemTimerNS();
669
 
#endif
 
777
   if (stats) {
 
778
      myContext->holder = GetReturnAddress();
 
779
      myContext->holdStart = Hostinfo_SystemTimerNS();
 
780
   }
670
781
}
671
782
 
672
783
 
675
786
 *
676
787
 * MXUser_AcquireForRead --
677
788
 *
678
 
 *      Acquire a read-write lock for read-shared access.
 
789
 *      Acquire a read-write lock for read-shared access. A thread may have
 
790
 *      only one read lock outstanding on a read-write lock - no recursive
 
791
 *      access.
679
792
 *
680
793
 * Results:
681
794
 *      The lock is acquired.
698
811
 *
699
812
 * MXUser_AcquireForWrite --
700
813
 *
701
 
 *      Acquire a read-write lock for write-exclusive access.
 
814
 *      Acquire a read-write lock for write-exclusive access. A thread may
 
815
 *      have only a single write lock outstanding on a read-write lock.
702
816
 *
703
817
 * Results:
704
818
 *      The lock is acquired.
754
868
      return myContext->state != RW_UNLOCKED;
755
869
 
756
870
   default:
757
 
#if defined(MXUSER_DEBUG)
758
871
      Panic("%s: unknown query type %d\n", __FUNCTION__, queryType);
759
 
#else   
760
 
      return FALSE;
761
 
#endif  
762
872
   }    
763
873
}
764
874
 
782
892
void
783
893
MXUser_ReleaseRWLock(MXUserRWLock *lock)  // IN/OUT:
784
894
{
 
895
   MXUserStats *stats;
785
896
   HolderContext *myContext;
786
897
 
787
 
#if defined(MXUSER_STATS)
788
 
   VmTimeType holdEnd = Hostinfo_SystemTimerNS();
789
 
   VmTimeType duration;
790
 
   MXUserHisto *histo;
791
 
#endif
792
 
 
793
898
   ASSERT(lock && (lock->header.signature == MXUSER_RW_SIGNATURE));
794
899
 
795
900
   myContext = MXUserGetHolderContext(lock);
796
901
 
 
902
   stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
 
903
 
 
904
   if (stats) {
 
905
      VmTimeType duration = Hostinfo_SystemTimerNS() - myContext->holdStart;
 
906
      MXUserHisto *histo;
 
907
 
 
908
      /*
 
909
       * The statistics are not always atomically safe so protect them
 
910
       * when necessary
 
911
       */
 
912
 
 
913
      if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
 
914
         MXRecLockAcquire(&lock->recursiveLock);
 
915
      }
 
916
 
 
917
      MXUserBasicStatsSample(&stats->heldStats, duration);
 
918
 
 
919
      histo = Atomic_ReadPtr(&stats->heldHisto);
 
920
 
 
921
      if (UNLIKELY(histo != NULL)) {
 
922
         MXUserHistoSample(histo, duration, myContext->holder);
 
923
         myContext->holder = NULL;
 
924
      }
 
925
 
 
926
      if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
 
927
         MXRecLockRelease(&lock->recursiveLock);
 
928
      }
 
929
   }
 
930
 
797
931
   if (UNLIKELY(myContext->state == RW_UNLOCKED)) {
798
932
      uint32 lockCount = Atomic_Read(&lock->holderCount);
799
933
 
803
937
                         lockCount == 0 ? "unacquired" : "acquired");
804
938
   }
805
939
 
806
 
#if defined(MXUSER_STATS)
807
 
   duration = holdEnd - myContext->holdStart;
808
 
 
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());
812
 
   }
813
 
 
814
 
   MXUserBasicStatsSample(&lock->heldStats, duration);
815
 
 
816
 
   histo = Atomic_ReadPtr(&lock->heldHisto);
817
 
 
818
 
   if (UNLIKELY(histo != NULL)) {
819
 
      MXUserHistoSample(histo, duration);
820
 
   }
821
 
 
822
 
   if ((myContext->state == RW_LOCKED_FOR_READ) && lock->useNative) {
823
 
      MXRecLockRelease(&lock->recursiveLock);
824
 
   }
825
 
#endif
826
 
 
827
940
   MXUserReleaseTracking(&lock->header);
828
941
 
829
942
   Atomic_Dec(&lock->holderCount);
830
943
 
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);
833
947
 
834
948
      if (UNLIKELY(err != 0)) {
835
949
         MXUserDumpAndPanic(&lock->header, "%s: Internal error (%d)\n",
875
989
   lock = (MXUserRWLock *) Atomic_ReadPtr(lockStorage);
876
990
 
877
991
   if (UNLIKELY(lock == NULL)) {
878
 
      MXUserRWLock *before;
879
 
 
880
 
      lock = MXUser_CreateRWLock(name, rank);
881
 
 
882
 
      before = (MXUserRWLock *) Atomic_ReadIfEqualWritePtr(lockStorage, NULL,
883
 
                                                           (void *) lock);
884
 
 
885
 
      if (before) {
886
 
         MXUser_DestroyRWLock(lock);
887
 
 
888
 
         lock = before;
 
992
      MXUserRWLock *newLock = MXUser_CreateRWLock(name, rank);
 
993
 
 
994
      lock = (MXUserRWLock *) Atomic_ReadIfEqualWritePtr(lockStorage, NULL,
 
995
                                                         (void *) newLock);
 
996
 
 
997
      if (lock) {
 
998
         MXUser_DestroyRWLock(newLock);
 
999
      } else {
 
1000
         lock = (MXUserRWLock *) Atomic_ReadPtr(lockStorage);
889
1001
      }
890
1002
   }
891
1003