ccollins476ad commented on issue #686: [DO NOT MERGE] BLE Host flow control URL: https://github.com/apache/mynewt-core/pull/686#issuecomment-348375749 ## Overview Controller to host flow control (hereon called "flow control") stops the controller from sending more ACL data packets than the host can accommodate. Briefly, this feature is implemented as follows: * On startup, host tells controller: * That flow control is being used. * About its ACL data buffer supply: * Total number of buffers. * Size of each buffer. * After startup, host sends updates to controller containing: The number of ACL data buffers it has freed since the last update, and which connection handle each buffer was associated with. * Host provides updates periodically (default: once per second). * Host sends an immediate update if the number of buffers freed since the last update exceeds a threshold (default: `total_buffers - 2`). * Host does not send an update if the number of buffers freed since the last update is 0. * If a connection with unfreed buffers is terminated, the controller can assume that all buffers are freed (i.e., no host update required). This feature prevents a buffer overrun as long as the controller keeps track of the host's free buffer count. ## Complications Flow control is quite simple as described above. Unfortunately, there is one feature of the nimble host that really complicates things. When the host tells the application about an incoming data packet, such as a write-attribute command, the application can keep the mbuf for later processing. If the application keeps the mbuf, then it is the application's responsibility to free the mbuf when it is done with it. This is a problem because the flow control implementation needs to know when a buffer is freed to properly update the controller. The solution I chose is to add a callback that gets called when a block is freed back to the ACL buffer pool. The callback would increment the appropriate freed buffer count, and possibly schedule a host update. Because the ACL buffer pool is an mbuf pool, there were two ways to implement this: 1. Add the callback to `struct os_mbuf_pool`. 2. Add the callback to the underlying `struct os_mempool`. I thought this functionality might be useful to others, so I chose the more generic option 2. First, here is how this is implemented: ``` struct os_mempool_ext; typedef void os_mempool_put_fn(struct os_mempool_ext *ome, void *data); struct os_mempool_ext { struct os_mempool mpe_mp; /* Callback that is executed immediately before a block is freed. */ os_mempool_put_fn *mpe_pre_put_cb; /* Callback that is executed immediately after a block is freed. The * contents of the block are indeterminate and should not be inspected. */ os_mempool_put_fn *mpe_post_put_cb; }; ``` And a new `flags` field was added to `struct os_mempool`: ``` struct os_mempool { // ... uint8_t mp_flags; /* Bitmap of OS_MEMPOOL_F_[...] values. */ // ... }; /** * Indicates an extended mempool. Address can be safely cast to * (struct os_mempool_ext *). */ #define OS_MEMPOOL_F_EXT 0x01 ``` When a block is freed back to a mempool, the free function uses the flags field to determine if it should cast to `struct os_mempool_ext *` and call the callbacks. What I don't like about this is the need for two callbacks. We need two because the user might need to know two separate things: * The contents of the block being freed, and * That the block is fully freed and ready to be reallocated. The contents of the block can only be inspected before it is freed, hence the need for two callbacks. I just worry that this mechanism is too complicated for people to understand and use.
---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services