< prev index next >

src/hotspot/share/runtime/objectMonitor.cpp

Print this page
rev 51780 : imported patch syncknobs-00-base
rev 51781 : imported patch syncknobs-01-Knob_ReportSettings
rev 51782 : imported patch syncknobs-02-Knob_SpinBackOff
rev 51783 : imported patch syncknobs-03-BackOffMask
rev 51784 : imported patch syncknobs-04-Knob_ExitRelease
rev 51785 : imported patch syncknobs-05-Knob_InlineNotify
rev 51786 : imported patch syncknobs-06-Knob_Verbose
rev 51787 : imported patch syncknobs-07-Knob_VerifyInUse
rev 51788 : imported patch syncknobs-08-Knob_VerifyMatch
rev 51789 : imported patch syncknobs-09-Knob_SpinBase
rev 51790 : imported patch syncknobs-10-Knob_CASPenalty
rev 51791 : imported patch syncknobs-11-Knob_OXPenalty
rev 51792 : imported patch syncknobs-12-Knob_SpinSetSucc
rev 51793 : imported patch syncknobs-13-Knob_SpinEarly
rev 51794 : imported patch syncknobs-14-Knob_SuccEnabled
rev 51795 : imported patch syncknobs-15-Knob_SuccRestrict
rev 51796 : imported patch syncknobs-16-Knob_MaxSpinners
rev 51797 : imported patch syncknobs-17-Knob_SpinAfterFutile
rev 51798 : imported patch syncknobs-18-Knob_OState
rev 51799 : imported patch syncknobs-19-Knob_UsePause
rev 51800 : imported patch syncknobs-20-Knob_ExitPolicy
rev 51801 : imported patch syncknobs-21-Knob_ResetEvent
rev 51802 : imported patch syncknobs-22-Knob_FastHSSEC
rev 51803 : imported patch syncknobs-23-Knob_MoveNotifyee


  93 #else //  ndef DTRACE_ENABLED
  94 
  95 #define DTRACE_MONITOR_WAIT_PROBE(obj, thread, millis, mon)    {;}
  96 #define DTRACE_MONITOR_PROBE(probe, obj, thread, mon)          {;}
  97 
  98 #endif // ndef DTRACE_ENABLED
  99 
 100 // Tunables ...
 101 // The knob* variables are effectively final.  Once set they should
 102 // never be modified hence.  Consider using __read_mostly with GCC.
 103 
 104 int ObjectMonitor::Knob_SpinLimit    = 5000;    // derived by an external tool -
 105 
 106 static int Knob_Bonus               = 100;     // spin success bonus
 107 static int Knob_BonusB              = 100;     // spin success bonus
 108 static int Knob_Penalty             = 200;     // spin failure penalty
 109 static int Knob_Poverty             = 1000;
 110 static int Knob_FixedSpin           = 0;
 111 static int Knob_PreSpin             = 10;      // 20-100 likely better
 112 
 113 static int Knob_MoveNotifyee        = 2;       // notify() - disposition of notifyee
 114 static int Knob_QMode               = 0;       // EntryList-cxq policy - queue discipline
 115 static volatile int InitDone        = 0;
 116 
 117 // -----------------------------------------------------------------------------
 118 // Theory of operations -- Monitors lists, thread residency, etc:
 119 //
 120 // * A thread acquires ownership of a monitor by successfully
 121 //   CAS()ing the _owner field from null to non-null.
 122 //
 123 // * Invariant: A thread appears on at most one monitor list --
 124 //   cxq, EntryList or WaitSet -- at any one time.
 125 //
 126 // * Contending threads "push" themselves onto the cxq with CAS
 127 //   and then spin/park.
 128 //
 129 // * After a contending thread eventually acquires the lock it must
 130 //   dequeue itself from either the EntryList or the cxq.
 131 //
 132 // * The exiting thread identifies and unparks an "heir presumptive"
 133 //   tentative successor thread on the EntryList.  Critically, the


