1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package libcore.java.lang; 18 19import junit.framework.TestCase; 20 21public class OldAndroidMonitorTest extends TestCase { 22 23 public void testWaitArgumentsTest() throws Exception { 24 /* Try some valid arguments. These should all 25 * return very quickly. 26 */ 27 try { 28 synchronized (this) { 29 /* millisecond version */ 30 wait(1); 31 wait(10); 32 33 /* millisecond + nanosecond version */ 34 wait(0, 1); 35 wait(0, 999999); 36 wait(1, 1); 37 wait(1, 999999); 38 } 39 } catch (InterruptedException ex) { 40 throw new RuntimeException("good Object.wait() interrupted", 41 ex); 42 } catch (Exception ex) { 43 throw new RuntimeException("Unexpected exception when calling" + 44 "Object.wait() with good arguments", ex); 45 } 46 47 /* Try some invalid arguments. 48 */ 49 boolean sawException = false; 50 try { 51 synchronized (this) { 52 wait(-1); 53 } 54 } catch (InterruptedException ex) { 55 throw new RuntimeException("bad Object.wait() interrupted", ex); 56 } catch (IllegalArgumentException ex) { 57 sawException = true; 58 } catch (Exception ex) { 59 throw new RuntimeException("Unexpected exception when calling" + 60 "Object.wait() with bad arguments", ex); 61 } 62 if (!sawException) { 63 throw new RuntimeException("bad call to Object.wait() should " + 64 "have thrown IllegalArgumentException"); 65 } 66 67 sawException = false; 68 try { 69 synchronized (this) { 70 wait(0, -1); 71 } 72 } catch (InterruptedException ex) { 73 throw new RuntimeException("bad Object.wait() interrupted", ex); 74 } catch (IllegalArgumentException ex) { 75 sawException = true; 76 } catch (Exception ex) { 77 throw new RuntimeException("Unexpected exception when calling" + 78 "Object.wait() with bad arguments", ex); 79 } 80 if (!sawException) { 81 throw new RuntimeException("bad call to Object.wait() should " + 82 "have thrown IllegalArgumentException"); 83 } 84 85 sawException = false; 86 try { 87 synchronized (this) { 88 /* The legal range of nanos is 0-999999. */ 89 wait(0, 1000000); 90 } 91 } catch (InterruptedException ex) { 92 throw new RuntimeException("bad Object.wait() interrupted", ex); 93 } catch (IllegalArgumentException ex) { 94 sawException = true; 95 } catch (Exception ex) { 96 throw new RuntimeException("Unexpected exception when calling" + 97 "Object.wait() with bad arguments", ex); 98 } 99 if (!sawException) { 100 throw new RuntimeException("bad call to Object.wait() should " + 101 "have thrown IllegalArgumentException"); 102 } 103 } 104 105 private class Interrupter extends Thread { 106 Waiter waiter; 107 108 Interrupter(String name, Waiter waiter) { 109 super(name); 110 this.waiter = waiter; 111 } 112 113 public void run() { 114 try { 115 run_inner(); 116 } catch (Throwable t) { 117 OldAndroidMonitorTest.errorException = t; 118 OldAndroidMonitorTest.testThread.interrupt(); 119 } 120 } 121 122 void run_inner() { 123 waiter.spin = true; 124 // System.out.println("InterruptTest: starting waiter"); 125 waiter.start(); 126 127 try { 128 Thread.currentThread().sleep(500); 129 } catch (InterruptedException ex) { 130 throw new RuntimeException("Test sleep interrupted.", ex); 131 } 132 133 /* Waiter is spinning, and its monitor should still be thin. 134 */ 135 // System.out.println("Test interrupting waiter"); 136 waiter.interrupt(); 137 waiter.spin = false; 138 139 for (int i = 0; i < 3; i++) { 140 /* Wait for the waiter to start waiting. 141 */ 142 synchronized (waiter.interrupterLock) { 143 try { 144 waiter.interrupterLock.wait(); 145 } catch (InterruptedException ex) { 146 throw new RuntimeException("Test wait interrupted.", ex); 147 } 148 } 149 150 /* Before interrupting, grab the waiter lock, which 151 * guarantees that the waiter is already sitting in wait(). 152 */ 153 synchronized (waiter) { 154 //System.out.println("Test interrupting waiter (" + i + ")"); 155 waiter.interrupt(); 156 } 157 } 158 159 // System.out.println("Test waiting for waiter to die."); 160 try { 161 waiter.join(); 162 } catch (InterruptedException ex) { 163 throw new RuntimeException("Test join interrupted.", ex); 164 } 165 // System.out.println("InterruptTest done."); 166 } 167 } 168 169 private class Waiter extends Thread { 170 Object interrupterLock = new Object(); 171 Boolean spin = false; 172 173 Waiter(String name) { 174 super(name); 175 } 176 177 public void run() { 178 try { 179 run_inner(); 180 } catch (Throwable t) { 181 OldAndroidMonitorTest.errorException = t; 182 OldAndroidMonitorTest.testThread.interrupt(); 183 } 184 } 185 186 void run_inner() { 187 // System.out.println("Waiter spinning"); 188 while (spin) { 189 // We're going to get interrupted while we spin. 190 } 191 if (interrupted()) { 192 // System.out.println("Waiter done spinning; interrupted."); 193 } else { 194 throw new RuntimeException("Thread not interrupted " + 195 "during spin"); 196 } 197 198 synchronized (this) { 199 Boolean sawEx = false; 200 201 try { 202 synchronized (interrupterLock) { 203 interrupterLock.notify(); 204 } 205 // System.out.println("Waiter calling wait()"); 206 this.wait(); 207 } catch (InterruptedException ex) { 208 sawEx = true; 209 // System.out.println("wait(): Waiter caught " + ex); 210 } 211 // System.out.println("wait() finished"); 212 213 if (!sawEx) { 214 throw new RuntimeException("Thread not interrupted " + 215 "during wait()"); 216 } 217 } 218 synchronized (this) { 219 Boolean sawEx = false; 220 221 try { 222 synchronized (interrupterLock) { 223 interrupterLock.notify(); 224 } 225 // System.out.println("Waiter calling wait(1000)"); 226 this.wait(1000); 227 } catch (InterruptedException ex) { 228 sawEx = true; 229 // System.out.println("wait(1000): Waiter caught " + ex); 230 } 231 // System.out.println("wait(1000) finished"); 232 233 if (!sawEx) { 234 throw new RuntimeException("Thread not interrupted " + 235 "during wait(1000)"); 236 } 237 } 238 synchronized (this) { 239 Boolean sawEx = false; 240 241 try { 242 synchronized (interrupterLock) { 243 interrupterLock.notify(); 244 } 245 // System.out.println("Waiter calling wait(1000, 5000)"); 246 this.wait(1000, 5000); 247 } catch (InterruptedException ex) { 248 sawEx = true; 249 // System.out.println("wait(1000, 5000): Waiter caught " + ex); 250 } 251 // System.out.println("wait(1000, 5000) finished"); 252 253 if (!sawEx) { 254 throw new RuntimeException("Thread not interrupted " + 255 "during wait(1000, 5000)"); 256 } 257 } 258 259 // System.out.println("Waiter returning"); 260 } 261 } 262 263 private static Throwable errorException; 264 private static Thread testThread; 265 266 // TODO: Flaky test. Add back MediumTest annotation once fixed 267 public void testInterruptTest() throws Exception { 268 269 270 testThread = Thread.currentThread(); 271 errorException = null; 272 273 Waiter waiter = new Waiter("InterruptTest Waiter"); 274 Interrupter interrupter = 275 new Interrupter("InterruptTest Interrupter", waiter); 276 interrupter.start(); 277 278 try { 279 interrupter.join(); 280 waiter.join(); 281 } catch (InterruptedException ex) { 282 throw new RuntimeException("Test join interrupted.", ex); 283 } 284 285 if (errorException != null) { 286 throw new RuntimeException("InterruptTest failed", 287 errorException); 288 } 289 290 291 292 293 } 294 295 private static void deepWait(int depth, Object lock) { 296 synchronized (lock) { 297 if (depth > 0) { 298 deepWait(depth - 1, lock); 299 } else { 300 String threadName = Thread.currentThread().getName(); 301 try { 302 // System.out.println(threadName + " waiting"); 303 lock.wait(); 304 // System.out.println(threadName + " done waiting"); 305 } catch (InterruptedException ex) { 306 // System.out.println(threadName + " interrupted."); 307 } 308 } 309 } 310 } 311 312 private class Worker extends Thread { 313 Object lock; 314 int id; 315 316 Worker(int id, Object lock) { 317 super("Worker(" + id + ")"); 318 this.id = id; 319 this.lock = lock; 320 } 321 322 public void run() { 323 int iterations = 0; 324 325 while (OldAndroidMonitorTest.running) { 326 OldAndroidMonitorTest.deepWait(id, lock); 327 iterations++; 328 } 329 // System.out.println(getName() + " done after " + iterations + " iterations."); 330 } 331 } 332 333 private static Object commonLock = new Object(); 334 private static Boolean running = false; 335 336 337 public void testNestedMonitors() throws Exception { 338 final int NUM_WORKERS = 5; 339 340 Worker w[] = new Worker[NUM_WORKERS]; 341 int i; 342 343 for (i = 0; i < NUM_WORKERS; i++) { 344 w[i] = new Worker(i * 2 - 1, new Object()); 345 } 346 347 running = true; 348 349 // System.out.println("NestedMonitors: starting workers"); 350 for (i = 0; i < NUM_WORKERS; i++) { 351 w[i].start(); 352 } 353 354 try { 355 Thread.currentThread().sleep(1000); 356 } catch (InterruptedException ex) { 357 // System.out.println("Test sleep interrupted."); 358 } 359 360 for (i = 0; i < 100; i++) { 361 for (int j = 0; j < NUM_WORKERS; j++) { 362 synchronized (w[j].lock) { 363 w[j].lock.notify(); 364 } 365 } 366 } 367 368 // System.out.println("NesterMonitors: stopping workers"); 369 running = false; 370 for (i = 0; i < NUM_WORKERS; i++) { 371 synchronized (w[i].lock) { 372 w[i].lock.notifyAll(); 373 } 374 } 375 } 376 377 private static class CompareAndExchange extends Thread { 378 static Object toggleLock = null; 379 static int toggle = -1; 380 static Boolean running = false; 381 382 public void run() { 383 toggleLock = new Object(); 384 toggle = -1; 385 386 Worker w1 = new Worker(0, 1); 387 Worker w2 = new Worker(2, 3); 388 Worker w3 = new Worker(4, 5); 389 Worker w4 = new Worker(6, 7); 390 391 running = true; 392 393 // System.out.println("CompareAndExchange: starting workers"); 394 395 w1.start(); 396 w2.start(); 397 w3.start(); 398 w4.start(); 399 400 try { 401 this.sleep(10000); 402 } catch (InterruptedException ex) { 403 // System.out.println(getName() + " interrupted."); 404 } 405 406 // System.out.println("MonitorTest: stopping workers"); 407 running = false; 408 409 toggleLock = null; 410 } 411 412 class Worker extends Thread { 413 int i1; 414 int i2; 415 416 Worker(int i1, int i2) { 417 super("Worker(" + i1 + ", " + i2 + ")"); 418 this.i1 = i1; 419 this.i2 = i2; 420 } 421 422 public void run() { 423 int iterations = 0; 424 425 /* Latch this because run() may set the static field to 426 * null at some point. 427 */ 428 Object toggleLock = CompareAndExchange.toggleLock; 429 430 // System.out.println(getName() + " running"); 431 try { 432 while (CompareAndExchange.running) { 433 synchronized (toggleLock) { 434 int test; 435 int check; 436 437 if (CompareAndExchange.toggle == i1) { 438 this.sleep(5 + i2); 439 CompareAndExchange.toggle = test = i2; 440 } else { 441 this.sleep(5 + i1); 442 CompareAndExchange.toggle = test = i1; 443 } 444 if ((check = CompareAndExchange.toggle) != test) { 445// System.out.println("Worker(" + i1 + ", " + 446// i2 + ") " + "test " + test + 447// " != toggle " + check); 448 throw new RuntimeException( 449 "locked value changed"); 450 } 451 } 452 453 iterations++; 454 } 455 } catch (InterruptedException ex) { 456 // System.out.println(getName() + " interrupted."); 457 } 458 459// System.out.println(getName() + " done after " + 460// iterations + " iterations."); 461 } 462 } 463 } 464} 465