-
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
sys/stdio: Precision on semantics, and fixes #20364
base: master
Are you sure you want to change the base?
Conversation
Checking the existing implementations:
|
Should we maybe add a warning to the docs, until the stdio implementations have been confirmed to adhere to the specification? |
Rebased to address conflicts (now that the base #19738 has been merged).
I think that's adequately covered by the "should" all over the place. <grumpy reason="no lunch yet">If we started placing warnings on all RIOT APIs where there are implementations that subtly misbehave, we'll have very red documentation with very little gained, I'd rather spend the time fixing impls.</grumpy> |
sys/stdio/stdio.c
Outdated
@@ -61,6 +68,21 @@ void stdio_close(void) { | |||
#define MAYBE_WEAK __attribute__((weak)) | |||
#endif | |||
|
|||
ssize_t stdio_write_all(const void* buffer, size_t len) |
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.
ssize_t stdio_write_all(const void* buffer, size_t len) | |
int stdio_write_all(const void* buffer, size_t len) |
To me, ssize_t
sends a lot of "this will return len
on success vibes.
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.
Thanks for the vibe check, it's spot on, fixed.
Thanks @maribu for the vibe check See-Also: RIOT-OS#20364 (comment)
break; | ||
} | ||
cursor += written; | ||
} |
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.
Didn't we say that we don't want to do this because with some backends, this would block forever if stdio is written from ISR?
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.
In an ISR situation, a backend will (or should) only do one of two things: return an error, or return the full length. Either terminates the loop.
while (len > 0) { | ||
ssize_t written = stdio_write(buffer, len); | ||
if (written < 0) { | ||
return written; | ||
break; | ||
} | ||
buffer += written; | ||
len -= written; | ||
} |
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 are already doing this in stdio_write()
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 when using the dispatch backend, because it can't practically return incomplete writes. Other backends may still return incomplete writes, and all the callers that were switched to stdio_write_all in this PR previously didn't do this loop manually.
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.
Then what do you still need stdio_write()
for?
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 allows applications to decide to slow things down if prints get chunked up too much, or decide to print less.
There is the alternative to make our stdio_write always behave like stdio_write_all, and block all the way through. That would be simpler, just less POSIXy, and I've clung (past tense) to the idea that at some point there'd have been a good reason to do things that way.
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.
No application will ever call stdio_write(), this hooks into libc.
@@ -25,6 +25,7 @@ | |||
#include <string.h> | |||
#include <unistd.h> | |||
|
|||
#include "stdio_base.h" |
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 this PR is a bit odd. If this was solved by calling There are either stdio implementations that will always write everything (e.g. To me this would be preferable to introducing weird edge cases that might lead to a hang. |
The reason the simple loop does work is that stdio_write has never been allowed to return 0 -- at latest when a driver would want to return 0, it'd need to block, and would have needed to block without this PR just as well. |
I stand corrected: It was allowed to return 0 from the API description, but that case was never actionable. (Like, what is the caller supposed to do?). Not being allowed to return 0 (except when stdiout was closed) is just what one would expect the API to do coming from a POSIX mindset. |
I see two ways towards an API that can be used:
As it is now, we're having callers to stdout writing all over the place that ignore error conditions, and may arbitrarily lose data. |
stdio in RIOT is just a debug tool. It should be reasonably reliable, but still kept as simple as possible. I don't think we need anything on top of that to prevent 'data loss'. |
It's not just debug output -- that's what the debug.h is. stdio is also what every single new user comes across when trying out RIOT the first time (as used in the shell), likely part of their first programs, and part of the data extraction of every RIOT based publication I've been involved with so far (with weird bugs showing up there because awk scripts processing the data tripped over gaps). Having an interface there that changes its behavior depending on the backends, has no clear guidance on how to use it, and is not used consistently throughout the code base, does not make a good first impression, and causes pain down the road as well. |
Any chance to move this forward for the upcoming release? |
In the current form, this PR will cause regressions when stdio is used from ISR. |
Contribution description
stdio_write has been used inconsistently with respect to whether or not incomplete writes were returned.
This
It does not yet attempt to verify that all stdio implementations behave as desired.
Testing procedure
Most of this is documentation updates and API usage correctness where I wouldn't know how to produce any different behavior. I'd leave it at that and set "CI: run tests" unless reviewers insist (and maybe have concrete suggestions).
Issues/PRs references
This came out of discussions around #19738, and builds on it.
There was earlier discussion on matrix.