-
Notifications
You must be signed in to change notification settings - Fork 3k
Use EventFlags instead of Semaphores #4580
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
Conversation
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.
Looking good, yay for reducing a semaphore object : )
features/netsocket/TCPSocket.cpp
Outdated
|
||
if (count < 1) { | ||
// Semaphore wait timed out so break out and return | ||
if (0 == (flag & WRITE_FLAG)) { |
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.
One of the surprising annoyances of the new osEventFlags API, is that wait actually returns error codes on timeout:
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__flags__error__codes.html
These conditions should probably be something like:
if ((flag & WRITE_FLAG) != WRITE_FLAG) {
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.
@geky: Both conditions are logically same. I prefer comparison with zero over fix values. Any specific reason for other condition?
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.
_event_flag.wait returns 0xFFFFFFFEU on timeout, not zero (I don't really get why but it is what it is):
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__flags__error__codes.html
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.
They set the most significant bit to 1 (osFlagsError
) to mark error. To check for any error it's enough to check ret | osFlagsError
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.
Ah good to know, that works too 👍
features/netsocket/TCPSocket.cpp
Outdated
@@ -18,8 +18,11 @@ | |||
#include "Timer.h" | |||
#include "mbed_assert.h" | |||
|
|||
#define READ_FLAG 0x1u | |||
#define WRITE_FLAG (0x1u << 1) |
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.
Can we have a final value here? It makes debugging way easier when you can actually grep the code to find what the value is. Also `<< 1`` doesn't help with readability here.
rtos/EventFlags.h
Outdated
|
||
/** Set the specified Event Flags. | ||
@param flags specifies the flags that shall be set. | ||
@return event flags after setting or error code if highest bit set. |
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.
Worth mentioning a osFlagsError
for all the return values, that's a macro with highest bit set, so people know they can use it rather than defining their own.
rtos/EventFlags.h
Outdated
@param timeout timeout value or 0 in case of no time-out. | ||
@return event flags before clearing or error code if highest bit set. | ||
*/ | ||
uint32_t wait (uint32_t flags, uint32_t options=osFlagsWaitAny, uint32_t timeout=0); |
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.
I'm not sure about that, it's a very thin wrapper on RTX, it caused us some grief with RTX update (as we are not supposed to break the APIs). I would say we could abstract it out a bit, wait could be for any flags if flag
is 0 and for specified flag in other cases. If we do that we can ignore the options parameter (and the remaining 'don't clear' option or add clear
parameter defaulting to true.
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.
@bulislaw : User can have multiple flags say 5, and can select any two bits in flag option to wait for any "one" of them to be set in case of "osFlagsWaitAny" If we set flag to "0", we cannot know wait for which specific set of bits.
This option will change the behavior of RTX API's.
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.
I think following is reasonable:
#define flag1 0x1
#define flag2 0x2
/*[...]*/
flag.wait(flag1) /* Waits only for the flag1 */
flag.wait(flag2) /* Waits only for the flag2 to be set */
res = flag.wait(0) /* Waits for anything to be set */
if (res | flag1 || res | flag2) { \*...*/ }
but we could also introduce wait_any
or something similar to only interrupt the wait if any one of the flags finish. I think this form of API is easier and more user friendly.
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.
Sounds good. But what should be the option for "osFlagsWaitAll" flag? Wait for flag1 and flag2 both
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.
wait(flag1 | flag2)
should translate to wait with osFlagsWaitAll
and wait(0)
to wait for 0x8FFFFFF
flag (msb set to one is an error so it's not allowed) with osFlagsWaitAny
.
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.
Only case I don't see getting covered here is: I need to wait for any 1 or 3
#define flag3 0x4
flag.wait(flag1 | flag3) - Will wait for 1 and 3
flag.wait(0) - Will wait for all three (2 is not required in my case)
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.
Also, forgot timeout: It should be wait(flag, timeout)
. Correct ?
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.
Yes I skipped the timeout for brevity as it has default 0. I think case s you mentioned can be handled by either:
res = flag.wait(0) /* Waits for anything to be set */
if (res | flag1 || res | flag3) { \*...*/ }
or the wait in a loop for that mater. Second option would be to add wait_any
member. I think adding second member function is cleaner. Also worth mentioning in docs that flags are 1bit long.
@bulislaw does this most recent commit address your comments? |
@theotherjimmy : Most recent comment by @bulislaw is related to event flag Class. |
EventFlag Class wasn't updated, I would say that because of 'no API breakage policy' new public classes shouldn't be introduced lightly, there should be wider discussion about them. I don't think the new class is ready. |
OK now I am confused, so #4517 is adding it , still under review, this is on top of it but doing also changes to the class itself :-) It would be easier to have only that class addition as it is in 4517 and doing edits there (having write access or take over that PR and send a new one ?) ? |
Ah i missed that! I'll have a look at #4517 |
c75f3c5
to
b2315b2
Compare
@bulislaw - I have rebased the code and using updated API's. Please review |
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.
@geky can you review as well.
features/netsocket/TCPSocket.cpp
Outdated
_write_sem.release(); | ||
_read_sem.release(); | ||
|
||
_event_flag.set(WRITE_FLAG); |
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.
Why not to set it in one go? WRITE_FLAG | READ_FLAG
?
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.
Done
EventFlags class is a wrapper for Event Flag functionality introduced in RTOS2/RTX5.
b2315b2
to
beb5aac
Compare
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.
LGTM
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.
Looks good to me 👍
/morph test-nightly |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
OutputAll builds and test passed! |
Description
Synchronization in sockets required binary semaphores which is not available
in RTX5, hence switching to event flags.
Issue #4575
Migrations
PR should be merged after PR #4517. EventFlags Class implementation is picked up from this PR.
Related PRs
PR #4517
PR #4560
Todos