1 /* 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 it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 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 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23 /* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Doug Lea with assistance from members of JCP JSR-166 30 * Expert Group and released to the public domain, as explained at 31 * http://creativecommons.org/publicdomain/zero/1.0/ 32 */ 33 34 /* 35 * @test 36 * @bug 8005697 37 * @summary Basic tests for StampedLock 38 * @library /test/lib 39 * @author Chris Hegarty 40 */ 41 42 import static java.util.concurrent.TimeUnit.SECONDS; 43 import static java.util.concurrent.TimeUnit.MILLISECONDS; 44 import static java.util.concurrent.TimeUnit.NANOSECONDS; 45 46 import java.util.Iterator; 47 import java.util.concurrent.Phaser; 48 import java.util.concurrent.TimeUnit; 49 import java.util.concurrent.atomic.AtomicInteger; 50 import java.util.concurrent.locks.Lock; 51 import java.util.concurrent.locks.ReadWriteLock; 52 import java.util.concurrent.locks.StampedLock; 53 import jdk.test.lib.Utils; 54 55 public class Basic { 56 static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000); 57 58 static void checkResult(Locker l, Class<? extends Throwable> c) { 59 Throwable t = l.thrown(); 60 if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) { 61 fail("Mismatch in thread " + 62 l.getName() + ": " + 63 t + ", " + 64 (c == null ? "<null>" : c.getName())); 65 } 66 67 if (c == null) 68 check(l.stamp() != 0L); // must have acquired the lock 69 else 70 check(l.stamp() == 0L); // must NOT have acquired the lock 71 } 72 73 //---------------------------------------------------------------- 74 // Mechanism to get all test threads into "running" mode. 75 //---------------------------------------------------------------- 76 static void toTheStartingGate(Phaser gate) { 77 try { 78 gate.arriveAndAwaitAdvance(); 79 } catch (Throwable t) { 80 unexpected(t); 81 } 82 } 83 84 abstract static class Locker extends Thread { 85 static AtomicInteger count = new AtomicInteger(1); 86 private volatile Throwable thrown; 87 private volatile long stamp; 88 protected void thrown(Throwable thrown) { this.thrown = thrown; } 89 public Throwable thrown() { return thrown; } 90 protected void stamp(long stamp) { this.stamp = stamp; } 91 public long stamp() { return stamp; } 92 93 Locker() { 94 this("Locker"); 95 } 96 97 Locker(String name) { 98 this.setName(name + ":" + count.getAndIncrement()); 99 this.setDaemon(true); 100 } 101 } 102 103 abstract static class Reader extends Locker { 104 Reader() { super("Reader"); } 105 Reader(String name) { super(name); } 106 } 107 108 static Reader reader(final StampedLock sl, final Phaser gate) { 109 return new Reader() { public void run() { 110 if (gate != null ) toTheStartingGate(gate); 111 stamp(sl.readLock()); 112 try { 113 check(sl.validate(stamp())); 114 check(sl.isReadLocked()); 115 check(!sl.isWriteLocked()); 116 } finally { sl.unlockRead(stamp()); } }}; 117 } 118 119 static Reader readerView(final StampedLock sl, final Phaser gate) { 120 return new Reader("ReaderView") { public void run() { 121 if (gate != null ) toTheStartingGate(gate); 122 final Lock rl = sl.asReadLock(); 123 rl.lock(); 124 try { 125 stamp(1L); // got the lock 126 check(sl.isReadLocked()); 127 check(!sl.isWriteLocked()); 128 } finally { rl.unlock(); } }}; 129 } 130 131 static Reader reader(StampedLock sl, Phaser gate, boolean view) { 132 return view ? readerView(sl, gate) : reader(sl, gate); 133 } 134 135 static Reader interruptibleReader(final StampedLock sl, 136 final long timeout, 137 final TimeUnit unit, 138 final Phaser gate) { 139 return new Reader("InterruptibleReader") { public void run() { 140 if (gate != null ) toTheStartingGate(gate); 141 try { 142 if (timeout < 0) 143 stamp(sl.readLockInterruptibly()); 144 else 145 stamp(sl.tryReadLock(timeout, unit)); 146 check(sl.validate(stamp())); 147 check(sl.isReadLocked()); 148 check(!sl.isWriteLocked()); 149 } catch (Throwable x) { thrown(x); 150 } finally { if (stamp() != 0L) sl.unlockRead(stamp()); } }}; 151 } 152 153 static Reader interruptibleReaderView(final StampedLock sl, 154 final long timeout, 155 final TimeUnit unit, 156 final Phaser gate) { 157 return new Reader("InterruptibleReaderView") { public void run() { 158 if (gate != null ) toTheStartingGate(gate); 159 final Lock rl = sl.asReadLock(); 160 161 try { 162 if (timeout < 0) 163 rl.lockInterruptibly(); 164 else 165 rl.tryLock(timeout, unit); 166 stamp(1L); // got the lock 167 check(sl.isReadLocked()); 168 check(!sl.isWriteLocked()); 169 } catch (Throwable x) { thrown(x); 170 } finally { if (stamp() != 0L) rl.unlock(); } }}; 171 } 172 173 static Reader interruptibleReader(final StampedLock sl, 174 final long timeout, 175 final TimeUnit unit, 176 final Phaser gate, 177 final boolean view) { 178 return view ? interruptibleReaderView(sl, timeout, unit, gate) 179 : interruptibleReader(sl, timeout, unit, gate); 180 } 181 182 abstract static class Writer extends Locker { 183 Writer() { super("Writer"); } 184 Writer(String name) { super(name); } 185 } 186 187 static Writer writer(final StampedLock sl, final Phaser gate) { 188 return new Writer() { public void run() { 189 if (gate != null ) toTheStartingGate(gate); 190 try { 191 stamp(sl.writeLock()); 192 check(sl.validate(stamp())); 193 check(!sl.isReadLocked()); 194 check(sl.isWriteLocked()); 195 } finally { sl.unlockWrite(stamp()); } }}; 196 } 197 198 static Writer writerView(final StampedLock sl, final Phaser gate) { 199 return new Writer("WriterView") { public void run() { 200 if (gate != null ) toTheStartingGate(gate); 201 Lock wl = sl.asWriteLock(); 202 wl.lock(); 203 try { 204 stamp(1L); // got the lock 205 check(!sl.isReadLocked()); 206 check(sl.isWriteLocked()); 207 } finally { wl.unlock(); } }}; 208 } 209 210 static Writer writer(StampedLock sl, Phaser gate, boolean view) { 211 return view ? writerView(sl, gate) : writer(sl, gate); 212 } 213 214 static Writer interruptibleWriter(final StampedLock sl, 215 final long timeout, 216 final TimeUnit unit, 217 final Phaser gate) { 218 return new Writer("InterruptibleWriter") { public void run() { 219 if (gate != null ) toTheStartingGate(gate); 220 try { 221 if (timeout < 0) 222 stamp(sl.writeLockInterruptibly()); 223 else 224 stamp(sl.tryWriteLock(timeout, unit)); 225 check(sl.validate(stamp())); 226 check(!sl.isReadLocked()); 227 check(sl.isWriteLocked()); 228 } catch (Throwable x) { thrown(x); 229 } finally { if (stamp() != 0L) sl.unlockWrite(stamp()); } }}; 230 } 231 232 static Writer interruptibleWriterView(final StampedLock sl, 233 final long timeout, 234 final TimeUnit unit, 235 final Phaser gate) { 236 return new Writer("InterruptibleWriterView") { public void run() { 237 if (gate != null ) toTheStartingGate(gate); 238 Lock wl = sl.asWriteLock(); 239 try { 240 if (timeout < 0) 241 wl.lockInterruptibly(); 242 else 243 wl.tryLock(timeout, unit); 244 stamp(1L); // got the lock 245 check(!sl.isReadLocked()); 246 check(sl.isWriteLocked()); 247 } catch (Throwable x) { thrown(x); 248 } finally { if (stamp() != 0L) wl.unlock(); } }}; 249 } 250 251 static Writer interruptibleWriter(final StampedLock sl, 252 final long timeout, 253 final TimeUnit unit, 254 final Phaser gate, 255 final boolean view) { 256 return view ? interruptibleWriterView(sl, timeout, unit, gate) 257 : interruptibleWriter(sl, timeout, unit, gate); 258 } 259 260 // Returns an infinite lazy list of all possible reader combinations. 261 static Iterator<Reader> readerIterator(final StampedLock sl, 262 final Phaser gate) { 263 return new Iterator<Reader>() { 264 int i = 0; 265 boolean view = false; 266 public boolean hasNext() { return true; } 267 public Reader next() { 268 switch ((i++)&7) { 269 case 1: case 4: case 7: 270 return reader(sl, gate, view ^= true); 271 case 2: case 5: 272 return interruptibleReader(sl, -1, SECONDS, gate, view ^= true); 273 default: 274 return interruptibleReader(sl, LONG_DELAY_MS, MILLISECONDS, gate, view ^= true); }} 275 public void remove() {throw new UnsupportedOperationException();}}; 276 } 277 278 // Returns an infinite lazy list of all possible writer combinations. 279 static Iterator<Writer> writerIterator(final StampedLock sl, 280 final Phaser gate) { 281 return new Iterator<Writer>() { 282 int i = 0; 283 boolean view = false; 284 public boolean hasNext() { return true; } 285 public Writer next() { 286 switch ((i++)&7) { 287 case 1: case 4: case 7: 288 return writer(sl, gate, view ^= true); 289 case 2: case 5: 290 return interruptibleWriter(sl, -1, SECONDS, gate, view ^= true); 291 default: 292 return interruptibleWriter(sl, LONG_DELAY_MS, MILLISECONDS, gate, view ^= true); }} 293 public void remove() {throw new UnsupportedOperationException();}}; 294 } 295 296 static class SimpleTimer { 297 long startTime = System.nanoTime(); 298 long elapsedMillis() { 299 long now = System.nanoTime(); 300 long elapsed = NANOSECONDS.toMillis(now - startTime); 301 startTime = now; 302 return elapsed; 303 } 304 void printElapsed() { System.out.println(elapsedMillis() + " ms"); } 305 } 306 307 static void waitForThreadToBlock(Thread thread) { 308 for (long startTime = 0;;) { 309 Thread.State state = thread.getState(); 310 if (state == Thread.State.WAITING || 311 state == Thread.State.TIMED_WAITING) 312 break; 313 if (startTime == 0) startTime = System.nanoTime(); 314 else if (System.nanoTime() - startTime > 10L * 1000L * 1000L * 1000L) 315 throw new AssertionError("timed out waiting for thread to block"); 316 } 317 } 318 319 private static void realMain(String[] args) throws Throwable { 320 SimpleTimer timer = new SimpleTimer(); 321 322 //---------------------------------------------------------------- 323 System.out.print("Some basic sanity: "); 324 //---------------------------------------------------------------- 325 try { 326 final StampedLock sl = new StampedLock(); 327 check(!sl.isReadLocked()); 328 check(!sl.isWriteLocked()); 329 long stamp = sl.tryOptimisticRead(); 330 check(stamp != 0L); 331 check(sl.validate(stamp)); 332 check(!sl.validate(0)); 333 334 stamp = sl.writeLock(); 335 try { 336 check(sl.validate(stamp)); 337 check(!sl.isReadLocked()); 338 check(sl.isWriteLocked()); 339 check(sl.tryReadLock() == 0L); 340 check(sl.tryReadLock(1, MILLISECONDS) == 0L); 341 check(sl.tryOptimisticRead() == 0L); 342 check(sl.tryWriteLock() == 0L); 343 check(sl.tryWriteLock(1, MILLISECONDS) == 0L); 344 check(!sl.tryUnlockRead()); 345 check(sl.tryConvertToWriteLock(stamp) == stamp); 346 try { 347 sl.unlockRead(stamp); 348 fail("Expected unlockRead to throw when not holding read lock"); 349 } catch (IllegalMonitorStateException x) { 350 pass(); 351 } 352 check(sl.validate(stamp)); 353 } finally { 354 sl.unlockWrite(stamp); 355 } 356 check(!sl.isWriteLocked()); 357 358 stamp = sl.readLock(); 359 try { 360 check(sl.validate(stamp)); 361 check(sl.isReadLocked()); 362 check(!sl.isWriteLocked()); 363 check(sl.tryOptimisticRead() != 0L); 364 check(sl.tryWriteLock() == 0L); 365 check(sl.tryWriteLock(1, MILLISECONDS) == 0L); 366 check(!sl.tryUnlockWrite()); 367 check(sl.tryConvertToReadLock(stamp) == stamp); 368 try { 369 sl.unlockWrite(stamp); 370 fail("Expected unlockWrite to throw when not holding read lock"); 371 } catch (IllegalMonitorStateException x) { 372 pass(); 373 } 374 check(sl.validate(stamp)); 375 } finally { 376 sl.unlockRead(stamp); 377 } 378 check(!sl.isReadLocked()); 379 380 stamp = sl.tryReadLock(1, MILLISECONDS); 381 try { 382 check(stamp != 0L); 383 } finally { 384 sl.unlockRead(stamp); 385 } 386 } catch (Throwable t) { unexpected(t); } 387 timer.printElapsed(); 388 389 //---------------------------------------------------------------- 390 System.out.print("Multiple writers single reader: "); 391 //---------------------------------------------------------------- 392 try { 393 StampedLock sl = new StampedLock(); 394 int nThreads = 10; 395 Phaser gate = new Phaser(nThreads + 2); 396 Iterator<Writer> writers = writerIterator(sl, gate); 397 Iterator<Reader> readers = readerIterator(sl, gate); 398 for (int i = 0; i < 2; i++) { 399 check(!sl.isReadLocked()); 400 check(!sl.isWriteLocked()); 401 check(!sl.tryUnlockRead()); 402 check(!sl.tryUnlockWrite()); 403 check(sl.tryOptimisticRead() != 0L); 404 Locker[] wThreads = new Locker[nThreads]; 405 for (int j=0; j<nThreads; j++) 406 wThreads[j] = writers.next(); 407 for (int j=0; j<nThreads; j++) 408 wThreads[j].start(); 409 Reader reader = readers.next(); reader.start(); 410 toTheStartingGate(gate); 411 reader.join(); 412 for (int j=0; j<nThreads; j++) 413 wThreads[j].join(); 414 for (int j=0; j<nThreads; j++) 415 checkResult(wThreads[j], null); 416 checkResult(reader, null); 417 } 418 } catch (Throwable t) { unexpected(t); } 419 timer.printElapsed(); 420 421 //---------------------------------------------------------------- 422 System.out.print("Multiple readers single writer: "); 423 //---------------------------------------------------------------- 424 try { 425 StampedLock sl = new StampedLock(); 426 int nThreads = 10; 427 Phaser gate = new Phaser(nThreads + 2); 428 Iterator<Writer> writers = writerIterator(sl, gate); 429 Iterator<Reader> readers = readerIterator(sl, gate); 430 for (int i = 0; i < 2; i++) { 431 check(!sl.isReadLocked()); 432 check(!sl.isWriteLocked()); 433 check(!sl.tryUnlockRead()); 434 check(!sl.tryUnlockWrite()); 435 check(sl.tryOptimisticRead() != 0L); 436 Locker[] rThreads = new Locker[nThreads]; 437 for (int j=0; j<nThreads; j++) 438 rThreads[j] = readers.next(); 439 for (int j=0; j<nThreads; j++) 440 rThreads[j].start(); 441 Writer writer = writers.next(); writer.start(); 442 toTheStartingGate(gate); 443 writer.join(); 444 for (int j=0; j<nThreads; j++) 445 rThreads[j].join(); 446 for (int j=0; j<nThreads; j++) 447 checkResult(rThreads[j], null); 448 checkResult(writer, null); 449 } 450 } catch (Throwable t) { unexpected(t); } 451 timer.printElapsed(); 452 453 //---------------------------------------------------------------- 454 System.out.print("thread interrupted: "); 455 //---------------------------------------------------------------- 456 try { 457 // We test interrupting both before and after trying to acquire 458 boolean view = false; 459 StampedLock sl = new StampedLock(); 460 for (long timeout : new long[] { -1L, LONG_DELAY_MS, -1L, LONG_DELAY_MS }) { 461 long stamp; 462 Thread.State state; 463 464 stamp = sl.writeLock(); 465 try { 466 Reader r = interruptibleReader(sl, timeout, MILLISECONDS, null, view); 467 r.start(); 468 r.interrupt(); 469 r.join(); 470 checkResult(r, InterruptedException.class); 471 } finally { 472 sl.unlockWrite(stamp); 473 } 474 475 stamp = sl.writeLock(); 476 try { 477 Reader r = interruptibleReader(sl, timeout, MILLISECONDS, null, view); 478 r.start(); 479 waitForThreadToBlock(r); 480 r.interrupt(); 481 r.join(); 482 checkResult(r, InterruptedException.class); 483 } finally { 484 sl.unlockWrite(stamp); 485 } 486 487 stamp = sl.readLock(); 488 try { 489 Writer w = interruptibleWriter(sl, timeout, MILLISECONDS, null, view); 490 w.start(); 491 w.interrupt(); 492 w.join(); 493 checkResult(w, InterruptedException.class); 494 } finally { 495 sl.unlockRead(stamp); 496 } 497 498 stamp = sl.readLock(); 499 try { 500 Writer w = interruptibleWriter(sl, timeout, MILLISECONDS, null, view); 501 w.start(); 502 waitForThreadToBlock(w); 503 w.interrupt(); 504 w.join(); 505 checkResult(w, InterruptedException.class); 506 } finally { 507 sl.unlockRead(stamp); 508 } 509 510 check(!sl.isReadLocked()); 511 check(!sl.isWriteLocked()); 512 check(!sl.tryUnlockRead()); 513 check(!sl.tryUnlockWrite()); 514 check(sl.tryOptimisticRead() != 0L); 515 if (timeout == LONG_DELAY_MS) 516 view = true; 517 } 518 } catch (Throwable t) { unexpected(t); } 519 timer.printElapsed(); 520 521 //---------------------------------------------------------------- 522 System.out.print("timeout: "); 523 //---------------------------------------------------------------- 524 try { 525 StampedLock sl = new StampedLock(); 526 for (long timeout : new long[] { 0L, 5L }) { 527 long stamp = sl.writeLock(); 528 try { 529 check(sl.tryReadLock(timeout, MILLISECONDS) == 0L); 530 } finally { 531 sl.unlockWrite(stamp); 532 } 533 stamp = sl.readLock(); 534 try { 535 check(sl.tryWriteLock(timeout, MILLISECONDS) == 0L); 536 } finally { 537 sl.unlockRead(stamp); 538 } 539 check(!sl.isReadLocked()); 540 check(!sl.isWriteLocked()); 541 check(!sl.tryUnlockRead()); 542 check(!sl.tryUnlockWrite()); 543 check(sl.tryOptimisticRead() != 0L); 544 } 545 } catch (Throwable t) { unexpected(t); } 546 timer.printElapsed(); 547 548 //---------------------------------------------------------------- 549 System.out.print("optimistic read: "); 550 //---------------------------------------------------------------- 551 try { 552 StampedLock sl = new StampedLock(); 553 Iterator<Writer> writers = writerIterator(sl, null); 554 Iterator<Reader> readers = readerIterator(sl, null); 555 for (int i = 0; i < 10; i++) { 556 check(!sl.isReadLocked()); 557 check(!sl.isWriteLocked()); 558 check(!sl.tryUnlockRead()); 559 check(!sl.tryUnlockWrite()); 560 long stamp = sl.tryOptimisticRead(); 561 check(stamp != 0L); 562 check(sl.tryConvertToOptimisticRead(stamp) == stamp); 563 Reader r = readers.next(); r.start(); 564 r.join(); 565 checkResult(r, null); 566 check(sl.validate(stamp)); 567 check(sl.tryConvertToOptimisticRead(stamp) == stamp); 568 Writer w = writers.next(); w.start(); 569 w.join(); 570 checkResult(w, null); 571 check(sl.validate(stamp) == false); 572 } 573 } catch (Throwable t) { unexpected(t); } 574 timer.printElapsed(); 575 576 //---------------------------------------------------------------- 577 System.out.print("convert: "); 578 //---------------------------------------------------------------- 579 try { 580 StampedLock sl = new StampedLock(); 581 for (int i = 0; i < 2; i++) { 582 check(!sl.isReadLocked()); 583 check(!sl.isWriteLocked()); 584 check(!sl.tryUnlockRead()); 585 check(!sl.tryUnlockWrite()); 586 long stamp = sl.tryOptimisticRead(); 587 check(stamp != 0L); 588 check((stamp = sl.tryConvertToReadLock(stamp)) != 0L); 589 check(sl.validate(stamp)); 590 check(sl.isReadLocked()); 591 check(sl.tryWriteLock() == 0L); 592 check(sl.tryWriteLock(1L, MILLISECONDS) == 0L); 593 check((stamp = sl.tryConvertToWriteLock(stamp)) != 0L); 594 check(sl.validate(stamp)); 595 check(!sl.isReadLocked()); 596 check(sl.isWriteLocked()); 597 check(sl.tryReadLock(1L, MILLISECONDS) == 0L); 598 if (i != 0) { 599 sl.unlockWrite(stamp); 600 continue; 601 } 602 // convert down 603 check((stamp = sl.tryConvertToReadLock(stamp)) != 0L); 604 check(sl.validate(stamp)); 605 check(sl.isReadLocked()); 606 check(!sl.isWriteLocked()); 607 check(sl.tryWriteLock() == 0L); 608 check(sl.tryWriteLock(1L, MILLISECONDS) == 0L); 609 check((stamp = sl.tryConvertToOptimisticRead(stamp)) != 0L); 610 check(sl.validate(stamp)); 611 check(!sl.isReadLocked()); 612 check(!sl.isWriteLocked()); 613 check(sl.validate(stamp)); 614 } 615 } catch (Throwable t) { unexpected(t); } 616 timer.printElapsed(); 617 618 //---------------------------------------------------------------- 619 System.out.print("views: "); 620 //---------------------------------------------------------------- 621 try { 622 StampedLock sl = new StampedLock(); 623 624 Lock rl = sl.asReadLock(); 625 Lock wl = sl.asWriteLock(); 626 for (int i = 0; i < 2; i++) { 627 rl.lock(); 628 try { 629 check(sl.isReadLocked()); 630 check(!sl.isWriteLocked()); 631 check(sl.tryWriteLock() == 0L); 632 check(sl.tryWriteLock(1L, MILLISECONDS) == 0L); 633 } finally { 634 rl.unlock(); 635 } 636 check(!sl.isReadLocked()); 637 check(!sl.isWriteLocked()); 638 639 wl.lock(); 640 try { 641 check(!sl.isReadLocked()); 642 check(sl.isWriteLocked()); 643 check(sl.tryWriteLock() == 0L); 644 check(sl.tryWriteLock(1L, MILLISECONDS) == 0L); 645 } finally { 646 wl.unlock(); 647 } 648 check(!sl.isReadLocked()); 649 check(!sl.isWriteLocked()); 650 651 ReadWriteLock rwl = sl.asReadWriteLock(); 652 rl = rwl.readLock(); 653 wl = rwl.writeLock(); 654 } 655 } catch (Throwable t) { unexpected(t); } 656 timer.printElapsed(); 657 } 658 659 //--------------------- Infrastructure --------------------------- 660 static volatile int passed = 0, failed = 0; 661 static void pass() {passed++;} 662 static void fail() {failed++; Thread.dumpStack();} 663 static void fail(String msg) {System.out.println(msg); fail();} 664 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 665 static void check(boolean cond) {if (cond) pass(); else fail();} 666 static void equal(Object x, Object y) { 667 if (x == null ? y == null : x.equals(y)) pass(); 668 else fail(x + " not equal to " + y);} 669 public static void main(String[] args) throws Throwable { 670 try {realMain(args);} catch (Throwable t) {unexpected(t);} 671 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 672 if (failed > 0) throw new AssertionError("Some tests failed");} 673 }