-
Notifications
You must be signed in to change notification settings - Fork 2k
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
tests: add test for priority inversion using muxes #7444
tests: add test for priority inversion using muxes #7444
Conversation
323f38d
to
88fdcf8
Compare
See also #7372 |
oh damn, completely overlooked that one... |
Both look very similar to me, which is not a surprise considering the issue at hand. Thus, no |
I added some more output (e.g. numbering the events to verify the order in which they occur). But you are right, first come first serve should be the way to go. So let's merge #7372 and I can add the improved output once merged. |
#7372 is merged now, please rebase and adapt as needed |
@@ -0,0 +1,9 @@ | |||
APPLICATION = mutex_priority_inversion |
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.
remove this line
#include "mutex.h" | ||
#include "xtimer.h" | ||
|
||
#define TICK_LEN (50 * US_PER_MS) |
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.
50UL
#define TICK_LEN (50 * US_PER_MS) | ||
#define EXSPECTED_RESULT (4) | ||
|
||
static mutex_t res_mtx; |
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.
static mutex_t res_mtx = MUTEX_INIT;
and remove dynamic initialization in main()?
#include "xtimer.h" | ||
|
||
#define TICK_LEN (50 * US_PER_MS) | ||
#define EXSPECTED_RESULT (4) |
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.
here and below: EXSPECTED -> EXPECTED
@haukepetersen any chance you'll adapt to #7372 and address comments to get this merged for 2018.01 release? Otherwise, please postpone to 2018.04. |
88fdcf8
to
0b08816
Compare
sorry for the long silence. Merged the previous test application for this matter with my approach. I see the following enhancements:
|
I'm unsure if the (re)naming makes sense, i.e., |
I also tended to this, but we can/should construct a second test that demonstrates the same behavior using So how about |
sounds semantically more right 😉 |
alright, will do. |
0b08816
to
ed12c91
Compare
renamed the test to IMHO this PR should be good to go, so please have one last good look :-) |
wait, something went wrong when rebasing, need to re-introduce the test script... |
Ok, will have a look when it's rebased |
0658194
to
2f03d68
Compare
done. |
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 two code convention comments should be addressed, the others don't need to be (although I think a thread timing diagram would be nice)
static kernel_pid_t _pid_high; | ||
|
||
static int _result = 0; | ||
static int _res_addsub = 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.
This could be local to event(), although for a test it doesn't really matter
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.
could be done, be so far we don't really use local static variables in RIOT - though I can't recall the reasons. Poking the Internet I found quotes like
Local statics may look useful, however they cause major problems when trying to port code to a multi-task/multi-threading environment, and should generally be avoided where possible.
Although this might no apply to this particular situation, IMHO it does not hurt either to have those variables in the compilation unit scope. On top I think declaring them like this makes it much easier to see the actual memory consumption of the module.
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.
Ok cool. Thanks for the info.
Event 7: t_high - unlocking mutex | ||
|
||
*** result: SUCCESS *** | ||
``` |
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.
A thread diagram could be useful, either here or in the code. Perhaps with some times along the x axis
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.
could be, but don't have the time to draw one...
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 mind: this is a test and not some user-friendly example application. So once verified that it actually tests for the intended behavior its not like people dig into this app on a daily basis.
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.
Ok sure.
{ | ||
/* record event */ | ||
_result += (_res_addsub * num); | ||
_res_addsub *= -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.
Just wondering - why this approach, rather than e.g. raising a flag _success = true
or something if the high priority thread finishes? That would be more readable IMO - unless there's something I'm missing re optimization or something like that?
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.
because this approach can actually detect if all threads were run in the correct order (at least to a large extend)
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.
Ok I see - IMO even with an order there might be a more readable way, e.g. keeping an i++ counter and comparing it with each event number or something. But that's your style/choice and it's not critical here anyway
Priority inversion is a known problem in real-time systems, leading in certain | ||
constellations to lower priority threads indirectly blocking higher priority | ||
threads. This test application constructs a simple situation, where exactly this | ||
occurs: t_low owns a mutex, which t_high is waiting on. Now t_mid gets all 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.
Instead of "Now t_mid gets all the CPU time" I suggest starting this sentence with "At that point, t_mid starts and pre-empts t_low"
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.
fixed
event(7, "t_high", "unlocking mutex"); | ||
mutex_unlock(&_res_mtx); | ||
|
||
return NULL; |
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.
indentation
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.
fixed
delay(2); | ||
|
||
event(4, "t_mid", "starting infinite loop, potentially starving others"); | ||
while(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.
while (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.
fixed
Re the premise/design/etc of the PR, all seems good |
2f03d68
to
7367676
Compare
addressed comments and rebased. |
unlocking the mutex shared with t_high. So t_mid is indirectly preventing t_high | ||
from running. | ||
occurs: t_low owns a mutex, which t_high is waiting on. At that point, t_mid | ||
starts and pre-emts t_low (as t_mid has a higher priority than t_low), |
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.
sorry, should be pre-empts. Last comment
After that, if you address Murdock and Travis complaints and squash (and rebase if necessary) then I'll merge it. |
fixed and squashed. |
7367676
to
0a3180b
Compare
0a3180b
to
75af392
Compare
fixed and squashed board blacklisting due to changed names of nucleo boards. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
Is this still relevant after #17040 or can we close it? |
next time please state reason for closing (even if it seems obvious to you). |
As pointed out in #7365, we do not have any protection against priority inversion in the default kernel.
As a starter, here is a simple test application, that showcases a constructed case of priority inversion. I use this test down the line to test my implementation of priority inheritance, but I think this test deserves to be merged stand-alone so we have something to keep reminding us of this issue...