< 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
rev 51804 : imported patch syncknobs-24-Knob_QMode


  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
 133 //   exiting thread doesn't unlink the successor thread from the EntryList.


 943     // thread would need to dequeue and wake a successor.
 944     // (Note that we'd need to make the post-drop spin short, but no
 945     // shorter than the worst-case round-trip cache-line migration time.
 946     // The dropped lock needs to become visible to the spinner, and then
 947     // the acquisition of the lock by the spinner must become visible to
 948     // the exiting thread).
 949 
 950     // It appears that an heir-presumptive (successor) must be made ready.
 951     // Only the current lock owner can manipulate the EntryList or
 952     // drain _cxq, so we need to reacquire the lock.  If we fail
 953     // to reacquire the lock the responsibility for ensuring succession
 954     // falls to the new owner.
 955     //
 956     if (!Atomic::replace_if_null(THREAD, &_owner)) {
 957       return;
 958     }
 959 
 960     guarantee(_owner == THREAD, "invariant");
 961 
 962     ObjectWaiter * w = NULL;
 963     int QMode = Knob_QMode;
 964 
 965     if (QMode == 2 && _cxq != NULL) {
 966       // QMode == 2 : cxq has precedence over EntryList.
 967       // Try to directly wake a successor from the cxq.
 968       // If successful, the successor will need to unlink itself from cxq.
 969       w = _cxq;
 970       assert(w != NULL, "invariant");
 971       assert(w->TState == ObjectWaiter::TS_CXQ, "Invariant");
 972       ExitEpilog(Self, w);
 973       return;
 974     }
 975 
 976     if (QMode == 3 && _cxq != NULL) {
 977       // Aggressively drain cxq into EntryList at the first opportunity.
 978       // This policy ensure that recently-run threads live at the head of EntryList.
 979       // Drain _cxq into EntryList - bulk transfer.
 980       // First, detach _cxq.
 981       // The following loop is tantamount to: w = swap(&cxq, NULL)
 982       w = _cxq;
 983       for (;;) {
 984         assert(w != NULL, "Invariant");
 985         ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
 986         if (u == w) break;
 987         w = u;
 988       }
 989       assert(w != NULL, "invariant");
 990 
 991       ObjectWaiter * q = NULL;
 992       ObjectWaiter * p;
 993       for (p = w; p != NULL; p = p->_next) {
 994         guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
 995         p->TState = ObjectWaiter::TS_ENTER;
 996         p->_prev = q;
 997         q = p;
 998       }
 999 
1000       // Append the RATs to the EntryList
1001       // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
1002       ObjectWaiter * Tail;
1003       for (Tail = _EntryList; Tail != NULL && Tail->_next != NULL;
1004            Tail = Tail->_next)
1005         /* empty */;
1006       if (Tail == NULL) {
1007         _EntryList = w;
1008       } else {
1009         Tail->_next = w;
1010         w->_prev = Tail;
1011       }
1012 
1013       // Fall thru into code that tries to wake a successor from EntryList
1014     }
1015 
1016     if (QMode == 4 && _cxq != NULL) {
1017       // Aggressively drain cxq into EntryList at the first opportunity.
1018       // This policy ensure that recently-run threads live at the head of EntryList.
1019 
1020       // Drain _cxq into EntryList - bulk transfer.
1021       // First, detach _cxq.
1022       // The following loop is tantamount to: w = swap(&cxq, NULL)
1023       w = _cxq;
1024       for (;;) {
1025         assert(w != NULL, "Invariant");
1026         ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
1027         if (u == w) break;
1028         w = u;
1029       }
1030       assert(w != NULL, "invariant");
1031 
1032       ObjectWaiter * q = NULL;
1033       ObjectWaiter * p;
1034       for (p = w; p != NULL; p = p->_next) {
1035         guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
1036         p->TState = ObjectWaiter::TS_ENTER;
1037         p->_prev = q;
1038         q = p;
1039       }
1040 
1041       // Prepend the RATs to the EntryList
1042       if (_EntryList != NULL) {
1043         q->_next = _EntryList;
1044         _EntryList->_prev = q;
1045       }
1046       _EntryList = w;
1047 
1048       // Fall thru into code that tries to wake a successor from EntryList
1049     }
1050 
1051     w = _EntryList;
1052     if (w != NULL) {
1053       // I'd like to write: guarantee (w->_thread != Self).
1054       // But in practice an exiting thread may find itself on the EntryList.
1055       // Let's say thread T1 calls O.wait().  Wait() enqueues T1 on O's waitset and
1056       // then calls exit().  Exit release the lock by setting O._owner to NULL.
1057       // Let's say T1 then stalls.  T2 acquires O and calls O.notify().  The
1058       // notify() operation moves T1 from O's waitset to O's EntryList. T2 then
1059       // release the lock "O".  T2 resumes immediately after the ST of null into
1060       // _owner, above.  T2 notices that the EntryList is populated, so it
1061       // reacquires the lock and then finds itself on the EntryList.
1062       // Given all that, we have to tolerate the circumstance where "w" is
1063       // associated with Self.
1064       assert(w->TState == ObjectWaiter::TS_ENTER, "invariant");
1065       ExitEpilog(Self, w);
1066       return;
1067     }
1068 
1069     // If we find that both _cxq and EntryList are null then just


