/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.backend.java.scheduling;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import abs.backend.java.lib.runtime.ABSGuard;
import abs.backend.java.lib.runtime.ABSRuntime;
import abs.backend.java.lib.runtime.ABSThread;
import abs.backend.java.lib.runtime.ABSThreadManager;
import abs.backend.java.lib.runtime.COG;
import abs.backend.java.lib.runtime.Logging;
import abs.backend.java.lib.runtime.Task;
import abs.backend.java.observing.TaskSchedulerView;
import abs.backend.java.observing.TaskView;
public class DefaultTaskScheduler implements TaskScheduler {
private static final Logger log = Logging.getLogger(ABSRuntime.class.getName());
private final List<Task<?>> newTasks = new LinkedList<Task<?>>();
private final List<SchedulerThread> suspendedTasks = new LinkedList<SchedulerThread>();
private Task<?> activeTask;
private volatile SchedulerThread thread;
private final COG cog;
private final ABSThreadManager threadManager;
public DefaultTaskScheduler(COG cog, ABSThreadManager m) {
this.cog = cog;
this.threadManager = m;
}
@Override
public synchronized void addTask(Task<?> task) {
newTasks.add(task);
if (view != null)
view.taskAdded(task.getView());
log.finest(task + " ADDED TO QUEUE");
if (thread == null) {
thread = new SchedulerThread();
thread.start();
} else {
notifyAll();
}
}
class SchedulerThread extends ABSThread {
private Task<?> runningTask;
public SchedulerThread() {
super(threadManager);
setName("ABS Scheduler Thread of " + cog.toString());
setCOG(cog);
}
@Override
public void run() {
try {
loop:
while (!shutdown) {
synchronized (DefaultTaskScheduler.this) {
activeTask = null;
if (newTasks.isEmpty()) {
thread = null;
DefaultTaskScheduler.this.notifyAll();
break loop;
}
activeTask = newTasks.remove(0);
runningTask = activeTask;
setName("ABS Scheduler Thread executing " + activeTask.toString());
}
View v = view;
log.finest("Executing " + runningTask);
try {
runningTask.run();
v = view;
log.finest("Task " + runningTask + " FINISHED");
} catch (Exception e) {
log.finest("EXCEPTION in Task " + runningTask);
e.printStackTrace();
}
}
} finally {
finished();
}
}
// assume called in synchronized block
public void suspendTask(ABSGuard g) {
log.finest(runningTask + " on " + g + " SUSPENDING");
synchronized (DefaultTaskScheduler.this) {
activeTask = null;
thread = null;
if (!newTasks.isEmpty()) {
log.finest(runningTask + " on " + g + " Starting new Scheduler Thread");
thread = new SchedulerThread();
thread.start();
} else {
DefaultTaskScheduler.this.notifyAll();
}
log.finest(runningTask + " on " + g + " SUSPENDING");
suspendedTasks.add(this);
}
View v = view;
if (v != null) {
v.taskSuspended(runningTask.getView(), g);
}
log.finest(runningTask + " AWAITING " + g);
boolean couldBecomeFalse = g.await();
if (Thread.interrupted()) {
return;
}
if (!couldBecomeFalse) {
log.finest(runningTask + " " + g + " READY");
if (v != null)
v.taskReady(runningTask.getView());
}
synchronized (DefaultTaskScheduler.this) {
while (!(g.isTrue() && thread == null)) {
try {
log.finest(runningTask + " " + g + " WAITING FOR WAKE UP");
DefaultTaskScheduler.this.wait();
log.finest(runningTask + " WOKE UP...");
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
thread = this;
activeTask = runningTask;
suspendedTasks.remove(this);
}
if (v != null)
v.taskResumed(runningTask.getView(), g);
log.finest(runningTask + " " + g + " ACTIVE");
}
}
@Override
public void await(ABSGuard g) {
thread.suspendTask(g);
}
@Override
public synchronized Task<?> getActiveTask() {
return activeTask;
}
private volatile View view;
@Override
public synchronized TaskSchedulerView getView() {
if (view == null) {
view = new View();
}
return view;
}
private class View extends AbstractTaskSchedulerView {
@Override
public List<TaskView> getReadyTasks() {
return null;
}
@Override
public List<TaskView> getSuspendedTasks() {
return null;
}
@Override
public List<TaskView> getSchedulableTasks() {
return null;
}
@Override
public TaskView getActiveTask() {
return DefaultTaskScheduler.this.getActiveTask().getView();
}
}
public static TaskSchedulerFactory getFactory() {
return new TaskSchedulerFactory() {
@Override
public TaskScheduler createTaskScheduler(ABSRuntime runtime, COG cog, ABSThreadManager m, ScheduableTasksFilter filter) {
return new DefaultTaskScheduler(cog, m);
}
};
}
@Override
public COG getCOG() {
return cog;
}
}