-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Event loop with mbed-events #2860
Conversation
More documentation willl follow, but the basic usage is this:
|
Also, @pan- |
@bogdanm I don't want to get too annoying with naming (seeing how I already asked you to move everything 😄), but should we remove the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! Excited to see this get in!
Added mbed-events from https://github.com/ARMMbed/mbed-events. Changes from upstream: - the whole code is licensed under the Apache license. Sources and headers were updates with this information. - removed the porting layers for Windows and FreeRTOS and the references to these porting layers in equeue_platform.h. - moved the TESTS directory in mbed-events to the TESTS directory of mbed-os.
93484ff
to
e7abc11
Compare
I forced-push a new version that just changed the name of the |
Awesome! /morph test |
I also added some documentation about how to use the event loop in mbed-os. It's not much (yet), but it should be enough to get people started, I think. |
#include "mbed.h" | ||
#include "mbed_events.h" | ||
|
||
using events::EventQueue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we provide the events library through the mbed.h header similarly to the rtos?
https://github.com/ARMmbed/mbed-os/blob/master/hal/api/mbed.h#L21-L23
Another note is that this using statement is not needed. The mbed_events.h entry point un-namespaces the library to be consistent with the rtos and nsapi (for better or worse):
https://github.com/ARMmbed/mbed-os/pull/2860/files#diff-de8f685be747e42feaafbdfaabed4d4fR28
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we provide the events library through the mbed.h header similarly to the rtos?
I'm inclined to say "no" for two reasons:
- it is a completely optional component at the moment.
- mbed classic builds compatibility. We'd have to add a configuration to events/ and add a conditional inclued in mbed.h. Not a big deal, I'm just not sure it's worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is a completely optional component at the moment.
This is also true of the nsapi, and that library is also exposed through mbed.h (for better or worse). It's even under the features directory.
If it's a conditional inclusion (such as rtos and nsapi) than users can opt-out by overriding the MBED_CONF_EVENTS_PRESENT
config option.
I don't have a strong feeling if you think we should keep the mbed-events as opt-in, just concerned about consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for consistency. To the API guidelines for clarification...
sw.rise(rise_handler); | ||
// The 'fall' handler will execute in the context of thread 't' | ||
sw.fall(queue.event(fall_handler)); | ||
Thread::wait(osWaitForever); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be fine to let main exit, so I'm not sure this line is necessary.
That's a very nice write up for introducing people to interrupt/queue contexts : ) |
Result: FAILUREYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 1003 Build failed! |
Welp, looks like our friend KL25Z is the only target that failed to build for IAR. It only has 16KB of RAM :/ Maybe this test needs to be broken apart a bit? |
queue.dispatch(N*100); | ||
} | ||
|
||
struct big { char data[1024]; } big; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the test issue is with this allocation. It looks like IAR's linker can't find a contiguous region of space?
We may want to omit this test (allocate_failure_test1) for now. It has had other problems such as overflowing stacks, and allocation failure is also tested by allocate_failure_test2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there any discussion around having a class that has no scheduling and executes enqueued tasks immediately? In many use cases, the scheduling functionality is not needed. An execute-only queue has a simpler user API and implementation. It also has a fixed time enqueue and dequeue. Using the existing Ticker class with an execute-only queue would provide nearly the same functionality as a scheduling queue. If a scheduling queue is needed, then it could inherit from the basic queue and be a separate class.
The above approach would be simpler and use more of the existing code with which users are familiar but would have the disadvantage of being less powerful. I'm not necessarily advocating for this, but I want to make sure that we have not overlooked anything simpler and more user-friendly. The last thing I want to see is an API that we are stuck with that has been designed hastily and is more complicated than it needs to be.
// Platform mutex type | ||
// | ||
// The equeue library requires at minimum a non-recursive mutex that is | ||
// safe in interrupt contexts. The mutex section is help for a bounded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo - I think you meant held
rather than help
. Also, this is a bit confusing since mutexes are never safe in interrupt context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The definition of a mutex does not disclude irq-safety:
https://en.wikipedia.org/wiki/Mutual_exclusion
In retrospect, the name may have not been the best choice, given the connotation of the name "mutex". However it's not unreasonable given that the user-space implementation is often the normal blocking mutex.
In mbed, this is implemented as a critical section, and the next line details that disabling interrupts is an acceptable implementation.
// and acts as a handle to the underlying event. If there is not enough memory | ||
// to allocate the event, equeue_alloc returns null. | ||
void *equeue_alloc(equeue_t *queue, size_t size); | ||
void equeue_dealloc(equeue_t *queue, void *event); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mention that fragmentation and runtime "grows linearly as the quantity of different sized allocations increases." As an alternative to this, could the memory management be decoupled from the queue in at least the C layer? The equeue_event struct has a "dtor" member which could be used to allow a user supplied free callback. This would allow the native rtos slab allocators to be used with true constant time (even for different sized chunks). It would also allow the standard library new
and malloc
to be used if the object is created on a thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The equeue library has some interesting properties for fixed-size allocations:
- Constant time allocation
- Constant time deallocation
- Constant time enqueueing
- Zero fragmentation
There is no asymptotic benefit to using a slab allocator, and the biggest downside of the rtos's allocators is that they can't handle different sized chunks.
If the user wants to use a custom allocator, they can reserve a single word of space for the pointer required, and the resulting usage will have the same runtime complexity as a redesigned equeue without memory management. This is actually provided already as the convenient equeue_call
function.
However, a memory-less C api is useless in the context of the C++ api, where the size of the callback itself is unbounded.
I don't see a benefit to separating the memory management component from the rest of the event queue, other than complicating the C api.
@c1728p9, long story short: yes You are describing @bogdanm's initial proposal: #2801 @pan- had a good write-up of his concerns based directly on his experience integrating the events library with BLE (#2801 (comment)):
I agree, a simple |
LWIP and other drivers which support asynchronous operation are able to operate on a queue which provides no scheduling so I'm not convinced the simpler approach is insufficient. What would really give me confidence in one of the solutions is to compare how they both look when hooked up to a more complicated driver that will/is using it. Something like BLE, Nanostack/Client or Atmel RF driver among other libraries. I have a couple of days off so if I'm not lazy I might try to implement this on a driver. What is your timeframe for merging this PR? |
LWIP is an excellent example where a full scheduler was needed to handle async operations: |
@geky, lwip depends on a mailbox implementation in the porting layer (sys_arch_mbox_fetch), which does not have any scheduling functionality. LWIP provides its own scheduling internally. For libraries which don't provide scheduling, Ticker and Timeout could be used. |
EoD Friday 30th Sept. |
I'm unsure on why are we going over this again? I thought we already discussed the disadvantages of the initial approach and went against it? |
This tests doesn't run on some MCUs with low RAM. According to @geky: "We may want to omit this test (allocate_failure_test1) for now. It has had other problems such as overflowing stacks, and allocation failure is also tested by allocate_failure_test2."
The inclusion is conditioned by the presence of the events library (`MBED_CONF_EVENTS_PRESENT`). This ensures backward compatibility with SDK builds.
/morph test |
Result: FAILUREYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: null Examples Build failed! |
@bogdanm The issue actually is that the BLE examples currently pull in the event loop as a separate library ( My suggestion is to remove these lines from the testing data here: https://github.com/ARMmbed/mbed-os/blob/master/tools/test/examples/examples.json#L3-L6 That will stop the current BLE examples from being tested. Those examples will then need to be updated to use the next release (probably test em manually), then we'll add them back to the testing data so they get tested on future PRs. |
As mbed-events is being brought into the mbed-os tree, the examples using the external mbed-events library will fail due to duplicate definitions. The tests for BLE examples will be readded after the examples are updated to only use the mbed-events library in the mbed-os tree.
/morph test |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 1015 All builds and test passed! |
Description
mbed event loop implementatio using the mbed-events library. Replaces #2828.
Status
Ready for PR, more documentation to follow.
Related PRs
List related PRs against other branches:
Todos