1076     // The following loop is tantamount to: w = swap(&cxq, NULL)
1077     for (;;) {
1078       assert(w != NULL, "Invariant");
1079       ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
1080       if (u == w) break;
1081       w = u;
1082     }
1083 
1084     assert(w != NULL, "invariant");
1085     assert(_EntryList == NULL, "invariant");
1086 
1087     // Convert the LIFO SLL anchored by _cxq into a DLL.
1088     // The list reorganization step operates in O(LENGTH(w)) time.
1089     // It's critical that this step operate quickly as
1090     // "Self" still holds the outer-lock, restricting parallelism
1091     // and effectively lengthening the critical section.
1092     // Invariant: s chases t chases u.
1093     // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
1094     // we have faster access to the tail.
1095 
1096     if (QMode == 1) {
1097       // QMode == 1 : drain cxq to EntryList, reversing order
1098       // We also reverse the order of the list.
1099       ObjectWaiter * s = NULL;
1100       ObjectWaiter * t = w;
1101       ObjectWaiter * u = NULL;
1102       while (t != NULL) {
1103         guarantee(t->TState == ObjectWaiter::TS_CXQ, "invariant");
1104         t->TState = ObjectWaiter::TS_ENTER;
1105         u = t->_next;
1106         t->_prev = u;
1107         t->_next = s;
1108         s = t;
1109         t = u;
1110       }
1111       _EntryList  = s;
1112       assert(s != NULL, "invariant");
1113     } else {
1114       // QMode == 0 or QMode == 2
1115       _EntryList = w;
1116       ObjectWaiter * q = NULL;
1117       ObjectWaiter * p;
1118       for (p = w; p != NULL; p = p->_next) {
1119         guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
1120         p->TState = ObjectWaiter::TS_ENTER;
1121         p->_prev = q;
1122         q = p;
1123       }
1124     }
1125 
1126     // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
1127     // The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
1128 
1129     // See if we can abdicate to a spinner instead of waking a thread.
1130     // A primary goal of the implementation is to reduce the
1131     // context-switch rate.
1132     if (_succ != NULL) continue;
1133 
1134     w = _EntryList;
1135     if (w != NULL) {
1136       guarantee(w->TState == ObjectWaiter::TS_ENTER, "invariant");
1137       ExitEpilog(Self, w);
1138       return;
1139     }
1140   }
1141 }
1142 
1143 // ExitSuspendEquivalent:




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


 942     // thread would need to dequeue and wake a successor.
 943     // (Note that we'd need to make the post-drop spin short, but no
 944     // shorter than the worst-case round-trip cache-line migration time.
 945     // The dropped lock needs to become visible to the spinner, and then
 946     // the acquisition of the lock by the spinner must become visible to
 947     // the exiting thread).
 948 
 949     // It appears that an heir-presumptive (successor) must be made ready.
 950     // Only the current lock owner can manipulate the EntryList or
 951     // drain _cxq, so we need to reacquire the lock.  If we fail
 952     // to reacquire the lock the responsibility for ensuring succession
 953     // falls to the new owner.
 954     //
 955     if (!Atomic::replace_if_null(THREAD, &_owner)) {
 956       return;
 957     }
 958 
 959     guarantee(_owner == THREAD, "invariant");
 960 
 961     ObjectWaiter * w = NULL;























































































 962 
 963     w = _EntryList;
 964     if (w != NULL) {
 965       // I'd like to write: guarantee (w->_thread != Self).
 966       // But in practice an exiting thread may find itself on the EntryList.
 967       // Let's say thread T1 calls O.wait().  Wait() enqueues T1 on O's waitset and
 968       // then calls exit().  Exit release the lock by setting O._owner to NULL.
 969       // Let's say T1 then stalls.  T2 acquires O and calls O.notify().  The
 970       // notify() operation moves T1 from O's waitset to O's EntryList. T2 then
 971       // release the lock "O".  T2 resumes immediately after the ST of null into
 972       // _owner, above.  T2 notices that the EntryList is populated, so it
 973       // reacquires the lock and then finds itself on the EntryList.
 974       // Given all that, we have to tolerate the circumstance where "w" is
 975       // associated with Self.
 976       assert(w->TState == ObjectWaiter::TS_ENTER, "invariant");
 977       ExitEpilog(Self, w);
 978       return;
 979     }
 980 
 981     // If we find that both _cxq and EntryList are null then just


 988     // The following loop is tantamount to: w = swap(&cxq, NULL)
 989     for (;;) {
 990       assert(w != NULL, "Invariant");
 991       ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
 992       if (u == w) break;
 993       w = u;
 994     }
 995 
 996     assert(w != NULL, "invariant");
 997     assert(_EntryList == NULL, "invariant");
 998 
 999     // Convert the LIFO SLL anchored by _cxq into a DLL.
1000     // The list reorganization step operates in O(LENGTH(w)) time.
1001     // It's critical that this step operate quickly as
1002     // "Self" still holds the outer-lock, restricting parallelism
1003     // and effectively lengthening the critical section.
1004     // Invariant: s chases t chases u.
1005     // TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
1006     // we have faster access to the tail.
1007 



















1008     _EntryList = w;
1009     ObjectWaiter * q = NULL;
1010     ObjectWaiter * p;
1011     for (p = w; p != NULL; p = p->_next) {
1012       guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
1013       p->TState = ObjectWaiter::TS_ENTER;
1014       p->_prev = q;
1015       q = p;

1016     }
1017 
1018     // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
1019     // The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
1020 
1021     // See if we can abdicate to a spinner instead of waking a thread.
1022     // A primary goal of the implementation is to reduce the
1023     // context-switch rate.
1024     if (_succ != NULL) continue;
1025 
1026     w = _EntryList;
1027     if (w != NULL) {
1028       guarantee(w->TState == ObjectWaiter::TS_ENTER, "invariant");
1029       ExitEpilog(Self, w);
1030       return;
1031     }
1032   }
1033 }
1034 
1035 // ExitSuspendEquivalent:


< prev index next >