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 */
013package org.jikesrvm.scheduler;
014
015import org.vmmagic.pragma.Unpreemptible;
016import 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
032public class Latch {
033  private final Monitor schedLock = new Monitor();
034  private boolean open;
035
036  /**
037   * Create a new latch, with the given open/closed state.
038   * @param open whether the latch is open or closed at
039   *  the beginning
040   */
041  public Latch(boolean open) {
042    this.open = open;
043  }
044  /**
045   * Open the latch and let all of the thread(s) waiting on it through.
046   * But - if any of the threads is using waitAndClose(), then as soon
047   * as that thread awakes further threads will be blocked.
048   */
049  public void openWithHandshake() {
050    schedLock.lockWithHandshake();
051    open = true;
052    schedLock.broadcast();
053    schedLock.unlock();
054  }
055  /**
056   * Like open(), but does it without letting the system know that we
057   * could potentially block.  This is faster, and better for use in
058   * interrupt handlers.
059   */
060  @Uninterruptible
061  public void openNoHandshake() {
062    schedLock.lockNoHandshake();
063    open = true;
064    schedLock.broadcast();
065    schedLock.unlock();
066  }
067  /**
068   * Close the latch, causing future calls to wait() or waitAndClose()
069   * to block.
070   */
071  public void closeWithHandshake() {
072    schedLock.lockWithHandshake();
073    open = false;
074    schedLock.unlock();
075  }
076  /**
077   * Wait for the latch to become open.  If it is already open, don't
078   * wait at all.
079   */
080  public void waitWithHandshake() {
081    schedLock.lockWithHandshake();
082    while (!open) {
083      schedLock.waitWithHandshake();
084    }
085    schedLock.unlock();
086  }
087  /**
088   * Wait for the latch to become open, and then close it and return.
089   * If the latch is already open, don't wait at all, just close it
090   * immediately and return.
091   */
092  public void waitAndCloseWithHandshake() {
093    schedLock.lockWithHandshake();
094    while (!open) {
095      schedLock.waitWithHandshake();
096    }
097    open = false;
098    schedLock.unlock();
099  }
100}