473,385 Members | 1,641 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Quickly exiting from nested calls

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 ?

Sep 29 '07 #1
4 1228
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 ?
1) The globals env and mylib_errno make me uncomfortable.

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.

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.

--
Eric Sosman
es*****@ieee-dot-org.invalid
Sep 29 '07 #2
On Sat, 29 Sep 2007 07:45:06 -0700, in comp.lang.c , Spiros Bousbouras
<sp****@gmail.comwrote:

<snip description of library which needs to gracefully handle internal
errors>
>How do you do that ?
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.

If you can't mod the interface, then provided you don't care about
re-entrancy, how about a global status variable?

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Sep 29 '07 #3
On Sep 30, 3:45 am, Spiros Bousbouras <spi...@gmail.comwrote:
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 ,
Yikes! In my code I simply return a value from foo() that
indicates there was an error in bar(). For debugging
purposes I have all functions write a descriptive
message to a log file when they encounter an error.

Oct 7 '07 #4
On Oct 11, 6:40 pm, Eric Sosman <Eric.Sos...@sun.comwrote:
Spiros Bousbouras wrote On 10/11/07 12:47,:
As for your example of bar1(), bar2(), and foo(),
I find it unconvincing. If I've understood your outline
correctly, foo() calls bar1() to open the stream, read
the entire thing into memory, and close the stream;
Not the entire thing ; bar1() reads bytes as needed. For
example a higher level function will decide it needs n
additional bytes from the stream to make a decision in its
parsing so it will tell bar1() "put n extra bytes into the
buffer". Also old bytes which do not influence the parsing
anymore get discarded so the buffer bar1 allocates may be
much smaller than the possible size of streams read.

I'm afraid I'm still missing something. Who closes the
input stream in the event of an error? foo? No, because
if bar1 or bar2 calls longjmp, foo will never get the chance.
bar1? No, because if foo or bar2 calls longjmp, bar1 will
never get the chance. bar2? No, same pattern. That's
why I assumed foo1 would do all the I/O in one gulp, so
it could close the stream before punting.
In the specific example I provided which you're not quoting
only bar1() may encounter a fatal error. In other situations
it may be that my method for error handling is not convenient;
as I've said I'm not claiming it's for every case.
There's an alternative: You could triplicate the cleanup
code in all three functions, so any of them could clean up
for itself and for the other two before punting. But that
would be really bad design, with no "it seems to me."
Or you could close the stream in the code which you call with
longjmp depending on the kind of error that occured.

Oct 13 '07 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Hal Vaughan | last post by:
I have a class that is sometimes called from the command line and sometimes from another class. When the user clicks "Quit" on the panel it opens, if it is running from the command line, it...
6
by: Andy Baker | last post by:
Hi there, I'm learning Python at the moment and trying to grok the thinking behind it's scoping and nesting rules. I was googling for nested functions and found this Guido quote:...
6
by: A | last post by:
Hi, How do you make use of nested functions in C++? I realize in C++ that everything must be declared first in a header file before implementation in a .cpp file. I tried to nest a method...
39
by: vineoff | last post by:
If I'm having nested loops like: for (...) for (..) for (...) { /* exit here */ } and I need to exit from there ^ . Is it better to use exceptions or goto or some other method?
2
by: Quinnie | last post by:
Hi, I have a homework assignment that I'm so confused and really need help with. Here's the description, any help would be appreciated. Thanks! Assume we have a statically-scoped language...
22
by: L. Westmeier | last post by:
Is there a way to have to exiting point in a void function? I don't want to exit the program but just this function. Any answers appreciated. L. Westmeier
5
by: Tim Werth | last post by:
I have a .NET console application that is kicked off by a .NET Windows service. They communicate via .NET Remoting, although there isn't much communication between the two while the console app is...
4
by: =?Utf-8?B?SmFtZXMgR2V1cnRz?= | last post by:
On my page, I have one repeater that contains a literal control and a nested repeater. The nested repeater contains a literal control. Both repeaters are databound with only one object (string). ...
8
by: Nathan Sokalski | last post by:
I have several nested For loops, as follows: For a As Integer = 0 To 255 For b As Integer = 0 To 255 For c As Integer = 0 To 255 If <Boolean ExpressionThen <My CodeElse Exit For Next If Not...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.