On 2021-09-15 3:16 a.m., Axel Dörfler wrote:
> Not having a consistent API is not a good idea, but if you notice
that this new way is actually better than before, it would still make
sense to move into this direction, and aiming for consistency in the
future, again, kit by kit.
Exceptions or status_t error codes could both use a rich layered error
message system, in an almost orthogonal way. You'd still have the error
codes (keeping consistency with the current API) or exceptions
happening, but on the side (rather than being returned directly) there
would be a layered rich error explanation. The best way to do that is
to add the rich error messages to per-thread storage.
So I had a look at thread local storage (TLS) in Haiku. It seems to set
aside per-thread space for an array of 64 pointer sized values, which
you can get to by specifying an index number. Digging under the hood,
on x86 processors TLS seems to be wherever segment register FS points,
which is initialized from thread->user_local_storage, which is taken
from the thread's stack after the user stack space, which is in a
per-thread memory area. The first few of the 64 slots are used for
system things (see
https://git.haiku-os.org/haiku/tree/headers/private/system/tls.h), like
pointers to the thread structure, and there's even a TLS_ERRNO_SLOT one
for Posix errno handling! We just have to add one for the rich error
structure and initialize it in arch_thread_init_tls() or rely on the
default zero value (only system TLS slots are zeroed - would it be
convenient to have the user ones zeroed too?). Alternatively, we can
stuff it into the kernel Thread structure (there's one per thread, which
is what we need).
Then whenever you wanted to add an error explanation to the stack of
text, you'd call a function that appends a string to the TLS storage,
such as BRichErrorAppend(const char *message). There would be a
BRichErrorClear() to reset the message (called only by lowest level
functions, possibly then appending strerror_r(code) to get a string for
classic error codes). And a const char *BRichErrorGet() to return the
stack of errors as a string.
The first hack implementation is to use a BString as the object, and
just prepend messages with a linefeed between them (so the highest level
error message is first). Though if the Haiku C++ runtime isn't
available (could happen), the second hack is to do it with malloc and
low level string copying operations. A stack of more structured objects
could be used, perhaps with separate fields for error codes for each
level, but it would be simpler to just use a string and have tabs to
separate fields (error code in ASCII, message text) and linefeeds to
separate records. Deallocate it in thread_exit(). Though it could be
useful to let it linger a bit in the thread_death_entry structure and
let people retrieve the error messages after the thread ends, like they
can do with status codes.
- Alex