Beispiel #1
0
  private Token receive0() {
    Node s = new Node(null, false); // the node to append

    retry:
    for (; ; ) { // restart on append race
      Object item = tryMatch(null, null, false);
      if (item != NO_MATCH) {
        s.item = item;
        return new Token(s, null);
      }

      Node pred = tryAppend(s, false);
      if (pred == null) continue retry; // lost race vs opposite mode

      if (sendClosed) {
        s.item = CHANNEL_CLOSED;
        unsplice(pred, s);
        setReceiveClosed();
        return new Token(s, null);
      }

      requestUnpark(s, Strand.currentStrand());
      return new Token(s, pred);
    }
  }
Beispiel #2
0
 @Override
 public boolean send(Message message, long timeout, TimeUnit unit)
     throws SuspendExecution, InterruptedException {
   if (message == null) throw new IllegalArgumentException("message is null");
   if (isSendClosed()) return true;
   if (xfer1(message, true, TIMED, unit.toNanos(timeout)) == null) return true;
   if (!Strand.interrupted()) return false;
   throw new InterruptedException();
 }
Beispiel #3
0
 /** Tries to artificially match a data node -- used by remove. */
 final boolean tryMatchData() {
   // assert isData;
   Object x = item;
   if (x != null && x != this && casItem(x, null)) {
     Strand.unpark(waiter, this);
     return true;
   }
   return false;
 }
Beispiel #4
0
  protected Message receiveInternal(long timeout, TimeUnit unit)
      throws SuspendExecution, InterruptedException {
    if (receiveClosed) return null;

    Object m = xfer1(null, false, TIMED, unit.toNanos(timeout));
    if (m != null || !Strand.interrupted()) {
      if (m == CHANNEL_CLOSED) return closeValue();
      return (Message) m;
    }
    throw new InterruptedException();
  }
Beispiel #5
0
  private Object tryMatch(SelectActionImpl sa, Message e, boolean haveData) {
    boolean closed = isSendClosed(); // must be read before trying to match so as not to miss puts

    for (Node h = head, p = h; p != null; ) { // find & match first node
      boolean isData = p.isData;
      Object item = p.item;

      if (item != p && (item != null) == isData) { // unmatched
        if (isData == haveData) // can't match
        break;

        // avoid deadlock by orderdering lease acquisition:
        // if p requires a lease and is of lower hashCode than sa, we return sa's lease, acquire
        // p's, and then reacquire sa's.
        SelectActionImpl sa2 = p.sa;
        boolean leasedp;
        if (sa != null && sa2 != null && sa2.selector().id < sa.selector().id) {
          sa.returnLease();
          leasedp = sa2.lease();
          if (!sa.lease()) {
            if (leasedp) sa2.returnLease();
            return LOST;
          }
        } else leasedp = p.lease();

        if (leasedp) {
          if (p.casItem(item, e)) { // match
            p.won();
            for (Node q = p; q != h; ) {
              Node n = q.next; // update by 2 unless singleton
              if (head == h && casHead(h, n == null ? q : n)) {
                h.forgetNext();
                break;
              } // advance and retry
              if ((h = head) == null || (q = h.next) == null || !q.isMatched())
                break; // unless slack < 2
            }
            Strand.unpark(p.waiter, this);
            return item;
          } else p.returnLease();
        }
      }
      Node n = p.next;
      p = (p != n) ? n : (h = head); // Use head if p offlist
    }

    if (closed) {
      assert !haveData;
      setReceiveClosed();
      return CHANNEL_CLOSED;
    }
    return NO_MATCH;
  }
 @Suspendable
 public static void handleDelayWithStrand() {
   if (delay > 0) {
     try {
       Strand.sleep(delay);
     } catch (final InterruptedException ie) {
       ie.printStackTrace(System.err);
       throw new RuntimeException(ie);
     } catch (final SuspendExecution se) {
       throw new AssertionError(se);
     }
   }
 }
Beispiel #7
0
 private void signalWaitersOnClose() {
   for (Node p = head; p != null; ) {
     if (!p.isMatched()) {
       if (!p.isData) {
         if (p.casItem(null, CHANNEL_CLOSED)) // match waiting requesters with CHANNEL_CLOSED
         Strand.unpark(p.waiter, this); // ... and wake 'em up
       } else p.tryMatchData();
     }
     Node n = p.next;
     if (n != p) p = n;
     else p = head;
   }
 }
Beispiel #8
0
 private static ActorRef getCurrentActor() {
   ActorRef actorRef = LocalActor.self();
   if (actorRef == null) {
     // create a "dummy actor" on the current strand
     Actor actor =
         new Actor(Strand.currentStrand(), null, new MailboxConfig(5, OverflowPolicy.THROW)) {
           @Override
           protected Object doRun() throws InterruptedException, SuspendExecution {
             throw new AssertionError();
           }
         };
     actorRef = new TempActor(actor);
   }
   return actorRef;
 }
Beispiel #9
0
  /**
   * 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();
    int spins =
        (w.isFiber()
            ? 0
            : -1); // no spins in fiber; otherwise, initialized after first item and cancel checks
    ThreadLocalRandom randomYields = null; // bound if needed

    if (spins == 0) requestUnpark(s, w);

    for (; ; ) {
      Object item = s.item;

      if (item == CHANNEL_CLOSED) setReceiveClosed();

      if (item != e) { // matched
        // assert item != s;
        s.forgetContents(); // avoid garbage
        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) Strand.yield(); // occasionally yield
      } else if (s.waiter == null) {
        requestUnpark(s, w); // request unpark then recheck
      } else if (timed) {
        long now = System.nanoTime();
        if ((nanos -= now - lastTime) > 0) Strand.parkNanos(this, nanos);
        lastTime = now;
      } else {
        Strand.park(this);
      }
    }
  }