1639 // constant-time list splice - prepend scavenged segment to gFreeList |
1641 // constant-time list splice - prepend scavenged segment to gFreeList |
1640 freeTailp->FreeNext = gFreeList; |
1642 freeTailp->FreeNext = gFreeList; |
1641 gFreeList = freeHeadp; |
1643 gFreeList = freeHeadp; |
1642 } |
1644 } |
1643 Thread::muxRelease(&gListLock); |
1645 Thread::muxRelease(&gListLock); |
1644 |
1646 timer.stop(); |
|
1647 |
|
1648 LogStreamHandle(Debug, monitorinflation) lsh_debug; |
|
1649 LogStreamHandle(Info, monitorinflation) lsh_info; |
|
1650 LogStream * ls = NULL; |
|
1651 if (log_is_enabled(Debug, monitorinflation)) { |
|
1652 ls = &lsh_debug; |
|
1653 } else if (deflated_count != 0 && log_is_enabled(Info, monitorinflation)) { |
|
1654 ls = &lsh_info; |
|
1655 } |
|
1656 if (ls != NULL) { |
|
1657 ls->print_cr("deflating global idle monitors, %3.7f secs, %d monitors", timer.seconds(), deflated_count); |
|
1658 } |
1645 } |
1659 } |
1646 |
1660 |
1647 void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* counters) { |
1661 void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* counters) { |
1648 if (log_is_enabled(Info, safepoint, cleanup)) { |
1662 // Report the cumulative time for deflating each thread's idle |
1649 // Report the cumulative time for deflating each thread's idle |
1663 // monitors. Note: if the work is split among more than one |
1650 // monitors. Note: if the work is split among more than one |
1664 // worker thread, then the reported time will likely be more |
1651 // worker thread, then the reported time will likely be more |
1665 // than a beginning to end measurement of the phase. |
1652 // than a beginning to end measurement of the phase. |
1666 log_info(safepoint, cleanup)("deflating per-thread idle monitors, %3.7f secs, monitors=%d", counters->perThreadTimes, counters->perThreadScavenged); |
1653 log_info(safepoint, cleanup)("deflating per-thread idle monitors, %3.7f secs", counters->perThreadTimes); |
1667 |
|
1668 LogStreamHandle(Debug, monitorinflation) lsh_debug; |
|
1669 LogStreamHandle(Info, monitorinflation) lsh_info; |
|
1670 LogStream * ls = NULL; |
|
1671 if (log_is_enabled(Debug, monitorinflation)) { |
|
1672 ls = &lsh_debug; |
|
1673 } else if (counters->perThreadScavenged != 0 && log_is_enabled(Info, monitorinflation)) { |
|
1674 ls = &lsh_info; |
|
1675 } |
|
1676 if (ls != NULL) { |
|
1677 ls->print_cr("deflating per-thread idle monitors, %3.7f secs, %d monitors", counters->perThreadTimes, counters->perThreadScavenged); |
1654 } |
1678 } |
1655 |
1679 |
1656 gMonitorFreeCount += counters->nScavenged; |
1680 gMonitorFreeCount += counters->nScavenged; |
1657 |
1681 |
1658 // Consider: audit gFreeList to ensure that gMonitorFreeCount and list agree. |
1682 if (log_is_enabled(Debug, monitorinflation)) { |
|
1683 // exit_globals()'s call to audit_and_print_stats() is done |
|
1684 // at the Info level. |
|
1685 ObjectSynchronizer::audit_and_print_stats(false /* on_exit */); |
|
1686 } |
1659 |
1687 |
1660 ForceMonitorScavenge = 0; // Reset |
1688 ForceMonitorScavenge = 0; // Reset |
1661 |
1689 |
1662 OM_PERFDATA_OP(Deflations, inc(counters->nScavenged)); |
1690 OM_PERFDATA_OP(Deflations, inc(counters->nScavenged)); |
1663 OM_PERFDATA_OP(MonExtant, set_value(counters->nInCirculation)); |
1691 OM_PERFDATA_OP(MonExtant, set_value(counters->nInCirculation)); |
1664 |
1692 |
1665 // TODO: Add objectMonitor leak detection. |
|
1666 // Audit/inventory the objectMonitors -- make sure they're all accounted for. |
|
1667 GVars.stwRandom = os::random(); |
1693 GVars.stwRandom = os::random(); |
1668 GVars.stwCycle++; |
1694 GVars.stwCycle++; |
1669 } |
1695 } |
1670 |
1696 |
1671 void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMonitorCounters* counters) { |
1697 void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMonitorCounters* counters) { |
1780 |
1808 |
1781 u_char* ObjectSynchronizer::get_gvars_stwRandom_addr() { |
1809 u_char* ObjectSynchronizer::get_gvars_stwRandom_addr() { |
1782 return (u_char*)&GVars.stwRandom; |
1810 return (u_char*)&GVars.stwRandom; |
1783 } |
1811 } |
1784 |
1812 |
|
1813 void ObjectSynchronizer::audit_and_print_stats(bool on_exit) { |
|
1814 assert(on_exit || SafepointSynchronize::is_at_safepoint(), "invariant"); |
|
1815 |
|
1816 LogStreamHandle(Debug, monitorinflation) lsh_debug; |
|
1817 LogStreamHandle(Info, monitorinflation) lsh_info; |
|
1818 LogStreamHandle(Trace, monitorinflation) lsh_trace; |
|
1819 LogStream * ls = NULL; |
|
1820 if (log_is_enabled(Trace, monitorinflation)) { |
|
1821 ls = &lsh_trace; |
|
1822 } else if (log_is_enabled(Debug, monitorinflation)) { |
|
1823 ls = &lsh_debug; |
|
1824 } else if (log_is_enabled(Info, monitorinflation)) { |
|
1825 ls = &lsh_info; |
|
1826 } |
|
1827 assert(ls != NULL, "sanity check"); |
|
1828 |
|
1829 if (!on_exit) { |
|
1830 // Not at VM exit so grab the global list lock. |
|
1831 Thread::muxAcquire(&gListLock, "audit_and_print_stats"); |
|
1832 } |
|
1833 |
|
1834 // Log counts for the global and per-thread monitor lists: |
|
1835 int chkMonitorPopulation = log_monitor_list_counts(ls); |
|
1836 int error_cnt = 0; |
|
1837 |
|
1838 ls->print_cr("Checking global lists:"); |
|
1839 |
|
1840 // Check gMonitorPopulation: |
|
1841 if (gMonitorPopulation == chkMonitorPopulation) { |
|
1842 ls->print_cr("gMonitorPopulation=%d equals chkMonitorPopulation=%d", |
|
1843 gMonitorPopulation, chkMonitorPopulation); |
|
1844 } else { |
|
1845 ls->print_cr("ERROR: gMonitorPopulation=%d is not equal to " |
|
1846 "chkMonitorPopulation=%d", gMonitorPopulation, |
|
1847 chkMonitorPopulation); |
|
1848 error_cnt++; |
|
1849 } |
|
1850 |
|
1851 // Check gOmInUseList and gOmInUseCount: |
|
1852 chk_global_in_use_list_and_count(ls, &error_cnt); |
|
1853 |
|
1854 // Check gFreeList and gMonitorFreeCount: |
|
1855 chk_global_free_list_and_count(ls, &error_cnt); |
|
1856 |
|
1857 if (!on_exit) { |
|
1858 Thread::muxRelease(&gListLock); |
|
1859 } |
|
1860 |
|
1861 ls->print_cr("Checking per-thread lists:"); |
|
1862 |
|
1863 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { |
|
1864 // Check omInUseList and omInUseCount: |
|
1865 chk_per_thread_in_use_list_and_count(jt, ls, &error_cnt); |
|
1866 |
|
1867 // Check omFreeList and omFreeCount: |
|
1868 chk_per_thread_free_list_and_count(jt, ls, &error_cnt); |
|
1869 } |
|
1870 |
|
1871 if (error_cnt == 0) { |
|
1872 ls->print_cr("No errors found in monitor list checks."); |
|
1873 } else { |
|
1874 log_error(monitorinflation)("found monitor list errors: error_cnt=%d", error_cnt); |
|
1875 } |
|
1876 |
|
1877 if ((on_exit && log_is_enabled(Info, monitorinflation)) || |
|
1878 (!on_exit && log_is_enabled(Trace, monitorinflation))) { |
|
1879 // When exiting this log output is at the Info level. When called |
|
1880 // at a safepoint, this log output is at the Trace level since |
|
1881 // there can be a lot of it. |
|
1882 log_in_use_monitor_details(ls, on_exit); |
|
1883 } |
|
1884 |
|
1885 ls->flush(); |
|
1886 |
|
1887 guarantee(error_cnt == 0, "ERROR: found monitor list errors: error_cnt=%d", error_cnt); |
|
1888 } |
|
1889 |
|
1890 // Check a free monitor entry; log any errors. |
|
1891 void ObjectSynchronizer::chk_free_entry(JavaThread * jt, ObjectMonitor * n, |
|
1892 outputStream * out, int *error_cnt_p) { |
|
1893 if (n->is_busy()) { |
|
1894 if (jt != NULL) { |
|
1895 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
1896 ": free per-thread monitor must not be busy.", p2i(jt), |
|
1897 p2i(n)); |
|
1898 } else { |
|
1899 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " |
|
1900 "must not be busy.", p2i(n)); |
|
1901 } |
|
1902 *error_cnt_p = *error_cnt_p + 1; |
|
1903 } |
|
1904 if (n->header() != NULL) { |
|
1905 if (jt != NULL) { |
|
1906 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
1907 ": free per-thread monitor must have NULL _header " |
|
1908 "field: _header=" INTPTR_FORMAT, p2i(jt), p2i(n), |
|
1909 p2i(n->header())); |
|
1910 } else { |
|
1911 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " |
|
1912 "must have NULL _header field: _header=" INTPTR_FORMAT, |
|
1913 p2i(n), p2i(n->header())); |
|
1914 } |
|
1915 *error_cnt_p = *error_cnt_p + 1; |
|
1916 } |
|
1917 if (n->object() != NULL) { |
|
1918 if (jt != NULL) { |
|
1919 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
1920 ": free per-thread monitor must have NULL _object " |
|
1921 "field: _object=" INTPTR_FORMAT, p2i(jt), p2i(n), |
|
1922 p2i(n->object())); |
|
1923 } else { |
|
1924 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " |
|
1925 "must have NULL _object field: _object=" INTPTR_FORMAT, |
|
1926 p2i(n), p2i(n->object())); |
|
1927 } |
|
1928 *error_cnt_p = *error_cnt_p + 1; |
|
1929 } |
|
1930 } |
|
1931 |
|
1932 // Check the global free list and count; log the results of the checks. |
|
1933 void ObjectSynchronizer::chk_global_free_list_and_count(outputStream * out, |
|
1934 int *error_cnt_p) { |
|
1935 int chkMonitorFreeCount = 0; |
|
1936 for (ObjectMonitor * n = gFreeList; n != NULL; n = n->FreeNext) { |
|
1937 chk_free_entry(NULL /* jt */, n, out, error_cnt_p); |
|
1938 chkMonitorFreeCount++; |
|
1939 } |
|
1940 if (gMonitorFreeCount == chkMonitorFreeCount) { |
|
1941 out->print_cr("gMonitorFreeCount=%d equals chkMonitorFreeCount=%d", |
|
1942 gMonitorFreeCount, chkMonitorFreeCount); |
|
1943 } else { |
|
1944 out->print_cr("ERROR: gMonitorFreeCount=%d is not equal to " |
|
1945 "chkMonitorFreeCount=%d", gMonitorFreeCount, |
|
1946 chkMonitorFreeCount); |
|
1947 *error_cnt_p = *error_cnt_p + 1; |
|
1948 } |
|
1949 } |
|
1950 |
|
1951 // Check the global in-use list and count; log the results of the checks. |
|
1952 void ObjectSynchronizer::chk_global_in_use_list_and_count(outputStream * out, |
|
1953 int *error_cnt_p) { |
|
1954 int chkOmInUseCount = 0; |
|
1955 for (ObjectMonitor * n = gOmInUseList; n != NULL; n = n->FreeNext) { |
|
1956 chk_in_use_entry(NULL /* jt */, n, out, error_cnt_p); |
|
1957 chkOmInUseCount++; |
|
1958 } |
|
1959 if (gOmInUseCount == chkOmInUseCount) { |
|
1960 out->print_cr("gOmInUseCount=%d equals chkOmInUseCount=%d", gOmInUseCount, |
|
1961 chkOmInUseCount); |
|
1962 } else { |
|
1963 out->print_cr("ERROR: gOmInUseCount=%d is not equal to chkOmInUseCount=%d", |
|
1964 gOmInUseCount, chkOmInUseCount); |
|
1965 *error_cnt_p = *error_cnt_p + 1; |
|
1966 } |
|
1967 } |
|
1968 |
|
1969 // Check an in-use monitor entry; log any errors. |
|
1970 void ObjectSynchronizer::chk_in_use_entry(JavaThread * jt, ObjectMonitor * n, |
|
1971 outputStream * out, int *error_cnt_p) { |
|
1972 if (n->header() == NULL) { |
|
1973 if (jt != NULL) { |
|
1974 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
1975 ": in-use per-thread monitor must have non-NULL _header " |
|
1976 "field.", p2i(jt), p2i(n)); |
|
1977 } else { |
|
1978 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global monitor " |
|
1979 "must have non-NULL _header field.", p2i(n)); |
|
1980 } |
|
1981 *error_cnt_p = *error_cnt_p + 1; |
|
1982 } |
|
1983 if (n->object() == NULL) { |
|
1984 if (jt != NULL) { |
|
1985 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
1986 ": in-use per-thread monitor must have non-NULL _object " |
|
1987 "field.", p2i(jt), p2i(n)); |
|
1988 } else { |
|
1989 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global monitor " |
|
1990 "must have non-NULL _object field.", p2i(n)); |
|
1991 } |
|
1992 *error_cnt_p = *error_cnt_p + 1; |
|
1993 } |
|
1994 const oop obj = (oop)n->object(); |
|
1995 const markOop mark = obj->mark(); |
|
1996 if (!mark->has_monitor()) { |
|
1997 if (jt != NULL) { |
|
1998 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
1999 ": in-use per-thread monitor's object does not think " |
|
2000 "it has a monitor: obj=" INTPTR_FORMAT ", mark=" |
|
2001 INTPTR_FORMAT, p2i(jt), p2i(n), p2i((address)obj), |
|
2002 p2i((address)mark)); |
|
2003 } else { |
|
2004 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global " |
|
2005 "monitor's object does not think it has a monitor: obj=" |
|
2006 INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), |
|
2007 p2i((address)obj), p2i((address)mark)); |
|
2008 } |
|
2009 *error_cnt_p = *error_cnt_p + 1; |
|
2010 } |
|
2011 ObjectMonitor * const obj_mon = mark->monitor(); |
|
2012 if (n != obj_mon) { |
|
2013 if (jt != NULL) { |
|
2014 out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT |
|
2015 ": in-use per-thread monitor's object does not refer " |
|
2016 "to the same monitor: obj=" INTPTR_FORMAT ", mark=" |
|
2017 INTPTR_FORMAT ", obj_mon=" INTPTR_FORMAT, p2i(jt), |
|
2018 p2i(n), p2i((address)obj), p2i((address)mark), |
|
2019 p2i((address)obj_mon)); |
|
2020 } else { |
|
2021 out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global " |
|
2022 "monitor's object does not refer to the same monitor: obj=" |
|
2023 INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" |
|
2024 INTPTR_FORMAT, p2i(n), p2i((address)obj), |
|
2025 p2i((address)mark), p2i((address)obj_mon)); |
|
2026 } |
|
2027 *error_cnt_p = *error_cnt_p + 1; |
|
2028 } |
|
2029 } |
|
2030 |
|
2031 // Check the thread's free list and count; log the results of the checks. |
|
2032 void ObjectSynchronizer::chk_per_thread_free_list_and_count(JavaThread *jt, |
|
2033 outputStream * out, |
|
2034 int *error_cnt_p) { |
|
2035 int chkOmFreeCount = 0; |
|
2036 for (ObjectMonitor * n = jt->omFreeList; n != NULL; n = n->FreeNext) { |
|
2037 chk_free_entry(jt, n, out, error_cnt_p); |
|
2038 chkOmFreeCount++; |
|
2039 } |
|
2040 if (jt->omFreeCount == chkOmFreeCount) { |
|
2041 out->print_cr("jt=" INTPTR_FORMAT ": omFreeCount=%d equals " |
|
2042 "chkOmFreeCount=%d", p2i(jt), jt->omFreeCount, chkOmFreeCount); |
|
2043 } else { |
|
2044 out->print_cr("ERROR: jt=" INTPTR_FORMAT ": omFreeCount=%d is not " |
|
2045 "equal to chkOmFreeCount=%d", p2i(jt), jt->omFreeCount, |
|
2046 chkOmFreeCount); |
|
2047 *error_cnt_p = *error_cnt_p + 1; |
|
2048 } |
|
2049 } |
|
2050 |
|
2051 // Check the thread's in-use list and count; log the results of the checks. |
|
2052 void ObjectSynchronizer::chk_per_thread_in_use_list_and_count(JavaThread *jt, |
|
2053 outputStream * out, |
|
2054 int *error_cnt_p) { |
|
2055 int chkOmInUseCount = 0; |
|
2056 for (ObjectMonitor * n = jt->omInUseList; n != NULL; n = n->FreeNext) { |
|
2057 chk_in_use_entry(jt, n, out, error_cnt_p); |
|
2058 chkOmInUseCount++; |
|
2059 } |
|
2060 if (jt->omInUseCount == chkOmInUseCount) { |
|
2061 out->print_cr("jt=" INTPTR_FORMAT ": omInUseCount=%d equals " |
|
2062 "chkOmInUseCount=%d", p2i(jt), jt->omInUseCount, |
|
2063 chkOmInUseCount); |
|
2064 } else { |
|
2065 out->print_cr("ERROR: jt=" INTPTR_FORMAT ": omInUseCount=%d is not " |
|
2066 "equal to chkOmInUseCount=%d", p2i(jt), jt->omInUseCount, |
|
2067 chkOmInUseCount); |
|
2068 *error_cnt_p = *error_cnt_p + 1; |
|
2069 } |
|
2070 } |
|
2071 |
|
2072 // Log details about ObjectMonitors on the in-use lists. The 'BHL' |
|
2073 // flags indicate why the entry is in-use, 'object' and 'object type' |
|
2074 // indicate the associated object and its type. |
|
2075 void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out, |
|
2076 bool on_exit) { |
|
2077 if (!on_exit) { |
|
2078 // Not at VM exit so grab the global list lock. |
|
2079 Thread::muxAcquire(&gListLock, "log_in_use_monitor_details"); |
|
2080 } |
|
2081 |
|
2082 if (gOmInUseCount > 0) { |
|
2083 out->print_cr("In-use global monitor info:"); |
|
2084 out->print_cr("(B -> is_busy, H -> has hashcode, L -> lock status)"); |
|
2085 out->print_cr("%18s %s %18s %18s", |
|
2086 "monitor", "BHL", "object", "object type"); |
|
2087 out->print_cr("================== === ================== =================="); |
|
2088 for (ObjectMonitor * n = gOmInUseList; n != NULL; n = n->FreeNext) { |
|
2089 const oop obj = (oop) n->object(); |
|
2090 const markOop mark = n->header(); |
|
2091 ResourceMark rm; |
|
2092 out->print_cr(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(n), |
|
2093 n->is_busy() != 0, mark->hash() != 0, n->owner() != NULL, |
|
2094 p2i(obj), obj->klass()->external_name()); |
|
2095 } |
|
2096 } |
|
2097 |
|
2098 if (!on_exit) { |
|
2099 Thread::muxRelease(&gListLock); |
|
2100 } |
|
2101 |
|
2102 out->print_cr("In-use per-thread monitor info:"); |
|
2103 out->print_cr("(B -> is_busy, H -> has hashcode, L -> lock status)"); |
|
2104 out->print_cr("%18s %18s %s %18s %18s", |
|
2105 "jt", "monitor", "BHL", "object", "object type"); |
|
2106 out->print_cr("================== ================== === ================== =================="); |
|
2107 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { |
|
2108 for (ObjectMonitor * n = jt->omInUseList; n != NULL; n = n->FreeNext) { |
|
2109 const oop obj = (oop) n->object(); |
|
2110 const markOop mark = n->header(); |
|
2111 ResourceMark rm; |
|
2112 out->print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT |
|
2113 " %s", p2i(jt), p2i(n), n->is_busy() != 0, |
|
2114 mark->hash() != 0, n->owner() != NULL, p2i(obj), |
|
2115 obj->klass()->external_name()); |
|
2116 } |
|
2117 } |
|
2118 |
|
2119 out->flush(); |
|
2120 } |
|
2121 |
|
2122 // Log counts for the global and per-thread monitor lists and return |
|
2123 // the population count. |
|
2124 int ObjectSynchronizer::log_monitor_list_counts(outputStream * out) { |
|
2125 int popCount = 0; |
|
2126 out->print_cr("%18s %10s %10s %10s", |
|
2127 "Global Lists:", "InUse", "Free", "Total"); |
|
2128 out->print_cr("================== ========== ========== =========="); |
|
2129 out->print_cr("%18s %10d %10d %10d", "", |
|
2130 gOmInUseCount, gMonitorFreeCount, gMonitorPopulation); |
|
2131 popCount += gOmInUseCount + gMonitorFreeCount; |
|
2132 |
|
2133 out->print_cr("%18s %10s %10s %10s", |
|
2134 "Per-Thread Lists:", "InUse", "Free", "Provision"); |
|
2135 out->print_cr("================== ========== ========== =========="); |
|
2136 |
|
2137 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { |
|
2138 out->print_cr(INTPTR_FORMAT " %10d %10d %10d", p2i(jt), |
|
2139 jt->omInUseCount, jt->omFreeCount, jt->omFreeProvision); |
|
2140 popCount += jt->omInUseCount + jt->omFreeCount; |
|
2141 } |
|
2142 return popCount; |
|
2143 } |
|
2144 |
1785 #ifndef PRODUCT |
2145 #ifndef PRODUCT |
1786 |
2146 |
1787 // Check if monitor belongs to the monitor cache |
2147 // Check if monitor belongs to the monitor cache |
1788 // The list is grow-only so it's *relatively* safe to traverse |
2148 // The list is grow-only so it's *relatively* safe to traverse |
1789 // the list of extant blocks without taking a lock. |
2149 // the list of extant blocks without taking a lock. |