co.paralleluniverse.strands.channels.QueuePrimitiveChannel Maven / Gradle / Ivy
/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.strands.channels;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.Stranded;
import co.paralleluniverse.strands.channels.Channels.OverflowPolicy;
import co.paralleluniverse.strands.queues.BasicSingleConsumerQueue;
import java.util.concurrent.TimeUnit;
/**
* Single consumer!
*
* @author pron
*/
public class QueuePrimitiveChannel extends QueueChannel implements Stranded {
private Strand owner;
public QueuePrimitiveChannel(BasicSingleConsumerQueue queue, OverflowPolicy policy) {
super(queue, policy, true);
}
@Override
public void setStrand(Strand strand) {
if (owner != null && strand != owner)
throw new IllegalStateException("Channel " + this + " is already owned by " + owner);
this.owner = strand;
}
@Override
public Strand getStrand() {
return owner;
}
protected void maybeSetCurrentStrandAsOwner() {
if (owner == null)
setStrand(Strand.currentStrand());
else {
assert Strand.equals(owner, Strand.currentStrand()) : "This method has been called by a different strand (thread or fiber) from that owning this object";
}
}
protected void checkClosed() throws EOFException {
if (isClosed()) {
if(getCloseException() != null)
throw new ProducerException(getCloseException());
throw EOFException.instance;
}
}
public boolean hasMessage() {
return queue().hasNext();
}
boolean awaitItem() throws SuspendExecution, InterruptedException, EOFException {
maybeSetCurrentStrandAsOwner();
Object n;
Object token = sync.register();
for (int i = 0; !queue().hasNext(); i++) {
if (isSendClosed()) {
setReceiveClosed();
checkClosed();
}
sync.await(i);
}
sync.unregister(token);
return true;
}
boolean awaitItem(long timeout, TimeUnit unit) throws SuspendExecution, InterruptedException, EOFException {
if (unit == null)
return awaitItem();
if (timeout <= 0)
return queue().hasNext();
maybeSetCurrentStrandAsOwner();
Object n;
long left = unit.toNanos(timeout);
final long deadline = System.nanoTime() + left;
Object token = sync.register();
try {
for (int i = 0; !queue().hasNext(); i++) {
if (isSendClosed()) {
setReceiveClosed();
checkClosed();
}
sync.await(i, left, TimeUnit.NANOSECONDS);
left = deadline - System.nanoTime();
if (left <= 0)
return false;
}
} finally {
sync.unregister(token);
}
return true;
}
protected BasicSingleConsumerQueue queue() {
return (BasicSingleConsumerQueue) queue;
}
}