blob: 8e2519dd0a9a5ce36980d798d40c5260d0f27c75 [file] [log] [blame]
Brian Carlstrom55621742011-10-17 00:41:56 -07001/*
2 * Copyright (C) 2011 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
17import java.util.ArrayList;
18import java.util.List;
Andreas Gampe93f3da12014-07-26 01:13:13 -070019import java.util.concurrent.BrokenBarrierException;
20import java.util.concurrent.CyclicBarrier;
21import java.util.concurrent.SynchronousQueue;
22import java.util.concurrent.TimeUnit;
23import java.util.concurrent.TimeoutException;
Brian Carlstrom55621742011-10-17 00:41:56 -070024
Andreas Gampe1c83cbc2014-07-22 18:52:29 -070025public class Main implements Runnable {
Andreas Gampe93f3da12014-07-26 01:13:13 -070026
27 public final static long TIMEOUT_VALUE = 5; // Timeout in minutes.
28 public final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate.
29
Brian Carlstrom55621742011-10-17 00:41:56 -070030 public static void main(String[] args) throws Exception {
31 Thread[] threads = new Thread[16];
Andreas Gampe93f3da12014-07-26 01:13:13 -070032
33 // Use a cyclic system of synchronous queues to pass a boolean token around.
34 //
35 // The combinations are:
36 //
37 // Worker receives: true false false true
38 // Worker has OOM: false false true true
39 // |
40 // v
41 // Value to pass: true false false false
42 // Exit out of loop: false true true true
43 // Wait on in queue: true false false true
44 //
45 // Finally, the workers are supposed to wait on the barrier to synchronize the GC run.
46
47 CyclicBarrier barrier = new CyclicBarrier(threads.length);
48 List<SynchronousQueue<Boolean>> queues = new ArrayList<SynchronousQueue<Boolean>>(
49 threads.length);
Brian Carlstrom55621742011-10-17 00:41:56 -070050 for (int i = 0; i < threads.length; i++) {
Andreas Gampe93f3da12014-07-26 01:13:13 -070051 queues.add(new SynchronousQueue<Boolean>());
52 }
53
54 for (int i = 0; i < threads.length; i++) {
55 threads[i] = new Thread(new Main(i, queues.get(i), queues.get((i + 1) % threads.length),
56 barrier));
Brian Carlstrom55621742011-10-17 00:41:56 -070057 }
58 for (Thread thread : threads) {
59 thread.start();
60 }
Andreas Gampe93f3da12014-07-26 01:13:13 -070061
62 // Push off the cycle.
63 checkTimeout(queues.get(0).offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
64
65 // Wait for the threads to finish.
Brian Carlstrom55621742011-10-17 00:41:56 -070066 for (Thread thread : threads) {
67 thread.join();
68 }
Andreas Gampe93f3da12014-07-26 01:13:13 -070069
70 // Allocate objects to definitely run GC before quitting.
71 try {
72 for (int i = 0; i < 1000; i++) {
73 new ArrayList<Object>(i);
74 }
75 } catch (OutOfMemoryError oom) {
76 }
77 }
78
79 private static void checkTimeout(Object o) {
80 checkTimeout(o != null);
81 }
82
83 private static void checkTimeout(boolean b) {
84 if (!b) {
85 // Something went wrong.
86 System.out.println("Bad things happened, timeout.");
87 System.exit(1);
88 }
Brian Carlstrom55621742011-10-17 00:41:56 -070089 }
90
91 private final int id;
Andreas Gampe93f3da12014-07-26 01:13:13 -070092 private final SynchronousQueue<Boolean> waitOn;
93 private final SynchronousQueue<Boolean> pushTo;
94 private final CyclicBarrier finalBarrier;
Brian Carlstrom55621742011-10-17 00:41:56 -070095
Andreas Gampe93f3da12014-07-26 01:13:13 -070096 private Main(int id, SynchronousQueue<Boolean> waitOn, SynchronousQueue<Boolean> pushTo,
97 CyclicBarrier finalBarrier) {
Brian Carlstrom55621742011-10-17 00:41:56 -070098 this.id = id;
Andreas Gampe93f3da12014-07-26 01:13:13 -070099 this.waitOn = waitOn;
100 this.pushTo = pushTo;
101 this.finalBarrier = finalBarrier;
Brian Carlstrom55621742011-10-17 00:41:56 -0700102 }
103
104 public void run() {
Andreas Gampe93f3da12014-07-26 01:13:13 -0700105 try {
106 work();
107 } catch (Exception exc) {
108 // Any exception is bad.
109 exc.printStackTrace(System.err);
110 System.exit(1);
Brian Carlstrom55621742011-10-17 00:41:56 -0700111 }
112 }
Andreas Gampe21b4bf82014-07-25 16:37:09 -0700113
Andreas Gampe93f3da12014-07-26 01:13:13 -0700114 public void work() throws BrokenBarrierException, InterruptedException, TimeoutException {
115 ArrayList<Object> l = new ArrayList<Object>();
116
117 // Main loop.
118 for (int i = 0; ; i++) {
119 Boolean receivedB = waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES);
120 checkTimeout(receivedB);
121 boolean received = receivedB;
122
123 // This is the first stage, try to allocate up till MAX_SIZE.
124 boolean oom = i >= MAX_SIZE;
125 try {
126 l.add(new ArrayList<Object>(i));
127 } catch (OutOfMemoryError oome) {
128 oom = true;
129 }
130
131 if (!received || oom) {
132 // First stage, always push false.
133 checkTimeout(pushTo.offer(Boolean.FALSE, TIMEOUT_VALUE, TimeUnit.MINUTES));
134
135 // If we received true, wait for the false to come around.
136 if (received) {
137 checkTimeout(waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES));
138 }
139
140 // Break out of the loop.
141 break;
142 } else {
143 // Pass on true.
144 checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
145 }
146 }
147
148 // We have reached the final point. Wait on the barrier, but at most a minute.
149 finalBarrier.await(TIMEOUT_VALUE, TimeUnit.MINUTES);
150
151 // Done.
152 }
Brian Carlstrom55621742011-10-17 00:41:56 -0700153}