Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/Wicket.java
40948 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package nsk.share;2425import java.io.PrintStream;26import java.util.concurrent.TimeUnit;27import java.util.concurrent.locks.Condition;28import java.util.concurrent.locks.Lock;29import java.util.concurrent.locks.ReentrantLock;3031/**32* Wicket provides a means for one or more threads to suspend execution33* (to wait) until notified by one or more other threads that some set34* of locks is now open.35*36* <p>Wicket instances are intended to be used generally in the following37* scenarios:38*39* <ul><li>One thread starts one or more child threads and waits until the40* child threads to be started.41*42* <li>One thread starts one or more child threads and waits until at least43* one of the child threads to be started.44*45* <li>One or more child threads wait until a main thread lets them46* to finish.47*48* <li>Disable the current thread for thread scheduling purposes, for up to49* the specified waiting time.</ul>50*/5152public class Wicket {5354/** Number of closed locks, can be greater or equal to zero */55private int count;5657/** Number of waiters **/58private int waiters = 0;5960/** Enable debug output */61private PrintStream debugOutput = null;6263/** Wicket's string identifier */64private String name = "";6566private final Lock lock = new ReentrantLock();67private final Condition condition = lock.newCondition();6869/**70* Construct a Wicket with only one closed lock.71*/72public Wicket() {73this(1);74}7576/**77* Construct a Wicket with the given number of closed locks.78*79* @param _name Wicket's identifier80* @param _count the initial number of closed locks81* @param _debugOutput whether to print debug info or not82* @throws IllegalArgumentException if count is less than 183*/84public Wicket(String _name, int _count, PrintStream _debugOutput) {85this(_count);86name = _name;87debugOutput = _debugOutput;88}8990/**91* Construct a Wicket with the given number of closed locks.92*93* @param count the initial number of closed locks94* @throws IllegalArgumentException if count is less than 195*/96public Wicket(int count) {97if (count < 1)98throw new IllegalArgumentException(99"count is less than one: " + count);100this.count = count;101}102103/**104* Wait for all locks of this Wicket to be open.105*106* <p>If all locks are already open then returns immediately.107*108* <p>If at least one lock is still closed then the current thread becomes109* disabled for thread scheduling purposes and lies dormant until all110* the locks will be open by some other threads. One lock can be open111* by invoking the unlock method for this Wicket.112*113* <p>Please note, that the method would ignore Thread.interrupt() requests.114*/115public void waitFor() {116long id = System.currentTimeMillis();117118lock.lock();119try {120++waiters;121if (debugOutput != null) {122debugOutput.printf("Wicket %d %s: waitFor(). There are %d waiters totally now.\n", id, name, waiters);123}124125while (count > 0) {126try {127condition.await();128} catch (InterruptedException e) {129}130}131--waiters;132} finally {133lock.unlock();134}135}136137/**138* Wait for all locks of this Wicket to be open within the given139* period of time.140*141* <p>If all locks are already open then returns immediately with zero.142*143* <p>If the time is equal to zero, the method will not144* wait and returns a number of closed locks,145* if all locks are open, the return value is zero.146*147* <p>If at least one lock is still closed then the current thread becomes148* disabled for thread scheduling purposes and lies dormant until149* of the two things happens:150*151* <ul><li>Some other threads invoke the unlock method for this Wicket152* to open all the closed locks; or153*154* <li>The specified waiting time elapses.</ul>155*156* <p>If all locks are open then the return value is 0.157*158* <p>If the specified waiting time elapses and some locks are still closed159* then the return value is equal to number of closed locks.160*161* <p>Please note, that the method would ignore Thread.interrupt() requests.162*163* @param timeout the maximum time to wait in milliseconds164* @return the number of closed locks165* @throws IllegalArgumentException if timeout is less than 0166*/167public int waitFor(long timeout) {168if (timeout < 0)169throw new IllegalArgumentException(170"timeout value is negative: " + timeout);171172long id = System.currentTimeMillis();173174lock.lock();175try {176++waiters;177if (debugOutput != null) {178debugOutput.printf("Wicket %d %s: waitFor(). There are %d waiters totally now.\n", id, name, waiters);179}180181long waitTime = timeout;182long startTime = System.currentTimeMillis();183184while (count > 0 && waitTime > 0) {185try {186condition.await(waitTime, TimeUnit.MILLISECONDS);187} catch (InterruptedException e) {188}189waitTime = timeout - (System.currentTimeMillis() - startTime);190}191--waiters;192return count;193} finally {194lock.unlock();195}196}197198/**199* Unlock one closed lock.200*201* <p>Open a lock, reducing the number of closed locks by one.202*203* <p>If last closed lock is opened then all of the threads waiting204* by invoking the waitFor method for this Wicket will be released205* and re-enabled for thread scheduling purposes.206*207* @throws IllegalStateException if there is no one closed lock208*/209public void unlock() {210211lock.lock();212try {213if (count == 0)214throw new IllegalStateException("locks are already open");215216--count;217if (debugOutput != null) {218debugOutput.printf("Wicket %s: unlock() the count is now %d\n", name, count);219}220221if (count == 0) {222condition.signalAll();223}224} finally {225lock.unlock();226}227}228229/**230* Unlock all closed locks.231*232* <p>Open all closed locks, setting the number of closed locks to zero.233*234* <p>If any threads are waiting by invoking the waitFor method for235* this Wicket then they will be released and re-enabled for thread236* scheduling purposes.237*/238public void unlockAll() {239if (debugOutput != null) {240debugOutput.printf("Wicket %s: unlockAll()\n", name);241}242243lock.lock();244try {245count = 0;246condition.signalAll();247} finally {248lock.unlock();249}250}251252/**253* Return current number of waiters - threads that are currently254* waiting using one of waitFor methods.255*256* @return number of waiters257*/258public int getWaiters() {259260lock.lock();261try {262if (debugOutput != null) {263debugOutput.printf("Wicket %s: getWaiters()\n", name);264}265return waiters;266} finally {267lock.unlock();268}269}270}271272273