The training course of “Introduction to Protocol Modeling” held May 11, 2007 at the Microsoft ATC by Colin Campbell was finished this weekend. It is quiet a good experience to join such a class, the teacher is kind and talkative and the training content is helpful. I shall write a memo of this training for further usage.
Our first task is learning to use Spec Explorer. Spec Explorer is a software-development tool for advanced model-based specification and conformance testing. Spec Explorer can help software-development teams detect errors in the design, the specification, and the implementation of their systems. Using Spec Explorer we can:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
Microsoft.Modeling;
namespace
ABP

...
{
public static class ABPclass

...{
// State
static bool initializing = true;
static bool bit1 = false; // true when bit is 1, 0 to start 1st msg
static bool inFlight = false; // true when sending x, but no ack x yet
static bool SendEnabled(bool bit)

...{
return (initializing
|| !initializing && bit == bit1);
}
[Action("Send(_, bit)")]
static void Send(bool bit)

...{
Contracts.Requires(SendEnabled(bit));
if (!bit) initializing = false; // send bit 0 to leave initial state
if (!initializing) inFlight = true;
}
static bool AckEnabled(bool bit)

...{
return (bit && initializing // initialy ack 1
|| bit && !initializing && inFlight
|| bit && !initializing && !inFlight && !bit1
|| !bit && !initializing && inFlight
|| !bit && !initializing && !inFlight && bit1);
}
[Action]
static void Ack(bool bit)

...{
Contracts.Requires(AckEnabled(bit));
if (!initializing && bit == bit1)

...{
bit1 = !bit1;
inFlight = false;
}
}
[AcceptingStateCondition]

static bool AcceptingState() ...{ return (initializing || !inFlight); }
}
}
Now let me tell my own understanding of the code.
1.
using
Microsoft.Modeling;
We using
Contracts
.Requires(
bool) later and it is in the namespace Microsoft.Modeling. If the function parameter is not true, it will throw an exception so with this line get those conditions meet the requirements.
2. There are only three
bool variables represent the state, so it is a finite model.
It is proved by Spec Explorer that there are 5 states as follows.
3.We can read the code better with the help of the picture displayed above.
S0:initializing=true,bit1=false,inFlight=false
S4:initializing=false,bit1=false,inFlight=true
S10:initializing=false,bit1=true,inFlight=false
S14:initializing=false,bit1=true,inFlight=true
S19:initializing=false,bit1=false,inFlight=false
In addtion, these states are genelated automatically by Spec Explorer.
The key
variable is inFlight which shows if the messege is flying(sending).
4.The [AcceptingStateCondition] indicates the states allowed.
The traces which are not ended with those state are not accepted.
5.[Action] indicates the action methods.
Each action method must express how the action changes the state (or leaves it unchanged). Usually, the body of an action method computes the next state from the current state, by assigning one or more state variables.
using
ABP;
config Actions

...
{
// concrete actions so !?! composition works
action static void ABPImpl.Send(string msg, bool bit);
action static void ABPImpl.Ack(bool bit);
switch graphtimeout = 0;
}
main machine ABPContract(): Actions

...
{
construct model program from Actions where namespace = "ABP"
}
machine AllowedScenario(): Actions

...
{
Send(_,true);
Ack(true);
Send(_, false);
Ack(false);
Send(_, true);
Ack(true);
}
machine CheckAllowedScenario(): Actions

...
{
AllowedScenario || ABPContract;
}
machine ForbiddenScenario(): Actions

...
{
Send(_,true);
Ack(true);
Send(_, false);
Ack(false);
Send(_, false); // FORBIDDEN! Must send true after Ack(false)
Ack(true);
}
machine CheckForbiddenScenario(): Actions

...
{
ForbiddenScenario || ABPContract;
}
machine MessageScenario(): Actions

...
{
Send("Initializing",true);
Ack(true);
Send("Message1", false);
Ack(false);
Send("Message2", true);
Ack(true);
}
machine CheckMessageScenario(): Actions

