-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add a simple re-entrancy lock for tu_printf. #2653
base: master
Are you sure you want to change the base?
Conversation
int tu_printf_r(const char *format, ...) | ||
{ | ||
// Simple re-entrancy lock, not safe for multi-core MCU | ||
static volatile bool lock = false; |
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.
Even on a single core, volatile
is not sufficient to prevent inconsistencies due to ISR execution interrupting another instance executing from user space. This needs an actual critical section, or similar.
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 you make a real example with disassembly ?
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 problem is with this sequence:
if (lock) {
return -1;
}
// <--- ISR COMES HERE
lock = true;
To make that work on uniprocessor with interrupt, then interrupt must be disabled between the test and the setting to true:
something like:
disable_interrupts();
if (lock) {
return -1;
}
lock = true;
enable_interrupts()
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.
And this is of course wrong, more like:
bool is_locked;
disable_interrupts();
is_locked = lock;
if (!is_locked)
lock = true;
enable_interrupts()
if (is_locked)
return (-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.
Hi,
The problem is with this sequence:
if (lock) {
return -1;
}
// <--- ISR COMES HERE
lock = true;
When ISR happened here, vprintf
hasn't been executed, so ISR will execute vprintf
in it's context then return to normal context. There is no case where the execution of vprintf
is interrupted.
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.
Actually you're right, sorry. need more coffee.
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.
But: what protect your IRQ from interrupting another vprintf() call, outside tinyusb?
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.
BTW: I'm using a stm32h747 with tinyusb, and I would love to see your DWC2 DMA patch going in, which is why I was lurking....
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.
But: what protect your IRQ from interrupting another vprintf() call, outside tinyusb?
Good question, currently TU_LOG_*
are available for user space logging.
BTW: I'm using a stm32h747 with tinyusb, and I would love to see your DWC2 DMA patch going in
We are few maintaining the repo, if you don't want to wait you can try the testing branch.
Thanks @HiFiPhile, though I think printf lock should be done in user space by implementing (nano)libc lock in _write_r(). Since not all retarget needs lock e.g. segger rtt |
The problem is libc's |
I may miss a thing though: the newlib reentrant implementation seems to the the exact same thing as this. For logging within ISR, we only do log in isr with level 3, which I used mainly with segger RTT. I will revise the code to see if there is any log1/log2 in the isr. PS: oh, I see you mean the global _REENT is also used by other libc like malloc() and not only printf(). For this, how about moving this guard into the _write(), I still think it should be done at user level. |
Eh... I think reentrant is kind of implementation dependent, I just read IAR's manual:
|
Describe the PR
Add a simple re-entrancy lock for TU_LOG, should resolve #2652 in most cases. An interlocked version is needed for multicore MCU.