Design note recorded from the #147 item 3 (SYNAD) work — deliberately NOT part of that fix, which keeps the API unchanged.
Once the SYNAD fix lands, an uncorrectable I/O error sets _FILE_FLAG_ERROR + errno=EIO and the stream keeps accepting write attempts: each subsequent __fputc()/__fflush() drives the same error path again, non-fatally, and fails again. That is the minimal-change behaviour and it is safe — but it is not what C callers expect, and it burns an I/O round trip per doomed write.
The idea to evaluate:
- Fail fast:
__fputc()/__fputs()/__fwrite() (and the read side: __fgetc()/__fread()) return EOF/0 immediately when _FILE_FLAG_ERROR is set, without touching the DCB again. C-standard-ish semantics: a stream in error state stays failed until explicitly cleared.
clearerr(FILE *): does not exist in libc370 today (feof()/ferror() are macros over fp->flags). Fail-fast without a way to clear the flag would make the state terminal; the two belong together. Also worth checking: rewind() traditionally clears the error indicator too.
Caveats to think through before building it:
_FILE_FLAG_ERROR is also set by older paths (e.g. __reopen() failure) — auditing every setter comes first, so fail-fast does not turn a previously recoverable state into a dead stream.
- Consumers: ftpd/httpd/ufsd log through these streams; a fail-fast stream that silently drops log lines after one transient error may be worse operationally than retrying. That trade-off is the real decision, and it belongs to this issue, not to the SYNAD fix.
Refs: #147 (item 3), #145.
Design note recorded from the #147 item 3 (SYNAD) work — deliberately NOT part of that fix, which keeps the API unchanged.
Once the SYNAD fix lands, an uncorrectable I/O error sets
_FILE_FLAG_ERROR+errno=EIOand the stream keeps accepting write attempts: each subsequent__fputc()/__fflush()drives the same error path again, non-fatally, and fails again. That is the minimal-change behaviour and it is safe — but it is not what C callers expect, and it burns an I/O round trip per doomed write.The idea to evaluate:
__fputc()/__fputs()/__fwrite()(and the read side:__fgetc()/__fread()) return EOF/0 immediately when_FILE_FLAG_ERRORis set, without touching the DCB again. C-standard-ish semantics: a stream in error state stays failed until explicitly cleared.clearerr(FILE *): does not exist in libc370 today (feof()/ferror()are macros overfp->flags). Fail-fast without a way to clear the flag would make the state terminal; the two belong together. Also worth checking:rewind()traditionally clears the error indicator too.Caveats to think through before building it:
_FILE_FLAG_ERRORis also set by older paths (e.g.__reopen()failure) — auditing every setter comes first, so fail-fast does not turn a previously recoverable state into a dead stream.Refs: #147 (item 3), #145.