Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.zeromq.ZLoop Maven / Gradle / Ivy
package org.zeromq;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.zeromq.ZMQ.Context;
import org.zeromq.ZMQ.PollItem;
import org.zeromq.ZMQ.Poller;
import zmq.util.Objects;
/**
* The ZLoop class provides an event-driven reactor pattern. The reactor
* handles zmq.PollItem items (pollers or writers, sockets or fds), and
* once-off or repeated timers. Its resolution is 1 msec. It uses a tickless
* timer to reduce CPU interrupts in inactive processes.
*/
public class ZLoop
{
public interface IZLoopHandler
{
public int handle(ZLoop loop, PollItem item, Object arg);
}
private class SPoller
{
PollItem item;
IZLoopHandler handler;
Object arg;
int errors; // If too many errors, kill poller
protected SPoller(PollItem item, IZLoopHandler handler, Object arg)
{
this.item = item;
this.handler = handler;
this.arg = arg;
errors = 0;
}
}
private class STimer
{
int delay;
int times;
IZLoopHandler handler;
Object arg;
long when; // Clock time when alarm goes off
public STimer(int delay, int times, IZLoopHandler handler, Object arg)
{
this.delay = delay;
this.times = times;
this.handler = handler;
this.arg = arg;
this.when = -1;
}
}
private final Context context; // Context managing the pollers.
private final List pollers; // List of poll items
private final List timers; // List of timers
private int pollSize; // Size of poll set
private Poller pollset; // zmq_poll set
private SPoller[] pollact; // Pollers for this poll set
private boolean dirty; // True if pollset needs rebuilding
private boolean verbose; // True if verbose tracing wanted
private final List zombies; // List of timers to kill
private final List newTimers; // List of timers to add
public ZLoop(Context context)
{
Objects.requireNonNull(context, "Context has to be supplied for ZLoop");
this.context = context;
pollers = new ArrayList<>();
timers = new ArrayList<>();
zombies = new ArrayList<>();
newTimers = new ArrayList<>();
}
public ZLoop(ZContext ctx)
{
this(ctx.getContext());
}
/**
* @deprecated no-op behaviour
*/
@Deprecated
public void destroy()
{
// do nothing
}
// We hold an array of pollers that matches the pollset, so we can
// register/cancel pollers orthogonally to executing the pollset
// activity on pollers. Returns 0 on success, -1 on failure.
private void rebuild()
{
pollact = null;
pollSize = pollers.size();
if (pollset != null) {
pollset.close();
}
pollset = context.poller(pollSize);
assert (pollset != null);
pollact = new SPoller[pollSize];
int itemNbr = 0;
for (SPoller poller : pollers) {
pollset.register(poller.item);
pollact[itemNbr] = poller;
itemNbr++;
}
dirty = false;
}
private long ticklessTimer()
{
// Calculate tickless timer, up to 1 hour
long tickless = System.currentTimeMillis() + 1000 * 3600;
for (STimer timer : timers) {
if (timer.when == -1) {
timer.when = timer.delay + System.currentTimeMillis();
}
if (tickless > timer.when) {
tickless = timer.when;
}
}
long timeout = tickless - System.currentTimeMillis();
if (timeout < 0) {
timeout = 0;
}
if (verbose) {
System.out.printf("I: zloop: polling for %d msec\n", timeout);
}
return timeout;
}
// --------------------------------------------------------------------------
// Register pollitem with the reactor. When the pollitem is ready, will call
// the handler, passing the arg. Returns 0 if OK, -1 if there was an error.
// If you register the pollitem more than once, each instance will invoke its
// corresponding handler.
public int addPoller(PollItem pollItem, IZLoopHandler handler, Object arg)
{
if (pollItem.getRawSocket() == null && pollItem.getSocket() == null) {
return -1;
}
SPoller poller = new SPoller(pollItem, handler, arg);
pollers.add(poller);
dirty = true;
if (verbose) {
System.out.printf(
"I: zloop: register %s poller (%s, %s)\n",
pollItem.getSocket() != null ? pollItem.getSocket().getType() : "RAW",
pollItem.getSocket(),
pollItem.getRawSocket());
}
return 0;
}
// --------------------------------------------------------------------------
// Cancel a pollitem from the reactor, specified by socket or FD. If both
// are specified, uses only socket. If multiple poll items exist for same
// socket/FD, cancels ALL of them.
public void removePoller(PollItem pollItem)
{
Iterator it = pollers.iterator();
while (it.hasNext()) {
SPoller p = it.next();
if (pollItem.equals(p.item)) {
it.remove();
dirty = true;
}
}
if (verbose) {
System.out.printf(
"I: zloop: cancel %s poller (%s, %s)",
pollItem.getSocket() != null ? pollItem.getSocket().getType() : "RAW",
pollItem.getSocket(),
pollItem.getRawSocket());
}
}
// --------------------------------------------------------------------------
// Register a timer that expires after some delay and repeats some number of
// times. At each expiry, will call the handler, passing the arg. To
// run a timer forever, use 0 times. Returns 0 if OK, -1 if there was an
// error.
public int addTimer(int delay, int times, IZLoopHandler handler, Object arg)
{
STimer timer = new STimer(delay, times, handler, arg);
// We cannot touch self->timers because we may be executing that
// from inside the poll loop. So, we hold the new timer on the newTimers
// list, and process that list when we're done executing timers.
newTimers.add(timer);
if (verbose) {
System.out.printf("I: zloop: register timer delay=%d times=%d\n", delay, times);
}
return 0;
}
// --------------------------------------------------------------------------
// Cancel all timers for a specific argument (as provided in zloop_timer)
// Returns 0 on success.
public int removeTimer(Object arg)
{
Objects.requireNonNull(arg, "Argument has to be supplied");
// We cannot touch self->timers because we may be executing that
// from inside the poll loop. So, we hold the arg on the zombie
// list, and process that list when we're done executing timers.
zombies.add(arg);
if (verbose) {
System.out.printf("I: zloop: cancel timer\n");
}
return 0;
}
// --------------------------------------------------------------------------
// Set verbose tracing of reactor on/off
public void verbose(boolean verbose)
{
this.verbose = verbose;
}
// --------------------------------------------------------------------------
// Start the reactor. Takes control of the thread and returns when the 0MQ
// context is terminated or the process is interrupted, or any event handler
// returns -1. Event handlers may register new sockets and timers, and
// cancel sockets. Returns 0 if interrupted, -1 if cancelled by a
// handler, positive on internal error
public int start()
{
int rc = 0;
timers.addAll(newTimers);
newTimers.clear();
// Recalculate all timers now
for (STimer timer : timers) {
timer.when = timer.delay + System.currentTimeMillis();
}
// Main reactor loop
while (!Thread.currentThread().isInterrupted()) {
if (dirty) {
// If s_rebuild_pollset() fails, break out of the loop and
// return its error
rebuild();
}
long wait = ticklessTimer();
rc = pollset.poll(wait);
if (rc == -1) {
if (verbose) {
System.out.printf("I: zloop: interrupted (%d)\n", rc);
}
rc = 0;
break; // Context has been shut down
}
// Handle any timers that have now expired
Iterator it = timers.iterator();
while (it.hasNext()) {
STimer timer = it.next();
if (System.currentTimeMillis() >= timer.when && timer.when != -1) {
if (verbose) {
System.out.println("I: zloop: call timer handler");
}
rc = timer.handler.handle(this, null, timer.arg);
if (rc == -1) {
break; // Timer handler signaled break
}
if (timer.times != 0 && --timer.times == 0) {
it.remove();
}
else {
timer.when = timer.delay + System.currentTimeMillis();
}
}
}
if (rc == -1) {
break; // Some timer signalled break from the reactor loop
}
// Handle any pollers that are ready
for (int itemNbr = 0; itemNbr < pollSize; itemNbr++) {
SPoller poller = pollact[itemNbr];
if (pollset.getItem(itemNbr).isError()) {
if (verbose) {
System.out.printf(
"I: zloop: can't poll %s socket (%s, %s)\n",
poller.item.getSocket() != null ? poller.item.getSocket().getType() : "RAW",
poller.item.getSocket(),
poller.item.getRawSocket());
}
// Give handler one chance to handle error, then kill
// poller because it'll disrupt the reactor otherwise.
if (poller.errors++ > 0) {
removePoller(poller.item);
}
}
else {
poller.errors = 0; // A non-error happened
}
if (pollset.getItem(itemNbr).readyOps() > 0) {
if (verbose) {
System.out.printf(
"I: zloop: call %s socket handler (%s, %s)\n",
poller.item.getSocket() != null ? poller.item.getSocket().getType() : "RAW",
poller.item.getSocket(),
poller.item.getRawSocket());
}
rc = poller.handler.handle(this, poller.item, poller.arg);
if (rc == -1) {
break; // Poller handler signaled break
}
}
}
// Now handle any timer zombies
// This is going to be slow if we have many zombies
for (Object arg : zombies) {
it = timers.iterator();
while (it.hasNext()) {
STimer timer = it.next();
if (timer.arg == arg) {
it.remove();
}
}
}
// Now handle any new timers added inside the loop
timers.addAll(newTimers);
newTimers.clear();
if (rc == -1) {
break;
}
}
return rc;
}
}