8335779: JFR: Hide sleep events
Reviewed-by: mgronlun
This commit is contained in:
parent
537d20afbf
commit
e0fb949460
@ -47,7 +47,7 @@ class JfrIntrinsicSupport : AllStatic {
|
||||
#define JFR_HAVE_INTRINSICS
|
||||
|
||||
#define JFR_TEMPLATES(template) \
|
||||
template(jdk_jfr_internal_HiddenWait, "jdk/jfr/internal/HiddenWait") \
|
||||
template(jdk_jfr_internal_management_HiddenWait, "jdk/jfr/internal/management/HiddenWait") \
|
||||
template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \
|
||||
template(jdk_jfr_internal_event_EventWriterFactory, "jdk/jfr/internal/event/EventWriterFactory") \
|
||||
template(jdk_jfr_internal_event_EventConfiguration_signature, "Ljdk/jfr/internal/event/EventConfiguration;") \
|
||||
|
@ -1442,7 +1442,7 @@ bool ObjectMonitor::check_owner(TRAPS) {
|
||||
static inline bool is_excluded(const Klass* monitor_klass) {
|
||||
assert(monitor_klass != nullptr, "invariant");
|
||||
NOT_JFR_RETURN_(false);
|
||||
JFR_ONLY(return vmSymbols::jdk_jfr_internal_HiddenWait() == monitor_klass->name();)
|
||||
JFR_ONLY(return vmSymbols::jdk_jfr_internal_management_HiddenWait() == monitor_klass->name();)
|
||||
}
|
||||
|
||||
static void post_monitor_wait_event(EventJavaMonitorWait* event,
|
||||
|
@ -31,6 +31,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.internal.event.EventConfiguration;
|
||||
import jdk.jfr.internal.event.EventWriter;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
|
||||
/**
|
||||
* Interface against the JVM.
|
||||
|
@ -30,6 +30,7 @@ import java.time.LocalDateTime;
|
||||
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.internal.event.EventConfiguration;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
import jdk.jfr.internal.util.Utils;
|
||||
import jdk.jfr.internal.util.ValueFormatter;
|
||||
|
||||
@ -118,7 +119,8 @@ public final class JVMSupport {
|
||||
lastTimestamp = time;
|
||||
return;
|
||||
}
|
||||
Utils.takeNap(1);
|
||||
HiddenWait hiddenWait = new HiddenWait();
|
||||
hiddenWait.takeNap(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ import jdk.jfr.Period;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.consumer.RepositoryFiles;
|
||||
import jdk.jfr.internal.event.EventConfiguration;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
import jdk.jfr.internal.periodic.PeriodicEvents;
|
||||
import jdk.jfr.internal.util.Utils;
|
||||
|
||||
@ -57,6 +58,7 @@ public final class MetadataRepository {
|
||||
private final Map<String, EventType> nativeEventTypes = LinkedHashMap.newHashMap(150);
|
||||
private final Map<String, EventControl> nativeControls = LinkedHashMap.newHashMap(150);
|
||||
private final SettingsManager settingsManager = new SettingsManager();
|
||||
private final HiddenWait threadSleeper = new HiddenWait();
|
||||
private Constructor<EventConfiguration> cachedEventConfigurationConstructor;
|
||||
private boolean staleMetadata = true;
|
||||
private boolean unregistered;
|
||||
@ -341,7 +343,7 @@ public final class MetadataRepository {
|
||||
lastMillis = millis;
|
||||
return;
|
||||
}
|
||||
Utils.takeNap(1);
|
||||
threadSleeper.takeNap(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2024, 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
|
||||
@ -33,6 +33,7 @@ import jdk.jfr.RecordingState;
|
||||
import jdk.jfr.internal.SecuritySupport;
|
||||
import jdk.jfr.internal.SecuritySupport.SafePath;
|
||||
import jdk.jfr.internal.management.EventByteStream;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
import jdk.jfr.internal.management.ManagementSupport;
|
||||
|
||||
public final class OngoingStream extends EventByteStream {
|
||||
@ -44,6 +45,7 @@ public final class OngoingStream extends EventByteStream {
|
||||
|
||||
private final RepositoryFiles repositoryFiles;
|
||||
private final Recording recording;
|
||||
private final HiddenWait threadSleeper = new HiddenWait();
|
||||
private final int blockSize;
|
||||
private final long endTimeNanos;
|
||||
private final byte[] headerBytes = new byte[HEADER_SIZE];
|
||||
@ -195,19 +197,13 @@ public final class OngoingStream extends EventByteStream {
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
takeNap();
|
||||
if (!threadSleeper.takeNap(10)) {
|
||||
throw new IOException("Read operation interrupted");
|
||||
}
|
||||
}
|
||||
return EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
private void takeNap() throws IOException {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException ie) {
|
||||
throw new IOException("Read operation interrupted", ie);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ensureInput() throws IOException {
|
||||
if (input == null) {
|
||||
if (SecuritySupport.getFileSize(new SafePath(path)) < HEADER_SIZE) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2024, 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
|
||||
@ -31,6 +31,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
import jdk.jfr.internal.util.Utils;
|
||||
|
||||
public final class RecordingInput implements DataInput, AutoCloseable {
|
||||
@ -67,6 +69,7 @@ public final class RecordingInput implements DataInput, AutoCloseable {
|
||||
}
|
||||
private final int blockSize;
|
||||
private final FileAccess fileAccess;
|
||||
private final HiddenWait threadSleeper = new HiddenWait();
|
||||
private long pollCount = 1000;
|
||||
private RandomAccessFile file;
|
||||
private String filename;
|
||||
@ -453,6 +456,6 @@ public final class RecordingInput implements DataInput, AutoCloseable {
|
||||
if (pollCount < 0) {
|
||||
throw new IOException("Recording file is stuck in locked stream state.");
|
||||
}
|
||||
Utils.takeNap(1);
|
||||
threadSleeper.takeNap(1);
|
||||
}
|
||||
}
|
||||
|
@ -46,9 +46,10 @@ import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.Repository;
|
||||
import jdk.jfr.internal.SecuritySupport.SafePath;
|
||||
import jdk.jfr.internal.management.HiddenWait;;
|
||||
|
||||
public final class RepositoryFiles {
|
||||
private static final Object WAIT_OBJECT = new Object();
|
||||
private static final HiddenWait WAIT_OBJECT = new HiddenWait();
|
||||
private static final String DIRECTORY_PATTERN = "DDDD_DD_DD_DD_DD_DD_";
|
||||
public static void notifyNewFile() {
|
||||
synchronized (WAIT_OBJECT) {
|
||||
@ -59,7 +60,7 @@ public final class RepositoryFiles {
|
||||
private final FileAccess fileAccess;
|
||||
private final NavigableMap<Long, Path> pathSet = new TreeMap<>();
|
||||
private final Map<Path, Long> pathLookup = new HashMap<>();
|
||||
private final Object waitObject;
|
||||
private final HiddenWait waitObject;
|
||||
private boolean allowSubDirectory;
|
||||
private volatile boolean closed;
|
||||
private Path repository;
|
||||
@ -67,7 +68,7 @@ public final class RepositoryFiles {
|
||||
public RepositoryFiles(FileAccess fileAccess, Path repository, boolean allowSubDirectory) {
|
||||
this.repository = repository;
|
||||
this.fileAccess = fileAccess;
|
||||
this.waitObject = repository == null ? WAIT_OBJECT : new Object();
|
||||
this.waitObject = repository == null ? WAIT_OBJECT : new HiddenWait();
|
||||
this.allowSubDirectory = allowSubDirectory;
|
||||
}
|
||||
|
||||
@ -108,7 +109,7 @@ public final class RepositoryFiles {
|
||||
// was accessed. Just ignore, and retry later.
|
||||
}
|
||||
if (wait) {
|
||||
nap();
|
||||
waitObject.takeNap(1000);
|
||||
} else {
|
||||
return pathLookup.size() > beforeSize;
|
||||
}
|
||||
@ -157,16 +158,6 @@ public final class RepositoryFiles {
|
||||
}
|
||||
}
|
||||
|
||||
private void nap() {
|
||||
try {
|
||||
synchronized (waitObject) {
|
||||
waitObject.wait(1000);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updatePaths() throws IOException, DirectoryIteratorException {
|
||||
boolean foundNew = false;
|
||||
Path repoPath = repository;
|
||||
|
@ -22,11 +22,21 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.internal;
|
||||
package jdk.jfr.internal.management;
|
||||
|
||||
/**
|
||||
* The HiddenWait class is used to exclude jdk.JavaMonitorWait events
|
||||
* from being generated when Object.wait() is called on an object of this type.
|
||||
*/
|
||||
public final class HiddenWait {
|
||||
|
||||
public synchronized boolean takeNap(long timeoutMillis) {
|
||||
try {
|
||||
this.wait(timeoutMillis);
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
// Ok, ignore
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -39,45 +39,57 @@ import java.io.IOException;
|
||||
* processing should not continue.
|
||||
*/
|
||||
public final class StreamBarrier implements Closeable {
|
||||
|
||||
private final HiddenWait lock = new HiddenWait();
|
||||
private boolean activated = false;
|
||||
private boolean used = false;
|
||||
private long end = Long.MAX_VALUE;
|
||||
|
||||
// Blocks thread until barrier is deactivated
|
||||
public synchronized void check() {
|
||||
while (activated) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
public void check() {
|
||||
synchronized (lock) {
|
||||
while (activated) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setStreamEnd(long timestamp) {
|
||||
end = timestamp;
|
||||
public void setStreamEnd(long timestamp) {
|
||||
synchronized(lock) {
|
||||
end = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized long getStreamEnd() {
|
||||
return end;
|
||||
public long getStreamEnd() {
|
||||
synchronized(lock) {
|
||||
return end;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void activate() {
|
||||
activated = true;
|
||||
used = true;
|
||||
public void activate() {
|
||||
synchronized (lock) {
|
||||
activated = true;
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
activated = false;
|
||||
this.notifyAll();
|
||||
synchronized (lock) {
|
||||
activated = false;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true) if barrier is, or has been, in active state, {@code false) otherwise.
|
||||
*/
|
||||
public synchronized boolean used() {
|
||||
return used;
|
||||
public boolean used() {
|
||||
synchronized (lock) {
|
||||
return used;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,19 +48,19 @@ import jdk.internal.module.Checks;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.RecordingState;
|
||||
import jdk.jfr.internal.HiddenWait;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.MirrorEvent;
|
||||
import jdk.jfr.internal.SecuritySupport;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
import jdk.jfr.internal.settings.PeriodSetting;
|
||||
import jdk.jfr.internal.settings.StackTraceSetting;
|
||||
import jdk.jfr.internal.settings.ThresholdSetting;
|
||||
|
||||
public final class Utils {
|
||||
private static final Object flushObject = new Object();
|
||||
private static final HiddenWait flushObject = new HiddenWait();
|
||||
private static final String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk.";
|
||||
|
||||
/**
|
||||
@ -351,17 +351,6 @@ public final class Utils {
|
||||
return Type.isValidJavaFieldType(type.getName());
|
||||
}
|
||||
|
||||
public static void takeNap(long millis) {
|
||||
HiddenWait hiddenWait = new HiddenWait();
|
||||
try {
|
||||
synchronized(hiddenWait) {
|
||||
hiddenWait.wait(millis);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyFlush() {
|
||||
synchronized (flushObject) {
|
||||
flushObject.notifyAll();
|
||||
@ -369,13 +358,7 @@ public final class Utils {
|
||||
}
|
||||
|
||||
public static void waitFlush(long timeOut) {
|
||||
synchronized (flushObject) {
|
||||
try {
|
||||
flushObject.wait(timeOut);
|
||||
} catch (InterruptedException e) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
flushObject.takeNap(timeOut);
|
||||
}
|
||||
|
||||
public static Instant epochNanosToInstant(long epochNanos) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2024, 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
|
||||
@ -30,12 +30,14 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.jfr.internal.management.ManagementSupport;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
|
||||
final class DownLoadThread extends Thread {
|
||||
private final RemoteRecordingStream stream;
|
||||
private final Instant startTime;
|
||||
private final Instant endTime;
|
||||
private final DiskRepository diskRepository;
|
||||
private final HiddenWait threadSleeper = new HiddenWait();
|
||||
|
||||
DownLoadThread(RemoteRecordingStream stream, String name) {
|
||||
super(name);
|
||||
@ -64,7 +66,7 @@ final class DownLoadThread extends Thread {
|
||||
if (bytes.length != 0) {
|
||||
diskRepository.write(bytes);
|
||||
} else {
|
||||
takeNap();
|
||||
threadSleeper.takeNap(1000);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
@ -73,12 +75,4 @@ final class DownLoadThread extends Thread {
|
||||
diskRepository.complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void takeNap() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ie) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,10 @@ import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
import jdk.management.jfr.DiskRepository.DiskChunk;
|
||||
import jdk.jfr.internal.management.HiddenWait;
|
||||
|
||||
final class FileDump {
|
||||
private final HiddenWait lock = new HiddenWait();
|
||||
private final Deque<DiskChunk> chunks = new ArrayDeque<>();
|
||||
private final long stopTimeMillis;
|
||||
private boolean complete;
|
||||
@ -42,45 +44,53 @@ final class FileDump {
|
||||
this.stopTimeMillis = stopTimeMillis;
|
||||
}
|
||||
|
||||
public synchronized void add(DiskChunk dc) {
|
||||
if (isComplete()) {
|
||||
return;
|
||||
}
|
||||
dc.acquire();
|
||||
chunks.addFirst(dc);
|
||||
long endMillis = dc.endTimeNanos / 1_000_000;
|
||||
if (endMillis >= stopTimeMillis) {
|
||||
setComplete();
|
||||
public void add(DiskChunk dc) {
|
||||
synchronized (lock) {
|
||||
if (isComplete()) {
|
||||
return;
|
||||
}
|
||||
dc.acquire();
|
||||
chunks.addFirst(dc);
|
||||
long endMillis = dc.endTimeNanos / 1_000_000;
|
||||
if (endMillis >= stopTimeMillis) {
|
||||
setComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public synchronized void setComplete() {
|
||||
complete = true;
|
||||
this.notifyAll();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
for (DiskChunk dc : chunks) {
|
||||
dc.release();
|
||||
public boolean isComplete() {
|
||||
synchronized (lock) {
|
||||
return complete;
|
||||
}
|
||||
}
|
||||
|
||||
public void setComplete() {
|
||||
synchronized (lock) {
|
||||
complete = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
synchronized (lock) {
|
||||
for (DiskChunk dc : chunks) {
|
||||
dc.release();
|
||||
}
|
||||
chunks.clear();
|
||||
complete = true;
|
||||
}
|
||||
chunks.clear();
|
||||
complete = true;
|
||||
}
|
||||
|
||||
private DiskChunk oldestChunk() throws InterruptedException {
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
if (!chunks.isEmpty()) {
|
||||
return chunks.pollLast();
|
||||
}
|
||||
if (complete) {
|
||||
return null;
|
||||
}
|
||||
this.wait();
|
||||
lock.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
88
test/jdk/jdk/jfr/jvm/TestHiddenWait.java
Normal file
88
test/jdk/jdk/jfr/jvm/TestHiddenWait.java
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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.jvm;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.FlightRecorder;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordingStream;
|
||||
import jdk.test.lib.jfr.Events;
|
||||
|
||||
/**
|
||||
* @test TestHiddenWait
|
||||
* @key jfr
|
||||
* @summary Checks that JFR code don't emit noise in the form of ThreadSleep and JavaMonitorWait events.
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib
|
||||
* @run main/othervm jdk.jfr.jvm.TestHiddenWait
|
||||
*/
|
||||
public class TestHiddenWait {
|
||||
static final String PERIODIC_EVENT_NAME = "test.Periodic";
|
||||
|
||||
@Name(PERIODIC_EVENT_NAME)
|
||||
public static class PeriodicEvent extends Event {
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
FlightRecorder.addPeriodicEvent(PeriodicEvent.class, () -> {
|
||||
PeriodicEvent event = new PeriodicEvent();
|
||||
event.commit();
|
||||
});
|
||||
try (Recording r = new Recording()) {
|
||||
AtomicLong counter = new AtomicLong();
|
||||
r.enable("jdk.ThreadSleep").withoutThreshold();
|
||||
r.enable("jdk.JavaMonitorWait").withoutThreshold();
|
||||
r.enable(PERIODIC_EVENT_NAME).withPeriod(Duration.ofMillis(100));
|
||||
r.start();
|
||||
// Triggers Object.wait() in stream barrier
|
||||
try (RecordingStream b = new RecordingStream()) {
|
||||
b.startAsync();
|
||||
b.stop();
|
||||
}
|
||||
// Wait for for periodic events
|
||||
try (RecordingStream s = new RecordingStream()) {
|
||||
s.onEvent(PERIODIC_EVENT_NAME, e -> {
|
||||
if (counter.incrementAndGet() >= 2) {
|
||||
s.close();
|
||||
}
|
||||
});
|
||||
s.start();
|
||||
}
|
||||
List<RecordedEvent> events = Events.fromRecording(r);
|
||||
for (RecordedEvent event : events) {
|
||||
if (!event.getEventType().getName().equals(PERIODIC_EVENT_NAME)) {
|
||||
System.out.println(event);
|
||||
throw new Exception("Didn't expect ThreadSleep or JavaMonitorWait events");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user