1506   // check if the notification happened
1507   if (!WasNotified) {
1508     // no, it could be timeout or Thread.interrupt() or both
1509     // check for interrupt event, otherwise it is timeout
1510     if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
1511       THROW(vmSymbols::java_lang_InterruptedException());
1512     }
1513   }
1514 
1515   // NOTE: Spurious wake up will be consider as timeout.
1516   // Monitor notify has precedence over thread interrupt.
1517 }
1518 
1519 
1520 // Consider:
1521 // If the lock is cool (cxq == null && succ == null) and we're on an MP system
1522 // then instead of transferring a thread from the WaitSet to the EntryList
1523 // we might just dequeue a thread from the WaitSet and directly unpark() it.
1524 
1525 void ObjectMonitor::INotify(Thread * Self) {
1526   const int policy = Knob_MoveNotifyee;
1527 
1528   Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");
1529   ObjectWaiter * iterator = DequeueWaiter();
1530   if (iterator != NULL) {
1531     guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant");
1532     guarantee(iterator->_notified == 0, "invariant");
1533     // Disposition - what might we do with iterator ?
1534     // a.  add it directly to the EntryList - either tail (policy == 1)
1535     //     or head (policy == 0).
1536     // b.  push it onto the front of the _cxq (policy == 2).
1537     // For now we use (b).
1538     if (policy != 4) {
1539       iterator->TState = ObjectWaiter::TS_ENTER;
1540     }
1541     iterator->_notified = 1;
1542     iterator->_notifier_tid = JFR_THREAD_ID(Self);
1543 
1544     ObjectWaiter * list = _EntryList;
1545     if (list != NULL) {
1546       assert(list->_prev == NULL, "invariant");
1547       assert(list->TState == ObjectWaiter::TS_ENTER, "invariant");
1548       assert(list != iterator, "invariant");
1549     }
1550 
1551     if (policy == 0) {       // prepend to EntryList
1552       if (list == NULL) {
1553         iterator->_next = iterator->_prev = NULL;
1554         _EntryList = iterator;
1555       } else {
1556         list->_prev = iterator;
1557         iterator->_next = list;
1558         iterator->_prev = NULL;
1559         _EntryList = iterator;
1560       }
1561     } else if (policy == 1) {      // append to EntryList
1562       if (list == NULL) {
1563         iterator->_next = iterator->_prev = NULL;
1564         _EntryList = iterator;
1565       } else {
1566         // CONSIDER:  finding the tail currently requires a linear-time walk of
1567         // the EntryList.  We can make tail access constant-time by converting to
1568         // a CDLL instead of using our current DLL.
1569         ObjectWaiter * tail;
1570         for (tail = list; tail->_next != NULL; tail = tail->_next) {}
1571         assert(tail != NULL && tail->_next == NULL, "invariant");
1572         tail->_next = iterator;
1573         iterator->_prev = tail;
1574         iterator->_next = NULL;
1575       }
1576     } else if (policy == 2) {      // prepend to cxq
1577       if (list == NULL) {
1578         iterator->_next = iterator->_prev = NULL;
1579         _EntryList = iterator;
1580       } else {
1581         iterator->TState = ObjectWaiter::TS_CXQ;
1582         for (;;) {
1583           ObjectWaiter * front = _cxq;
1584           iterator->_next = front;
1585           if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
1586             break;
1587           }
1588         }
1589       }
1590     } else if (policy == 3) {      // append to cxq
1591       iterator->TState = ObjectWaiter::TS_CXQ;
1592       for (;;) {
1593         ObjectWaiter * tail = _cxq;
1594         if (tail == NULL) {
1595           iterator->_next = NULL;
1596           if (Atomic::replace_if_null(iterator, &_cxq)) {
1597             break;
1598           }
1599         } else {
1600           while (tail->_next != NULL) tail = tail->_next;
1601           tail->_next = iterator;
1602           iterator->_prev = tail;
1603           iterator->_next = NULL;
1604           break;
1605         }
1606       }
1607     } else {
1608       ParkEvent * ev = iterator->_event;
1609       iterator->TState = ObjectWaiter::TS_RUN;
1610       OrderAccess::fence();
1611       ev->unpark();
1612     }
1613 
1614     // _WaitSetLock protects the wait queue, not the EntryList.  We could
1615     // move the add-to-EntryList operation, above, outside the critical section
1616     // protected by _WaitSetLock.  In practice that's not useful.  With the
1617     // exception of  wait() timeouts and interrupts the monitor owner
1618     // is the only thread that grabs _WaitSetLock.  There's almost no contention
1619     // on _WaitSetLock so it's not profitable to reduce the length of the
1620     // critical section.
1621 
1622     if (policy < 4) {
1623       iterator->wait_reenter_begin(this);
1624     }
1625   }
1626   Thread::SpinRelease(&_WaitSetLock);
1627 }
1628 
1629 // Consider: a not-uncommon synchronization bug is to use notify() when
1630 // notifyAll() is more appropriate, potentially resulting in stranded
1631 // threads; this is one example of a lost wakeup. A useful diagnostic
1632 // option is to force all notify() operations to behave as notifyAll().
1633 //
1634 // Note: We can also detect many such problems with a "minimum wait".
1635 // When the "minimum wait" is set to a small non-zero timeout value
1636 // and the program does not hang whereas it did absent "minimum wait",
1637 // that suggests a lost wakeup bug.
1638 
1639 void ObjectMonitor::notify(TRAPS) {
1640   CHECK_OWNER();
1641   if (_WaitSet == NULL) {
1642     return;
1643   }
1644   DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);




  93 #else //  ndef DTRACE_ENABLED
  94 
  95 #define DTRACE_MONITOR_WAIT_PROBE(obj, thread, millis, mon)    {;}
  96 #define DTRACE_MONITOR_PROBE(probe, obj, thread, mon)          {;}
  97 
  98 #endif // ndef DTRACE_ENABLED
  99 
 100 // Tunables ...
 101 // The knob* variables are effectively final.  Once set they should
 102 // never be modified hence.  Consider using __read_mostly with GCC.
 103 
 104 int ObjectMonitor::Knob_SpinLimit    = 5000;    // derived by an external tool -
 105 
 106 static int Knob_Bonus               = 100;     // spin success bonus
 107 static int Knob_BonusB              = 100;     // spin success bonus
 108 static int Knob_Penalty             = 200;     // spin failure penalty
 109 static int Knob_Poverty             = 1000;
 110 static int Knob_FixedSpin           = 0;
 111 static int Knob_PreSpin             = 10;      // 20-100 likely better
 112 

 113 static int Knob_QMode               = 0;       // EntryList-cxq policy - queue discipline
 114 static volatile int InitDone        = 0;
 115 
 116 // -----------------------------------------------------------------------------
 117 // Theory of operations -- Monitors lists, thread residency, etc:
 118 //
 119 // * A thread acquires ownership of a monitor by successfully
 120 //   CAS()ing the _owner field from null to non-null.
 121 //
 122 // * Invariant: A thread appears on at most one monitor list --
 123 //   cxq, EntryList or WaitSet -- at any one time.
 124 //
 125 // * Contending threads "push" themselves onto the cxq with CAS
 126 //   and then spin/park.
 127 //
 128 // * After a contending thread eventually acquires the lock it must
 129 //   dequeue itself from either the EntryList or the cxq.
 130 //
 131 // * The exiting thread identifies and unparks an "heir presumptive"
 132 //   tentative successor thread on the EntryList.  Critically, the


