/** * 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.lib.runtime; import java.util.ArrayList; import java.util.List; import abs.backend.java.lib.runtime.TaskStack.Frame; import abs.backend.java.lib.types.ABSRef; import abs.backend.java.lib.types.ABSValue; import abs.backend.java.observing.COGView; import abs.backend.java.observing.ClassView; import abs.backend.java.observing.FutView; import abs.backend.java.observing.ObjectView; import abs.backend.java.observing.TaskObserver; import abs.backend.java.observing.TaskStackView; import abs.backend.java.observing.TaskView; public class Task<T extends ABSRef> { private final ABSFut<? super ABSValue> future; private final int id; private Thread executingThread; private ABSException exception; private final TaskStack stack; private final AsyncCall<T> call; /** * Real time attributes */ private final long arrival; private final long cost; private final long deadline; private final boolean critical; private final int value; private long start; private long finish; public Task(AsyncCall<T> call) { this.call = call; future = new ABSTaskFut(this); ABSRuntime runtime = ((ABSObject)call.getTarget()).__ABS_getRuntime(); id = runtime.freshTaskID(); if (runtime.debuggingEnabled()) { stack = new TaskStack(this); } else { stack = null; } this.arrival = System.currentTimeMillis(); if (call instanceof AbstractAsyncCallRT) { AbstractAsyncCallRT<?> callRT = (AbstractAsyncCallRT<?>)call; this.cost = callRT.getCost(); this.deadline = callRT.getDeadline(); this.critical = callRT.isCritical(); } else { this.cost = -1; this.deadline = -1; this.critical = false; } this.start = -1; // TODO set to time when task is first scheduled this.finish = 0; // TODO this.value = 0; // TODO } public int getID() { return id; } public long getArrival() { return arrival; } public long getCost() { return cost; } public long getDeadline() { return deadline; } public long getStart() { return start; } public void setStart(long ms) { start = ms; } public long getFinish() { return finish; } public boolean isCritical() { return critical; } public int getValue() { return value; } public synchronized void setLocalVariable(String name, ABSValue v) { if (stack != null) { Frame f = stack.getCurrentFrame(); f.setValue(name,v); if (view != null) { view.localVariableChanged(f,name,v); } } } public synchronized boolean isDeadlocked() { return exception != null && exception.isDeadlock(); } public synchronized boolean hasException() { return exception != null; } public synchronized ABSException getException() { return exception; } // not synchronized as only called when task is locked public void setException(ABSException exception) { this.exception = exception; } public COG getCOG() { return ((ABSObject)call.getTarget()).getCOG(); } public void schedule() { getCOG().addTask(this); } public ABSFut<?> getFut() { return future; } // only for observing void calledGetOnFut(ABSFut<?> someFut) { View v = view; if (v != null) v.calledGetOnFut(someFut); } // only for observing void futureReady(ABSFut<?> someFut) { View v = view; if (v != null) v.futureReady(someFut); } public void popStackFrame() { if (stack != null) { Frame oldFrame = stack.popFrame(); if (view != null) { view.stackFrameRemoved(oldFrame); } } } public void newStackFrame(ABSObject target, String methodName) { if (stack != null) { ClassView cv = null; if (target != null) cv = target.getView().getClassView(); Frame f = stack.pushNewFrame(new ABSMethod(cv,methodName)); if (view != null) { view.newStackFrameCreated(f); } } } public void run() { synchronized (this) { if (view != null) view.taskStarted(); executingThread = Thread.currentThread(); } try { ABSValue res = (ABSValue) call.execute(); future.resolve(res); } catch (ABSException e) { this.exception = e; future.smash(e); getCOG().getRuntime().handleABSException(this,e); } catch (SystemTerminatedException e) { } catch (Exception e) { e.printStackTrace(); ABSException absException = new ABSAssertException("Sorry, this is a bug in the Java backend of ABS: " + "Unexpected exception: " + e); // TODO new subclass for internal error absException.setStackTrace(e.getStackTrace()); getCOG().getRuntime().handleABSException(this, absException ); } synchronized (this) { if (view != null) view.taskFinished(); } } public String toString() { return "Task (" + id + ") [" + getCOG() + ", Method: " + call.getTarget().getClass().getSimpleName() + "." + call.methodName() + "]"; } private volatile View view; private Object viewCreationLock = new Object(); private boolean finished = false; public TaskView getView() { synchronized(viewCreationLock) { if (view == null) { view = new View(); } return view; } } public synchronized Thread getExecutingThread() { return executingThread; } public AsyncCall<?> getCall() { return call; } public synchronized void nextStep(String fileName, int line) { if (view != null) view.nextStep(fileName, line); } private class View implements TaskView { private List<TaskObserver> taskListener; @Override public TaskView getSender() { if (call.getSender() == null) return null; return call.getSender().getView(); } public void stackFrameRemoved(Frame oldFrame) { for (TaskObserver l : getObservers()) { l.stackFrameRemoved(this, oldFrame); } } public synchronized void localVariableChanged(Frame f,String name, ABSValue v) { for (TaskObserver l : getObservers()) { l.localVariableChanged(f,name, v); } } public synchronized void newStackFrameCreated(Frame f) { for (TaskObserver l : getObservers()) { l.stackFrameCreated(this,f); } } public synchronized void nextStep(String fileName, int line) { for (TaskObserver l : getObservers()) { l.taskStep(this, fileName, line); } } public synchronized void futureReady(ABSFut<?> someFut) { for (TaskObserver l : getObservers()) { l.taskRunningAfterWaiting(this, someFut.getView()); } } public synchronized void calledGetOnFut(ABSFut<?> someFut) { for (TaskObserver l : getObservers()) { l.taskBlockedOnFuture(this, someFut.getView()); } } @Override public ObjectView getSource() { if (call.getSource() == null) return null; return call.getSource().getView(); } @Override public ObjectView getTarget() { return ((ABSObject)call.getTarget()).getView(); } private synchronized List<TaskObserver> getObservers() { if (taskListener == null) taskListener = new ArrayList<TaskObserver>(1); return taskListener; } public synchronized void taskStarted() { for (TaskObserver l : getObservers()) { l.taskStarted(this); } } public synchronized void taskFinished() { for (TaskObserver l : getObservers()) { l.taskFinished(this); } } @Override public COGView getCOG() { return Task.this.getCOG().getView(); } @Override public String getMethodName() { return Task.this.call.methodName(); } @Override public List<ABSValue> getArgs() { return Task.this.call.getArgs(); } @Override public FutView getFuture() { return future.getView(); } @Override public int getID() { return id; } @Override public boolean isDeadlocked() { return Task.this.isDeadlocked(); } @Override public synchronized void registerTaskListener(TaskObserver listener) { getObservers().add(listener); } @Override public boolean hasException() { return Task.this.hasException(); } @Override public ABSException getException() { return Task.this.getException(); } @Override public TaskStackView getStack() { return stack; } } public synchronized boolean isFinished() { return finished; } public synchronized void setFinished(boolean b) { finished = b; } }