240 // and last are the inflated Java Monitor (ObjectMonitor) checks. |
240 // and last are the inflated Java Monitor (ObjectMonitor) checks. |
241 lock->set_displaced_header(markOopDesc::unused_mark()); |
241 lock->set_displaced_header(markOopDesc::unused_mark()); |
242 |
242 |
243 if (owner == NULL && Atomic::replace_if_null(Self, &(m->_owner))) { |
243 if (owner == NULL && Atomic::replace_if_null(Self, &(m->_owner))) { |
244 assert(m->_recursions == 0, "invariant"); |
244 assert(m->_recursions == 0, "invariant"); |
245 assert(m->_owner == Self, "invariant"); |
|
246 return true; |
245 return true; |
247 } |
246 } |
248 } |
247 } |
249 |
248 |
250 // Note that we could inflate in quick_enter. |
249 // Note that we could inflate in quick_enter. |
1028 // and list coherency traffic, but also tends to increase the |
1027 // and list coherency traffic, but also tends to increase the |
1029 // number of objectMonitors in circulation as well as the STW |
1028 // number of objectMonitors in circulation as well as the STW |
1030 // scavenge costs. As usual, we lean toward time in space-time |
1029 // scavenge costs. As usual, we lean toward time in space-time |
1031 // tradeoffs. |
1030 // tradeoffs. |
1032 const int MAXPRIVATE = 1024; |
1031 const int MAXPRIVATE = 1024; |
|
1032 stringStream ss; |
1033 for (;;) { |
1033 for (;;) { |
1034 ObjectMonitor * m; |
1034 ObjectMonitor * m; |
1035 |
1035 |
1036 // 1: try to allocate from the thread's local omFreeList. |
1036 // 1: try to allocate from the thread's local omFreeList. |
1037 // Threads will attempt to allocate first from their local list, then |
1037 // Threads will attempt to allocate first from their local list, then |
1063 for (int i = Self->omFreeProvision; --i >= 0 && gFreeList != NULL;) { |
1063 for (int i = Self->omFreeProvision; --i >= 0 && gFreeList != NULL;) { |
1064 gMonitorFreeCount--; |
1064 gMonitorFreeCount--; |
1065 ObjectMonitor * take = gFreeList; |
1065 ObjectMonitor * take = gFreeList; |
1066 gFreeList = take->FreeNext; |
1066 gFreeList = take->FreeNext; |
1067 guarantee(take->object() == NULL, "invariant"); |
1067 guarantee(take->object() == NULL, "invariant"); |
1068 guarantee(!take->is_busy(), "invariant"); |
|
1069 take->Recycle(); |
1068 take->Recycle(); |
1070 omRelease(Self, take, false); |
1069 omRelease(Self, take, false); |
1071 } |
1070 } |
1072 Thread::muxRelease(&gListLock); |
1071 Thread::muxRelease(&gListLock); |
1073 Self->omFreeProvision += 1 + (Self->omFreeProvision/2); |
1072 Self->omFreeProvision += 1 + (Self->omFreeProvision/2); |
1165 |
1164 |
1166 void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m, |
1165 void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m, |
1167 bool fromPerThreadAlloc) { |
1166 bool fromPerThreadAlloc) { |
1168 guarantee(m->header() == NULL, "invariant"); |
1167 guarantee(m->header() == NULL, "invariant"); |
1169 guarantee(m->object() == NULL, "invariant"); |
1168 guarantee(m->object() == NULL, "invariant"); |
1170 guarantee(((m->is_busy()|m->_recursions) == 0), "freeing in-use monitor"); |
1169 stringStream ss; |
|
1170 guarantee((m->is_busy() | m->_recursions) == 0, "freeing in-use monitor: " |
|
1171 "%s, recursions=" INTPTR_FORMAT, m->is_busy_to_string(&ss), |
|
1172 m->_recursions); |
1171 // Remove from omInUseList |
1173 // Remove from omInUseList |
1172 if (fromPerThreadAlloc) { |
1174 if (fromPerThreadAlloc) { |
1173 ObjectMonitor* cur_mid_in_use = NULL; |
1175 ObjectMonitor* cur_mid_in_use = NULL; |
1174 bool extracted = false; |
1176 bool extracted = false; |
1175 for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; cur_mid_in_use = mid, mid = mid->FreeNext) { |
1177 for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; cur_mid_in_use = mid, mid = mid->FreeNext) { |
1218 ObjectMonitor * list = Self->omFreeList; // Null-terminated SLL |
1220 ObjectMonitor * list = Self->omFreeList; // Null-terminated SLL |
1219 ObjectMonitor * tail = NULL; |
1221 ObjectMonitor * tail = NULL; |
1220 int tally = 0; |
1222 int tally = 0; |
1221 if (list != NULL) { |
1223 if (list != NULL) { |
1222 ObjectMonitor * s; |
1224 ObjectMonitor * s; |
1223 // The thread is going away, the per-thread free monitors |
1225 // The thread is going away. Set 'tail' to the last per-thread free |
1224 // are freed via set_owner(NULL) |
1226 // monitor which will be linked to gFreeList below under the gListLock. |
1225 // Link them to tail, which will be linked into the global free list |
1227 stringStream ss; |
1226 // gFreeList below, under the gListLock |
|
1227 for (s = list; s != NULL; s = s->FreeNext) { |
1228 for (s = list; s != NULL; s = s->FreeNext) { |
1228 tally++; |
1229 tally++; |
1229 tail = s; |
1230 tail = s; |
1230 guarantee(s->object() == NULL, "invariant"); |
1231 guarantee(s->object() == NULL, "invariant"); |
1231 guarantee(!s->is_busy(), "invariant"); |
1232 guarantee(!s->is_busy(), "must be !is_busy: %s", s->is_busy_to_string(&ss)); |
1232 s->set_owner(NULL); // redundant but good hygiene |
|
1233 } |
1233 } |
1234 guarantee(tail != NULL, "invariant"); |
1234 guarantee(tail != NULL, "invariant"); |
1235 assert(Self->omFreeCount == tally, "free-count off"); |
1235 assert(Self->omFreeCount == tally, "free-count off"); |
1236 Self->omFreeList = NULL; |
1236 Self->omFreeList = NULL; |
1237 Self->omFreeCount = 0; |
1237 Self->omFreeCount = 0; |
1377 // Optimistically prepare the objectmonitor - anticipate successful CAS |
1377 // Optimistically prepare the objectmonitor - anticipate successful CAS |
1378 // We do this before the CAS in order to minimize the length of time |
1378 // We do this before the CAS in order to minimize the length of time |
1379 // in which INFLATING appears in the mark. |
1379 // in which INFLATING appears in the mark. |
1380 m->Recycle(); |
1380 m->Recycle(); |
1381 m->_Responsible = NULL; |
1381 m->_Responsible = NULL; |
1382 m->_recursions = 0; |
|
1383 m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // Consider: maintain by type/class |
1382 m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // Consider: maintain by type/class |
1384 |
1383 |
1385 markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark); |
1384 markOop cmp = object->cas_set_mark(markOopDesc::INFLATING(), mark); |
1386 if (cmp != mark) { |
1385 if (cmp != mark) { |
1387 omRelease(Self, m, true); |
1386 omRelease(Self, m, true); |
1470 assert(mark->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(mark)); |
1469 assert(mark->is_neutral(), "invariant: header=" INTPTR_FORMAT, p2i(mark)); |
1471 ObjectMonitor * m = omAlloc(Self); |
1470 ObjectMonitor * m = omAlloc(Self); |
1472 // prepare m for installation - set monitor to initial state |
1471 // prepare m for installation - set monitor to initial state |
1473 m->Recycle(); |
1472 m->Recycle(); |
1474 m->set_header(mark); |
1473 m->set_header(mark); |
1475 m->set_owner(NULL); |
|
1476 m->set_object(object); |
1474 m->set_object(object); |
1477 m->_recursions = 0; |
|
1478 m->_Responsible = NULL; |
1475 m->_Responsible = NULL; |
1479 m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class |
1476 m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class |
1480 |
1477 |
1481 if (object->cas_set_mark(markOopDesc::encode(m), mark) != mark) { |
1478 if (object->cas_set_mark(markOopDesc::encode(m), mark) != mark) { |
1482 m->set_header(NULL); |
1479 m->set_header(NULL); |
1923 } |
1920 } |
1924 |
1921 |
1925 // Check a free monitor entry; log any errors. |
1922 // Check a free monitor entry; log any errors. |
1926 void ObjectSynchronizer::chk_free_entry(JavaThread * jt, ObjectMonitor * n, |
1923 void ObjectSynchronizer::chk_free_entry(JavaThread * jt, ObjectMonitor * n, |
1927 outputStream * out, int *error_cnt_p) { |
1924 outputStream * out, int *error_cnt_p) { |
|
1925 stringStream ss; |
1928 if (n->is_busy()) { |
1926 if (n->is_busy()) { |
1929 if (jt != NULL) { |
1927 if (jt != NULL) { |
1930 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
1928 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
1931 ": free per-thread monitor must not be busy.", p2i(jt), |
1929 ": free per-thread monitor must not be busy: %s", p2i(jt), |
1932 p2i(n)); |
1930 p2i(n), n->is_busy_to_string(&ss)); |
1933 } else { |
1931 } else { |
1934 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " |
1932 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " |
1935 "must not be busy.", p2i(n)); |
1933 "must not be busy: %s", p2i(n), n->is_busy_to_string(&ss)); |
1936 } |
1934 } |
1937 *error_cnt_p = *error_cnt_p + 1; |
1935 *error_cnt_p = *error_cnt_p + 1; |
1938 } |
1936 } |
1939 if (n->header() != NULL) { |
1937 if (n->header() != NULL) { |
1940 if (jt != NULL) { |
1938 if (jt != NULL) { |
2109 if (!on_exit) { |
2107 if (!on_exit) { |
2110 // Not at VM exit so grab the global list lock. |
2108 // Not at VM exit so grab the global list lock. |
2111 Thread::muxAcquire(&gListLock, "log_in_use_monitor_details"); |
2109 Thread::muxAcquire(&gListLock, "log_in_use_monitor_details"); |
2112 } |
2110 } |
2113 |
2111 |
|
2112 stringStream ss; |
2114 if (gOmInUseCount > 0) { |
2113 if (gOmInUseCount > 0) { |
2115 out->print_cr("In-use global monitor info:"); |
2114 out->print_cr("In-use global monitor info:"); |
2116 out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); |
2115 out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); |
2117 out->print_cr("%18s %s %18s %18s", |
2116 out->print_cr("%18s %s %18s %18s", |
2118 "monitor", "BHL", "object", "object type"); |
2117 "monitor", "BHL", "object", "object type"); |
2119 out->print_cr("================== === ================== =================="); |
2118 out->print_cr("================== === ================== =================="); |
2120 for (ObjectMonitor * n = gOmInUseList; n != NULL; n = n->FreeNext) { |
2119 for (ObjectMonitor * n = gOmInUseList; n != NULL; n = n->FreeNext) { |
2121 const oop obj = (oop) n->object(); |
2120 const oop obj = (oop) n->object(); |
2122 const markOop mark = n->header(); |
2121 const markOop mark = n->header(); |
2123 ResourceMark rm; |
2122 ResourceMark rm; |
2124 out->print_cr(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(n), |
2123 out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(n), |
2125 n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL, |
2124 n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL, |
2126 p2i(obj), obj->klass()->external_name()); |
2125 p2i(obj), obj->klass()->external_name()); |
|
2126 if (n->is_busy() != 0) { |
|
2127 out->print(" (%s)", n->is_busy_to_string(&ss)); |
|
2128 ss.reset(); |
|
2129 } |
|
2130 out->cr(); |
2127 } |
2131 } |
2128 } |
2132 } |
2129 |
2133 |
2130 if (!on_exit) { |
2134 if (!on_exit) { |
2131 Thread::muxRelease(&gListLock); |
2135 Thread::muxRelease(&gListLock); |
2139 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { |
2143 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { |
2140 for (ObjectMonitor * n = jt->omInUseList; n != NULL; n = n->FreeNext) { |
2144 for (ObjectMonitor * n = jt->omInUseList; n != NULL; n = n->FreeNext) { |
2141 const oop obj = (oop) n->object(); |
2145 const oop obj = (oop) n->object(); |
2142 const markOop mark = n->header(); |
2146 const markOop mark = n->header(); |
2143 ResourceMark rm; |
2147 ResourceMark rm; |
2144 out->print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT |
2148 out->print(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT |
2145 " %s", p2i(jt), p2i(n), n->is_busy() != 0, |
2149 " %s", p2i(jt), p2i(n), n->is_busy() != 0, |
2146 mark->hash() != 0, n->owner() != NULL, p2i(obj), |
2150 mark->hash() != 0, n->owner() != NULL, p2i(obj), |
2147 obj->klass()->external_name()); |
2151 obj->klass()->external_name()); |
|
2152 if (n->is_busy() != 0) { |
|
2153 out->print(" (%s)", n->is_busy_to_string(&ss)); |
|
2154 ss.reset(); |
|
2155 } |
|
2156 out->cr(); |
2148 } |
2157 } |
2149 } |
2158 } |
2150 |
2159 |
2151 out->flush(); |
2160 out->flush(); |
2152 } |
2161 } |