Beispiel #1
0
  /**
   * Adds a new FSM instance to the CFSM. Once all the FSMs have been added, the CFSM is considered
   * initialized.
   *
   * @param fsm
   */
  public void addFSM(FSM fsm) {
    assert unSpecifiedPids > 0;
    assert fsm != null;

    int pid = fsm.getPid();

    if (CSightMain.assertsOn) {
      // Must be a valid pid (in the right range).
      assert (pid >= 0 && pid < numProcesses);
      // Only allow to set the FSM for a pid once.
      assert (fsms.get(pid) == null);

      // Check that the FSM alphabet conforms to the expected number of
      // processes.
      int ppid;
      for (DistEventType e : fsm.getAlphabet()) {
        if (e.isCommEvent()) {
          ppid = e.getChannelId().getDstPid();
          assert ppid >= 0 && ppid < numProcesses;

          ppid = e.getChannelId().getSrcPid();
          assert ppid >= 0 && ppid < numProcesses;
        } else {
          ppid = e.getPid();
          assert ppid >= 0 && ppid < numProcesses;
        }
      }
    }

    fsms.set(pid, fsm);
    alphabet.addAll(fsm.getAlphabet());

    unSpecifiedPids -= 1;
  }
Beispiel #2
0
 @Override
 public String toString() {
   String ret = "CFSM: \n";
   for (FSM f : fsms) {
     ret += "\t" + f.toString() + "\n\n";
   }
   return ret.substring(0, ret.length() - 1);
 }
Beispiel #3
0
  /**
   * Generate SCM representation of this CFSM, with bad states if this CFSM was augmented with any
   * invariants.
   */
  public String toScmString(String cfsmName) {
    assert unSpecifiedPids == 0;

    String ret = "scm " + cfsmName + ":\n\n";

    // Channels:
    // Add a special channel for handling local events, represented as
    // messages on this channel.
    LocalEventsChannelId localChId;
    if (localEventsChIndex == Integer.MAX_VALUE) {
      localChId = new LocalEventsChannelId(this.channelIds.size());
      localEventsChIndex = localChId.getScmId();
      this.channelIds.add(localChId);
    } else {
      localChId = (LocalEventsChannelId) this.channelIds.get(localEventsChIndex);
    }

    ret += "nb_channels = " + channelIds.size() + " ;\n";
    ret += "/*\n";
    for (int i = 0; i < channelIds.size(); i++) {
      ret += "channel " + Integer.toString(i) + " : " + channelIds.get(i).toString() + "\n";
    }
    ret += "*/\n\n";

    // Whether or not any channels are lossy:
    // TODO: add lossy field to ChannelId and list all channel ids that
    // are lossy here.

    // Parameters/Alphabet:
    ret += "parameters :\n";
    ret += alphabet.toScmParametersString();
    ret += "\n";

    // FSMS:
    for (int pid = 0; pid < numProcesses; pid++) {
      FSM f = fsms.get(pid);
      ret += "automaton p" + Integer.toString(pid) + " :\n";
      ret += f.toScmString(localChId);
      ret += "\n";
    }

    // Bad states:
    if (!invs.isEmpty()) {
      ret += "\nbad_states:\n";
      for (BadState b : getBadStates()) {
        ret += b.toScmString() + "\n";
      }
    }

    return ret;
  }
Beispiel #4
0
 /**
  * Traverse the graph of FSM f and replace all transitions on e to some state s to transition to a
  * new state X, and add a transition from X to s that enqueues event e on channel identified by
  * invCid.
  *
  * @param visited
  * @param f1
  * @param e1
  * @param invCid
  */
 private void addSendToEventTx(
     FSM f,
     DistEventType eToTrace,
     DistEventType eTracer1,
     DistEventType eTracer2,
     Set<FSMState> visited) {
   for (FSMState init : f.getInitStates()) {
     recurseAddSendToEventTx(f, init, eToTrace, eTracer1, eTracer2, visited);
   }
 }
Beispiel #5
0
  /**
   * Recursive call to perform DFA exploration of FSM f. Helper to addSendToEventTx
   *
   * @param visited
   */
  private void recurseAddSendToEventTx(
      FSM f,
      FSMState parent,
      DistEventType eToTrace,
      DistEventType eTracer1,
      DistEventType eTracer2,
      Set<FSMState> visited) {

    if (visited.contains(parent)) {
      return;
    }

    visited.add(parent);

    // If there is a transition on to-trace event, then perform the
    // re-writing.
    if (parent.getTransitioningEvents().contains(eToTrace)) {
      for (FSMState child : parent.getNextStates(eToTrace)) {
        f.addSyntheticState(parent, child, eToTrace, eTracer1, eTracer2);

        if (!visited.contains(child)) {
          // If we haven't visited the child yet, then recurse to it.
          recurseAddSendToEventTx(f, child, eToTrace, eTracer1, eTracer2, visited);
        }
      }
    }

    for (DistEventType e : parent.getTransitioningEvents()) {
      // Now handle all the non-to-trace events. Note, however, that these
      // have been re-written above with eTracer1 events, so this is what
      // we check for.
      if (!e.equals(eTracer1)) {
        for (FSMState nextF : parent.getNextStates(e)) {
          if (visited.contains(nextF)) {
            continue;
          }

          recurseAddSendToEventTx(f, nextF, eToTrace, eTracer1, eTracer2, visited);
        }
      }
    }
  }
