Re: Quickly exiting from nested calls
- From: Spiros Bousbouras <spibou@xxxxxxxxx>
- Date: Wed, 03 Oct 2007 16:57:05 -0000
On Sep 29, 8:05 pm, Eric Sosman <esos...@xxxxxxxxxxxxxxxxxxxx> wrote:
Spiros Bousbouras wrote:
Assume you have a library which contains the functions
foo1, ... , foon which the outside world knows about and
may call and the functions bar1, ... , barm which the outside
world doesn't know about. The library code does not call
anywhere the foo functions but any of the foo or bar functions
may call any bar function.
So let's say that a bar function (or it could be one of the foo
functions) detects an error serious enough that whatever foo
function was originally called cannot perform its task so the
only thing that can be done is to return with as little fuss as
possible to the outside world and report somehow the error.
How do you do that ?
The best solution I could think of goes as follows:
For every foo function you have a corresponding realfoo
function which takes the same list of arguments and has
the same return type as foo. The library code also contains
a global variable of type jmp_buf , let's call it env , and a
global variable mylib_errno of a type which is appropriate
for error reporting , int would probably do. The outside world
may or may not know about mylib_errno depending on whether
you want to report errors through the return values of the foo
functions or through mylib_errno.
So for some i with 1<= i <= n, fooi corresponding to realfooi would
look like this:
/* Same return type as realfooi */ fooi( /* List of arguments */ ) {
if ( setjmp(env) == 0 ) {
return realfooi( /* Same list of arguments fooi
was called with */ ) ;
/* If realfooi returns void then the return in the statement above
would be omitted.
*/
} else {
/* The bar function which detected the error will have put inside
mylib_errno an appropriate value and then called longjmp(env,1)
If errors get reported to the outside world through mylib_errno
then here we return with some random value if fooi has return
type other than void or we don't do anything if fooi returns void.
If errors do not get reported to the outside world through
mylib_errno then we return with some value appropriate for the
error.
*/
}
}
Comments ? Other ideas ?
2) Bailing out with longjmp() requires a strict discipline
in implementing the realfoo() and bar() function families. They
must be written in such a way that they never need to perform
any kind of cleanup -- like calling fclose() or free() -- after
calling a more deeply-nested realfoo() or bar(). I have never
seen a compiler or tool that's able to enforce such a discipline,
so you'll need to rely on nothing but vigilance.
C always requires discipline and vigilance , no ?
3) If the bar() function knows enough about the foo() that
called it to make a unilateral decision that the foo() is doomed,
it seems to me there's something wrong with the architecture of
the library.
Assume that bar1 which doesn't call any other functions
in the library opens a stream , reads bytes and puts them
in a buffer. bar2 breaks the content of the buffer into
tokens and foo parses the sequence of tokens. bar2 and
foo may allocate buffers but they reuse them every time
the library is called so they don't need to free them. If
bar1 encounters a reading error then we are in the situation
I describe. Do you see anything wrong with such an
architecture ?
Anyhow you're not offering any alternative suggestions.
On Sep 29, 8:18 pm, Mark McIntyre <markmcint...@xxxxxxxxxxx> wrote:
Modify the interfaces so that an error status can be returned by each
function and the result can be cascaded back up the call chain.
With such a solution each call would look something like
this:
i = bar( /*...*/ ) ;
if ( i == ERROR ) {
/* Return an error and perhaps also do cleanup */
}
Consider the example I gave to Eric Sosman above. Only
bar1 directly deals with streams and only bar1 may encounter
a reading error but with your suggestion the code of the
other functions would have to be cluttered with checking
for a reading error returned from bar1. It makes the whole
thing less orderly and modular.
If you can't mod the interface, then provided you don't care about
re-entrancy, how about a global status variable?
Who would set and who would check the value of the status
variable ?
.
- Follow-Ups:
- Re: Quickly exiting from nested calls
- From: Eric Sosman
- Re: Quickly exiting from nested calls
- Prev by Date: Re: malloc under linux
- Next by Date: Re: malloc under linux
- Previous by thread: malloc under linux
- Next by thread: Re: Quickly exiting from nested calls
- Index(es):
Relevant Pages
|
|