1 /*
2  * Copyright (c) 2017, 2020, 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 largeSize = false;
50     private boolean enabled = false;
51     private boolean stackTraceEnabled = true;
52     private long thresholdTicks = 0;
53     private long period = 0;
54     private boolean hasHook;
55 
56     private boolean beginChunk;
57     private boolean endChunk;
58     private boolean hasStackTrace = true;
59     private boolean hasDuration = true;
60     private boolean hasPeriod = true;
61     private boolean hasCutoff = false;
62     private boolean hasThrottle = false;
63     private boolean isInstrumented;
64     private boolean markForInstrumentation;
65     private boolean registered = true;
66     private boolean committable = enabled && registered;
67 
68 
69     // package private
PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings)70     PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
71         super(name, Type.SUPER_TYPE_EVENT, id);
72         this.dynamicSettings = dynamicSettings;
73         this.isJVM = Type.isDefinedByJVM(id);
74         this.isMethodSampling = isJVM && (name.equals(Type.EVENT_NAME_PREFIX + "ExecutionSample") || name.equals(Type.EVENT_NAME_PREFIX + "NativeMethodSample"));
75         this.isJDK = isJDK;
76         this.stackTraceOffset = stackTraceOffset(name, isJDK);
77     }
78 
isExceptionEvent(String name)79     private static boolean isExceptionEvent(String name) {
80         switch (name) {
81             case Type.EVENT_NAME_PREFIX + "JavaErrorThrow" :
82             case Type.EVENT_NAME_PREFIX + "JavaExceptionThrow" :
83                 return true;
84         }
85         return false;
86     }
87 
isUsingHandler(String name)88     private static boolean isUsingHandler(String name) {
89         switch (name) {
90             case Type.EVENT_NAME_PREFIX + "SocketRead"  :
91             case Type.EVENT_NAME_PREFIX + "SocketWrite" :
92             case Type.EVENT_NAME_PREFIX + "FileRead"    :
93             case Type.EVENT_NAME_PREFIX + "FileWrite"   :
94             case Type.EVENT_NAME_PREFIX + "FileForce"   :
95                 return true;
96         }
97         return false;
98     }
99 
stackTraceOffset(String name, boolean isJDK)100     private static int stackTraceOffset(String name, boolean isJDK) {
101         if (isJDK) {
102             if (isExceptionEvent(name)) {
103                 return 4;
104             }
105             if (isUsingHandler(name)) {
106                 return 3;
107             }
108         }
109         return 4;
110     }
111 
add(SettingDescriptor settingDescriptor)112     public void add(SettingDescriptor settingDescriptor) {
113         Objects.requireNonNull(settingDescriptor);
114         settings.add(settingDescriptor);
115     }
116 
getSettings()117     public List<SettingDescriptor> getSettings() {
118         if (dynamicSettings) {
119             List<SettingDescriptor> list = new ArrayList<>(settings.size());
120             for (SettingDescriptor s : settings) {
121                 if (Utils.isSettingVisible(s.getTypeId(), hasHook)) {
122                     list.add(s);
123                 }
124             }
125             return list;
126         }
127         return settings;
128     }
129 
getAllSettings()130     public List<SettingDescriptor> getAllSettings() {
131         return settings;
132     }
133 
setHasStackTrace(boolean hasStackTrace)134     public void setHasStackTrace(boolean hasStackTrace) {
135         this.hasStackTrace = hasStackTrace;
136     }
137 
setHasDuration(boolean hasDuration)138     public void setHasDuration(boolean hasDuration) {
139         this.hasDuration = hasDuration;
140     }
141 
setHasCutoff(boolean hasCutoff)142     public void setHasCutoff(boolean hasCutoff) {
143        this.hasCutoff = hasCutoff;
144     }
145 
setHasThrottle(boolean hasThrottle)146     public void setHasThrottle(boolean hasThrottle) {
147         this.hasThrottle = hasThrottle;
148     }
149 
setCutoff(long cutoffNanos)150     public void setCutoff(long cutoffNanos) {
151         if (isJVM) {
152             long cutoffTicks = Utils.nanosToTicks(cutoffNanos);
153             JVM.getJVM().setCutoff(getId(), cutoffTicks);
154         }
155     }
156 
setThrottle(long eventSampleSize, long period_ms)157     public void setThrottle(long eventSampleSize, long period_ms) {
158         if (isJVM) {
159             JVM.getJVM().setThrottle(getId(), eventSampleSize, period_ms);
160         }
161     }
162 
setHasPeriod(boolean hasPeriod)163     public void setHasPeriod(boolean hasPeriod) {
164         this.hasPeriod = hasPeriod;
165     }
166 
hasStackTrace()167     public boolean hasStackTrace() {
168         return this.hasStackTrace;
169     }
170 
hasDuration()171     public boolean hasDuration() {
172         return this.hasDuration;
173     }
174 
hasPeriod()175     public boolean hasPeriod() {
176         return this.hasPeriod;
177     }
178 
hasCutoff()179     public boolean hasCutoff() {
180         return this.hasCutoff;
181     }
182 
hasThrottle()183     public boolean hasThrottle() {
184         return this.hasThrottle;
185     }
186 
isEnabled()187     public boolean isEnabled() {
188         return enabled;
189     }
190 
isJVM()191     public boolean isJVM() {
192         return isJVM;
193     }
194 
isJDK()195     public boolean isJDK() {
196         return isJDK;
197     }
198 
setEnabled(boolean enabled)199     public void setEnabled(boolean enabled) {
200         this.enabled = enabled;
201         updateCommittable();
202         if (isJVM) {
203             if (isMethodSampling) {
204                 long p = enabled ? period : 0;
205                 JVM.getJVM().setMethodSamplingInterval(getId(), p);
206             } else {
207                 JVM.getJVM().setEnabled(getId(), enabled);
208             }
209         }
210     }
211 
setPeriod(long periodMillis, boolean beginChunk, boolean endChunk)212     public void setPeriod(long periodMillis, boolean beginChunk, boolean endChunk) {
213         if (isMethodSampling) {
214             long p = enabled ? periodMillis : 0;
215             JVM.getJVM().setMethodSamplingInterval(getId(), p);
216         }
217         this.beginChunk = beginChunk;
218         this.endChunk = endChunk;
219         this.period = periodMillis;
220     }
221 
setStackTraceEnabled(boolean stackTraceEnabled)222     public void setStackTraceEnabled(boolean stackTraceEnabled) {
223         this.stackTraceEnabled = stackTraceEnabled;
224         if (isJVM) {
225             JVM.getJVM().setStackTraceEnabled(getId(), stackTraceEnabled);
226         }
227     }
228 
setThreshold(long thresholdNanos)229     public void setThreshold(long thresholdNanos) {
230         this.thresholdTicks = Utils.nanosToTicks(thresholdNanos);
231         if (isJVM) {
232             JVM.getJVM().setThreshold(getId(), thresholdTicks);
233         }
234     }
235 
isEveryChunk()236     public boolean isEveryChunk() {
237         return period == 0;
238     }
239 
getStackTraceEnabled()240     public boolean getStackTraceEnabled() {
241         return stackTraceEnabled;
242     }
243 
getThresholdTicks()244     public long getThresholdTicks() {
245         return thresholdTicks;
246     }
247 
getPeriod()248     public long getPeriod() {
249         return period;
250     }
251 
hasEventHook()252     public boolean hasEventHook() {
253         return hasHook;
254     }
255 
setEventHook(boolean hasHook)256     public void setEventHook(boolean hasHook) {
257         this.hasHook = hasHook;
258     }
259 
isBeginChunk()260     public boolean isBeginChunk() {
261         return beginChunk;
262     }
263 
isEndChunk()264     public boolean isEndChunk() {
265         return endChunk;
266     }
267 
isInstrumented()268     public boolean isInstrumented() {
269         return isInstrumented;
270     }
271 
setInstrumented()272     public void setInstrumented() {
273         isInstrumented = true;
274     }
275 
markForInstrumentation(boolean markForInstrumentation)276     public void markForInstrumentation(boolean markForInstrumentation) {
277         this.markForInstrumentation = markForInstrumentation;
278     }
279 
isMarkedForInstrumentation()280     public boolean isMarkedForInstrumentation() {
281         return markForInstrumentation;
282     }
283 
setRegistered(boolean registered)284     public boolean setRegistered(boolean registered) {
285         if (this.registered != registered) {
286             this.registered = registered;
287             updateCommittable();
288             LogTag logTag = isJVM() || isJDK() ? LogTag.JFR_SYSTEM_EVENT : LogTag.JFR_EVENT;
289             if (registered) {
290                 Logger.log(logTag, LogLevel.INFO, "Registered " + getLogName());
291             } else {
292                 Logger.log(logTag, LogLevel.INFO, "Unregistered " + getLogName());
293             }
294             if (!registered) {
295                 MetadataRepository.getInstance().setUnregistered();
296             }
297             return true;
298         }
299         return false;
300     }
301 
updateCommittable()302     private void updateCommittable() {
303         this.committable = enabled && registered;
304     }
305 
isRegistered()306     public final boolean isRegistered() {
307         return registered;
308     }
309 
310     // Efficient check of enabled && registered
isCommittable()311     public boolean isCommittable() {
312         return committable;
313     }
314 
getStackTraceOffset()315     public int getStackTraceOffset() {
316         return stackTraceOffset;
317     }
318 
isLargeSize()319     public boolean isLargeSize() {
320         return largeSize;
321     }
322 
setLargeSize()323     public void setLargeSize() {
324         largeSize = true;
325     }
326 }
327