/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.mmtk.harness.scheduler; import org.mmtk.harness.Harness; import org.mmtk.harness.Mutator; import org.mmtk.harness.scheduler.javathreads.JavaThreadModel; import org.mmtk.harness.scheduler.rawthreads.RawThreadModel; import org.mmtk.plan.CollectorContext; import org.mmtk.utility.Log; import org.mmtk.vm.Monitor; import org.vmmagic.unboxed.harness.Clock; /** * Facade class for the command-line selectable threading models available * in the MMTk harness. */ public class Scheduler { /** * Possible threading models */ public enum Model { /** Schedule using the Java thread scheduler */ JAVA, /** Schedule in the harness using deterministic algorithms */ DETERMINISTIC; /** @return The values of this enum, converted to strings */ public static String[] valueNames() { String[] result = new String[Scheduler.Model.values().length]; for (int i = 0; i < Scheduler.Model.values().length; i++) { result[i] = Scheduler.Model.values()[i].toString(); } return result; } } /** * Possible thread-scheduling policies */ public enum SchedPolicy { /** Reschedule every nth yield point */ FIXED, /** Reschedule on a pseudo-random sequence of intervals */ RANDOM, /** Only reschedule when the thread is blocked */ NEVER; /** @return The values of this enum, converted to strings */ public static String[] valueNames() { String[] result = new String[Scheduler.SchedPolicy.values().length]; for (int i = 0; i < Scheduler.SchedPolicy.values().length; i++) { result[i] = Scheduler.SchedPolicy.values()[i].toString(); } return result; } } /** * Thread Model factory - returns the thread model selected by user options. */ public static ThreadModel newThreadModel(Model model) { switch (model) { case JAVA: return new JavaThreadModel(); case DETERMINISTIC: return new RawThreadModel(); default: throw new RuntimeException("Unknown thread model"); } } private static ThreadModel model; /** * Yield policy factory - return an instance of the the command-line * selected yield policy * @param thread The Java thread * @return A new policy for the given thread */ public static Policy yieldPolicy(Thread thread) { switch (Harness.policy.policy()) { case FIXED: int yieldInterval = Harness.yieldInterval.getValue(); if (yieldInterval == 1) { return new YieldAlways(thread); } return new YieldEvery(thread,yieldInterval); case RANDOM: return new YieldRandomly(thread, Harness.randomPolicySeed.getValue(), Harness.randomPolicyLength.getValue(), Harness.randomPolicyMin.getValue(), Harness.randomPolicyMax.getValue()); case NEVER: return new YieldNever(thread); default: throw new RuntimeException("Unknown scheduler policy"); } } /** * Initialization */ public static void init() { setThreadModel(Harness.scheduler.model()); } /** * Set the thread model * @param modelType */ public static void setThreadModel(Scheduler.Model modelType) { model = newThreadModel(modelType); } /** * Advance collector threads to their initial 'wait for collection' barrier */ public static void initCollectors() { model.initCollectors(); } /** * A yield-point. */ public static void yield() { model.yield(); } /** * Create and start a new Mutator thread * @param item The executable code to run in this thread */ public static void scheduleMutator(Schedulable item) { model.scheduleMutator(item); } /** * Create and start a new collector thread with the given collector context */ public static void scheduleCollector(CollectorContext context) { model.scheduleCollector(context); } /** * Create and start a new collector thread running a particular code * sequence. Used to schedule unit tests in collector context. * * @param item The schedulable object * @return A java thread for the item */ public static Thread scheduleCollectorContext(CollectorContext item) { return model.scheduleCollectorContext(item); } /** * @return The current Log object. */ public static Log currentLog() { return ((MMTkThread)Thread.currentThread()).getLog(); } /** * @return The current mutator object (if the current thread is a Mutator) */ public static Mutator currentMutator() { return model.currentMutator(); } /** * @return The current collector object (if the current thread is a Collector) */ public static CollectorContext currentCollector() { return model.currentCollector(); } /** * @return Has a GC been triggered? */ public static boolean gcTriggered() { return model.gcTriggered(); } /** * Wait at a barrier in user code * @param name The name of the barrier * @param expected The number of threads expected to arrive * @return An integer from 0..expected-1, unique to each arriving thread */ public static int mutatorRendezvous(String name, int expected) { try { Clock.stop(); return model.mutatorRendezvous(name,expected); } finally { Clock.start(); } } /** * Cause the current thread to wait for a triggered GC to proceed. */ public static void waitForGC() { model.waitForGC(); } /** * Schedule the threads */ public static void schedule() { model.schedule(); } /** * Schedule the GC threads as though a GC had been triggered * Used to run unit tests that must run in collector context. */ public static void scheduleGcThreads() { model.scheduleGcThreads(); } /** * An MMTk lock - a factory method. * @param name The name of the lock * @return The newly created lock */ public static Lock newLock(String name) { try { Clock.stop(); return model.newLock(name); } finally { Clock.start(); } } /** * Model-specific MMTk Monitor factory * @return A new monitor of the appropriate class */ public static Monitor newMonitor(String name) { try { Clock.stop(); return model.newMonitor(name); } finally { Clock.start(); } } /** * Stop all mutator threads. This is current intended to be run by a single thread. */ public static void stopAllMutators() { try { Clock.stop(); model.stopAllMutators(); } finally { Clock.start(); } } /** * Resume all mutators blocked for GC. */ public static void resumeAllMutators() { try { Clock.stop(); model.resumeAllMutators(); } finally { Clock.start(); } } /** @return {@code true} if the current thread is a mutator thread */ public static boolean isMutator() { return model.isMutator(); } /** @return {@code true} if the current thread is a mutator thread */ public static boolean isCollector() { return model.isCollector(); } }