/** * 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 java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; import abs.backend.java.lib.types.ABSBool; import abs.backend.java.lib.types.ABSBuiltInDataType; import abs.backend.java.lib.types.ABSValue; import abs.backend.java.observing.FutObserver; import abs.backend.java.observing.FutView; import abs.backend.java.observing.TaskView; import abs.backend.java.scheduling.GuardWaiter; public abstract class ABSFut<V extends ABSValue> extends ABSBuiltInDataType { protected static final Logger log = Logger.getLogger(ABSRuntime.class.getName()); private static final AtomicInteger counter = new AtomicInteger(); private final int id = counter.incrementAndGet(); protected V value; protected ABSException exception; protected boolean isResolved; protected ABSFut() { super("Fut"); } public int getID() { return id; } public abstract V get(); public synchronized V getValue() { return value; } public synchronized boolean isResolved() { return isResolved; } public synchronized void await() { log.finest("awaiting future"); while (!isResolved) { try { wait(); } catch (InterruptedException e) { log.finest("was interruped during await"); Thread.currentThread().interrupt(); break; } } if (exception != null) throw exception; log.finest("future ready"); } private List<GuardWaiter> waitingThreads; public void resolve(final V o) { resolve(o,null); } protected void resolve(final V o, final ABSException e) { synchronized (this) { if (isResolved) throw new IllegalStateException("Future is already resolved"); log.finest(this + " is resolved to " + o); value = o; exception = e; isResolved = true; notifyAll(); } informWaitingThreads(); View v = view; if (v != null) v.onResolved(o); } public void smash(ABSException e) { resolve(null,e); } private void informWaitingThreads() { log.finest(this + " inform awaiting threads..."); ArrayList<GuardWaiter> copy = null; synchronized (this) { if (waitingThreads == null) return; copy = new ArrayList<GuardWaiter>(waitingThreads); waitingThreads.clear(); } for (GuardWaiter s : copy) { s.checkGuard(); } } @Override public ABSBool eq(ABSValue other) { return ABSBool.fromBoolean(other == this); } @Override public ABSBool gt(ABSValue o) { if (o == null) return ABSBool.FALSE; if (!(o instanceof ABSFut)) return ABSBool.FALSE; return ABSBool.fromBoolean(getID() > ((ABSFut)o).getID()); } @Override public ABSBool lt(ABSValue o) { if (o == null) return ABSBool.FALSE; if (!(o instanceof ABSFut)) return ABSBool.FALSE; return ABSBool.fromBoolean(getID() < ((ABSFut)o).getID()); } @Override public ABSBool gtEq(ABSValue o) { if (this.eq(o).toBoolean()) return ABSBool.TRUE; else return this.gt(o); } @Override public ABSBool ltEq(ABSValue o) { if (this.eq(o).toBoolean()) return ABSBool.TRUE; else return this.lt(o); } @Override public synchronized String toString() { return "Future (" + (isResolved ? value : "unresolved") + ")"; } public synchronized boolean addWaitingThread(GuardWaiter thread) { if (isResolved) { log.fine("===== "+this+" is already resolved"); return false; } if (waitingThreads == null) waitingThreads = new ArrayList<GuardWaiter>(1); waitingThreads.add(thread); return true; } protected volatile View view; public synchronized FutView getView() { if (view == null) { view = createView(); } return view; } protected View createView() { return new View(); } protected class View implements FutView { private List<FutObserver> futObserver; private synchronized List<FutObserver> getObservers() { if (futObserver == null) futObserver = new ArrayList<FutObserver>(1); return futObserver; } synchronized void onResolved(ABSValue v) { for (FutObserver f : getObservers()) { f.onResolved(this, v); } } @Override public TaskView getResolvingTask() { return null; } @Override public boolean isResolved() { return ABSFut.this.isResolved(); } @Override public int getID() { return ABSFut.this.getID(); } @Override public ABSValue getValue() { return ABSFut.this.getValue(); } @Override public void registerFutObserver(FutObserver obs) { getObservers().add(obs); } } }