Package pt.ul.jarmus

Source Code of pt.ul.jarmus.ResourceManager$State

package pt.ul.jarmus;

import java.util.Collection;

import pt.ul.armus.Resource;
import pt.ul.armus.deadlockresolver.DeadlockFoundException;
import pt.ul.armus.edgebuffer.EdgeSet;
import pt.ul.armus.edgebuffer.EdgeSetFactory;
import pt.ul.armus.edgebuffer.TaskHandle;

import com.carrotsearch.hppc.ObjectIntOpenHashMap;
import com.carrotsearch.hppc.ObjectStack;

/**
* Maintains the registered resources.
*
* @author Tiago Cogumbreiro (cogumbreiro@di.fc.ul.pt)
*
*/
public class ResourceManager {
  private static final class State {
    final ObjectIntOpenHashMap<Object> res;
    final TaskHandle handle;

    public State(ObjectIntOpenHashMap<Object> res,
        TaskHandle handle) {
      this.res = res;
      this.handle = handle;
    }
  }

  /*
   * Obtains the phase of each registered synchronization object. The range is
   * the set of registered synchronization objects.
   */
  private ObjectIntOpenHashMap<Object> phases = new ObjectIntOpenHashMap<>();
  /*
   * Holds the state of each task.
   */
  private final ObjectStack<State> stack = new ObjectStack<>();
  /*
   * Used to interact with the deadlock verifier.
   */
  private TaskHandle handle;

  public ResourceManager(TaskHandle handle) {
    assert handle != null;
    this.handle = handle;
  }

  /**
   * Begins a new context. This should be called when the thread is executing
   * a new task.
   */
  public void beginTask(TaskHandle newHandle) {
    assert newHandle != null;
    // save the state
    stack.push(new State(phases, handle));
    // create a fresh state
    phases = new ObjectIntOpenHashMap<>();
    handle = newHandle;
  }

  /**
   * Finish the context. This should be called after the task executes a task.
   * @return
   */
  public TaskHandle endTask() {
    // discard current state and revert to the previous state
    TaskHandle oldHandle = handle;
    State state = stack.pop();
    this.phases = state.res;
    this.handle = state.handle;
    return oldHandle;
  }

  /**
   * Checks if the synchronization object is being managed.
   *
   * @param synch
   * @return
   */
  public boolean isRegistered(Object synch) {
    return phases.containsKey(synch);
  }

  /**
   * Track the synchronization object, starting at a given phase.
   *
   * @param synch
   * @param phase
   */
  public void register(Object synch, int phase) {
    phases.put(synch, phase);
  }

  /**
   * De-registers from a synchronization object.
   *
   * @param synch
   */
  public boolean deregister(Object synch) {
    return phases.remove(synch) > 0;
  }

  /**
   * Advances the current phase of the object.
   *
   * @param synch
   *            The synchronization object.
   * @return The value of the previous phase.
   */
  public int advance(Object synch) {
    ensureRegistered(synch);
    return phases.addTo(synch, 1) - 1;
  }

  /**
   * @param synch
   * @throw Throws an exception when the given task is not registered with
   *        <code>synch</code>.
   */
  public void ensureRegistered(Object synch) throws IllegalStateException {
    if (!phases.containsKey(synch))
      throw new IllegalStateException(
          "Synchronization object is not registered: " + synch);
  }

  /**
   * Get the phases on which the task is registered with.
   *
   * @return
   */
  private ResourceVariable[] getRegistered() {
    final Object[] keys = phases.keys;
    final int[] values = phases.values;
    final boolean[] allocated = phases.allocated;
    ResourceVariable[] result = new ResourceVariable[phases.size()];
    int index = 0;
    for (int i = 0; i < allocated.length; i++) {
      if (allocated[i]) {
        result[index] = new ResourceVariable(keys[i], values[i]);
        index++;
      }
    }
    return result;
  }

  /**
   * De-registers from every resource.
   */
  public void clear() {
    phases.clear();
  }

  /**
   * Generates the restrictions when waiting for a given resource.
   *
   * @param var
   * @return
   */
  public void beforeAwaitMany(
      Collection<?> synchs, int phase) {
    ResourceVariable[] left = new ResourceVariable[synchs.size()];
    int index = 0;
    for (Object synch : synchs) {
      left[index] = new ResourceVariable(synch, phase);
      index++;
    }
    EdgeSet edgeSet = EdgeSetFactory.requestManyAllocateManyArray(left, getRegistered());
    setBlocked(edgeSet);
  }

  /**
   * Generates the restrictions when waiting for a given resource.
   *
   * @param var
   * @return
   */
  public void beforeAwait(Object synch, int phase) {
    ResourceVariable var = new ResourceVariable(synch, phase);
    setBlocked(EdgeSetFactory.requestManyAllocateManyArray(new Resource[]{var}, getRegistered()));
  }

  /**
   * Marks the task as blocked.
   * @param group
   * @throws DeadlockIdentifiedException when a deadlock is found
   */
  private void setBlocked(EdgeSet group) throws DeadlockIdentifiedException {
    try {
      handle.setBlocked(group);
    } catch (DeadlockFoundException e) {
      // we throw an exception and cancel the invocation of await
      if (handle.isBlocked()) {
        handle.clearBlocked();
      }
      throw new DeadlockIdentifiedException(e.getDeadlock());
    }
  }

  /**
   * Must be called after the blocking call.
   */
  public void afterAwait() {
    handle.clearBlocked();
  }

  /**
   * Return the phase number of the given synchronisation object.
   * @param synch
   * @return
   */
  public int getPhase(Object synch) {
    return phases.get(synch);
  }
}
TOP

Related Classes of pt.ul.jarmus.ResourceManager$State

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.