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"); } }
/** * 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; }
/** * 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(); }
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(); } }