use of co.paralleluniverse.strands.Strand in project quasar by puniverse.
the class ActorTest method testSpawnWithStrandFactory.
@Test
public void testSpawnWithStrandFactory() throws Exception {
final AtomicBoolean run = new AtomicBoolean(false);
Actor<Message, Integer> actor = new BasicActor<Message, Integer>(mailboxConfig) {
@Override
protected Integer doRun() throws SuspendExecution, InterruptedException {
run.set(true);
return 3;
}
};
ActorRef a = actor.spawn(new StrandFactoryBuilder().setFiber(null).setNameFormat("my-fiber-%d").build());
Strand s = LocalActor.getStrand(a);
assertTrue(s.isFiber());
assertThat(s.getName(), equalTo("my-fiber-0"));
assertThat((Integer) LocalActor.get(a), equalTo(3));
assertThat(run.get(), is(true));
run.set(false);
actor = new BasicActor<Message, Integer>(mailboxConfig) {
@Override
protected Integer doRun() throws SuspendExecution, InterruptedException {
run.set(true);
return 3;
}
};
a = actor.spawn(new StrandFactoryBuilder().setThread(false).setNameFormat("my-thread-%d").build());
s = LocalActor.getStrand(a);
assertTrue(!s.isFiber());
assertThat(s.getName(), equalTo("my-thread-0"));
LocalActor.join(a);
assertThat(run.get(), is(true));
run.set(false);
Actor<Message, Integer> actor2 = new BasicActor<Message, Integer>("coolactor", mailboxConfig) {
@Override
protected Integer doRun() throws SuspendExecution, InterruptedException {
run.set(true);
return 3;
}
};
a = actor2.spawn(new StrandFactoryBuilder().setFiber(null).setNameFormat("my-fiber-%d").build());
s = LocalActor.getStrand(a);
assertTrue(s.isFiber());
assertThat(s.getName(), equalTo("coolactor"));
assertThat((Integer) LocalActor.get(a), equalTo(3));
assertThat(run.get(), is(true));
run.set(false);
actor2 = new BasicActor<Message, Integer>("coolactor", mailboxConfig) {
@Override
protected Integer doRun() throws SuspendExecution, InterruptedException {
run.set(true);
return 3;
}
};
a = actor2.spawn(new StrandFactoryBuilder().setThread(false).setNameFormat("my-thread-%d").build());
s = LocalActor.getStrand(a);
assertTrue(!s.isFiber());
assertThat(s.getName(), equalTo("coolactor"));
LocalActor.join(a);
assertThat(run.get(), is(true));
run.set(false);
}
use of co.paralleluniverse.strands.Strand in project quasar by puniverse.
the class StampedLock method acquireWrite.
/**
* See above for explanation.
*
* @param interruptible true if should check interrupts and if so
* return INTERRUPTED
* @param deadline if nonzero, the System.nanoTime value to timeout
* at (and return zero)
* @return next state, or INTERRUPTED
*/
private long acquireWrite(boolean interruptible, long deadline) throws SuspendExecution {
WNode node = null, p;
for (int spins = -1; ; ) {
// spin while enqueuing
long s, ns;
if (((s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
return ns;
} else if (spins > 0) {
if (ThreadLocalRandom.current().nextInt() >= 0)
--spins;
} else if ((p = wtail) == null) {
// initialize queue
WNode h = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, h))
wtail = h;
} else if (spins < 0)
spins = (p == whead) ? SPINS : 0;
else if (node == null)
node = new WNode(WMODE, p);
else if (node.prev != p)
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
p.next = node;
break;
}
}
for (int spins = SPINS; ; ) {
WNode np, pp;
int ps;
long s, ns;
Strand w;
while ((np = node.prev) != p && np != null) // stale
(p = np).next = node;
if (whead == p) {
for (int k = spins; ; ) {
// spin at head
if (((s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) {
whead = node;
node.prev = null;
return ns;
}
} else if (ThreadLocalRandom.current().nextInt() >= 0 && --k <= 0)
break;
}
if (spins < MAX_HEAD_SPINS)
spins <<= 1;
}
if ((ps = p.status) == 0)
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {
if ((pp = p.prev) != null) {
node.prev = pp;
pp.next = node;
}
} else {
// 0 argument to park means no timeout
long time;
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
node.strand = Strand.currentStrand();
if (// recheck
node.prev == p && p.status == WAITING && (p != whead || (state & ABITS) != 0L))
park(time);
node.strand = null;
if (interruptible && Strand.interrupted())
return cancelWaiter(node, node, true);
}
}
}
use of co.paralleluniverse.strands.Strand in project quasar by puniverse.
the class StampedLock method cancelWaiter.
/**
* If node non-null, forces cancel status and unsplices it from
* queue if possible and wakes up any cowaiters (of the node, or
* group, as applicable), and in any case helps release current
* first waiter if lock is free. (Calling with null arguments
* serves as a conditional form of release, which is not currently
* needed but may be needed under possible future cancellation
* policies). This is a variant of cancellation methods in
* AbstractQueuedSynchronizer (see its detailed explanation in AQS
* internal documentation).
*
* @param node if nonnull, the waiter
* @param group either node or the group node is cowaiting with
* @param interrupted if already interrupted
* @return INTERRUPTED if interrupted or Strand.interrupted, else zero
*/
private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
if (node != null && group != null) {
Strand w;
node.status = CANCELLED;
node.strand = null;
// unsplice cancelled nodes from group
for (WNode p = group, q; (q = p.cowait) != null; ) {
if (q.status == CANCELLED)
U.compareAndSwapObject(p, WNEXT, q, q.next);
else
p = q;
}
if (group == node) {
// detach and wake up uncancelled co-waiters
WNode r;
while ((r = node.cowait) != null) {
if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) && (w = r.strand) != null) {
r.strand = null;
w.unpark();
}
}
for (WNode pred = node.prev; pred != null; ) {
// unsplice
// find valid successor
WNode succ, pp;
while ((succ = node.next) == null || succ.status == CANCELLED) {
// find successor the slow way
WNode q = null;
for (WNode t = wtail; t != null && t != node; t = t.prev) if (t.status != CANCELLED)
// don't link if succ cancelled
q = t;
if (// ensure accurate successor
succ == q || U.compareAndSwapObject(node, WNEXT, succ, succ = q)) {
if (succ == null && node == wtail)
U.compareAndSwapObject(this, WTAIL, node, pred);
break;
}
}
if (// unsplice pred link
pred.next == node)
U.compareAndSwapObject(pred, WNEXT, node, succ);
if (succ != null && (w = succ.strand) != null) {
succ.strand = null;
// wake up succ to observe new pred
w.unpark();
}
if (pred.status != CANCELLED || (pp = pred.prev) == null)
break;
// repeat if new pred wrong/cancelled
node.prev = pp;
U.compareAndSwapObject(pp, WNEXT, pred, succ);
pred = pp;
}
}
}
// Possibly release first waiter
WNode h;
while ((h = whead) != null) {
long s;
// similar to release() but check eligibility
WNode q;
if ((q = h.next) == null || q.status == CANCELLED) {
for (WNode t = wtail; t != null && t != h; t = t.prev) if (t.status <= 0)
q = t;
}
if (h == whead) {
if (q != null && h.status == 0 && // waiter is eligible
((s = state) & ABITS) != WBIT && (s == 0L || q.mode == RMODE))
release(h);
break;
}
}
return (interrupted || Strand.interrupted()) ? INTERRUPTED : 0L;
}
use of co.paralleluniverse.strands.Strand in project quasar by puniverse.
the class TransferChannel method awaitMatch.
/**
* Spins/yields/blocks until node s is matched or caller gives up.
*
* @param s the waiting node
* @param pred the predecessor of s, or s itself if it has no
* predecessor, or null if unknown (the null case does not occur
* in any current calls but may in possible future extensions)
* @param e the comparison value for checking match
* @param timed if true, wait only until timeout elapses
* @param nanos timeout in nanosecs, used only if timed is true
* @return matched item, or e if unmatched on interrupt or timeout
*/
private Message awaitMatch(Node s, Node pred, Message e, boolean timed, long nanos) throws SuspendExecution {
long lastTime = timed ? System.nanoTime() : 0L;
Strand w = Strand.currentStrand();
// no spins in fiber; otherwise, initialized after first item and cancel checks
int spins = (w.isFiber() ? 0 : -1);
// bound if needed
ThreadLocalRandom randomYields = null;
if (spins == 0)
requestUnpark(s, w);
for (; ; ) {
Object item = s.item;
if (item == CHANNEL_CLOSED)
setReceiveClosed();
if (item != e) {
// matched
// assert item != s;
// avoid garbage
s.forgetContents();
return this.<Message>cast(item);
}
if ((w.isInterrupted() || (timed && nanos <= 0)) && s.casItem(e, s)) {
// cancel
unsplice(pred, s);
return e;
}
if (spins < 0) {
// establish spins at/near front
if ((spins = spinsFor(pred, s.isData)) > 0)
randomYields = ThreadLocalRandom.current();
} else if (spins > 0) {
// spin
--spins;
if (randomYields.nextInt(CHAINED_SPINS) == 0)
// occasionally yield
Strand.yield();
} else if (s.waiter == null) {
// request unpark then recheck
requestUnpark(s, w);
} else if (timed) {
long now = System.nanoTime();
if ((nanos -= now - lastTime) > 0)
Strand.parkNanos(this, nanos);
lastTime = now;
} else {
Strand.park(this);
}
}
}
use of co.paralleluniverse.strands.Strand in project quasar by puniverse.
the class AbstractQueuedLongSynchronizer method fullGetFirstQueuedStrand.
/**
* Version of getFirstQueuedStrand called when fastpath fails
*/
private Strand fullGetFirstQueuedStrand() {
/*
* The first node is normally head.next. Try to get its
* strand field, ensuring consistent reads: If strand
* field is nulled out or s.prev is no longer head, then
* some other strand(s) concurrently performed setHead in
* between some of our reads. We try this twice before
* resorting to traversal.
*/
Node h, s;
Strand st;
if (((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.strand) != null) || ((h = head) != null && (s = h.next) != null && s.prev == head && (st = s.strand) != null))
return st;
/*
* Head's next field might not have been set yet, or may have
* been unset after setHead. So we must check to see if tail
* is actually first node. If not, we continue on, safely
* traversing from tail back to head to find first,
* guaranteeing termination.
*/
Node t = tail;
Strand firstStrand = null;
while (t != null && t != head) {
Strand tt = t.strand;
if (tt != null)
firstStrand = tt;
t = t.prev;
}
return firstStrand;
}
Aggregations