...
{
MessageScenario || ABPContract;
}
config SendAction

...
{
action static void ABPImpl.Send(string msg, bool bit);
switch graphtimeout = 0;
}
machine MessageOnlyScenario(): SendAction

...
{
Send("Initializing", true);
Send("Message1", false);
Send("Message2", true);
}
machine CheckMessageOnlyScenario(): Actions

...
{
MessageOnlyScenario || ABPContract;
}
//
Concrete actions are needed for this!
machine CheckMessageInterleaveScenario(): Actions

...
{
MessageOnlyScenario |?| ABPContract;
}
machine MessageResendScenario(): SendAction

...
{
Send("Initializing", true)+; // + means one or more
Send("Message1", false)+;
Send("Message2", true)+;
}
machine CheckMessageResendScenario(): Actions

...
{
MessageResendScenario |?| ABPContract;
}
Follows are
my own understanding of the code.
1.config: block declares actions
actions must be declared before use.
2.machine: block describes behaviors
construct model program from Actions where namespace = "ABP"
Contract model program describes all allowed traces
machine AllowedScenario(): Actions
Scenario machine describes particular traces of interest (perhaps just one)
3.|| and |?|
Combines two (or more) machines. Combines can form composition of contract model program with scenario machine, the result is intersection of traces.
And combines can also checks whether contract model program can execute scenario (when intersection includes the entire scenario)
1.This is the design mode of the code.
2.Double click the name of the machine or click the Explorer, the FSM is displayed in the exploration window.
3.The state window shows the state of all variables.
using
System;
using
System.Collections.Generic;
using
System.Text;
using
Microsoft.Modeling;
namespace
CEP1Model

