1 /*
   2  * Copyright (c) 2017, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.jfr.internal;
  27 
  28 import java.util.ArrayList;
  29 import java.util.List;
  30 import java.util.Objects;
  31 
  32 import jdk.jfr.SettingDescriptor;
  33 
  34 /**
  35  * Implementation of event type.
  36  *
  37  * To avoid memory leaks, this class must not hold strong reference to an event
  38  * class or a setting class
  39  */
  40 public final class PlatformEventType extends Type {
  41     private final boolean isJVM;
  42     private final boolean  isJDK;
  43     private final boolean isMethodSampling;
  44     private final List<SettingDescriptor> settings = new ArrayList<>(5);
  45     private final boolean dynamicSettings;
  46     private final int stackTraceOffset;
  47 
  48     // default values
  49     private boolean enabled = false;
  50     private boolean stackTraceEnabled = true;
  51     private long thresholdTicks = 0;
  52     private long period = 0;
  53     private boolean hasHook;
  54 
  55     private boolean beginChunk;
  56     private boolean endChunk;
  57     private boolean hasStackTrace = true;
  58     private boolean hasDuration = true;
  59     private boolean hasPeriod = true;
  60     private boolean hasCutoff = false;
  61     private boolean isInstrumented;
  62     private boolean markForInstrumentation;
  63     private boolean registered = true;
  64     private boolean commitable = enabled && registered;
  65 
  66 
  67     // package private
  68     PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
  69         super(name, Type.SUPER_TYPE_EVENT, id);
  70         this.dynamicSettings = dynamicSettings;
  71         this.isJVM = Type.isDefinedByJVM(id);
  72         this.isMethodSampling = name.equals(Type.ORACLE_EVENT_PREFIX + "ExecutionSample") || name.equals(Type.ORACLE_EVENT_PREFIX + "NativeMethodSample");
  73         this.isJDK = isJDK;
  74         this.stackTraceOffset = stackTraceOffset(name, isJDK);
  75     }
  76 
  77     private static int stackTraceOffset(String name, boolean isJDK) {
  78         if (isJDK) {
  79             if (name.equals(Type.ORACLE_EVENT_PREFIX + "JavaExceptionThrow")) {
  80                 return 5;
  81             }
  82             if (name.equals(Type.ORACLE_EVENT_PREFIX + "JavaErrorThrow")) {
  83                 return 5;
  84             }
  85         }
  86         return 4;
  87     }
  88 
  89     public void add(SettingDescriptor settingDescriptor) {
  90         Objects.requireNonNull(settingDescriptor);
  91         settings.add(settingDescriptor);
  92     }
  93 
  94     public List<SettingDescriptor> getSettings() {
  95         if (dynamicSettings) {
  96             List<SettingDescriptor> list = new ArrayList<>(settings.size());
  97             for (SettingDescriptor s : settings) {
  98                 if (Utils.isSettingVisible(s.getTypeId(), hasHook)) {
  99                     list.add(s);
 100                 }
 101             }
 102             return list;
 103         }
 104         return settings;
 105     }
 106 
 107     public List<SettingDescriptor> getAllSettings() {
 108         return settings;
 109     }
 110 
 111     public void setHasStackTrace(boolean hasStackTrace) {
 112         this.hasStackTrace = hasStackTrace;
 113     }
 114 
 115     public void setHasDuration(boolean hasDuration) {
 116         this.hasDuration = hasDuration;
 117     }
 118 
 119     public void setHasCutoff(boolean hasCutoff) {
 120        this.hasCutoff = hasCutoff;
 121     }
 122 
 123     public void setCutoff(long cutoffNanos) {
 124         if (isJVM) {
 125             long cutoffTicks = Utils.nanosToTicks(cutoffNanos);
 126             JVM.getJVM().setCutoff(getId(), cutoffTicks);
 127         }
 128     }
 129 
 130     public void setHasPeriod(boolean hasPeriod) {
 131         this.hasPeriod = hasPeriod;
 132     }
 133 
 134     public boolean hasStackTrace() {
 135         return this.hasStackTrace;
 136     }
 137 
 138     public boolean hasDuration() {
 139         return this.hasDuration;
 140     }
 141 
 142     public boolean hasPeriod() {
 143         return this.hasPeriod;
 144     }
 145 
 146     public boolean hasCutoff() {
 147         return this.hasCutoff;
 148     }
 149 
 150     public boolean isEnabled() {
 151         return enabled;
 152     }
 153 
 154     public boolean isJVM() {
 155         return isJVM;
 156     }
 157 
 158     public boolean isJDK() {
 159         return isJDK;
 160     }
 161 
 162     public void setEnabled(boolean enabled) {
 163         this.enabled = enabled;
 164         updateCommitable();
 165         if (isJVM) {
 166             if (isMethodSampling) {
 167                 long p = enabled ? period : 0;
 168                 JVM.getJVM().setMethodSamplingInterval(getId(), p);
 169             } else {
 170                 JVM.getJVM().setEnabled(getId(), enabled);
 171             }
 172         }
 173     }
 174 
 175     public void setPeriod(long periodMillis, boolean beginChunk, boolean endChunk) {
 176         if (isMethodSampling) {
 177             long p = enabled ? periodMillis : 0;
 178             JVM.getJVM().setMethodSamplingInterval(getId(), p);
 179         }
 180         this.beginChunk = beginChunk;
 181         this.endChunk = endChunk;
 182         this.period = periodMillis;
 183     }
 184 
 185     public void setStackTraceEnabled(boolean stackTraceEnabled) {
 186         this.stackTraceEnabled = stackTraceEnabled;
 187         if (isJVM) {
 188             JVM.getJVM().setStackTraceEnabled(getId(), stackTraceEnabled);
 189         }
 190     }
 191 
 192     public void setThreshold(long thresholdNanos) {
 193         this.thresholdTicks = Utils.nanosToTicks(thresholdNanos);
 194         if (isJVM) {
 195             JVM.getJVM().setThreshold(getId(), thresholdTicks);
 196         }
 197     }
 198 
 199     public boolean isEveryChunk() {
 200         return period == 0;
 201     }
 202 
 203     public boolean getStackTraceEnabled() {
 204         return stackTraceEnabled;
 205     }
 206 
 207     public long getThresholdTicks() {
 208         return thresholdTicks;
 209     }
 210 
 211     public long getPeriod() {
 212         return period;
 213     }
 214 
 215     public boolean hasEventHook() {
 216         return hasHook;
 217     }
 218 
 219     public void setEventHook(boolean hasHook) {
 220         this.hasHook = hasHook;
 221     }
 222 
 223     public boolean isBeginChunk() {
 224         return beginChunk;
 225     }
 226 
 227     public boolean isEndChunk() {
 228         return endChunk;
 229     }
 230 
 231     public boolean isInstrumented() {
 232         return isInstrumented;
 233     }
 234 
 235     public void setInstrumented() {
 236         isInstrumented = true;
 237     }
 238 
 239     public void markForInstrumentation(boolean markForInstrumentation) {
 240         this.markForInstrumentation = markForInstrumentation;
 241     }
 242 
 243     public boolean isMarkedForInstrumentation() {
 244         return markForInstrumentation;
 245     }
 246 
 247     public boolean setRegistered(boolean registered) {
 248         if (this.registered != registered) {
 249             this.registered = registered;
 250             updateCommitable();
 251             LogTag logTag = isJVM() || isJDK() ? LogTag.JFR_SYSTEM_EVENT : LogTag.JFR_EVENT;
 252             if (registered) {
 253                 Logger.log(logTag, LogLevel.INFO, "Registered " + getLogName());
 254             } else {
 255                 Logger.log(logTag, LogLevel.INFO, "Unregistered " + getLogName());
 256             }
 257             if (!registered) {
 258                 MetadataRepository.getInstance().setUnregistered();
 259             }
 260             return true;
 261         }
 262         return false;
 263     }
 264 
 265     private void updateCommitable() {
 266         this.commitable = enabled && registered;
 267     }
 268 
 269     public final boolean isRegistered() {
 270         return registered;
 271     }
 272 
 273     // Efficient check of enabled && registered
 274     public boolean isCommitable() {
 275         return commitable;
 276     }
 277 
 278     public int getStackTraceOffset() {
 279         return stackTraceOffset;
 280     }
 281 }