/* * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.jfr.internal; import java.util.ArrayList; import java.util.List; import java.util.Objects; import jdk.jfr.SettingDescriptor; /** * Implementation of event type. * * To avoid memory leaks, this class must not hold strong reference to an event * class or a setting class */ public final class PlatformEventType extends Type { private final boolean isJVM; private final boolean isJDK; private final boolean isMethodSampling; private final List settings = new ArrayList<>(5); private final boolean dynamicSettings; private final int stackTraceOffset; // default values private boolean enabled = false; private boolean stackTraceEnabled = true; private long thresholdTicks = 0; private long period = 0; private boolean hasHook; private boolean beginChunk; private boolean endChunk; private boolean hasStackTrace = true; private boolean hasDuration = true; private boolean hasPeriod = true; private boolean hasCutoff = false; private boolean isInstrumented; private boolean markForInstrumentation; private boolean registered = true; private boolean commitable = enabled && registered; // package private PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) { super(name, Type.SUPER_TYPE_EVENT, id); this.dynamicSettings = dynamicSettings; this.isJVM = Type.isDefinedByJVM(id); this.isMethodSampling = name.equals(Type.ORACLE_EVENT_PREFIX + "ExecutionSample") || name.equals(Type.ORACLE_EVENT_PREFIX + "NativeMethodSample"); this.isJDK = isJDK; this.stackTraceOffset = stackTraceOffset(name, isJDK); } private static int stackTraceOffset(String name, boolean isJDK) { if (isJDK) { if (name.equals(Type.ORACLE_EVENT_PREFIX + "JavaExceptionThrow")) { return 5; } if (name.equals(Type.ORACLE_EVENT_PREFIX + "JavaErrorThrow")) { return 5; } } return 4; } public void add(SettingDescriptor settingDescriptor) { Objects.requireNonNull(settingDescriptor); settings.add(settingDescriptor); } public List getSettings() { if (dynamicSettings) { List list = new ArrayList<>(settings.size()); for (SettingDescriptor s : settings) { if (Utils.isSettingVisible(s.getTypeId(), hasHook)) { list.add(s); } } return list; } return settings; } public List getAllSettings() { return settings; } public void setHasStackTrace(boolean hasStackTrace) { this.hasStackTrace = hasStackTrace; } public void setHasDuration(boolean hasDuration) { this.hasDuration = hasDuration; } public void setHasCutoff(boolean hasCutoff) { this.hasCutoff = hasCutoff; } public void setCutoff(long cutoffNanos) { if (isJVM) { long cutoffTicks = Utils.nanosToTicks(cutoffNanos); JVM.getJVM().setCutoff(getId(), cutoffTicks); } } public void setHasPeriod(boolean hasPeriod) { this.hasPeriod = hasPeriod; } public boolean hasStackTrace() { return this.hasStackTrace; } public boolean hasDuration() { return this.hasDuration; } public boolean hasPeriod() { return this.hasPeriod; } public boolean hasCutoff() { return this.hasCutoff; } public boolean isEnabled() { return enabled; } public boolean isJVM() { return isJVM; } public boolean isJDK() { return isJDK; } public void setEnabled(boolean enabled) { this.enabled = enabled; updateCommitable(); if (isJVM) { if (isMethodSampling) { long p = enabled ? period : 0; JVM.getJVM().setMethodSamplingInterval(getId(), p); } else { JVM.getJVM().setEnabled(getId(), enabled); } } } public void setPeriod(long periodMillis, boolean beginChunk, boolean endChunk) { if (isMethodSampling) { long p = enabled ? periodMillis : 0; JVM.getJVM().setMethodSamplingInterval(getId(), p); } this.beginChunk = beginChunk; this.endChunk = endChunk; this.period = periodMillis; } public void setStackTraceEnabled(boolean stackTraceEnabled) { this.stackTraceEnabled = stackTraceEnabled; if (isJVM) { JVM.getJVM().setStackTraceEnabled(getId(), stackTraceEnabled); } } public void setThreshold(long thresholdNanos) { this.thresholdTicks = Utils.nanosToTicks(thresholdNanos); if (isJVM) { JVM.getJVM().setThreshold(getId(), thresholdTicks); } } public boolean isEveryChunk() { return period == 0; } public boolean getStackTraceEnabled() { return stackTraceEnabled; } public long getThresholdTicks() { return thresholdTicks; } public long getPeriod() { return period; } public boolean hasEventHook() { return hasHook; } public void setEventHook(boolean hasHook) { this.hasHook = hasHook; } public boolean isBeginChunk() { return beginChunk; } public boolean isEndChunk() { return endChunk; } public boolean isInstrumented() { return isInstrumented; } public void setInstrumented() { isInstrumented = true; } public void markForInstrumentation(boolean markForInstrumentation) { this.markForInstrumentation = markForInstrumentation; } public boolean isMarkedForInstrumentation() { return markForInstrumentation; } public boolean setRegistered(boolean registered) { if (this.registered != registered) { this.registered = registered; updateCommitable(); LogTag logTag = isJVM() || isJDK() ? LogTag.JFR_SYSTEM_EVENT : LogTag.JFR_EVENT; if (registered) { Logger.log(logTag, LogLevel.INFO, "Registered " + getLogName()); } else { Logger.log(logTag, LogLevel.INFO, "Unregistered " + getLogName()); } if (!registered) { MetadataRepository.getInstance().setUnregistered(); } return true; } return false; } private void updateCommitable() { this.commitable = enabled && registered; } public final boolean isRegistered() { return registered; } // Efficient check of enabled && registered public boolean isCommitable() { return commitable; } public int getStackTraceOffset() { return stackTraceOffset; } }