face: decoupling forwarder_receive from ISR
Opened this issue · 2 comments
Timer discussion #11 got me think of our network face implementation might also be problematic. For example, current 802.15.4 face uses ISR to receive frames from network, and transfers data by directly invoking callback from forwarder, which may further invoke callbacks from direct face (which application code be involved with). Thus, the interrupt probably reaches to application region. Given that we can't expect what application do in direct face's onData()/onInterest(), we better decouple forwarder callback from this ISR.
Wonder if using event queue could solve this. We can do it with timer implementation together. Plus, I suggest to keep interrupts confined in "kernel space" and keep all ISR use cases in NDN-Lite as short and simple as possible to ensure interrupts can return quickly.
Current face_receive
is still called inside ISR, though only the last segment will trigger it. Our UDP face in POSIX adaptation is a good example, showing how to utilize msg queue to avoid abusing ISR, in order to receive and drive forwarder processing packets. Faces should be refactored with msg queue's help.
The fundamental difference is pull-style vs push-style API.
POSIX UDP faces are sockets. Kernel buffers incoming frames, waiting for you to pull a frame in a normal thread using recvfrom
and pass to forwarder/application.
https://github.com/named-data-iot/ndn-iot-package-over-posix/blob/f6cc43a6b60b12d8c485bf78f1400165931e80a0/adaptation/udp/udp-face.c#L203-L207
nRF52 SDK pushes a frame to you in ISR by calling your nrf_802154_received
function. There is no buffering before you.
https://github.com/named-data-iot/ndn-iot-package-over-nordic-sdk-gcc/blob/b65851c385ca39f79986821f23823f26d20cf262/adaptation/802154-adaptation/ndn-nrf-802154-face.c#L229-L241
The classical way to turn a push into a pull is adding a queue. nrf_802154_received
pushes the frame into a queue, and a normal thread pulls from the queue.
I had this trouble when developing esp8266ndn's EthernetTransport, and ended up adding a queue.
ESP32 variant uses FreeRTOS Queue API because incoming frames are arriving on another CPU; ESP8266 variant is a simple circular buffer.