--- /dev/null 2010-01-11 13:24:46.000000000 -0800 +++ new/test/sun/misc/Continuation/ContinuationTest9.java 2010-08-30 12:48:17.957591000 -0700 @@ -0,0 +1,180 @@ +/* + * Copyright 2010 Google, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.util.LinkedList; +import sun.misc.Continuation; + +/* + * This class demonstrates the continuation feature by implementing a + * user-thread-like object. + */ +public class ContinuationTest9 { + private static int ITER = 10000; + + public static void test() throws Exception { + Runnable r1 = new Runnable() { + public void run() { + while (true) { + System.out.println("t1: " + counter++); + UserThread.yield(); + if (counter > ITER) { + return; + } + } + }}; + Runnable r2 = new Runnable() { + public void run() { + while (true) { + System.out.println("t2: " + counter++); + UserThread.yield(); + if (counter > ITER) { + return; + } + } + }}; + UserThread t1 = new UserThread(r1); + UserThread t2 = new UserThread(r2); + t1.start(); + t2.start(); + UserThread.join(); + } + + private static int counter = 0; + + public static void main(String[] args) throws Exception { + test(); + System.exit(0); + } +} + +class UserThread { + // The schedule queue + private static final LinkedList queue = new LinkedList(); + // The currently scheduled UserThread + private static UserThread currentThread; + // Used to synchronize between the internal thread and the outside world + // This guards queue, nthreads and currentThread + private static final Object lock = new Object(); + // The number of live UserThreads + private static int nthreads = 0; + // Lock for join + private static final Object awaitLock = new Object(); + + // The backing Java thread that executes + // all UserThreads + private static final Thread jthread = + new Thread(new Runnable() { + public void run() { + while (true) { + try { + UserThread ut_to_run; + synchronized (lock) { + if (queue.size() == 0) { + // Wait if there's no user thread to schedule + lock.wait(); + } + // Get the user thread to be scheduled next + ut_to_run = queue.remove(); + currentThread = ut_to_run; + } + final UserThread ut = ut_to_run; + final Continuation c = ut.continuation; + // If it's scheduled for the first time, + if (c == null) { + // simply execute the given Runnable in a scope + Continuation.enter(ut.runnable, null); + } else { + // Otherwise, resume the saved continuation + Runnable r = new Runnable() { + public void run() { + c.resume(null); + }}; + Continuation.enter(r, null); + } + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + } + }); + + static { + jthread.start(); + } + + private final Runnable runnable; + private Continuation continuation; + + public UserThread(final Runnable r) { + runnable = new Runnable() { + public void run() { + r.run(); + UserThread.exit(); + } + }; + } + + public void start() { + synchronized(lock) { + nthreads++; + // Add the given user thread to the schedule queue + queue.add(this); + // Notify the Java thread if it's waiting + lock.notify(); + } + } + + public static void yield() { + // Create a new continuation for each yield + final Continuation c = new Continuation(); + synchronized (lock) { + // Save it in the user thread + currentThread.continuation = c; + // Put the user thread back to the schedule queue + queue.add(currentThread); + } + // Save the current scope into it. It will cause + // the enter at the bottom of the scope to return. + c.save(); + } + + private static void exit() { + int new_nthreads; + synchronized (lock) { + nthreads--; + new_nthreads = nthreads; + if (new_nthreads == 0) { + synchronized (awaitLock) { + awaitLock.notify(); + } + } + } + } + + public static void join() throws InterruptedException { + synchronized (awaitLock) { + awaitLock.wait(); + } + } +}