...
{

/**////<summary>
/// An example model program.
///</summary>
static class ModelProgram

...{
static Set<int> idsUsed = new Set<int>();
static Set<int> pendingARequests = new Set<int>();
static Set<int> pendingBRequests = new Set<int>();
static bool isFinished = false;
static Set<int> pendingCancellations = new Set<int>();
static Set<int> completedCancellations = new Set<int>();
static int creditLimit = 0;
static int creditUsage = 0;
static Map<int, int> creditRequests = new Map<int, int>();
static bool RequestPossible(int x, int creditRequest)

...{
return (0 <= x && x <= creditLimit &&
creditRequest >= 0 &&
((x == creditLimit || x == creditUsage) ? creditRequest > 0 : true));
}
static bool GrantPossible(int x, int creditGrant)

...{
return creditGrant >= 0 &&
creditRequests.ContainsKey(x) &&
creditRequests[x] >= creditGrant &&
(creditUsage == creditLimit ? creditGrant > 0 : true);
}
static void UpdateCreditUsage(int x)

...{
creditUsage = Math.Max(x, creditUsage);
}
static void UpdateCreditLimit(int creditGrant)

...{
creditLimit += creditGrant;
}
[Action("ARequest(x, creditRequest)")]
static void ARequest(int x, int creditRequest)

...{
Contracts.Requires(x >= 0 && !idsUsed.Contains(x));
Contracts.Requires(!isFinished);
Contracts.Requires(RequestPossible(x, creditRequest));
pendingARequests = pendingARequests.Add(x);
idsUsed = idsUsed.Add(x);
creditRequests = creditRequests.Add(x, creditRequest);
UpdateCreditUsage(x);
}
[Action("AResponse(x, creditGrant)")]
static void AResponse(int x, int creditGrant)

...{
Contracts.Requires(pendingARequests.Contains(x));
Contracts.Requires(!isFinished);
Contracts.Requires(GrantPossible(x, creditGrant));
pendingARequests = pendingARequests.Remove(x);
pendingCancellations = pendingCancellations.Remove(x);
UpdateCreditLimit(creditGrant);
}
[Action("BRequest(x, creditRequest)")]
static void BRequest(int x, int creditRequest)

...{
Contracts.Requires(x >= 0 && !idsUsed.Contains(x));
Contracts.Requires(!isFinished);
Contracts.Requires(RequestPossible(x, creditRequest));
pendingBRequests = pendingBRequests.Add(x);
idsUsed = idsUsed.Add(x);
creditRequests = creditRequests.Add(x, creditRequest);
UpdateCreditUsage(x);
}
[Action("BResponse(x, creditGrant)")]
static void BResponse(int x, int creditGrant)

...{
Contracts.Requires(pendingBRequests.Contains(x));
Contracts.Requires(!isFinished);
Contracts.Requires(GrantPossible(x, creditGrant));
pendingBRequests = pendingBRequests.Remove(x);
pendingCancellations = pendingCancellations.Remove(x);
UpdateCreditLimit(creditGrant);
}
[Action("Cancel(x)")]
static void Cancel(int x)

...{
Contracts.Requires(idsUsed.Contains(x));
Contracts.Requires(!pendingCancellations.Contains(x));
Contracts.Requires(!completedCancellations.Contains(x));
Contracts.Requires(!isFinished);
pendingCancellations = pendingCancellations.Add(x);
}
[Action("CancelCompleted(x, creditGrant)")]
static void CancelCompleted(int x, int creditGrant)

...{
Contracts.Requires(pendingCancellations.Contains(x));
Contracts.Requires(!isFinished);
Contracts.Requires(GrantPossible(x, creditGrant));
pendingCancellations = pendingCancellations.Remove(x);
completedCancellations = completedCancellations.Add(x);
pendingARequests = pendingARequests.Remove(x);
pendingBRequests = pendingBRequests.Remove(x);
UpdateCreditLimit(creditGrant);
}
[Action("Finish(x, creditRequest)")]
static void Finish(int x, int creditRequest)

...{
Contracts.Requires(x >= 0 && !idsUsed.Contains(x));
Contracts.Requires(!isFinished);
Contracts.Requires(RequestPossible(x, creditRequest));
isFinished = true;
}
[AcceptingStateCondition]
public static bool NoPendingRequests()

...{
return (pendingARequests.Count == 0 &&
pendingBRequests.Count == 0);
}
[AcceptingStateCondition]
public static bool IsFinished()

...{
return isFinished;
}
}
}
1.This is a Infinite State Machine Example with Set<int> as variable.
//
This is a Spec Explorer coordination script (Cord version 1.0).
//
Here you define configurations and machines describing the
//
exploration task you want to perform.
using
CEP1Implementation;

/**/
/// Contains actions of the model, bounds, and switches.
config Actions

...
{
action abstract static void Implementation.ARequest(int x, int creditRequest);
action abstract static void Implementation.AResponse(int x, int creditGrant);
action abstract static void Implementation.BRequest(int x, int creditRequest);
action abstract static void Implementation.BResponse(int x, int creditGrant);
action abstract static void Implementation.Cancel(int x);
action abstract static void Implementation.CancelCompleted(int x, int creditGrant);
action abstract static void Implementation.Finish(int x, int creditRequest);
bound steps = 128;
bound pathdepth = 128;
switch graphtimeout = 0;
}

/**/
/// Constructs a machine from the model program.
/// Since the model is not finite, this machine explodes
/// and exploration is stopped by a bound.
machine CEP2() : Actions

...
{
construct model program from Actions where namespace = "CEP1Model"
}
machine Trace1() : Actions

...
{
BRequest(0, 1);
BResponse(0, 1);
Cancel(0);
ARequest(1, 2);
AResponse(1, 2);
ARequest(3, 2);
Cancel(1);
AResponse(3, 1);
BRequest(4, 2);
BResponse(4, 0);
Finish(2, 2)
}
machine Trace1AndContract() : Actions

...
{
Trace1() || CEP2()
}
1.
bound steps and pathdepth are usually used in infinite machines.