jdk/test/java/lang/Thread/ThreadStateController.java
changeset 27340 d86f2d125146
parent 21614 c7336876755e
child 30352 551e7993450a
equal deleted inserted replaced
27339:2cf6bc8c2d2c 27340:d86f2d125146
     1 /*
     1 /*
     2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    25 import java.util.concurrent.TimeUnit;
    25 import java.util.concurrent.TimeUnit;
    26 import java.util.concurrent.TimeoutException;
    26 import java.util.concurrent.TimeoutException;
    27 import java.util.concurrent.atomic.AtomicInteger;
    27 import java.util.concurrent.atomic.AtomicInteger;
    28 import java.util.concurrent.locks.LockSupport;
    28 import java.util.concurrent.locks.LockSupport;
    29 
    29 
       
    30 import jdk.testlibrary.LockFreeLogManager;
       
    31 
    30 /**
    32 /**
    31  * ThreadStateController allows a thread to request this thread to transition
    33  * ThreadStateController allows a thread to request this thread to transition
    32  * to a specific thread state.  The {@linkplain #transitionTo request} is
    34  * to a specific thread state.  The {@linkplain #transitionTo request} is
    33  * a blocking call that the calling thread will wait until this thread is about
    35  * a blocking call that the calling thread will wait until this thread is about
    34  * going to the new state.  Only one request of state transition at a time
    36  * going to the new state.  Only one request of state transition at a time
    92     private static final int S_TIMED_PARKED = 6;
    94     private static final int S_TIMED_PARKED = 6;
    93     private static final int S_SLEEPING = 7;
    95     private static final int S_SLEEPING = 7;
    94     private static final int S_TERMINATE = 8;
    96     private static final int S_TERMINATE = 8;
    95 
    97 
    96     // for debugging
    98     // for debugging
    97     private AtomicInteger iterations = new AtomicInteger();
    99     private final AtomicInteger iterations = new AtomicInteger();
    98     private AtomicInteger interrupted = new AtomicInteger();
   100     private final AtomicInteger interrupted = new AtomicInteger();
       
   101 
       
   102     private final LockFreeLogManager logManager = new LockFreeLogManager();
       
   103 
       
   104     @Override
    99     public void run() {
   105     public void run() {
   100         // this thread has started
   106         // this thread has started
   101         while (!done) {
   107         while (!done) {
   102             // state transition
   108             // state transition
   103             int nextState = state;
   109             int nextState = state;
   117                        sum += x - r;
   123                        sum += x - r;
   118                     }
   124                     }
   119                     break;
   125                     break;
   120                 }
   126                 }
   121                 case S_BLOCKED: {
   127                 case S_BLOCKED: {
   122                     System.out.format("%d: %s is going to block (interations %d)%n",
   128                     log("%d: %s is going to block (iterations %d)%n",
   123                                       getId(), getName(), iterations.get());
   129                         getId(), getName(), iterations.get());
   124                     stateChange(nextState);
   130                     stateChange(nextState);
   125                     // going to block on lock
   131                     // going to block on lock
   126                     synchronized (lock) {
   132                     synchronized (lock) {
   127                         System.out.format("%d:   %s acquired the lock (interations %d)%n",
   133                         log("%d:   %s acquired the lock (iterations %d)%n",
   128                                           getId(), getName(), iterations.get());
   134                             getId(), getName(), iterations.get());
   129                         try {
   135                         try {
   130                             // this thread has escaped the BLOCKED state
   136                             // this thread has escaped the BLOCKED state
   131                             // release the lock and a short wait before continue
   137                             // release the lock and a short wait before continue
   132                             lock.wait(10);
   138                             lock.wait(10);
   133                         } catch (InterruptedException e) {
   139                         } catch (InterruptedException e) {
   137                     }
   143                     }
   138                     break;
   144                     break;
   139                 }
   145                 }
   140                 case S_WAITING: {
   146                 case S_WAITING: {
   141                     synchronized (lock) {
   147                     synchronized (lock) {
   142                         System.out.format("%d: %s is going to waiting (interations %d interrupted %d)%n",
   148                         log("%d: %s is going to waiting (iterations %d interrupted %d)%n",
   143                                           getId(), getName(), iterations.get(), interrupted.get());
   149                             getId(), getName(), iterations.get(), interrupted.get());
   144                         try {
   150                         try {
   145                             stateChange(nextState);
   151                             stateChange(nextState);
   146                             lock.wait();
   152                             lock.wait();
   147                             System.out.format("%d:   %s wakes up from waiting (interations %d interrupted %d)%n",
   153                             log("%d:   %s wakes up from waiting (iterations %d interrupted %d)%n",
   148                                               getId(), getName(), iterations.get(), interrupted.get());
   154                                 getId(), getName(), iterations.get(), interrupted.get());
   149                         } catch (InterruptedException e) {
   155                         } catch (InterruptedException e) {
   150                             // ignore
   156                             // ignore
   151                             interrupted.incrementAndGet();
   157                             interrupted.incrementAndGet();
   152                         }
   158                         }
   153                     }
   159                     }
   154                     break;
   160                     break;
   155                 }
   161                 }
   156                 case S_TIMED_WAITING: {
   162                 case S_TIMED_WAITING: {
   157                     synchronized (lock) {
   163                     synchronized (lock) {
   158                         System.out.format("%d: %s is going to timed waiting (interations %d interrupted %d)%n",
   164                         log("%d: %s is going to timed waiting (iterations %d interrupted %d)%n",
   159                                           getId(), getName(), iterations.get(), interrupted.get());
   165                             getId(), getName(), iterations.get(), interrupted.get());
   160                         try {
   166                         try {
   161                             stateChange(nextState);
   167                             stateChange(nextState);
   162                             lock.wait(10000);
   168                             lock.wait(10000);
   163                             System.out.format("%d:   %s wakes up from timed waiting (interations %d interrupted %d)%n",
   169                             log("%d:   %s wakes up from timed waiting (iterations %d interrupted %d)%n",
   164                                               getId(), getName(), iterations.get(), interrupted.get());
   170                                 getId(), getName(), iterations.get(), interrupted.get());
   165                         } catch (InterruptedException e) {
   171                         } catch (InterruptedException e) {
   166                             // ignore
   172                             // ignore
   167                             interrupted.incrementAndGet();
   173                             interrupted.incrementAndGet();
   168                         }
   174                         }
   169                     }
   175                     }
   170                     break;
   176                     break;
   171                 }
   177                 }
   172                 case S_PARKED: {
   178                 case S_PARKED: {
   173                     System.out.format("%d: %s is going to park (interations %d)%n",
   179                     log("%d: %s is going to park (iterations %d)%n",
   174                                       getId(), getName(), iterations.get());
   180                         getId(), getName(), iterations.get());
   175                     stateChange(nextState);
   181                     stateChange(nextState);
   176                     LockSupport.park();
   182                     LockSupport.park();
   177                     break;
   183                     break;
   178                 }
   184                 }
   179                 case S_TIMED_PARKED: {
   185                 case S_TIMED_PARKED: {
   180                     System.out.format("%d: %s is going to timed park (interations %d)%n",
   186                     log("%d: %s is going to timed park (iterations %d)%n",
   181                                       getId(), getName(), iterations.get());
   187                         getId(), getName(), iterations.get());
   182                     long deadline = System.currentTimeMillis() + 10000*1000;
   188                     long deadline = System.currentTimeMillis() + 10000*1000;
   183                     stateChange(nextState);
   189                     stateChange(nextState);
   184                     LockSupport.parkUntil(deadline);
   190                     LockSupport.parkUntil(deadline);
   185                     break;
   191                     break;
   186                 }
   192                 }
   187                 case S_SLEEPING: {
   193                 case S_SLEEPING: {
   188                     System.out.format("%d: %s is going to sleep (interations %d interrupted %d)%n",
   194                     log("%d: %s is going to sleep (iterations %d interrupted %d)%n",
   189                                       getId(), getName(), iterations.get(), interrupted.get());
   195                         getId(), getName(), iterations.get(), interrupted.get());
   190                     try {
   196                     try {
   191                         stateChange(nextState);
   197                         stateChange(nextState);
   192                         Thread.sleep(1000000);
   198                         Thread.sleep(1000000);
   193                     } catch (InterruptedException e) {
   199                     } catch (InterruptedException e) {
   194                         // finish sleeping
   200                         // finish sleeping
   217 
   223 
   218         // transition to the new state
   224         // transition to the new state
   219         if (newState == nextState) {
   225         if (newState == nextState) {
   220             state = nextState;
   226             state = nextState;
   221             phaser.arrive();
   227             phaser.arrive();
   222             System.out.format("%d:   state change: %s %s%n",
   228             log("%d:   state change: %s %s%n",
   223                               getId(), toStateName(nextState), phaserToString(phaser));
   229                 getId(), toStateName(nextState), phaserToString(phaser));
   224             return;
   230             return;
   225         }
   231         }
   226 
   232 
   227         // should never reach here
   233         // should never reach here
   228         throw new RuntimeException("current " + state + " next " + nextState +
   234         throw new RuntimeException("current " + state + " next " + nextState +
   268         nextState(timed ? S_TIMED_PARKED : S_PARKED);
   274         nextState(timed ? S_TIMED_PARKED : S_PARKED);
   269     }
   275     }
   270 
   276 
   271     private void nextState(int s) throws InterruptedException {
   277     private void nextState(int s) throws InterruptedException {
   272         final long id = Thread.currentThread().getId();
   278         final long id = Thread.currentThread().getId();
   273         System.out.format("%d: wait until the thread transitions to %s %s%n",
   279         log("%d: wait until the thread transitions to %s %s%n",
   274                           id, toStateName(s), phaserToString(phaser));
   280             id, toStateName(s), phaserToString(phaser));
   275         this.newState = s;
   281         this.newState = s;
   276         int phase = phaser.arrive();
   282         int phase = phaser.arrive();
   277         System.out.format("%d:   awaiting party arrive %s %s%n",
   283         log("%d:   awaiting party arrive %s %s%n",
   278                            id, toStateName(s), phaserToString(phaser));
   284             id, toStateName(s), phaserToString(phaser));
   279         for (;;) {
   285         for (;;) {
   280             // when this thread has changed its state before it waits or parks
   286             // when this thread has changed its state before it waits or parks
   281             // on a lock, a potential race might happen if it misses the notify
   287             // on a lock, a potential race might happen if it misses the notify
   282             // or unpark.  Hence await for the phaser to advance with timeout
   288             // or unpark.  Hence await for the phaser to advance with timeout
   283             // to cope with this race condition.
   289             // to cope with this race condition.
   299                 default:
   305                 default:
   300                     break;
   306                     break;
   301             }
   307             }
   302             try {
   308             try {
   303                 phaser.awaitAdvanceInterruptibly(phase, 100, TimeUnit.MILLISECONDS);
   309                 phaser.awaitAdvanceInterruptibly(phase, 100, TimeUnit.MILLISECONDS);
   304                 System.out.format("%d:   arrived at %s %s%n",
   310                 log("%d:   arrived at %s %s%n",
   305                                   id, toStateName(s), phaserToString(phaser));
   311                     id, toStateName(s), phaserToString(phaser));
   306                 return;
   312                 return;
   307             } catch (TimeoutException ex) {
   313             } catch (TimeoutException ex) {
   308                 // this thread hasn't arrived at this phase
   314                 // this thread hasn't arrived at this phase
   309                 System.out.format("%d: Timeout: %s%n", id, phaser);
   315                 log("%d: Timeout: %s%n", id, phaser);
   310             }
   316             }
   311         }
   317         }
   312     }
   318     }
       
   319 
   313     private String phaserToString(Phaser p) {
   320     private String phaserToString(Phaser p) {
   314         return "[phase = " + p.getPhase() +
   321         return "[phase = " + p.getPhase() +
   315                " parties = " + p.getRegisteredParties() +
   322                " parties = " + p.getRegisteredParties() +
   316                " arrived = " + p.getArrivedParties() + "]";
   323                " arrived = " + p.getArrivedParties() + "]";
   317     }
   324     }
       
   325 
   318     private String toStateName(int state) {
   326     private String toStateName(int state) {
   319         switch (state) {
   327         switch (state) {
   320             case S_RUNNABLE:
   328             case S_RUNNABLE:
   321                 return "runnable";
   329                 return "runnable";
   322             case S_WAITING:
   330             case S_WAITING:
   335                 return "terminated";
   343                 return "terminated";
   336             default:
   344             default:
   337                 return "unknown " + state;
   345                 return "unknown " + state;
   338         }
   346         }
   339     }
   347     }
       
   348 
       
   349     private void log(String msg, Object ... params) {
       
   350         logManager.log(msg, params);
       
   351     }
       
   352 
       
   353     /**
       
   354      * Waits for the controller to complete the test run and returns the
       
   355      * generated log
       
   356      * @return The controller log
       
   357      * @throws InterruptedException
       
   358      */
       
   359     public String getLog() throws InterruptedException {
       
   360         this.join();
       
   361 
       
   362         return logManager.toString();
       
   363     }
   340 }
   364 }