IPDL/Getting started: Difference between revisions

m
Line 37: Line 37:
These Parent and Child classes are abstract.  They will contain a "Send" function implementation for each message type in the protocol (which inheriting classes can call to initiate communication), and a pure virtual "Recv" function for the message receiver (which needs to be implemented by the inheriting class).  For example, the PluginProtocolParent class will look something like the following in C++
These Parent and Child classes are abstract.  They will contain a "Send" function implementation for each message type in the protocol (which inheriting classes can call to initiate communication), and a pure virtual "Recv" function for the message receiver (which needs to be implemented by the inheriting class).  For example, the PluginProtocolParent class will look something like the following in C++


   class PluginProtocolParent {
   '''class''' PluginProtocolParent {
   public:
   '''public''':
       void SendInit()
       '''void''' SendInit()
       {
       {
           // boilerplate generated code ...
           // boilerplate generated code ...
       }
       }
       void SendDeinit()
       '''void''' SendDeinit()
       {
       {
           // boilerplate generated code ...
           // boilerplate generated code ...
Line 51: Line 51:
and the PluginProtocolChild will be something like:
and the PluginProtocolChild will be something like:


   class PluginProtocolChild {
   '''class''' PluginProtocolChild {
   protected:
   '''protected''':
       virtual void RecvInit() = 0;
       '''virtual''' '''void''' RecvInit() = 0;
       virtual void RecvDeinit() = 0;
       '''virtual''' '''void''' RecvDeinit() = 0;
   };
   };


Line 61: Line 61:
So these abstract Parent and Child classes are meant to be subclassed by C++ ''implementors''.  Below is a dirt simple example of how a browser implementor might utilize the PluginProtocolParent
So these abstract Parent and Child classes are meant to be subclassed by C++ ''implementors''.  Below is a dirt simple example of how a browser implementor might utilize the PluginProtocolParent


   class PluginParent : public PluginProtocolParent {
   '''class''' PluginParent : '''public''' PluginProtocolParent {
   public:
   '''public''':
       PluginParent(string pluginDsoFile) {
       PluginParent(String pluginDsoFile) {
           // launch child plugin process
           // launch child plugin process
       }
       }
Line 72: Line 72:
Here's how the PluginProtocolChild might be used by a C++ implementor in the plugin process:
Here's how the PluginProtocolChild might be used by a C++ implementor in the plugin process:


   class PluginChild : public PluginProtocolChild {
   '''class''' PluginChild : '''public''' PluginProtocolChild {
   protected:
   '''protected''':
       // implement the PluginProtocolChild "interface"
       // implement the PluginProtocolChild "interface"
       void RecvInit() {
       '''void''' RecvInit() {
           printf("Init() message received\n");
           printf("Init() message received\n");
           // initialize the plugin module
           // initialize the plugin module
       }
       }
       void RecvDeinit() {
       '''void''' RecvDeinit() {
           printf("Deinit() message received\n");
           printf("Deinit() message received\n");
           // deinitialize the plugin module
           // deinitialize the plugin module
       }
       }
    
    
   public:
   '''public''':
       PluginChild(string pluginDsoFile) {
       PluginChild(String pluginDsoFile) {
           // load the plugin DSO
           // load the plugin DSO
       }
       }
Line 132: Line 132:


  // this protocol ...
  // this protocol ...
  protocol Direction {
  '''protocol''' Direction {
  child:
  '''child''':
     Foo();  // can be sent from-parent-to-child
     Foo();  // can be sent from-parent-to-child
  parent:
  '''parent''':
     Bar();  // can be sent from-child-to-parent
     Bar();  // can be sent from-child-to-parent
  both:
  '''both''':
     Baz();  // can be sent both ways
     Baz();  // can be sent both ways
  };   
  };   
Line 143: Line 143:


  // ----- DirectionProtocolParent.h -----
  // ----- DirectionProtocolParent.h -----
  class DirectionProtocolParent {
  '''class''' DirectionProtocolParent {
  protected:
  '''protected''':
     virtual void RecvBar() = 0;
     '''virtual''' '''void''' RecvBar() = 0;
     virtual void RecvBaz() = 0;
     '''virtual''' '''void''' RecvBaz() = 0;
   
   
  public:
  '''public''':
     void SendFoo() { /* boilerplate */ }
     '''void''' SendFoo() { /* boilerplate */ }
     void SendBaz() { /* boilerplate */ }
     '''void''' SendBaz() { /* boilerplate */ }
  };
  };


  // ----- DirectionProtocolChild.h -----
  // ----- DirectionProtocolChild.h -----
  class DirectionProtocolChild {
  '''class''' DirectionProtocolChild {
  protected:
  '''protected''':
     virtual void RecvFoo() = 0;
     '''virtual''' '''void''' RecvFoo() = 0;
     virtual void RecvBaz() = 0;
     '''virtual''' '''void''' RecvBaz() = 0;
   
   
  public:
  '''public''':
     void SendBar() { /* boilerplate */ }
     '''void''' SendBar() { /* boilerplate */ }
     void SendBaz() { /* boilerplate */ }
     '''void''' SendBaz() { /* boilerplate */ }
  };
  };


Line 171: Line 171:


   // protocol Blah { ...
   // protocol Blah { ...
   child:
   '''child''':
     Foo(int parameter);
     Foo(int parameter);
    
    
   // class BlahProtocolParent { ...
   // class BlahProtocolParent { ...
     void SendFoo(const int& parameter) { // boilerplate }
     '''void''' SendFoo('''const''' '''int'''& parameter) { // boilerplate }
    
    
   // class BlahProtocolChild { ...
   // class BlahProtocolChild { ...
     virtual void RecvFoo(const int& paramter) = 0;
     '''virtual''' '''void''' RecvFoo('''const''' '''int'''& paramter) = 0;


The IPDL compiler has a set of "builtin" types for which library code exists to serialize and deserialize parameters of that type.  These builtin types include the C/C++ integer types (bool, char, int, ..., int8_t, uint16_t, ...), a string type (<code>String</code> in IPDL), and some array types (<code>StringArray</code>, for example).  These builtin types are in flux and will certainly be expanded.  The most up-to-date reference for builtins is the file <code>ipc/glue/MessageTypes.h</code>.
The IPDL compiler has a set of "builtin" types for which library code exists to serialize and deserialize parameters of that type.  These builtin types include the C/C++ integer types (bool, char, int, ..., int8_t, uint16_t, ...), a string type (<code>String</code> in IPDL), and some array types (<code>StringArray</code>, for example).  These builtin types are in flux and will certainly be expanded.  The most up-to-date reference for builtins is the file <code>ipc/glue/MessageTypes.h</code>.
Line 216: Line 216:


  // class PluginProtocolParent { ...
  // class PluginProtocolParent { ...
     int SendInit() { /* boilerplate */ }
     '''int''' SendInit() { /* boilerplate */ }
   
   
  // class PluginProtocolChild { ...
  // class PluginProtocolChild { ...
     virtual int RecvInit() = 0;
     '''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 229: Line 229:
  // sync protocol Blah {
  // sync protocol Blah {
  '''child''':
  '''child''':
     sync Foo(int param1, char param2) returns (long ret1, int64_t ret2);
     '''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.  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
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 { ...
  // class BlahProtocolParent { ...
     nsresult SendFoo(const int& param1, const int& param2, long* ret1, int64_t* ret2) { /* boilerplate */ }
     nsresult SendFoo('''const''' '''int'''& param1, '''const''' '''int'''& param2, '''long'''* ret1, int64_t* ret2) { /* boilerplate */ }
   
   
  // class BlahProtocolChild { ...
  // class BlahProtocolChild { ...
     virtual nsresult RecvFoo(const int& param1, const int& param2, long* ret1, int64_t* ret2) = 0;
     '''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 { ...
  // class PluginProtocolParent { ...
     nsresult SendInit(int* rv) { /* boilerplate */ }
     nsresult SendInit('''int'''* rv) { /* boilerplate */ }
   
   
  // class PluginProtocolChild { ...
  // class PluginProtocolChild { ...
     virtual nsresult RecvInit(int* rv) = 0;
     '''virtual''' nsresult RecvInit('''int'''* rv) = 0;


=== RPC semantics ===
=== RPC semantics ===
Line 253: Line 253:
In the example protocol below, the child actor offers a "CallMeCallYou()" RPC interface, and the parent offers a "CallYou()" RPC interface.  The <code>'''rpc'''</code> qualifiers mean that if the parent calls "CallMeCallYou()" on the child actor, then the child actor, while servicing this call, is allowed to call back into the parent actor's "CallYou()" message.
In the example protocol below, the child actor offers a "CallMeCallYou()" RPC interface, and the parent offers a "CallYou()" RPC interface.  The <code>'''rpc'''</code> qualifiers mean that if the parent calls "CallMeCallYou()" on the child actor, then the child actor, while servicing this call, is allowed to call back into the parent actor's "CallYou()" message.


  rpc protocol Example {
  '''rpc''' '''protocol''' Example {
  child:
  '''child''':
     rpc CallMeCallYou() return (int rv);
     '''rpc''' CallMeCallYou() '''returns''' (int rv);
   
   
  parent:
  '''parent''':
     rpc CallYou() returns (int rv);
     '''rpc''' CallYou() '''returns''' (int rv);
  };
  };


Confirmed users
699

edits