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