Clover coverage report -
Coverage timestamp: Wed Jan 31 2007 15:38:53 EST
file stats: LOC: 621   Methods: 31
NCLOC: 424   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
NonBlockingWriterLockTest.java 56% 84.7% 93.5% 81.1%
coverage coverage
 1    package org.jboss.cache.lock;
 2   
 3    import java.util.concurrent.TimeUnit;
 4    import java.util.concurrent.locks.Lock;
 5    import junit.framework.Test;
 6    import junit.framework.TestCase;
 7    import junit.framework.TestSuite;
 8    import org.jboss.cache.misc.TestingUtil;
 9   
 10    import java.io.FileWriter;
 11    import java.io.IOException;
 12    import java.io.Writer;
 13    import java.util.Vector;
 14   
 15    /**
 16    * NonBlockingWriterLock is a read/write lock (with upgrade) that has
 17    * non-blocking write lock acquisition on existing read lock(s).
 18    * <p>Note that the write lock is exclusive among write locks, e.g.,
 19    * only one write lock can be granted at one time, but the write lock
 20    * is independent of the read locks. For example,
 21    * a read lock to be acquired will be blocked if there is existing write lock, but
 22    * will not be blocked if there are mutiple read locks already granted to other
 23    * owners. On the other hand, a write lock can be acquired as long as there
 24    * is no existing write lock, regardless how many read locks have been
 25    * granted.
 26    *
 27    * @author <a href="mailto:cavin_song@yahoo.com">Cavin Song</a> April 22, 2004
 28    * @version 1.0
 29    */
 30    public class NonBlockingWriterLockTest extends TestCase
 31    {
 32    static final NonBlockingWriterLock lock_ = new NonBlockingWriterLock();
 33    static long SLEEP_MSECS = 500;
 34    Vector lockResult = new Vector();
 35    int NO_MORE_OP = 0;
 36    int INVOKE_READ = 1;
 37    int INVOKE_WRITE = 2;
 38    int INVOKE_UPGRADE = 3;
 39   
 40  11 public NonBlockingWriterLockTest(String name)
 41    {
 42  11 super(name);
 43    }
 44   
 45   
 46  0 public static void main(String[] args) throws Exception
 47    {
 48  0 log("\nBeginning NonBlockingWriterLock automated testing ...\n");
 49   
 50  0 junit.textui.TestRunner.run(suite());
 51    }
 52   
 53    // Needed for JUnit.
 54  1 public static Test suite()
 55    {
 56  1 TestSuite suite = new TestSuite();
 57    // Adding test cases here ...
 58  1 suite.addTestSuite(NonBlockingWriterLockTest.class);
 59  1 return suite;
 60    }
 61   
 62  11 public void setUp() throws Exception {
 63  11 super.setUp();
 64  11 logX("\n");
 65  11 log("Setting up test case ...");
 66    }
 67   
 68  11 public void tearDown() throws Exception {
 69  11 super.tearDown();
 70  11 log("Tearing down test case ...");
 71    }
 72   
 73  132 public static void log(String str)
 74    {
 75  132 System.out.println(Thread.currentThread() + ": "
 76    + java.util.Calendar.getInstance().getTime() + " : " + str);
 77    }
 78   
 79    // For debugging purpose
 80  110 public static void logX(String str)
 81    {
 82  110 log(str);
 83    // try {
 84    // logToFile(str);
 85    // } catch (IOException ioe) {
 86    // }
 87    }
 88   
 89    // Debugging intrnal function
 90  0 public static void logToFile(String str) throws IOException
 91    {
 92  0 Writer out = new FileWriter("./ReadCommittedLog.txt", true/*append*/);
 93  0 out.write(str);
 94  0 out.close();
 95    }
 96   
 97    /***************************************************************/
 98    /* Utility functions to creat threads for RL, WL and UL */
 99    /***************************************************************/
 100    /**
 101    * Creates a new thread and acquires a read lock with a timeout
 102    * value specified by the caller. Optionally, the caller can request
 103    * a second read or write lock after the first read lock request.
 104    * The locking result is stored in a vector with the following
 105    * format:
 106    * <p><DL>
 107    * <DD>'case number'-'thread name'-[RL|WL|UL]-[0|1]
 108    * </DL>
 109    * <p>where:
 110    * <DL>
 111    * <DD> 'case number' is the passed in test case # by the caller.
 112    * <DD> 'thread name' is the passed in thread name by the caller.
 113    * <DD> RL - indicating was doing read lock request.
 114    * <DD> WL - indicating was doing write lock request.
 115    * <DD> UL - indicating was doing upgrade lock request.
 116    * <DD> 0 - indicating the locking request failed.
 117    * <DD> 1 - indicating the locking request succeeded.
 118    * </DL>
 119    * <p>
 120    * After all threads in each test case terminate, the test case
 121    * should make the following call to verify the test result:
 122    * <DL>
 123    * <DD> asssertTrue(checkLockingResult(expected-result-string);
 124    * </DL>
 125    * <p>
 126    * 'expected-result-string' is the locking result string
 127    * described above. For example, "8-t1-RL-0" means that thread
 128    * t1 in test case #8 doing a Read Lock request expects the
 129    * operation to fail. If the expected result string can't be
 130    * found then the test case is considered FAILED (ie, either
 131    * the read lock request was successful or did not complete).
 132    * <p>
 133    * Each test case should also call cleanLockingResult() to reset
 134    * result vector for the next test cases.
 135    * @param caseNum Arbitrary string for the test case number.
 136    * @param name Arbitrary string for the calling thread name.
 137    * @param msecs Milliseconds that the thread should sleep after
 138    * acquiring the read lock.
 139    * @param errMsg Error msg to log in case of error.
 140    * @param secondOP Set to NO_MORE_OP if a 2nd lock request is not required.
 141    * Set to INVOKE_READ, INVOKE_READ or INVOKE_UPGRADE
 142    * respectively if the 2nd lock is a read, write or
 143    * upgrade request respectively.
 144    */
 145   
 146  12 protected Thread readThread(final String caseNum, final String name,
 147    final long msecs, final long sleepSecs,
 148    final String errMsg, final int secondOP)
 149    {
 150  12 return new Thread(name)
 151    {
 152  12 public void run()
 153    {
 154  12 Lock rlock = lock_.readLock();
 155  12 try {
 156  12 if (! rlock.tryLock(msecs, TimeUnit.MILLISECONDS)) {
 157  1 logX(caseNum+"-"+name+" requesting read lock failed!\n");
 158  1 String str = caseNum + "-" + name + "-RL-0";
 159  1 postLockingResult(str);
 160  1 return;
 161    }
 162    // OK, read lock obtained, sleep and release it.
 163  11 logX(caseNum+"-"+name+" requesting read lock succeeded!\n");
 164  11 String str = caseNum + "-" + name + "-RL-1";
 165  11 postLockingResult(str);
 166  11 TestingUtil.sleepThread(sleepSecs);
 167   
 168  11 if (secondOP == INVOKE_READ)
 169  0 acquireReadLock(caseNum, name, msecs, errMsg);
 170  11 else if (secondOP == INVOKE_WRITE)
 171  2 acquireWriteLock(caseNum, name, msecs, errMsg);
 172  9 else if (secondOP == INVOKE_UPGRADE)
 173  2 acquireUpgradeLock(caseNum, name, msecs, errMsg);
 174   
 175  11 rlock.unlock();
 176  11 logX(caseNum+"-"+name+" releasing read lock.\n");
 177    } catch (Exception ex) {
 178    }
 179    }
 180    };
 181    }
 182   
 183    /**
 184    * Creates a new thread and acquires a write lock with a timeout
 185    * value specified by the caller. Similar to {@link #readThread readThread()}
 186    * except it's used for write locks.
 187    * @see #readThread readThread()
 188    */
 189  4 protected Thread writeThread(final String caseNum, final String name,
 190    final long msecs, final long sleepSecs,
 191    final String errMsg, final int secondOP)
 192    {
 193  4 return new Thread(name)
 194    {
 195  4 public void run()
 196    {
 197  4 try {
 198  4 Lock wlock = lock_.writeLock();
 199  4 if (! wlock.tryLock(msecs, TimeUnit.MILLISECONDS)) {
 200  1 logX(caseNum+"-"+name+" requesting write lock failed!\n");
 201  1 String str = caseNum + "-" + name + "-WL-0";
 202  1 postLockingResult(str);
 203  1 return;
 204    }
 205    // OK, write lock obtained, sleep and release it.
 206  3 logX(caseNum+"-"+name+" requesting write lock succeeded!\n");
 207  3 String str = caseNum + "-" + name + "-WL-1";
 208  3 postLockingResult(str);
 209  3 TestingUtil.sleepThread(sleepSecs);
 210   
 211  3 if (secondOP == INVOKE_READ)
 212  0 acquireReadLock(caseNum, name, msecs, errMsg);
 213  3 else if (secondOP == INVOKE_WRITE)
 214  0 acquireWriteLock(caseNum, name, msecs, errMsg);
 215  3 else if (secondOP == INVOKE_UPGRADE)
 216  0 acquireUpgradeLock(caseNum, name, msecs, errMsg);
 217   
 218  3 wlock.unlock();
 219  3 logX(caseNum+"-"+name+" releasing write lock.\n");
 220    } catch (Exception ex) {
 221    }
 222    }
 223    };
 224    }
 225   
 226    /**
 227    * Creates a new thread, acquires a read lock, sleeps for a while
 228    * and then tries to upgrade the read lock to a write one. Similar
 229    * to {@link #readThread readThread()} except it's used for upgrading
 230    * locks.
 231    * @see #readThread readThread()
 232    */
 233  1 protected Thread upgradeThread(final String caseNum, final String name,
 234    final long msecs, final String errMsg)
 235    {
 236  1 return new Thread(name)
 237    {
 238  1 public void run()
 239    {
 240  1 try {
 241  1 Lock rlock = lock_.readLock();
 242  1 Lock wlock = null;
 243  1 if (! rlock.tryLock(msecs, TimeUnit.MILLISECONDS)) {
 244  0 logX(caseNum+"-"+name+" requesting read lock failed!\n");
 245  0 String str = caseNum + "-" + name + "-RL-0";
 246  0 postLockingResult(str);
 247  0 return;
 248    }
 249    // OK, read lock obtained, sleep and upgrade it later.
 250  1 logX(caseNum+"-"+name+" requesting read lock succeeded (upgrade later)!\n");
 251  1 TestingUtil.sleepThread(SLEEP_MSECS/2);
 252  1 String str = caseNum + "-" + name + "-UL-";
 253  ? if ((wlock = lock_.upgradeLockAttempt(msecs)) == null)
 254    {
 255  0 logX(caseNum+"-"+name+" requesting upgrade lock failed!\n");
 256  0 str += "0";
 257    }
 258    else
 259    {
 260  1 logX(caseNum+"-"+name+" requesting upgrade lock succeeded!\n");
 261  1 str += "1";
 262    }
 263  1 postLockingResult(str);
 264    // Sleep again and then release the lock.
 265  1 TestingUtil.sleepThread(SLEEP_MSECS);
 266  1 if (wlock != null)
 267    {
 268  1 wlock.unlock();
 269  1 logX(caseNum+"-"+name+" releasing upgrade lock.\n");
 270    }
 271  1 rlock.unlock();
 272    } catch (Exception ex) {
 273    }
 274    }
 275    };
 276    }
 277   
 278    /***************************************************************/
 279    /* Utility functions to acquire RL and WL (no thread) */
 280    /***************************************************************/
 281    /**
 282    * This routine tries to acquire a read lock with a timeout value
 283    * passed in by the caller. Like {@link #readThread readThread()}
 284    * it then stores the locking result in the result vector depending
 285    * on the outcome of the request.
 286    */
 287   
 288  2 protected void acquireReadLock(final String caseNum, final String name,
 289    final long msecs, final String errMsg)
 290    {
 291  2 try {
 292  2 Lock rlock = lock_.readLock();
 293  2 if (! rlock.tryLock(msecs, TimeUnit.MILLISECONDS)) {
 294  0 logX(caseNum+"-"+name+" requesting read lock failed!\n");
 295  0 String str = caseNum + "-" + name + "-RL-0";
 296  0 postLockingResult(str);
 297  0 return;
 298    }
 299    // OK, read lock obtained, sleep and release it.
 300  2 logX(caseNum+"-"+name+" requesting read lock succeeded!\n");
 301  2 String str = caseNum + "-" + name + "-RL-1";
 302  2 postLockingResult(str);
 303  2 TestingUtil.sleepThread(SLEEP_MSECS);
 304  2 rlock.unlock();
 305  2 logX(caseNum+"-"+name+" releasing read lock.\n");
 306    } catch (Exception ex) {
 307    }
 308    }
 309   
 310    /**
 311    * Same as {@link #acquireReadLock acquireReadLock()} except
 312    * it's for write lock request.
 313    */
 314  4 protected void acquireWriteLock(final String caseNum, final String name,
 315    final long msecs, final String errMsg)
 316    {
 317  4 try {
 318  4 Lock wlock = lock_.writeLock();
 319  4 if (! wlock.tryLock(msecs, TimeUnit.MILLISECONDS)) {
 320  0 logX(caseNum+"-"+name+" requesting write lock failed!\n");
 321  0 String str = caseNum + "-" + name + "-WL-0";
 322  0 postLockingResult(str);
 323  0 return;
 324    }
 325    // OK, write lock obtained, sleep and release it.
 326  4 logX(caseNum+"-"+name+" requesting write lock succeeded!\n");
 327  4 String str = caseNum + "-" + name + "-WL-1";
 328  4 postLockingResult(str);
 329  4 TestingUtil.sleepThread(SLEEP_MSECS);
 330  4 wlock.unlock();
 331  4 logX(caseNum+"-"+name+" releasing write lock.\n");
 332    } catch (Exception ex) {
 333    }
 334    }
 335   
 336    /**
 337    * Same as {@link #acquireReadLock acquireReadLock()} except
 338    * it's for upgrade lock request.
 339    */
 340  2 protected void acquireUpgradeLock(final String caseNum, final String name,
 341    final long msecs, final String errMsg)
 342    {
 343  2 try {
 344  2 Lock ulock = null;
 345  ? if ((ulock = lock_.upgradeLockAttempt(msecs)) == null) {
 346  0 logX(caseNum+"-"+name+" requesting upgrade lock failed!\n");
 347  0 String str = caseNum + "-" + name + "-UL-0";
 348  0 postLockingResult(str);
 349  0 return;
 350    }
 351    // OK, write lock obtained, sleep and release it.
 352  2 logX(caseNum+"-"+name+" requesting upgrade lock succeeded!\n");
 353  2 String str = caseNum + "-" + name + "-UL-1";
 354  2 postLockingResult(str);
 355  2 TestingUtil.sleepThread(SLEEP_MSECS);
 356  2 ulock.unlock();
 357  2 logX(caseNum+"-"+name+" releasing upgrade lock.\n");
 358    } catch (Exception ex) {
 359    }
 360    }
 361   
 362    /***************************************************************/
 363    /* Synchronized methods handling locking result vector */
 364    /***************************************************************/
 365    /**
 366    * Clean/remove all locking results in the vector.
 367    */
 368  11 protected synchronized void cleanLockingResult()
 369    {
 370  11 lockResult.removeAllElements();
 371    }
 372   
 373    /**
 374    * Post a locking result to the vector for later verification.
 375    */
 376  25 protected synchronized void postLockingResult(Object obj)
 377    {
 378  25 logX(" Added *" + obj + "* to the result vector\n");
 379    // Make sure we only have one in the vector
 380    //if (!checkLockingResult((String)obj))
 381  25 lockResult.addElement(obj);
 382    }
 383   
 384    /**
 385    * Check if a given expected locking result is in the vector.
 386    */
 387  25 protected synchronized boolean checkLockingResult(String expected)
 388    {
 389  25 boolean rc = false;
 390  42 for (int i=0; i<lockResult.size(); i++)
 391    {
 392  42 Object ele = lockResult.elementAt(i);
 393  42 String str = (String)ele;
 394  42 if (expected.equals(str))
 395    {
 396  25 rc = true;
 397  25 break;
 398    }
 399    }
 400  25 if (rc)
 401  25 logX(" Searching for *" + expected + "* SUCCEEDED.\n");
 402    else
 403  0 logX(" Searching for *" + expected + "* FAILED.\n");
 404  25 return rc;
 405    }
 406   
 407    /***************************************************************/
 408    /* T e s t C a s e s */
 409    /***************************************************************/
 410    /** Case #10 - T1 acquires RL, T2 acquires RL followed by WL. */
 411  1 public void testWriteWithMultipleReaders() throws Exception
 412    {
 413  1 String caseNum = "10";
 414  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS*2,
 415    "1st read lock attempt failed", NO_MORE_OP);
 416  1 Thread t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
 417    "2nd read lock attempt failed", INVOKE_WRITE);
 418   
 419  1 t1.start();
 420  1 t2.start();
 421  1 t1.join(3000);
 422  1 t2.join(3000);
 423  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 424    checkLockingResult(caseNum+"-t2-RL-1") &&
 425    checkLockingResult(caseNum+"-t2-WL-1"));
 426  1 cleanLockingResult();
 427    // possilbe deadlock check
 428  1 if (t1.isAlive() || t2.isAlive())
 429  0 fail("Possible deadlock resulted in testRead.");
 430    }
 431   
 432    /** Case #11 - T1 acquires RL followed by WL, T2 acquires RL. */
 433  1 public void testUpgradeWithMultipleReadersOn1() throws Exception
 434    {
 435  1 String caseNum = "11";
 436  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
 437    "1st read lock attempt failed", INVOKE_WRITE);
 438  1 Thread t2=readThread(caseNum, "t2", 0, SLEEP_MSECS*2,
 439    "2nd read lock attempt failed", NO_MORE_OP);
 440   
 441  1 t1.start();
 442  1 t2.start();
 443  1 t1.join(3000);
 444  1 t2.join(3000);
 445  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 446    checkLockingResult(caseNum+"-t2-RL-1") &&
 447    checkLockingResult(caseNum+"-t1-WL-1"));
 448  1 cleanLockingResult();
 449    // possilbe deadlock check
 450  1 if (t1.isAlive() || t2.isAlive())
 451  0 fail("Possible deadlock resulted in testRead.");
 452    }
 453   
 454    /** Case #2 - T1 acquires RL followed by UL. */
 455  1 public void testUpgradeReadLock() throws Exception
 456    {
 457  1 String caseNum = "2";
 458  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
 459    "1st read lock attempt failed", INVOKE_UPGRADE);
 460   
 461  1 t1.start();
 462  1 t1.join(3000);
 463  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 464    checkLockingResult(caseNum+"-t1-UL-1"));
 465  1 cleanLockingResult();
 466    }
 467   
 468    /** Case #3 - T1 acquires RL followed by WL. */
 469   
 470  1 public void testReadThenWrite() throws Exception
 471    {
 472  1 String caseNum = "3";
 473  1 acquireReadLock(caseNum, "t1", 0, "1st read lock attempt failed");
 474  1 acquireWriteLock(caseNum, "t1.1", 0, "2nd write lock attempt failed");
 475  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 476    checkLockingResult(caseNum+"-t1.1-WL-1"));
 477  1 cleanLockingResult();
 478    }
 479   
 480   
 481    /** Case #5 - T1 acquires WL followed by RL.*/
 482   
 483  1 public void testWriteThenRead() throws Exception
 484    {
 485  1 String caseNum = "5";
 486  1 acquireWriteLock(caseNum, "t1", 0, "1st write lock attempt failed");
 487  1 acquireReadLock(caseNum, "t1.1", 0, "2nd read lock attempt failed");
 488  1 assertTrue(checkLockingResult(caseNum+"-t1-WL-1") &&
 489    checkLockingResult(caseNum+"-t1.1-RL-1"));
 490  1 cleanLockingResult();
 491    }
 492   
 493   
 494    /** Case #6 - T1 acquires RL, T2 acquires RL.*/
 495  1 public void testMultipleReadlock() throws Exception
 496    {
 497  1 String caseNum = "6";
 498  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
 499    "1st read lock attempt failed", NO_MORE_OP);
 500  1 Thread t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
 501    "2nd read lock attempt failed", NO_MORE_OP);
 502   
 503  1 t1.start();
 504  1 t2.start();
 505  1 t1.join(3000);
 506  1 t2.join(3000);
 507  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 508    checkLockingResult(caseNum+"-t2-RL-1"));
 509  1 cleanLockingResult();
 510    // possilbe deadlock check
 511  1 if (t1.isAlive() || t2.isAlive())
 512  0 fail("Possible deadlock resulted in testRead.");
 513    }
 514   
 515    /** Case #8 - T1 acquires RL, T2 acquires WL.*/
 516  1 public void testWriteWithExistingReader() throws Exception
 517    {
 518  1 String caseNum = "8";
 519  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
 520    "1st write lock attempt failed", NO_MORE_OP);
 521  1 Thread t2=writeThread(caseNum, "t2", 0, SLEEP_MSECS,
 522    "2nd read lock attempt failed", NO_MORE_OP);
 523   
 524  1 t1.start();
 525  1 t2.start();
 526  1 t1.join(3000);
 527  1 t2.join(3000);
 528  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 529    checkLockingResult(caseNum+"-t2-WL-1"));
 530  1 cleanLockingResult();
 531    // possilbe deadlock check
 532  1 if (t1.isAlive() || t2.isAlive())
 533  0 fail("Possible deadlock resulted in testRead.");
 534    }
 535   
 536    /** Case #13 - T1 acquires RL, T2 acquires WL.*/
 537  1 public void testReadWithExistingWriter() throws Exception
 538    {
 539  1 String caseNum = "13";
 540  1 Thread t1=writeThread(caseNum, "t1", 0, SLEEP_MSECS,
 541    "1st write lock attempt failed", NO_MORE_OP);
 542  1 Thread t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
 543    "2nd read lock attempt failed", NO_MORE_OP);
 544   
 545  1 t1.start();
 546  1 t2.start();
 547  1 t1.join(3000);
 548  1 t2.join(3000);
 549  1 assertTrue(checkLockingResult(caseNum+"-t1-WL-1") &&
 550    checkLockingResult(caseNum+"-t2-RL-0"));
 551  1 cleanLockingResult();
 552    // possilbe deadlock check
 553  1 if (t1.isAlive() || t2.isAlive())
 554  0 fail("Possible deadlock resulted in testRead.");
 555    }
 556   
 557    /** Case #14 - T1 acquires WL, T2 acquires WL.*/
 558  1 public void testMultipleWritelocks() throws Exception
 559    {
 560  1 String caseNum = "14";
 561  1 Thread t1=writeThread(caseNum, "t1", 0, SLEEP_MSECS,
 562    "1st write lock attempt failed", NO_MORE_OP);
 563  1 Thread t2=writeThread(caseNum, "t2", 0, SLEEP_MSECS,
 564    "2nd write lock attempt failed", NO_MORE_OP);
 565   
 566  1 t1.start();
 567  1 t2.start();
 568  1 t1.join(3000);
 569  1 t2.join(3000);
 570  1 assertTrue(checkLockingResult(caseNum+"-t1-WL-1") &&
 571    checkLockingResult(caseNum+"-t2-WL-0"));
 572  1 cleanLockingResult();
 573    // possilbe deadlock check
 574  1 if (t1.isAlive() || t2.isAlive())
 575  0 fail("Possible deadlock resulted in testRead.");
 576    }
 577   
 578    /** Case #7 - T1 acquires RL, T2 acquires UL.*/
 579  1 public void testUpgradeWithExistingReader() throws Exception
 580    {
 581  1 String caseNum = "7";
 582  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS,
 583    "1st read lock attempt failed", NO_MORE_OP);
 584  1 Thread t2=upgradeThread(caseNum, "t2", 0,
 585    "2nd upgrade lock attempt failed");
 586   
 587  1 t1.start();
 588  1 t2.start();
 589  1 t1.join(3000);
 590  1 t2.join(3000);
 591  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 592    checkLockingResult(caseNum+"-t2-UL-1"));
 593  1 cleanLockingResult();
 594    // possilbe deadlock check
 595  1 if (t1.isAlive() || t2.isAlive())
 596  0 fail("Possible deadlock resulted in testRead.");
 597    }
 598   
 599    /** Case #9 - T1 acquires RL, T2 acquires RL followed by UL.*/
 600  1 public void testUpgradeWithMultipleReaders() throws Exception
 601    {
 602  1 String caseNum = "9";
 603  1 Thread t1=readThread(caseNum, "t1", 0, SLEEP_MSECS*2,
 604    "1st read lock attempt failed", NO_MORE_OP);
 605  1 Thread t2=readThread(caseNum, "t2", 0, SLEEP_MSECS,
 606    "2nd read lock attempt failed", INVOKE_UPGRADE);
 607   
 608  1 t1.start();
 609  1 t2.start();
 610  1 t1.join(3000);
 611  1 t2.join(3000);
 612  1 assertTrue(checkLockingResult(caseNum+"-t1-RL-1") &&
 613    checkLockingResult(caseNum+"-t2-RL-1") &&
 614    checkLockingResult(caseNum+"-t2-UL-1"));
 615  1 cleanLockingResult();
 616    // possilbe deadlock check
 617  1 if (t1.isAlive() || t2.isAlive())
 618  0 fail("Possible deadlock resulted in testRead.");
 619    }
 620    }
 621