/**
   * Create a guarded communication with a send communication. This constructor allows actors which
   * are not CSPActors access to CSP functionality by providing their own
   * ConditionalBranchController.
   *
   * @param guard The guard for the guarded communication statement represented by this object.
   * @param port The IOPort containing the channel (and thus receiver) that this branch will try to
   *     rendezvous with.
   * @param channel The channel in the IOPort that this branch is trying to rendezvous with.
   * @param branchID The identification number assigned to this branch upon creation by the
   *     CSPActor.
   * @param token The token this branch is trying to send.
   * @param controller The controller that this branch uses.
   * @exception IllegalActionException If the channel has more than one receiver or if the receiver
   *     is not of type CSPReceiver.
   */
  public ConditionalSend(
      boolean guard,
      IOPort port,
      int channel,
      int branchID,
      Token token,
      ConditionalBranchController controller)
      throws IllegalActionException {
    super(guard, port, branchID, controller);
    _port = port;
    _channel = channel;

    try {
      port.workspace().getReadAccess();

      if (!port.isOutput()) {
        throw new IllegalActionException(
            port, "ConditionalSend: " + "tokens only sent from an output port.");
      }

      if (channel >= port.getWidth() || channel < 0) {
        throw new IllegalActionException(port, "ConditionalSend: " + "channel index out of range.");
      }

      Receiver[][] receivers = port.getRemoteReceivers();

      if (receivers == null || receivers[channel] == null) {
        throw new IllegalActionException(
            port, "ConditionalSend: " + "Trying to rendezvous with null receiver");
      }
      if (!(receivers[channel][0] instanceof CSPReceiver)) {
        throw new IllegalActionException(
            port,
            "ConditionalSend: "
                + "channel "
                + channel
                + " does not have a receiver "
                + "of type CSPReceiver.");
      }
      _setReceivers(receivers[channel]);
    } finally {
      port.workspace().doneReading();
    }

    _setToken(token);
  }
Example #2
0
  /**
   * Return the director that created this receiver. If this receiver is an inside receiver of an
   * output port of an opaque composite actor, then the director will be the local director of the
   * container of its port. Otherwise, it's the executive director of the container of its port.Note
   * that the director returned is guaranteed to be non-null. This method is read synchronized on
   * the workspace.
   *
   * @return An instance of DEDirector.
   * @exception IllegalActionException If there is no container port, or if the port has no
   *     container actor, or if the actor has no director, or if the director is not an instance of
   *     DEDirector.
   */
  private DEDirector _getDirector() throws IllegalActionException {
    IOPort port = getContainer();

    if (port != null) {
      if (_directorVersion == port.workspace().getVersion()) {
        return _director;
      }

      // Cache is invalid.  Reconstruct it.
      try {
        port.workspace().getReadAccess();

        Actor actor = (Actor) port.getContainer();

        if (actor != null) {
          Director dir;

          if (!port.isInput()
              && (actor instanceof CompositeActor)
              && ((CompositeActor) actor).isOpaque()) {
            dir = actor.getDirector();
          } else {
            dir = actor.getExecutiveDirector();
          }

          if (dir != null) {
            if (dir instanceof DEDirector) {
              _director = (DEDirector) dir;
              _directorVersion = port.workspace().getVersion();
              return _director;
            } else {
              throw new IllegalActionException(getContainer(), "Does not have a DEDirector.");
            }
          }
        }
      } finally {
        port.workspace().doneReading();
      }
    }

    throw new IllegalActionException(
        getContainer(), "Does not have a IOPort as the container of the receiver.");
  }
Example #3
0
  /**
   * Put a token on the queue contained in this receiver. If the queue is full, then suspend the
   * calling thread (blocking write) and inform the director of the same. Resume the process on
   * detecting room in the queue. If a termination is requested, then initiate the termination of
   * the calling process by throwing a TerminateProcessException. On detecting a room in the queue,
   * put a token in the queue. Check whether any process is blocked on a read from this receiver. If
   * a process is indeed blocked, then unblock the process, and inform the director of the same.
   *
   * @param token The token to be put in the receiver, or null to not put anything.
   * @exception NoRoomException If during initialization, capacity cannot be increased enough to
   *     accommodate initial tokens.
   */
  public void put(Token token) throws NoRoomException {
    IOPort port = getContainer();
    if (port == null || token == null) {
      return; // Nothing to do.
    }
    Workspace workspace = port.workspace();
    while (!_terminate) {
      int depth = 0;
      try {
        // NOTE: Avoid acquiring read access on the workspace
        // while holding the lock on the director because if
        // some other process is trying to acquire write access,
        // the request for read access will be deferred.
        Nameable container = getContainer().getContainer();
        Manager manager = ((Actor) container).getManager();
        // NOTE: This used to synchronize on this, but since it calls
        // director methods that are synchronized on the director,
        // this can cause deadlock.
        synchronized (_director) {
          // Need to check this again after acquiring the lock.
          // Otherwise, could end up calling wait() below _after_
          // notification has occurred.
          if (_terminate) {
            break;
          }

          // If we are in the initialization phase, then we may have
          // to increase the queue capacity before proceeding. This
          // may be needed to support PublisherPorts that produce
          // initial tokens (or, I suppose, any actor that produces
          // initial tokens during initialize()?).
          if (!super.hasRoom()) {
            if (container instanceof Actor) {
              if (manager.getState().equals(Manager.INITIALIZING)) {
                try {
                  _queue.setCapacity(_queue.getCapacity() + 1);
                } catch (IllegalActionException e) {
                  throw new NoRoomException(
                      getContainer(),
                      "Failed to increase queue capacity enough to accommodate initial tokens");
                }
              }
            }
          }
          // Try to write.
          if (super.hasRoom()) {
            super.put(token);

            // If any thread is blocked on a get(), then it will become
            // unblocked. Notify the director now so that there isn't a
            // spurious deadlock detection.
            if (_readPending != null) {
              _director.threadUnblocked(_readPending, this, PNDirector.READ_BLOCKED);
              _readPending = null;
            }

            // Normally, the _writePending reference will have
            // been cleared by the read that unblocked this write.
            // However, it might be that the director increased the
            // buffer size, which would also have the affect of unblocking
            // this write. Hence, we clear it here if it is set.
            if (_writePending != null) {
              _director.threadUnblocked(_writePending, this, PNDirector.WRITE_BLOCKED);
              _writePending = null;
            }

            break;
          }

          // Wait to try again.
          _writePending = Thread.currentThread();
          _director.threadBlocked(_writePending, this, PNDirector.WRITE_BLOCKED);

          // NOTE: We cannot use workspace.wait(Object) here without
          // introducing a race condition, because we have to release
          // the lock on the _director before calling workspace.wait(_director).
          depth = workspace.releaseReadPermission();
          _director.wait();
        } // release lock on _director before reacquiring read permissions.
      } catch (InterruptedException e) {
        _terminate = true;
      } finally {
        if (depth > 0) {
          workspace.reacquireReadPermission(depth);
        }
      }
    }

    if (_terminate) {
      throw new TerminateProcessException("Process terminated.");
    }
  }