1505   // check if the notification happened
1506   if (!WasNotified) {
1507     // no, it could be timeout or Thread.interrupt() or both
1508     // check for interrupt event, otherwise it is timeout
1509     if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
1510       THROW(vmSymbols::java_lang_InterruptedException());
1511     }
1512   }
1513 
1514   // NOTE: Spurious wake up will be consider as timeout.
1515   // Monitor notify has precedence over thread interrupt.
1516 }
1517 
1518 
1519 // Consider:
1520 // If the lock is cool (cxq == null && succ == null) and we're on an MP system
1521 // then instead of transferring a thread from the WaitSet to the EntryList
1522 // we might just dequeue a thread from the WaitSet and directly unpark() it.
1523 
1524 void ObjectMonitor::INotify(Thread * Self) {


1525   Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");
1526   ObjectWaiter * iterator = DequeueWaiter();
1527   if (iterator != NULL) {
1528     guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant");
1529     guarantee(iterator->_notified == 0, "invariant");
1530     // Disposition - what might we do with iterator ?
1531     // a.  add it directly to the EntryList - either tail (policy == 1)
1532     //     or head (policy == 0).
1533     // b.  push it onto the front of the _cxq (policy == 2).
1534     // For now we use (b).
1535 
1536     iterator->TState = ObjectWaiter::TS_ENTER;
1537 
1538     iterator->_notified = 1;
1539     iterator->_notifier_tid = JFR_THREAD_ID(Self);
1540 
1541     ObjectWaiter * list = _EntryList;
1542     if (list != NULL) {
1543       assert(list->_prev == NULL, "invariant");
1544       assert(list->TState == ObjectWaiter::TS_ENTER, "invariant");
1545       assert(list != iterator, "invariant");
1546     }
1547 
1548     // prepend to cxq

























1549     if (list == NULL) {
1550       iterator->_next = iterator->_prev = NULL;
1551       _EntryList = iterator;
1552     } else {
1553       iterator->TState = ObjectWaiter::TS_CXQ;
1554       for (;;) {
1555         ObjectWaiter * front = _cxq;
1556         iterator->_next = front;
1557         if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
1558           break;
1559         }
1560       }
1561     }























1562 
1563     // _WaitSetLock protects the wait queue, not the EntryList.  We could
1564     // move the add-to-EntryList operation, above, outside the critical section
1565     // protected by _WaitSetLock.  In practice that's not useful.  With the
1566     // exception of  wait() timeouts and interrupts the monitor owner
1567     // is the only thread that grabs _WaitSetLock.  There's almost no contention
1568     // on _WaitSetLock so it's not profitable to reduce the length of the
1569     // critical section.
1570 

1571     iterator->wait_reenter_begin(this);

1572   }
1573   Thread::SpinRelease(&_WaitSetLock);
1574 }
1575 
1576 // Consider: a not-uncommon synchronization bug is to use notify() when
1577 // notifyAll() is more appropriate, potentially resulting in stranded
1578 // threads; this is one example of a lost wakeup. A useful diagnostic
1579 // option is to force all notify() operations to behave as notifyAll().
1580 //
1581 // Note: We can also detect many such problems with a "minimum wait".
1582 // When the "minimum wait" is set to a small non-zero timeout value
1583 // and the program does not hang whereas it did absent "minimum wait",
1584 // that suggests a lost wakeup bug.
1585 
1586 void ObjectMonitor::notify(TRAPS) {
1587   CHECK_OWNER();
1588   if (_WaitSet == NULL) {
1589     return;
1590   }
1591   DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);


< prev index next >