Calling an active connector will directly call the handler registered at the connected passive connector. This way the call and data are handed across the connections until an I/O module will finally handle the request (by not calling any other connectors).
Throttling is handled in the same way: Throttling a passive connector will call a corresponding (internal) method of the connected active connector. This method will call registered handlers and will analyze the routing information of the module for other (passive) connectors to call and throttle. This will again create a call chain which terminates at the I/O modules. An event which is called to be throttled will disable the event temporarily. Unthrottling works in the same way.
This simple structure is complicated by the existence of the input queues. This affects both data forwarding and throttling:
Every module manages a collection of all it's connectors and every connector has a reference to it's containing module. In addition, every connector maintains a collection of all it's routing targets.
All this data is initialized via the routing statements. This is, why every connector must appear in at least one routing statement: These statements will as a side effect initialize the connector with it's containing module.
Since all access to the PPI via the module is via it's base class, unbound member function pointers can be provided as handler arguments: They will automatically be bound to the current instance. This simplifies the PPI usage considerably. The same is true for the connectors: Since they know the containing module, they can explicitly bind unbound member function pointers to the instance.