Confirmed users
699
edits
| Line 195: | Line 195: | ||
In the Plugin protocol example above, we might want the Init() message to be synchronous. It may not make sense for the browser to continue executing until it knows whether the plugin was successfully initialized. (We will discuss which semantics, asynchronous or synchronous, is preferred in a later section.) So for this particular case, let's extend the Plugin protocol's Init() message to be synchronous and return an error code: 0 if the plugin was initialized successfully, non-zero if not. Here's a first attempt at that | In the Plugin protocol example above, we might want the Init() message to be synchronous. It may not make sense for the browser to continue executing until it knows whether the plugin was successfully initialized. (We will discuss which semantics, asynchronous or synchronous, is preferred in a later section.) So for this particular case, let's extend the Plugin protocol's Init() message to be synchronous and return an error code: 0 if the plugin was initialized successfully, non-zero if not. Here's a first attempt at that | ||
'''protocol''' Plugin { | |||
'''child''': | |||
'''sync''' Init() '''returns''' (int rv); | |||
Deinit(); | |||
}; | |||
We added two new keywords to the Plugin protocol, '''sync''' and '''returns'''. '''sync''' marks a message as being sent synchronously; note that the Deinit() message has no specifier. The default semantics is asynchronous. The '''returns''' keyword marks the beginning of the list of values that are returned in the reply to the message. | We added two new keywords to the Plugin protocol, '''sync''' and '''returns'''. '''sync''' marks a message as being sent synchronously; note that the Deinit() message has no specifier. The default semantics is asynchronous. The '''returns''' keyword marks the beginning of the list of values that are returned in the reply to the message. (It is a type error to add a '''returns''' block to an asynchronous message.) | ||
'''Detour''': the above protocol will fail the IPDL type checker. Why? IPDL protocols also have "semantics specifiers", just like messages. A protocol must be declared to have semantics at least as "strong" as its strongest message semantics. Synchronous semantics is called "stronger than" asynchronous. Like message declarations, the default protocol semantics is asynchronous; however, since the Plugin protocol declares a synchronous message, this type rule is violated. The fixed up Plugin protocol is shown below. | '''Detour''': the above protocol will fail the IPDL type checker. Why? IPDL protocols also have "semantics specifiers", just like messages. A protocol must be declared to have semantics at least as "strong" as its strongest message semantics. Synchronous semantics is called "stronger than" asynchronous. Like message declarations, the default protocol semantics is asynchronous; however, since the Plugin protocol declares a synchronous message, this type rule is violated. The fixed up Plugin protocol is shown below. | ||
'''sync''' '''protocol''' Plugin { | |||
'''child''': | |||
'''sync''' Init() '''returns''' (int rv); | |||
Deinit(); | |||
}; | |||
This new '''sync''' message with '''returns''' values changes the PluginProtocolParent and PluginProtocolChild headers as follows | This new '''sync''' message with '''returns''' values changes the generated PluginProtocolParent and PluginProtocolChild headers as follows | ||
// class PluginProtocolParent { ... | |||
int SendInit() { /* boilerplate */ } | |||
// class PluginProtocolChild { ... | |||
virtual int RecvInit() = 0; | |||
To the parent implementor, the new SendInit() method signature means that it receives an int return code back from the child. To the child implementor, the new RecvInit() method signature means that it must return an int back from the handler, signifying whether the plugin was initialized successfully. | To the parent implementor, the new SendInit() method signature means that it receives an int return code back from the child. To the child implementor, the new RecvInit() method signature means that it must return an int back from the handler, signifying whether the plugin was initialized successfully. | ||
| Line 223: | Line 225: | ||
'''Implementation detail''': IPDL supports multiple '''returns''' values, such as in the following example message declaration | '''Implementation detail''': IPDL supports multiple '''returns''' values, such as in the following example message declaration | ||
// sync protocol Blah { | |||
'''child''': | |||
sync Foo(int param1, char param2) returns (long ret1, int64_t ret2); | |||
C++ does not have syntax that allows returning multiple values from functions/methods | C++ does not have syntax that allows returning multiple values from functions/methods. Additionally, IPDL needs to allow implementor code to signal error conditions, and IPDL itself needs to notify implementors of errors. To those ends, IPDL generates interface methods with nsresult return types and "outparams" for the IPDL '''returns''' values. So in reality, the C++ interface generated for the Blah example above would be | ||
// class BlahProtocolParent { ... | |||
nsresult SendFoo(const int& param1, const int& param2, long* ret1, int64_t* ret2) { /* boilerplate */ } | |||
// class BlahProtocolChild { ... | |||
virtual nsresult RecvFoo(const int& param1, const int& param2, long* ret1, int64_t* ret2) = 0; | |||
And the actual interface generated for the Plugin protocol is | And the actual interface generated for the Plugin protocol is | ||
// class PluginProtocolParent { ... | |||
nsresult SendInit(int* rv) { /* boilerplate */ } | |||
// class PluginProtocolChild { ... | |||
virtual nsresult RecvInit(int* rv) = 0; | |||
=== RPC semantics === | === RPC semantics === | ||
=== Preferred semantics === | === Preferred semantics === | ||