001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.scheduler;
014    
015    import org.vmmagic.pragma.Unpreemptible;
016    import org.vmmagic.pragma.Uninterruptible;
017    
018    /**
019     * An implementation of a latch using the HeavyCondLock in "nice" mode.
020     * This essentially gives you park/unpark functionality.  It can also
021     * be used like the Win32-style AutoResetEvent or ManualResetEvent.
022     * <p>
023     * Park/unpark example: use open() to unpark and waitAndClose() to park.
024     * <p>
025     * AutoResetEvent example: use open() to set, close() to reset, and
026     * waitAndClose() to wait.
027     * <p>
028     * ManualResetEvent example: use open() to set, close() to reset, and
029     * wait() to wait.
030     */
031    @Unpreemptible
032    public class Latch {
033      private final Monitor schedLock = new Monitor();
034      private boolean open;
035      /** Create a new latch, with the given open/closed state. */
036      public Latch(boolean open) {
037        this.open = open;
038      }
039      /**
040       * Open the latch and let all of the thread(s) waiting on it through.
041       * But - if any of the threads is using waitAndClose(), then as soon
042       * as that thread awakes further threads will be blocked.
043       */
044      public void openWithHandshake() {
045        schedLock.lockWithHandshake();
046        open=true;
047        schedLock.broadcast();
048        schedLock.unlock();
049      }
050      /**
051       * Like open(), but does it without letting the system know that we
052       * could potentially block.  This is faster, and better for use in
053       * interrupt handlers.
054       */
055      @Uninterruptible
056      public void openNoHandshake() {
057        schedLock.lockNoHandshake();
058        open=true;
059        schedLock.broadcast();
060        schedLock.unlock();
061      }
062      /**
063       * Close the latch, causing future calls to wait() or waitAndClose()
064       * to block.
065       */
066      public void closeWithHandshake() {
067        schedLock.lockWithHandshake();
068        open=false;
069        schedLock.unlock();
070      }
071      /**
072       * Wait for the latch to become open.  If it is already open, don't
073       * wait at all.
074       */
075      public void waitWithHandshake() {
076        schedLock.lockWithHandshake();
077        while (!open) {
078          schedLock.waitWithHandshake();
079        }
080        schedLock.unlock();
081      }
082      /**
083       * Wait for the latch to become open, and then close it and return.
084       * If the latch is already open, don't wait at all, just close it
085       * immediately and return.
086       */
087      public void waitAndCloseWithHandshake() {
088        schedLock.lockWithHandshake();
089        while (!open) {
090          schedLock.waitWithHandshake();
091        }
092        open=false;
093        schedLock.unlock();
094      }
095    }