![JAR search and dependency download from the Maven repository](/logo.png)
net.openhft.chronicle.threads.VanillaEventLoop Maven / Gradle / Ivy
/*
* Copyright 2016-2020 chronicle.software
*
* https://chronicle.software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.openhft.chronicle.threads;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.io.AbstractCloseable;
import net.openhft.chronicle.core.io.Closeable;
import net.openhft.chronicle.core.threads.EventHandler;
import net.openhft.chronicle.core.threads.EventLoop;
import net.openhft.chronicle.core.threads.HandlerPriority;
import net.openhft.chronicle.core.threads.InvalidEventHandlerException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.openhft.chronicle.threads.Threads.eventLoopQuietly;
import static net.openhft.chronicle.threads.Threads.loopStartedCall;
public class VanillaEventLoop extends MediumEventLoop {
public static final Set ALLOWED_PRIORITIES =
Collections.unmodifiableSet(
EnumSet.of(HandlerPriority.HIGH,
HandlerPriority.MEDIUM,
HandlerPriority.TIMER,
HandlerPriority.DAEMON));
private final List timerHandlers = new CopyOnWriteArrayList<>();
private final List daemonHandlers = new CopyOnWriteArrayList<>();
private final long timerIntervalMS;
private final Set priorities;
/**
* @param parent the parent event loop
* @param name the name of this event handler
* @param pauser the pause strategy
* @param timerIntervalMS how long to pause, Long.MAX_VALUE = always check.
* @param daemon is a demon thread
* @param binding set affinity description, "any", "none", "1", "last-1"
*/
public VanillaEventLoop(@Nullable final EventLoop parent,
final String name,
final Pauser pauser,
final long timerIntervalMS,
final boolean daemon,
final String binding,
final Set priorities) {
super(parent, name, pauser, daemon, binding);
this.timerIntervalMS = timerIntervalMS;
this.priorities = EnumSet.copyOf(priorities);
}
public static void closeAll(@NotNull final List handlers) {
// do not remove the handler here, remove all at end instead
Closeable.closeQuietly(handlers);
}
private static void clearUsedByThread(@NotNull EventHandler handler) {
if (handler instanceof AbstractCloseable)
((AbstractCloseable) handler).singleThreadedCheckReset();
}
@NotNull
@Override
public String toString() {
return "VanillaEventLoop{" +
"name='" + name + '\'' +
", parent=" + parent +
", service=" + service +
", highHandler=" + highHandler +
", mediumHandlers=" + mediumHandlers +
", timerHandlers=" + timerHandlers +
", daemonHandlers=" + daemonHandlers +
", newHandlers=" + newHandlers +
", pauser=" + pauser +
'}';
}
@Override
public void addHandler(@NotNull final EventHandler handler) {
throwExceptionIfClosed();
final HandlerPriority priority = handler.priority();
if (DEBUG_ADDING_HANDLERS)
Jvm.startup().on(getClass(), "Adding " + priority + " " + handler + " to " + this.name);
if (!priorities.contains(priority))
throw new IllegalStateException(name() + ": Unexpected priority " + priority + " for " + handler + " allows " + priorities);
addHandlerInternal(handler);
}
@Override
protected void loopStartedAllHandlers() {
super.loopStartedAllHandlers();
loopStartedForHandlerList(timerHandlers);
loopStartedForHandlerList(daemonHandlers);
}
@Override
protected void loopFinishedAllHandlers() {
super.loopFinishedAllHandlers();
if (!timerHandlers.isEmpty())
timerHandlers.forEach(Threads::loopFinishedQuietly);
if (!daemonHandlers.isEmpty())
daemonHandlers.forEach(Threads::loopFinishedQuietly);
}
@Override
protected long timerIntervalMS() {
return timerIntervalMS;
}
@Override
protected void runTimerHandlers() {
runAllHandlers(timerHandlers);
}
@Override
protected void runDaemonHandlers() {
runAllHandlers(daemonHandlers);
}
private void runAllHandlers(List handlers) {
for (int i = 0; i < handlers.size(); i++) {
EventHandler handler = null;
try {
handler = handlers.get(i);
handler.action();
} catch (InvalidEventHandlerException e) {
removeHandler(handler, handlers);
} catch (Throwable e) {
if (handle(this, handler, e))
removeHandler(handler, handlers);
}
}
}
@SuppressWarnings("fallthrough")
@Override
protected void addNewHandler(@NotNull final EventHandler handler) {
final HandlerPriority t1 = handler.priority();
switch (t1.alias()) {
case HIGH:
if (updateHighHandler(handler)) {
break;
} else {
Jvm.warn().on(getClass(), "Only one high handler supported was " + highHandler + ", treating " + handler + " as MEDIUM");
// fall through to MEDIUM
}
case MEDIUM:
if (!mediumHandlers.contains(handler)) {
clearUsedByThread(handler);
eventLoopQuietly(parent != null ? parent : this, handler);
mediumHandlers.add(handler);
mediumHandlers.sort(Comparator.comparing(EventHandler::priority).reversed());
updateMediumHandlersArray();
}
break;
case TIMER:
if (!timerHandlers.contains(handler)) {
clearUsedByThread(handler);
eventLoopQuietly(parent != null ? parent : this, handler);
timerHandlers.add(handler);
}
break;
case DAEMON:
if (!daemonHandlers.contains(handler)) {
clearUsedByThread(handler);
eventLoopQuietly(parent != null ? parent : this, handler);
daemonHandlers.add(handler);
}
break;
default:
throw new IllegalArgumentException("Cannot add a " + handler.priority() + " task to a busy waiting thread");
}
if (thread == Thread.currentThread()) {
if (loopStartedCall(this, handler)) {
if (handler == this.highHandler) {
removeHighHandler();
} else {
if (mediumHandlers.contains(handler))
removeHandler(handler, mediumHandlers);
else if (timerHandlers.contains(handler))
removeHandler(handler, timerHandlers);
else if (daemonHandlers.contains(handler))
removeHandler(handler, daemonHandlers);
}
}
}
}
@Override
public int handlerCount() {
return nonDaemonHandlerCount() + daemonHandlers.size() + timerHandlers.size();
}
@Override
protected void performClose() {
try {
super.performClose();
} finally {
daemonHandlers.clear();
timerHandlers.clear();
}
}
@Override
protected void closeAllHandlers() {
closeAll(daemonHandlers);
closeAll(timerHandlers);
super.closeAllHandlers();
}
@Override
public void dumpRunningHandlers() {
final int handlerCount = handlerCount();
if (handlerCount <= 0)
return;
final List collect = Stream.of(Collections.singletonList(highHandler), mediumHandlers, daemonHandlers, timerHandlers)
.flatMap(List::stream)
.filter(e -> e != EventHandlers.NOOP)
.filter(Closeable.class::isInstance)
.collect(Collectors.toList());
if (collect.isEmpty())
return;
Jvm.debug().on(getClass(), "Handlers still running after being closed, handlerCount=" + handlerCount);
collect.forEach(h -> Jvm.debug().on(getClass(), "\t" + h));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy