OSDN Git Service

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