Created
September 10, 2013 22:13
-
-
Save jimbaker/6516506 to your computer and use it in GitHub Desktop.
An example of using JMX from Jython. In particular, running kill_deadlocked_jvms.py will kill any deadlocked JVM process. To cause a deadlock, simply run deadlock.py with Jython. Although deadlock.py is portable Python, running with Jython does allow for the deadlock detection supported by the JVM. Examples are from my 2012 OSCON talk.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from threading import Thread, Lock | |
import threading | |
def cause_deadlock(): | |
lock_one = Lock() | |
lock_two = Lock() | |
counter = [0] # Shared resource for both locks | |
Thread(name="thread #1", target=acquire_locks, | |
args=(counter, lock_one, lock_two)).start() | |
Thread(name="thread #2 (reversed)", target=acquire_locks, | |
args=(counter, lock_two, lock_one)).start() | |
def acquire_locks(counter, lock1, lock2): | |
# Will eventually deadlock if locks are acquired in different order | |
name = threading.currentThread().getName() | |
thread_count = 0 | |
while True: | |
with lock1: | |
with lock2: | |
counter[0] += 1 | |
thread_count += 1 | |
print "name={}, total count={}, thread count={}".\ | |
format(name, counter[0], thread_count) | |
if __name__ == '__main__': | |
cause_deadlock() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os.path | |
import signal | |
from contextlib import closing | |
from com.sun.tools.attach import VirtualMachine | |
from java.lang import Class | |
from java.lang.management import ManagementFactory | |
from javax.management.remote import JMXServiceURL, JMXConnectorFactory | |
def get_vm_connectors(exclude_self=True): | |
my_pid = os.getpid() | |
for desc in VirtualMachine.list(): | |
vm = VirtualMachine.attach(desc) | |
pid = int(desc.id()) | |
if exclude_self and pid == my_pid: | |
continue | |
connector_addr = vm.agentProperties["com.sun.management.jmxremote.localConnectorAddress"] | |
if connector_addr is None: | |
# Need to load a JMX agent into the JVM | |
system_props = vm.systemProperties | |
agent = os.path.join( | |
system_props["java.home"], "lib", "management-agent.jar") | |
print "Loading management agent={} for pid={}...".format(agent, pid) | |
vm.loadAgent(agent) | |
connector_addr = vm.agentProperties["com.sun.management.jmxremote.localConnectorAddress"] | |
yield pid, connector_addr | |
def check_and_kill_deadlocked_vm(pid, connector_addr): | |
url = JMXServiceURL(connector_addr) | |
print "Checking vm pid={}, url={}".format(pid, url) | |
with closing(JMXConnectorFactory.connect(url)) as connector: | |
mbean = connector.MBeanServerConnection | |
thread_mxbean = ManagementFactory.getPlatformMXBean( | |
mbean, Class.forName("java.lang.management.ThreadMXBean")) | |
thread_ids = thread_mxbean.findDeadlockedThreads() | |
if thread_ids: | |
print "Deadlock detected, shutting down pid={}, threads={}".\ | |
format(pid, list(thread_ids)) | |
os.kill(pid, signal.SIGINT) | |
def main(): | |
for pid, connector_addr in get_vm_connectors(): | |
check_and_kill_deadlocked_vm(pid, connector_addr) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment