Confirmed users
699
edits
No edit summary |
|||
| Line 361: | Line 361: | ||
== Protocol state machines == | == Protocol state machines == | ||
The astute reader might question why IPDL includes the word "protocol" when all that has been introduced so far are unstructured grab-bags of messages. IPDL allows protocol authors to define the order and structure of how messages may be sent/received by defining protocol ''state machines'' (finite state machines). | |||
IPDL parent and child actors follow the same state machine, and keep states that are the "same" (though the parent and child states may be momentarily out of sync while messages cross the wire). IPDL arbitrarily requires state machines to be defined from the perspective of the parent side of the protocol. For example, when you see the <code>'''send''' Msg</code> syntax, it means "when the parent actor sends Msg." | |||
The following example shows one such state machine for the Plugin protocol. | |||
include protocol "PluginInstance.ipdl"; | |||
sync protocol Plugin { | |||
manages PluginInstance; | |||
child: | |||
sync Init() returns (int rv); | |||
Deinit(); | |||
sync PluginInstance(String type, StringArray args) returns (int rv); | |||
~PluginInstance(); | |||
// NOTE: state machine follows | |||
state START: | |||
send Init goto IDLE; | |||
state IDLE: | |||
send PluginInstance goto ACTIVE; | |||
state ACTIVE: | |||
send PluginInstance goto ACTIVE; | |||
send ~PluginInstance goto ACTIVE; | |||
send Deinit goto DYING; | |||
state DYING: | |||
send ~PluginInstance goto DYING; | |||
}; | |||
The new syntax here is threefold. First are "state declarations" --- <code>'''state''' FOO:</code> declares a state "FOO". (States are capitalized by convention, not because of syntactic rules.) The first state to be declared is the protocol's "start state"; when an actor is created, its initial state is the "start state." | |||
The second new syntax is <code>'''send''' MsgDecl</code> which defines a ''trigger'' for a state ''transition''; in this case, the trigger is <code>'''send'''</code>ing the async or sync message "MsgDecl." The other triggers available are (i) <code>'''recv'''</code>ing a async or sync message; (ii) <code>'''call'''</code>ing an RPC; and (iii) <code>'''answer'''</code>ing an RPC. | |||
'''Aside''': this is why actor ctors/dtors act like normal messages, with directions etc.: this allows them to be checked against the protocol state machine like any other message. | |||
The third new syntax is <code>'''goto''' NEXT_STATE</code>, a state ''transition''. When the trigger preceding this transition occurs, the protocol actor's internal state is changed to, in this case, "NEXT_STATE." | |||
Another example state machine, for PluginInstance, follows. | |||
sync protocol PluginInstance { | |||
manager Plugin; | |||
child: | |||
SetWindow(PluginWindow window); | |||
Paint(); | |||
parent: | |||
sync GetBrowserValue(String key) returns (String value); | |||
state START: | |||
send SetWindow goto SENT_WINDOW; | |||
recv GetBrowserValue goto START; | |||
state SENT_WINDOW: | |||
send SetWindow goto SENT_WINDOW; | |||
send Paint goto SENT_WINDOW; | |||
recv GetBrowserValue goto SENT_WINDOW; | |||
}; | |||
A few additional notes: | |||
* protocol state machines are optional, but strongly encouraged. simple state machines are useful too! | |||
* all actor states, trigger matching, and transitions are managed by IPDL-generated code. your C++ never sees this | |||
* all messages sent and received are checked against the protocol's state machine. if a message violates the state machine, generic error handling code is invoked; this will probably mean that the child process containing the child actor is terminated with extreme prejudice, and all parent actors are made invalid. | |||
* lots of syntactic sugar is possible for state machine definitions. ping the Electrolysis team if you have good proposals. | |||