/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CyclicBarrier;

public class Main implements Runnable {

    // Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
    // ART on timeout when running on the host.
    private final static long TIMEOUT_VALUE = 7;

    private final static long MAX_SIZE = 1000;  // Maximum size of array-list to allocate.

    private final static int THREAD_COUNT = 16;

    // Use a couple of different forms of synchronizing to test some of these...
    private final static AtomicInteger counter = new AtomicInteger();
    private final static Object gate = new Object();
    private volatile static int waitCount = 0;

    public static void main(String[] args) throws Exception {
        Thread[] threads = new Thread[THREAD_COUNT];

        // This barrier is used to synchronize the threads starting to allocate.
        // Note: Even though a barrier is not allocation-free, this one is fine, as it will be used
        //       before filling the heap.
        CyclicBarrier startBarrier = new CyclicBarrier(threads.length);

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(new Main(startBarrier));
            threads[i].start();
        }

        // Wait for the threads to finish.
        for (Thread thread : threads) {
            thread.join();
        }

        // Allocate objects to definitely run GC before quitting.
        allocateObjectsToRunGc();

        new ArrayList<Object>(50);
    }

    private static void allocateObjectsToRunGc() {
      ArrayList<Object> l = new ArrayList<Object>();
      try {
          for (int i = 0; i < 100000; i++) {
              l.add(new ArrayList<Object>(i));
          }
      } catch (OutOfMemoryError oom) {
      }
    }

    private Main(CyclicBarrier startBarrier) {
        this.startBarrier = startBarrier;
    }

    private ArrayList<Object> store;
    private CyclicBarrier startBarrier;

    public void run() {
        try {
            work();
        } catch (Throwable t) {
            // Any exception or error getting here is bad.
            try {
                // May need allocations...
                t.printStackTrace(System.err);
            } catch (Throwable tInner) {
            }
            System.exit(1);
        }
    }

    private void work() throws Exception {
        // Any exceptions except an OOME in the allocation loop are bad and handed off to the
        // caller which should abort the whole runtime.

        ArrayList<Object> l = new ArrayList<Object>();
        store = l;  // Keep it alive.

        // Wait for the start signal.
        startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES);

        // Allocate.
        try {
            for (int i = 0; i < MAX_SIZE; i++) {
                l.add(new ArrayList<Object>(i));
            }
        } catch (OutOfMemoryError oome) {
            // Fine, we're done.
        }

        // Atomically increment the counter and check whether we were last.
        int number = counter.incrementAndGet();

        if (number < THREAD_COUNT) {
            // Not last.
            synchronized (gate) {
                // Increment the wait counter.
                waitCount++;
                gate.wait(TIMEOUT_VALUE * 1000 * 60);
            }
        } else {
            // Last. Wait until waitCount == THREAD_COUNT - 1.
            for (int loops = 0; ; loops++) {
                synchronized (gate) {
                    if (waitCount == THREAD_COUNT - 1) {
                        // OK, everyone's waiting. Notify and break out.
                        gate.notifyAll();
                        break;
                    } else if (loops > 40) {
                        // 1s wait, too many tries.
                        System.out.println("Waited too long for the last thread.");
                        System.exit(1);
                    }
                }
                // Wait a bit.
                Thread.sleep(25);
            }
        }

        store = null;  // Allow GC to reclaim it.
    }
}
