Пример #1
0
    final void test() throws Exception {
      Future[] futures = new Future[nthreads];
      for (int i = 0; i < nthreads; ++i) futures[i] = pool.submit(this);

      barrier.await();
      Thread.sleep(TIMEOUT);
      boolean tooLate = false;
      for (int i = 1; i < nthreads; ++i) {
        if (!futures[i].cancel(true)) tooLate = true;
        // Unbunch some of the cancels
        if ((i & 3) == 0) Thread.sleep(1 + rng.next() % 10);
      }

      Object f0 = futures[0].get();
      if (!tooLate) {
        for (int i = 1; i < nthreads; ++i) {
          if (!futures[i].isDone() || !futures[i].isCancelled())
            throw new Error("Only one thread should complete");
        }
      } else System.out.print("(cancelled too late) ");

      long endTime = System.nanoTime();
      long time = endTime - timer.startTime;
      if (print) {
        double secs = (double) (time) / 1000000000.0;
        System.out.println("\t " + secs + "s run time");
      }
    }
Пример #2
0
 /**
  * Spins/blocks until node s is matched by a fulfill operation.
  *
  * @param s the waiting node
  * @param timed true if timed wait
  * @param nanos timeout value
  * @return matched node, or s if cancelled
  */
 SNode awaitFulfill(SNode s, boolean timed, long nanos) {
   /*
    * When a node/thread is about to block, it sets its waiter
    * field and then rechecks state at least one more time
    * before actually parking, thus covering race vs
    * fulfiller noticing that waiter is non-null so should be
    * woken.
    *
    * When invoked by nodes that appear at the point of call
    * to be at the head of the stack, calls to park are
    * preceded by spins to avoid blocking when producers and
    * consumers are arriving very close in time.  This can
    * happen enough to bother only on multiprocessors.
    *
    * The order of checks for returning out of main loop
    * reflects fact that interrupts have precedence over
    * normal returns, which have precedence over
    * timeouts. (So, on timeout, one last check for match is
    * done before giving up.) Except that calls from untimed
    * SynchronousQueue.{poll/offer} don't check interrupts
    * and don't wait at all, so are trapped in transfer
    * method rather than calling awaitFulfill.
    */
   long lastTime = timed ? System.nanoTime() : 0;
   Thread w = Thread.currentThread();
   SNode h = head;
   int spins = (shouldSpin(s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0);
   for (; ; ) {
     if (w.isInterrupted()) s.tryCancel();
     SNode m = s.match;
     if (m != null) return m;
     if (timed) {
       long now = System.nanoTime();
       nanos -= now - lastTime;
       lastTime = now;
       if (nanos <= 0) {
         s.tryCancel();
         continue;
       }
     }
     if (spins > 0) spins = shouldSpin(s) ? (spins - 1) : 0;
     else if (s.waiter == null) s.waiter = w; // establish waiter so can park next iter
     else if (!timed) LockSupport.park(this);
     else if (nanos > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanos);
   }
 }
 private boolean discardAvailableConnections(long timeout, TimeUnit unit)
     throws InterruptedException {
   long start = System.nanoTime();
   boolean success = true;
   for (Connection connection : connections) {
     success &= connection.close(timeout - Cluster.timeSince(start, unit), unit);
     open.decrementAndGet();
   }
   return success;
 }
Пример #4
0
 /**
  * Spins/blocks until node s is fulfilled.
  *
  * @param s the waiting node
  * @param e the comparison value for checking match
  * @param timed true if timed wait
  * @param nanos timeout value
  * @return matched item, or s if cancelled
  */
 Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) {
   /* Same idea as TransferStack.awaitFulfill */
   long lastTime = timed ? System.nanoTime() : 0;
   Thread w = Thread.currentThread();
   int spins = ((head.next == s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0);
   for (; ; ) {
     if (w.isInterrupted()) s.tryCancel(e);
     Object x = s.item;
     if (x != e) return x;
     if (timed) {
       long now = System.nanoTime();
       nanos -= now - lastTime;
       lastTime = now;
       if (nanos <= 0) {
         s.tryCancel(e);
         continue;
       }
     }
     if (spins > 0) --spins;
     else if (s.waiter == null) s.waiter = w;
     else if (!timed) LockSupport.park(this);
     else if (nanos > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanos);
   }
 }
  private Connection waitForConnection(long timeout, TimeUnit unit)
      throws ConnectionException, TimeoutException {
    long start = System.nanoTime();
    long remaining = timeout;
    do {
      try {
        awaitAvailableConnection(remaining, unit);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        // If we're interrupted fine, check if there is a connection available but stop waiting
        // otherwise
        timeout = 0; // this will make us stop the loop if we don't get a connection right away
      }

      if (isShutdown()) throw new ConnectionException(host.getAddress(), "Pool is shutdown");

      int minInFlight = Integer.MAX_VALUE;
      Connection leastBusy = null;
      for (Connection connection : connections) {
        int inFlight = connection.inFlight.get();
        if (inFlight < minInFlight) {
          minInFlight = inFlight;
          leastBusy = connection;
        }
      }

      while (true) {
        int inFlight = leastBusy.inFlight.get();

        if (inFlight >= Connection.MAX_STREAM_PER_CONNECTION) break;

        if (leastBusy.inFlight.compareAndSet(inFlight, inFlight + 1)) return leastBusy;
      }

      remaining = timeout - Cluster.timeSince(start, unit);
    } while (remaining > 0);

    throw new TimeoutException();
  }
Пример #6
0
    void updateStateMachines(UPDATE_STATE_MACHINE caller)
          // We've got quite the little state machine here!
        {
      synchronized (callbackLock) {
        // ----------------------------------------------------------------------------------
        // If we're calling from other than the callback (in which we *know* the port is
        // ready), we need to check whether things are currently busy. We defer until
        // later if they are.
        if (caller == UPDATE_STATE_MACHINE.FROM_USER_WRITE) {
          if (!i2cDevice.isI2cPortReady() || callbackThread == null) return;

          // Optimized calling from user mode is not yet implemented
          return;
        }

        // ----------------------------------------------------------------------------------
        // Some ancillary bookkeeping

        if (caller == UPDATE_STATE_MACHINE.FROM_CALLBACK) {
          // Capture the current callback thread if we haven't already
          if (callbackThread == null) {
            callbackThread = Thread.currentThread();
            callbackThreadOriginalPriority = callbackThread.getPriority();
          } else
            assertTrue(
                !BuildConfig.DEBUG || callbackThread.getId() == Thread.currentThread().getId());

          // Set the thread name to make the system more debuggable
          if (0 == hardwareCycleCount)
            Thread.currentThread().setName(String.format("RWLoop(%s)", i2cDevice.getDeviceName()));

          // Adjust the target thread priority. Note that we only ever adjust it upwards,
          // not downwards, because in reality the thread is shared by other I2C objects
          // on the same controller and we don't want to fight with their understanding
          // of what the priority should be.
          int targetPriority = callbackThreadOriginalPriority + callbackThreadPriorityBoost;
          if (callbackThread.getPriority() < targetPriority) {
            try {
              callbackThread.setPriority(targetPriority);
            } catch (Exception e) {
              /* ignore: just run as is */
            }
          }

          // Update cycle statistics
          hardwareCycleCount++;
        }

        // ----------------------------------------------------------------------------------
        // Initialize state for managing state transition

        setActionFlag = false;
        queueFullWrite = false;
        queueRead = false;
        heartbeatRequired =
            (msHeartbeatInterval > 0
                && milliseconds(timeSinceLastHeartbeat) >= msHeartbeatInterval);
        enabledReadMode = false;
        enabledWriteMode = false;

        prevReadCacheStatus = readCacheStatus;
        prevWriteCacheStatus = writeCacheStatus;
        prevModeCacheStatus = modeCacheStatus;

        // ----------------------------------------------------------------------------------
        // Handle the state machine

        if (caller == UPDATE_STATE_MACHINE.FROM_CALLBACK) {
          // --------------------------------------------------------------------------
          // Deal with the fact that we've completed any previous queueing operation

          if (modeCacheStatus == MODE_CACHE_STATUS.QUEUED) modeCacheStatus = MODE_CACHE_STATUS.IDLE;

          if (readCacheStatus == READ_CACHE_STATUS.QUEUED
              || readCacheStatus == READ_CACHE_STATUS.VALID_QUEUED) {
            readCacheStatus = READ_CACHE_STATUS.QUEUE_COMPLETED;
            nanoTimeReadCacheValid = System.nanoTime();
          }

          if (writeCacheStatus == WRITE_CACHE_STATUS.QUEUED) {
            writeCacheStatus = WRITE_CACHE_STATUS.IDLE;
            // Our write mode status should have been reported back to us
            assertTrue(!BuildConfig.DEBUG || i2cDevice.isI2cPortInWriteMode());
          }

          // --------------------------------------------------------------------------
          // That limits the number of states the caches can now be in

          assertTrue(
              !BuildConfig.DEBUG
                  || (readCacheStatus == READ_CACHE_STATUS.IDLE
                      || readCacheStatus == READ_CACHE_STATUS.SWITCHINGTOREADMODE
                      || readCacheStatus == READ_CACHE_STATUS.VALID_ONLYONCE
                      || readCacheStatus == READ_CACHE_STATUS.QUEUE_COMPLETED));
          assertTrue(
              !BuildConfig.DEBUG
                  || (writeCacheStatus == WRITE_CACHE_STATUS.IDLE
                      || writeCacheStatus == WRITE_CACHE_STATUS.DIRTY));

          // --------------------------------------------------------------------------
          // Complete any read mode switch if there is one

          if (readCacheStatus == READ_CACHE_STATUS.SWITCHINGTOREADMODE) {
            // We're trying to switch into read mode. Are we there yet?
            if (i2cDevice.isI2cPortInReadMode()) {
              // See also below XYZZY
              readCacheStatus = READ_CACHE_STATUS.QUEUED;
              setActionFlag = true; // actually do an I2C read
              queueRead = true; // read the I2C read results
            } else {
              queueRead = true; // read the mode byte
            }
          }

          // --------------------------------------------------------------------------
          // If there's a write request pending, and it's ok to issue the write, do so

          else if (writeCacheStatus == WRITE_CACHE_STATUS.DIRTY) {
            issueWrite();

            // Our ordering rules are that any reads after a write have to wait until
            // the write is actually sent to the hardware, so anything we've read before is junk.
            // Note that there's an analogous check in read().
            readCacheStatus = READ_CACHE_STATUS.IDLE;
          }

          // --------------------------------------------------------------------------
          // Initiate reading if we should. Be sure to honor the policy of the read mode

          else if (readCacheStatus == READ_CACHE_STATUS.IDLE || readWindowChanged) {
            if (readWindow != null && readWindow.isOkToRead()) {
              // We're going to read from this window. If it's an only-once, then
              // ensure we don't come down this path again with the same ReadWindow instance.
              readWindow.setReadIssued();

              // You know...we might *already* have set up the controller to read what we want.
              // Maybe the previous read was a one-shot, for example.
              if (readWindowSentToController != null
                  && readWindowSentToController.contains(readWindow)
                  && i2cDevice.isI2cPortInReadMode()) {
                // Lucky us! We can go ahead and queue the read right now!
                // See also above XYZZY
                readWindowActuallyRead = readWindowSentToController;
                readCacheStatus = READ_CACHE_STATUS.QUEUED;
                setActionFlag = true; // actually do an I2C read
                queueRead = true; // read the results of the read
              } else {
                // We'll start switching now, and queue the read later
                readWindowActuallyRead = readWindow;
                startSwitchingToReadMode(readWindow);
              }
            } else {
              // There's nothing to read. Make *sure* we are idle.
              readCacheStatus = READ_CACHE_STATUS.IDLE;
            }

            readWindowChanged = false;
          }

          // --------------------------------------------------------------------------
          // Reissue any previous read if we should. The only way we are here and
          // see READ_CACHE_STATUS.QUEUE_COMPLETED is if we completed a queuing operation
          // above.

          else if (readCacheStatus == READ_CACHE_STATUS.QUEUE_COMPLETED) {
            if (readWindow != null && readWindow.isOkToRead()) {
              readCacheStatus = READ_CACHE_STATUS.VALID_QUEUED;
              setActionFlag = true; // actually do an I2C read
              queueRead = true; // read the results of the read
            } else {
              readCacheStatus = READ_CACHE_STATUS.VALID_ONLYONCE;
            }
          }

          // --------------------------------------------------------------------------
          // Completing the possibilities:

          else if (readCacheStatus == READ_CACHE_STATUS.VALID_ONLYONCE) {
            // Just leave it there until someone reads it
          }

          // ----------------------------------------------------------------------------------
          // Ok, after all that we finally know what how we're required to
          // interact with the device controller according to what we've been
          // asked to read or write. But what, now, about heartbeats?

          if (!setActionFlag && heartbeatRequired) {
            if (heartbeatAction != null) {
              if (readWindowSentToController != null && heartbeatAction.rereadLastRead) {
                // Controller is in or is switching to read mode. If he's there
                // yet, then issue an I2C read; if he's not, then he soon will be.
                if (i2cDevice.isI2cPortInReadMode()) {
                  setActionFlag = true; // issue an I2C read
                } else {
                  assertTrue(
                      !BuildConfig.DEBUG
                          || readCacheStatus == READ_CACHE_STATUS.SWITCHINGTOREADMODE);
                }
              } else if (readWindowSentToControllerInitialized
                  && readWindowSentToController == null
                  && heartbeatAction.rewriteLastWritten) {
                // Controller is in write mode, and the write cache has what we last wrote
                queueFullWrite = true;
                setActionFlag = true; // issue an I2C write
              } else if (heartbeatAction.heartbeatReadWindow != null) {
                // The simplest way to do this is just to do a new read from the outside, as that
                // means it has literally zero impact here on our state machine. That unfortunately
                // introduces concurrency where otherwise none might exist, but that's ONLY if you
                // choose this flavor of heartbeat, so that's a reasonable tradeoff.
                final ReadWindow window =
                    heartbeatAction
                        .heartbeatReadWindow; // capture here while we still have the lock
                Thread thread =
                    new Thread(
                        new Runnable() {
                          @Override
                          public void run() {
                            try {
                              I2cDeviceClient.this.read(window.getIregFirst(), window.getCreg());
                            } catch (Exception e) // paranoia
                            {
                              // ignored
                            }
                          }
                        });
                // Start the thread a-going. It will run relatively quickly and then shut down
                thread.setName("I2C heartbeat read thread");
                thread.setPriority(heartbeatAction.explicitReadPriority);
                thread.start();
              }
            }
          }

          if (setActionFlag) {
            // We're about to communicate on I2C right now, so reset the heartbeat.
            // Note that we reset() *before* we talk to the device so as to do
            // conservative timing accounting.
            timeSinceLastHeartbeat.reset();
          }
        } else if (caller == UPDATE_STATE_MACHINE.FROM_USER_WRITE) {
          // There's nothing we know to do that would speed things up, so we
          // just do nothing here and wait until the next portIsReady() callback.
        }

        // ----------------------------------------------------------------------------------
        // Read, set action flag and / or queue to module as requested

        if (setActionFlag) i2cDevice.setI2cPortActionFlag();
        else clearActionFlag();

        if (setActionFlag && !queueFullWrite) {
          i2cDevice.writeI2cPortFlagOnlyToController();
        } else if (queueFullWrite) {
          i2cDevice.writeI2cCacheToController();
          //
          if (modeCacheStatus == MODE_CACHE_STATUS.DIRTY)
            modeCacheStatus = MODE_CACHE_STATUS.QUEUED;
        }

        // Queue a read after queuing any write for a bit of paranoia: if we're mode switching
        // to write, we want that write to go out first, THEN read the mode status. It probably
        // would anyway, but why not...
        if (queueRead) {
          i2cDevice.readI2cCacheFromController();
        }

        // ----------------------------------------------------------------------------------
        // Do logging

        if (loggingEnabled) {
          StringBuilder message = new StringBuilder();

          switch (caller) {
            case FROM_CALLBACK:
              message.append(String.format("cyc %d", hardwareCycleCount));
              break;
            case FROM_USER_WRITE:
              message.append(String.format("usr write"));
              break;
          }
          if (setActionFlag) message.append("|flag");
          if (setActionFlag && !queueFullWrite) message.append("|f");
          else if (queueFullWrite) message.append("|w");
          else message.append("|.");
          if (queueRead) message.append("|r");
          if (readCacheStatus != prevReadCacheStatus)
            message.append(
                "| R." + prevReadCacheStatus.toString() + "->" + readCacheStatus.toString());
          if (writeCacheStatus != prevWriteCacheStatus)
            message.append(
                "| W." + prevWriteCacheStatus.toString() + "->" + writeCacheStatus.toString());
          // if (modeCacheStatus != prevModeCacheStatus)   message.append("| M." +
          // prevModeCacheStatus.toString() + "->" + modeCacheStatus.toString());
          if (enabledWriteMode)
            message.append(String.format("| setWrite(0x%02x,%d)", iregWriteFirst, cregWrite));
          if (enabledReadMode)
            message.append(
                String.format(
                    "| setRead(0x%02x,%d)", readWindow.getIregFirst(), readWindow.getCreg()));

          log(Log.DEBUG, message.toString());
        }

        // ----------------------------------------------------------------------------------
        // Notify anyone blocked in read() or write()
        callbackLock.notifyAll();
      }
    }