[haiku-development] Re: Error Handling (was: Re: Plan for NetServices Kit (v2))

  • From: "Alexander G. M. Smith" <agmsmith@xxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Fri, 3 Sep 2021 17:35:43 -0400

On 2021-09-03 4:23 p.m., Adrien Destugues wrote:
> 3 septembre 2021 22:07 "Alexander G. M. Smith" <agmsmith@xxxxxx> a écrit:
>> On 2021-09-03 3:47 p.m., Alexander G. M. Smith wrote:
>>> If you want to turn exceptions inside-out, make the error object a
>> stack. Each level that wishes to can add a string explaining why it
>> failed. So you can drill down to see what happened.
>>
>> On further thought, using a second area of memory to store the stack
>> isn't that complex.  It's always being written to, not edited, so you
>> can sequentially write the strings, error codes and debug info into
>> memory.  Don't even bother indexing it, just linearly search through it
>> to find a particular entry.  There shouldn't be too many, well, except
>> in a recursive crash (change it into a queue when it gets too big and
>> forget the deeper entries?).
>>
>> If it needs to be multitasking safe, use fixed size memory blocks and a
>> free list and a semaphore.  Link in another block when you need more
>> space to append the data.  Linearly searching through the error stack
>> now requires a jump once in a while, but overall speed is still O(n*n)
>> to find a particular stack entry.  Not great, but good enough.
>
> Nothing is impossible, but that is a lot of effort and complexity to
> essentially do "exceptions without actually using exceptions".

It's partly like exceptions, but with user readable strings only at interesting levels of callback.  Though now that you mention it, you could do the same with exceptions, if you had a stack-of-strings exception object and remembered to append an error message string to it at each level of interest.

That would be exceptions with a strict discipline on using them.

So, how are exceptions actually implemented?  Google time...

https://www.codeproject.com/Articles/2126/How-a-C-compiler-implements-exception-handling

Each function call has an exception record inside its stack frame, specifying a handler subroutine (created by the compiler for each function), some sizes and a next pointer.  An OS pointer at FS:[0] (one per thread) is used to add the record to the list of exception handlers in the function prologue.  There's also data about catch blocks used by the function, stored somewhere else just once and set up by the compiler.  And an id number that identifies which try block is active (updated as the function runs, by code inserted by the compiler).  There are also id numbers that identify which variables are active.

On an exception, the list of exception records is tested starting at FS:[0] until one of the handlers says it wants to handle that kind of exception (catch is based on the data type of the exception object).  Then the stack needs to be unwound, by calling all the handlers before the one which can do the exception, telling each one to unwind its particular stack (calling destructors mostly, for variables that are in scope, however it knows that - there's a whole other section about that topic).  Then the exception object is copied to the frame of the function that's catching the exception. Then it can run the user catch code, then clean up the exception object and stack, and maybe throw an exception again.

Nah, I think my stack of strings is simpler. :-)

But however you do it, I'd like a way of getting multiple levels of readable error messages to the user.  I expect they would initially just see the top one and can drill down to see the details.  A single error code isn't enough.  A single readable string is better (one which includes related values - such as which database record was being processed).  But multiple levels of failure explanation is best.

- Alex


Other related posts: