/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.jini.thread;
/**
* This class provides a blocking mechanism that will not proceed while
* some operation bounded by this object is in progress. The thread
* performing the operation invokes <code>start</code> and
* <code>stop</code> on this object when it starts and stops the
* operation in progress. The thread that wants to block itself while
* the operation is in progress invokes <code>waitWhileStarted</code>,
* which will block if <code>start</code> has been invoked without a
* matching <code>stop</code>. The block will continue until a
* matching <code>stop</code> is invoked. Each <code>start</code> adds
* one to the number of operations; each <code>stop</code> subtracts
* one. When the number of operations is zero, the operation bounded
* by this object is not in progress, and <code>waitWhileStarted</code>
* will return.
* <p>
* The operation can also be blocked by invoking <code>block</code> and
* <code>unblock</code>, which nest like <code>start</code> and
* <code>stop</code>. When a <code>block</code> is invoked on this
* object, no <code>start</code> will proceed until the matching
* <code>unblock</code> call is made. The reverse is also true: when a
* <code>stop</code> call has been made on this object, no
* <code>block</code> call will proceed until the matching
* <code>stop</code> call is made. A <code>waitUntilUnblocked</code>
* method allows selective waiting for the unblocked state without
* invoking <code>start</code>.
* <p>
* A <code>waitUntilQuiet</code> call waits until the object is neither
* blocked nor stopped.
*
* @author Sun Microsystems, Inc.
*
*/
public class InProgress {
/** The state. */
private int count = 0;
private String name;
private boolean debug;
public InProgress(String name) {
this.name = name;
}
/** Signal the start of the operation this object bounds. */
public synchronized void start() throws InterruptedException {
while (count < 0)
wait();
count++;
if (debug)
show("start");
}
/** Signal the stop of the operation this object bounds. */
public synchronized void stop() {
if (--count == 0)
notifyAll();
if (count < 0) {
count = 0;
throw new IllegalMonitorStateException("Too many stop invocations");
// set to a sane state in case the exception is caught and this
// object gets re-used
}
if (debug)
show("stop");
}
/**
* Return <code>true</code> if at least one <code>start</code> has been
* invoked without its corresponding <code>stop</code>.
*/
public boolean inProgress() {
return (count > 0);
}
/**
* Wait if the operation bounded by this object is in progress, i.e.,
* between a <code>start</code> and a <code>stop</code>.
*/
public synchronized void waitWhileStarted() throws InterruptedException {
if (debug)
show("waitWhileStarted");
while (count > 0) {
wait();
if (debug)
show("waitWhileStarted");
}
}
/** Signal the blocking of the operation this object bounds. */
public synchronized void block() throws InterruptedException {
while (count > 0)
wait();
count--;
if (debug)
show("block");
}
/** Signal the unblocking of the operation this object bounds. */
public synchronized void unblock() {
if (++count == 0)
notifyAll();
if (count > 0) {
count = 0;
throw new
IllegalMonitorStateException("Too many unblock invocations");
// set to a sane state in case the exception is caught and this
// object gets re-used
}
if (debug)
show("unblock");
}
/**
* Return <code>true</code> if at least one <code>block</code> has been
* invoked without its corresponding <code>unblock</code>.
*/
public boolean blocked() {
return (count < 0);
}
/**
* Wait if the operation bounded by this object has been blocked, i.e.,
* between a <code>block</code> and a <code>unblock</code>.
*/
public synchronized void waitWhileBlocked() throws InterruptedException {
if (debug)
show("waitWhileBlocked");
while (count < 0) {
wait();
if (debug)
show("waitWhileBlocked");
}
}
/**
* Wait if the operation bounded by this object is either started
* or blocked.
*/
public synchronized void waitUntilQuiet() throws InterruptedException {
if (debug)
show("waitUntilQuiet");
while (count != 0) {
wait();
if (debug)
show("waitUntilQuiet");
}
}
/**
* Set the debug mode on or off.
*/
public void debug(boolean debugOn) {
debug = debugOn;
}
/**
* Show the current state of this object (used in debug mode).
*/
private void show(String label) {
System.out.print(name);
System.out.print(":");
System.out.print(label);
System.out.print(": count = ");
System.out.println(count);
}
}