Beispiel #6
0
  /**
   * Generates a Promela representation of this CFSM, to be used with SPIN. The never claim is not
   * specified here and it is appended to the CFSM elsewhere.
   */
  public String toPromelaString(List<BinaryInvariant> invariants, int chanCapacity) {
    assert unSpecifiedPids == 0;

    String ret = "/* Spin-promela Multiple invariants */\n\n";

    // Message types:
    //
    // mtype is global and can only be declared once.
    // There is also limit of 255 for the size of mtype.

    // This outputs a set of event types for the CFSM.
    ret += "/* Message types: */\n";
    ret += "mtype = { ";

    Set<String> eventTypes = Util.newSet();
    for (DistEventType e : alphabet) {
      eventTypes.add(e.getPromelaEType());
    }

    ret += StringUtils.join(eventTypes, ", ");

    ret += " };\n"; // End mtype declaration.
    ret += "\n\n";

    // Define the channels:
    ret += "/* Channels: */\n\n";

    // Specifying channels as an array to work with inlines.
    ret +=
        String.format("chan channel[%d] = [%d] of { mtype };\n", channelIds.size(), chanCapacity);

    // The following block defines EMPTYCHANNELCHECK as a conditional that
    // checks if all the channels are empty. This is used in the never claim
    // to make sure our channels are empty before terminating.
    String emptyChannelCheck = "";
    for (int i = 0; i < channelIds.size(); i++) {
      ret += "/* Channel " + channelIds.get(i).toString() + " */\n";
      if (i != 0) {
        emptyChannelCheck += " && ";
      }
      emptyChannelCheck += "empty(channel[" + i + "])";
    }
    ret += String.format("#define EMPTYCHANNELCHECK (%s)\n", emptyChannelCheck);
    ret += "\n\n";

    // Tracks if the current states of each of the FSM are terminal.
    ret += "bit terminal[" + numProcesses + "];\n";

    // ENDSTATECHECK is the conditional used by the never claim to
    // check the terminal states in all CFSMs. The never claim has this to
    // ensure that the processes are in a proper terminal state when the
    // never claim is done.

    String endStateCheck = "";
    for (int pid = 0; pid < numProcesses; pid++) {
      // Set up the terminal check conditional.
      if (pid != 0) {
        endStateCheck += " && ";
      }
      endStateCheck += "terminal[" + pid + "]";
    }

    ret += String.format("#define ENDSTATECHECK (%s)\n", endStateCheck);

    // Event type definitions for type tracking

    // OTHEREVENTs are used for other transitions so we do not accidentally
    // trigger an "a NFby b". This can happen when a == b. This invariant
    // can be accepted if a transition happens that does not call
    // setRecentEvent. OTHEREVENT does not match any event we are interested
    // in tracking so it is safe to use during these transitions.

    ret += "#define OTHEREVENT (0)\n";
    // Event types we're actively tracking.
    ret += "#define LOCAL (1)\n";
    ret += "#define SEND (2)\n";
    ret += "#define RECV (3)\n";

    // Custom datatype to assist in tracking recent event.
    ret += "typedef myEvent {\n";
    // The type of event: LOCAL, SEND or RECV
    ret += "    byte type;\n";
    // id is the process id if the type is LOCAL and the channel id if the
    // type is SEND or RECV.
    ret += "    byte id;\n";
    // The event itself. These are the previously defined mtypes.
    ret += "    mtype event;\n";
    ret += "};\n";

    // Declaration of event tracker.
    ret += "myEvent recentEvent;\n";

    // Custom inline function to update most recent event.
    ret += "inline setRecentEvent(event_type, owner_id, event_message) {\n";
    ret += "  d_step{\n";
    ret += "    recentEvent.type = event_type;\n";
    ret += "    recentEvent.id = owner_id;\n";
    ret += "    recentEvent.event = event_message;\n";
    ret += "  };\n";
    ret += "}\n";

    // Each of the FSMs in the CFSM:
    for (int pid = 0; pid < numProcesses; pid++) {
      String labelPrefix = "state" + Integer.toString(pid);
      FSM f = fsms.get(pid);
      ret += "active proctype p" + Integer.toString(pid) + "(){\n";
      ret += f.toPromelaString(invariants, labelPrefix);
      ret += "}\n\n";
    }

    ret += "\n\n";

    for (BinaryInvariant inv : invariants) {
      ret += "/* " + inv.toString() + "*/\n";
      ret += inv.promelaNeverClaim();
      ret += "\n\n";
    }
    return ret;
  }