1 /* 2 * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.hotspot.management; 26 27 import java.lang.management.ManagementFactory; 28 import java.util.ArrayList; 29 30 import javax.management.InstanceAlreadyExistsException; 31 import javax.management.MBeanRegistrationException; 32 import javax.management.MBeanServer; 33 import javax.management.MBeanServerFactory; 34 import javax.management.MalformedObjectNameException; 35 import javax.management.NotCompliantMBeanException; 36 import javax.management.ObjectName; 37 38 import org.graalvm.compiler.debug.TTY; 39 import org.graalvm.compiler.hotspot.HotSpotGraalManagementRegistration; 40 import org.graalvm.compiler.hotspot.HotSpotGraalRuntime; 41 import org.graalvm.compiler.serviceprovider.ServiceProvider; 42 43 /** 44 * Dynamically registers an MBean with the {@link ManagementFactory#getPlatformMBeanServer()}. 45 * 46 * Polling for an active platform MBean server is done by calling 47 * {@link MBeanServerFactory#findMBeanServer(String)} with an argument value of {@code null}. Once 48 * this returns an non-empty list, {@link ManagementFactory#getPlatformMBeanServer()} can be called 49 * to obtain a reference to the platform MBean server instance. 50 */ 51 @ServiceProvider(HotSpotGraalManagementRegistration.class) 52 public final class HotSpotGraalManagement implements HotSpotGraalManagementRegistration { 53 54 private HotSpotGraalRuntimeMBean bean; 55 private volatile boolean needsRegistration = true; 56 HotSpotGraalManagement nextDeferred; 57 58 @Override 59 public void initialize(HotSpotGraalRuntime runtime) { 60 if (bean == null) { 61 if (runtime.getManagement() != this) { 62 throw new IllegalArgumentException("Cannot initialize a second management object for runtime " + runtime.getName()); 63 } 64 try { 65 String name = runtime.getName().replace(':', '_'); 66 ObjectName objectName = new ObjectName("org.graalvm.compiler.hotspot:type=" + name); 67 bean = new HotSpotGraalRuntimeMBean(objectName, runtime); 68 registration.add(this); 69 } catch (MalformedObjectNameException err) { 70 err.printStackTrace(TTY.out); 71 } 72 } else if (bean.getRuntime() != runtime) { 73 throw new IllegalArgumentException("Cannot change the runtime a management interface is associated with"); 74 } 75 } 76 77 static final class RegistrationThread extends Thread { 78 79 private MBeanServer platformMBeanServer; 80 private HotSpotGraalManagement deferred; 81 82 RegistrationThread() { 83 super("HotSpotGraalManagement Bean Registration"); 84 this.setPriority(Thread.MIN_PRIORITY); 85 this.setDaemon(true); 86 this.start(); 87 } 88 89 /** 90 * Poll for active MBean server every 2 seconds. 91 */ 92 private static final int POLL_INTERVAL_MS = 2000; 93 94 /** 95 * Adds a {@link HotSpotGraalManagement} to register with an active MBean server when one 96 * becomes available. 97 */ 98 synchronized void add(HotSpotGraalManagement e) { 99 if (deferred != null) { 100 e.nextDeferred = deferred; 101 } 102 deferred = e; 103 104 // Notify the registration thread that there is now 105 // a deferred registration to process 106 notify(); 107 } 108 109 /** 110 * Processes and clears any deferred registrations. 111 */ 112 private void process() { 113 for (HotSpotGraalManagement m = deferred; m != null; m = m.nextDeferred) { 114 HotSpotGraalRuntimeMBean bean = m.bean; 115 if (m.needsRegistration && bean != null) { 116 try { 117 platformMBeanServer.registerMBean(bean, bean.getObjectName()); 118 } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) { 119 e.printStackTrace(TTY.out); 120 // Registration failed - don't try again 121 m.bean = null; 122 } 123 m.needsRegistration = false; 124 } 125 } 126 deferred = null; 127 } 128 129 @Override 130 public void run() { 131 while (true) { 132 try { 133 synchronized (this) { 134 // Wait until there are deferred registrations to process 135 while (deferred == null) { 136 wait(); 137 } 138 } 139 poll(); 140 Thread.sleep(POLL_INTERVAL_MS); 141 } catch (InterruptedException e) { 142 // Be verbose about unexpected interruption and then continue 143 e.printStackTrace(TTY.out); 144 } 145 } 146 } 147 148 /** 149 * Checks for active MBean server and if available, processes deferred registrations. 150 */ 151 synchronized void poll() { 152 if (platformMBeanServer == null) { 153 ArrayList<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null); 154 if (!servers.isEmpty()) { 155 platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); 156 process(); 157 } 158 } else { 159 process(); 160 } 161 } 162 } 163 164 private static final RegistrationThread registration = new RegistrationThread(); 165 166 @Override 167 public ObjectName poll(boolean sync) { 168 if (sync) { 169 registration.poll(); 170 } 171 if (bean == null || needsRegistration) { 172 // initialize() has not been called, it failed or registration failed 173 return null; 174 } 175 return bean.getObjectName(); 176 } 177 }