You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Rodent of Unusual Size <Ke...@Golux.Com> on 1999/01/22 19:47:06 UTC

[APR] Universal return syntax

One of the aspects of the current APR proposal in apr-function.txt
is a strict requirement that *all* APR functions return a
status value (i.e., be declared as returning APRStatus).  This will
mean lots of 'char **' arguments for string-related operations,
such as those already in libap.

I rather expect this to be the source of some discussion.  Anyone
want to open the ball? :-)  I'm personally in favour of everything
returning a status value..
-- 
#ken	P-)}

Ken Coar                    <http://Web.Golux.Com/coar/>
Apache Group member         <http://www.apache.org/>
"Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>

Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Rodent of Unusual Size writes:
>One of the aspects of the current APR proposal in apr-function.txt
>is a strict requirement that *all* APR functions return a
>status value (i.e., be declared as returning APRStatus).  This will
>mean lots of 'char **' arguments for string-related operations,
>such as those already in libap.
>
>I rather expect this to be the source of some discussion.  Anyone
>want to open the ball? :-)  I'm personally in favour of everything
>returning a status value..

I'd prefer that all APR functions return an exceptional value to
denote an error, and that error details be registered with an out of
band mechanism.  This is a slight generalization of the errno model of
unix.  This would give rise to code that looks like so:

In the users of an apr function:

  if( EXCEPTION == (result = apr_foobar(...))){ deal with the fire }

In the APR implementation:
  if( ...trouble...){
     if(apr_note_exception(code, "Bad thing happening")){
       return EXCEPTION;
     }
     ... prepare to tolerate the error...
   }

In Unix, of course, the out of band description is found in errno
I'd like to see a scheme that was a tiny bit richer, i.e. a data
structure.

I'd very much a user installed callback is invoked as soon as possible
when the error is discovered.

   /* Exception handlers are invoked was close as possible to the
    * exception.  They should return true if they were unable to
    * resolve the exception. and false if they want the code that
    * encountered the exception to attempt to continue.
   typedef boolean exception_handler(os_error_value *n, const char *what);

   /* Push and pop are used to bracket dynamic extents that
    * errors are handled in a particular manner. */
   void apr_push_exception_handler(exception_handler *f);
   void apr_pop_exception_handler(exception_handler *f);

   static boolean default_error_handler(void)
   {
      ...
      fprintf(stderr, thread_state->current_exception.description ...);
      ...
      return TRUE;
   }

   boolean apr_note_exception(error_value *ex, const char *description)
   {
      thread_state->current_exception.errno = ex;
      thread_state->current_exception.desription = description);
      if ( thread_state->current_exception_handler ){
	(thread_state->current_exception_handler)();
      } else {
	default_error_handler();
      }
   }

  - ben

Re: [APR] Universal return syntax

Posted by Tony Finch <do...@dotat.at>.
Dean Gaudet <dg...@arctic.org> wrote:
>
>Yeah, it's really unfortunate that setjmp is as it is.  There's a lot less
>expensive ways to get similar functionality.  Really all that's required
>is "unwind the stack", saving registers so they can be restored is a waste
>of time if you're using it for error conditions. 

Not only that, but since setjmp/longjmp have nasty interactions with
what goes on with the locals in the intervening time the fact that the
registers are saved & restored is usually fairly useless.

>There's nothing stopping you from defining your own globals ;)

Apart from thread safety, perhaps.

Tony.
-- 
f.a.n.finch  dot@dotat.at  fanf@demon.net

Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Dean Gaudet writes:
>
>
>On Mon, 1 Feb 1999, Dean Gaudet wrote:
>
>> On Tue, 26 Jan 1999, Ben Hyde wrote:
>> 
>> > I like getting some descriptive text ASAP, close to the error, a lot!
>> 
>> strerror()?
>> 
>> I still see complex error setting as a waste of code, and a waste
>> of stack.
>> 
>> Please give me an example of a unix API function whose errors are not
>> verbose enough.  APR is at its most basic level an abstraction of
>> the unix API.
>
>P.S. I'm also finding it hard to imagine that you'd suggest the error text
>by dynamically allocated... so that limits it to just static messages. 
>That's easily handled by an enumerated type... so I'm really confused why
>you want texts to be available by anything except something like
>strerror().

I think we agree entirely about error protocols as of my email with
the title "APR Error Protocol - take 2".  I wanted to get logging and
error handling in one bite, now I've decided it is better to nibble.
I'll blame my moment of gluttony on your example of logging in the
buff error handler upon timeout.

 - ben

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Mon, 1 Feb 1999, Dean Gaudet wrote:

> On Tue, 26 Jan 1999, Ben Hyde wrote:
> 
> > I like getting some descriptive text ASAP, close to the error, a lot!
> 
> strerror()?
> 
> I still see complex error setting as a waste of code, and a waste
> of stack.
> 
> Please give me an example of a unix API function whose errors are not
> verbose enough.  APR is at its most basic level an abstraction of
> the unix API.

P.S. I'm also finding it hard to imagine that you'd suggest the error text
by dynamically allocated... so that limits it to just static messages. 
That's easily handled by an enumerated type... so I'm really confused why
you want texts to be available by anything except something like
strerror().

Dean



Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.
On Tue, 26 Jan 1999, Ben Hyde wrote:

> I like getting some descriptive text ASAP, close to the error, a lot!

strerror()?

I still see complex error setting as a waste of code, and a waste
of stack.

Please give me an example of a unix API function whose errors are not
verbose enough.  APR is at its most basic level an abstraction of
the unix API.

Dean


Re: [APR] Universal return syntax

Posted by Rodent of Unusual Size <Ke...@Golux.Com>.
Ryan Bloom wrote:
> 
> > I lean toward a structure.
> 
> I don't see a need for a structure.

My mailbox is scrozzled, so I may be missing some messages.

I think it's safe to assume that we should have some sort of
status key that can fit into an architecture-natural size
(such as an int) for performance reasons.

I don't like the idea of a single per-thread status key.

I really don't like the idea of attaching error text to
the key when the key is composed.

I would prefer to have something along the lines of perror(),
which can construct the error text from the key and a
lookup table.  (Needed for I18N, anyway).  Unfortunately,
that doesn't solve the question of error text strings which
contain runtime-variable components.

Taking a step back from the performance concerns, and basically
writing as I think it, perhaps we could do something by
adding three fields to a context structure (this hasn't been
raised on the list yet; shortly..):

    boolean full_status;
    APRstatus status;
    array_header *status_details;

APR routines would figure out what to do based upon this.
They'd always return the value of the status field, but
IFF full_status was true they'd put more information into
the array.  Subsequently an apr_perror() given this structure
could assemble the appropriate result text from feeding the
looked-up value from the table and the values in the array to
sprintf().

If the lookup table of error texts is actually a list of
format strings, status APR_FOO could map to a string such
as "failed to frob %s %d", and APR routines that could return
that status would (if full_status was true) push "widget"
and "42" onto the array.  apr_perror() could later be called
to build the result "failed to from widget 42" from this
information.

Blue-skying from the top of my head; lots of holes, I'm sure.
Conceptual and for external use only. :-)
-- 
#ken    P-)}

Ken Coar                    <http://Web.Golux.Com/coar/>
Apache Group member         <http://www.apache.org/>
"Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>

Re: [APR] Universal return syntax

Posted by Ryan Bloom <rb...@raleigh.ibm.com>.
> >So, here is the thought for how to fix this.  Each thread gets an
> >APRErrStruct when the thread is created.  Ignore how it is attached to the
> >thread, that is another discussion.
> >
> >struct APRErrStruct {
> >	Error Class
> >	Error Code
> >	Descriptive Text
> >}
> >
> >The error class is an enumerated type, that is a small set of possible
> >outcomes, from everything is great, to SIGSEGV impending.
> 
> I lean toward a structure.

I don't see a need for a structure.  This should be a very simple check,
that says what kind of error do I have.  This is the first value to check
on returning from a function.  If the function worked properly, then the
class will be APR_SUCCESS (or something like it), and you can move on.  If
the class is APR_WARNING, then maybe we want to output an error message,
or maybe we don't, depending on the LogLevel.  If the class is
APR_FAILURE, we probably want to output some message.  The the class is
APR_UHOH, then we have a seg fault coming, and lets do some cleanup.  The
whole idea of the cleanup, is to get us a quick and dirty idea for where
we are, so we can make an intelligent decision for what to do next.

> 
> The structure's complexity needs to make a strong case for it's self
> since it's going to tax a lot of code.  Dean's "why more than errno"
> being the strongest instance of that demand.

That's one of the nice things about this.  For places that don't need more
than an success/failuer, our class code gives us that with a minimum
amount of comparisons.  If we actually want to know what happened, we can
look at the error code.

> 
> I like getting some descriptive text ASAP, close to the error, a lot!

We can also pass an Or'ed value down, to determine if we should bother
creating the error text.  For example, for a warning, we can tell APR not
to create the error text, if the Loglevel is just going to ignore it
anyway.  This will take some fleshing out, but it shouldn't be hard to do.

> 
> I don't think I have a strong intuition for what error_class get's
> used for.  The analogy to the parameters of the logging routines is
> strong.  Logging, dispatch during stack unwind?  Let's set that aside
> for the moment.

See above.

The analagy to the Apache loglevel is right on.  This value is there,
because we will ave a very small set of possible values for error class,
so we can check them easily.  We can also use the error classes to
determine if we should generate a message or not.
> 
> >The error code, is an actual error code, to tell the program what is
> >happening.  No more memory, could not open file, etc.  These are specific
> >to the Sub-system.
> >
> >The text, is an actual text string that the sub-system generates.  This
> >has any data that might be useful to diagnosing the problem.
> 
> Yes, I like that.  I remain hopeful we will get alloc core functionality
> down REAL low so this text can alloc from a the thread's global
> heartbeat pool.
> 
> >All functions get passed this structure.
> 
> I rather just put it in the thread state, along with the thread's
> "pid", global pool, and heart beat pool.

I mis-spoke.  I didn't want to deal with how this structure gets passed
around in that message, because we still need to tackle the idea of pools,
or contexts, or thread-local data.  The idea was that each function had
access to write to that structure.

Ryan

_______________________________________________________________________
Ryan Bloom		rbb@raleigh.ibm.com
4205 S Miami Blvd	
RTP, NC 27709		It's a beautiful sight to see good dancers 
			doing simple steps.  It's a painful sight to
			see beginners doing complicated patterns.	


Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Ryan - 

This is a nice proposal moving in, I think, the right direction.

Ryan Bloom writes:
>As one of the writers of the original document, I was hoping for
>acceptance of the always return an APRStatus.  However, you have convinced
>me this is not a great idea, so I have another thought.

Most gracious, thank you.

>One of the problems with the APRStatus as it is currently defined, is that
>any data internal to the APR-Sub-System (File I/O, Network I/O, Threads),
>will not be put into the error message.  For example, "could not open file
>filename" is not as descriptive as "Could not open file filename, out of
>space on device devicename."  devicename can not be filled out by the
>Apache process, but the APR-File I/O subsystem should have access to that
>data.

One of my concerns as well.

>So, here is the thought for how to fix this.  Each thread gets an
>APRErrStruct when the thread is created.  Ignore how it is attached to the
>thread, that is another discussion.
>
>struct APRErrStruct {
>	Error Class
>	Error Code
>	Descriptive Text
>}
>
>The error class is an enumerated type, that is a small set of possible
>outcomes, from everything is great, to SIGSEGV impending.

I lean toward a structure.

The structure's complexity needs to make a strong case for it's self
since it's going to tax a lot of code.  Dean's "why more than errno"
being the strongest instance of that demand.

I like getting some descriptive text ASAP, close to the error, a lot!

I don't think I have a strong intuition for what error_class get's
used for.  The analogy to the parameters of the logging routines is
strong.  Logging, dispatch during stack unwind?  Let's set that aside
for the moment.

>The error code, is an actual error code, to tell the program what is
>happening.  No more memory, could not open file, etc.  These are specific
>to the Sub-system.
>
>The text, is an actual text string that the sub-system generates.  This
>has any data that might be useful to diagnosing the problem.

Yes, I like that.  I remain hopeful we will get alloc core functionality
down REAL low so this text can alloc from a the thread's global
heartbeat pool.

>All functions get passed this structure.

I rather just put it in the thread state, along with the thread's
"pid", global pool, and heart beat pool.

>The only field that must be
>filled out, is the Error Class field.  If everything is fine, the other
>fields are ignored.  With string functions (and others that don't really
>need error codes 99% of the time), this provides a simple check for
>whether or not things were okay, and a basic idea of how severe the
>problem was.

Mapping from OS error codes to APR error codes needs work.

I remain confused by the concept of error class.

  - ben

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Tue, 26 Jan 1999, Ryan Bloom wrote:

> As one of the writers of the original document, I was hoping for
> acceptance of the always return an APRStatus.  However, you have convinced
> me this is not a great idea, so I have another thought.

I would much rather have a simple integer APRStatus than some of the other
proposals floating around.

That is, my first choice is:

- result = f(); /* int errno in thread-local-storage */

    This method does not force every function to have a stack frame.  The
    cost of the second return value is essentially the same as the cost
    of thread-local storage access -- which is something the kernel/libc
    folks have to optimize... and they can optimize it because they
    know the architecture and don't have to worry about portability.

    The simplicity of an integer errno means at no time will any CPU be
    wasted setting up strings and a structure which aren't going to
    be used.

and my second choice is:

- int errno = f(&result);

    This method costs a stack frame for all functions, no matter how
    small, using APR.  But maintains the simplicity of an enumerated
    error type.

In any case I strongly advocate that a single comparison *against zero*
be sufficient to answer the question "did an error occur?"  This is
the most portable fast comparison.  (This isn't true of the current
APRStatus proposal.)

And uh, I'm sorry for dragging this debate out.

Dean


Re: [APR] Universal return syntax

Posted by Ryan Bloom <rb...@raleigh.ibm.com>.
As one of the writers of the original document, I was hoping for
acceptance of the always return an APRStatus.  However, you have convinced
me this is not a great idea, so I have another thought.

One of the problems with the APRStatus as it is currently defined, is that
any data internal to the APR-Sub-System (File I/O, Network I/O, Threads),
will not be put into the error message.  For example, "could not open file
filename" is not as descriptive as "Could not open file filename, out of
space on device devicename."  devicename can not be filled out by the
Apache process, but the APR-File I/O subsystem should have access to that
data.

So, here is the thought for how to fix this.  Each thread gets an
APRErrStruct when the thread is created.  Ignore how it is attached to the
thread, that is another discussion.

struct APRErrStruct {
	Error Class
	Error Code
	Descriptive Text
}

The error class is an enumerated type, that is a small set of possible
outcomes, from everything is great, to SIGSEGV impending.

The error code, is an actual error code, to tell the program what is
happening.  No more memory, could not open file, etc.  These are specific
to the Sub-system.

The text, is an actual text string that the sub-system generates.  This
has any data that might be useful to diagnosing the problem.

All functions get passed this structure.  The only field that must be
filled out, is the Error Class field.  If everything is fine, the other
fields are ignored.  With string functions (and others that don't really
need error codes 99% of the time), this provides a simple check for
whether or not things were okay, and a basic idea of how severe the
problem was.

If the calling program wants more data about the error, it can check the
error code field.  Based on this, it can decided whether or not to log the
error message.  The message logged will be the one generated by the
sub-system.

This allows us to use the return register for ALL functions, and it only
adds one parameter that is consistant across all APR functions.  Because
all APRThreads will have this structure allocated at creation time, the
user doesn't have to think about what to pass in for that function.

This also allows some functions to perform better in all cases.  The
original APRStatus definition required that every time a function was
called, it filled out the whole structure.  This is a huge performance
drain on little errors.  With this structure, the APR function is allowed
to determine how much data it must generate for each error.

Any thoughts?

Ryan

On Tue, 26 Jan 1999, Ben Hyde wrote:

> Dean Gaudet writes:
> >On Mon, 25 Jan 1999, Ben Hyde wrote:
> >
> >> I'd like to see a rich error description object/struct, a lot of
> >> unwind via longjmp upon error, the occational exceptional value 
> >> return, and a hook that let's me get control ASAP on when the
> >> exception is encountered.
> >> 
> >> The current carefully packed error value design that's on the
> >> table doesn't tickle my fancy, but it does move toward the rich
> >> error description struct I yearn for.
> >
> >How exactly is errno not rich enough?  What exactly are you intending to
> >do with this rich information?
> 
> The instance specific info: text for logging, source position info.
> It's important that the set of error codes can be extended by the
> users of the API.  
> 
> Consider multiple_symbol_handler in os/unix/os.c it's calling into
> logging implies that alloc and buffer, and logging are all below it in
> the layering.  Only alloc ought to be below it - and possibly a call
> back into a error hook.
> 
> >People have a hard enough time writing code to properly check error
> >results.  
> 
> And most of it is wrong too. :-).
> 
> >Making them more rich isn't going to improve anything if nobody
> >is taking advantage of it. 
> 
> Parsimony is a virtue.  Logging needs help too.
> 
> >> Handling the error continuation is a performance bear.  Establishing
> >> and invoking longjmp is usually expensive.
> >
> >Yeah, it's really unfortunate that setjmp is as it is.  There's a lot less
> >expensive ways to get similar functionality.  Really all that's required
> >is "unwind the stack", saving registers so they can be restored is a waste
> >of time if you're using it for error conditions. 
> 
> It's neither here nor there but if compiler writers "get it" then
> setjmp/longjmp can be done very efficiently, but they very rarely do.
> I've seen setjmp implementations who's only cost was a little chill on
> the register aliveness and some data space for tables to delimit the
> instruction regions being guarded.
> 
> >> Errno is slime since the I can't extend it easily with my errors and
> >> a single int is a pretty thin handle to  describe an error.  Those are
> >> fixable problems.
> >
> >There's nothing stopping you from defining your own globals ;)
> 
> Yes, maybe in the design of APR.  Just a little richer.
> 
>  - ben
> 

_______________________________________________________________________
Ryan Bloom		rbb@raleigh.ibm.com
4205 S Miami Blvd	
RTP, NC 27709		It's a beautiful sight to see good dancers 
			doing simple steps.  It's a painful sight to
			see beginners doing complicated patterns.	


Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Dean Gaudet writes:
>On Mon, 25 Jan 1999, Ben Hyde wrote:
>
>> I'd like to see a rich error description object/struct, a lot of
>> unwind via longjmp upon error, the occational exceptional value 
>> return, and a hook that let's me get control ASAP on when the
>> exception is encountered.
>> 
>> The current carefully packed error value design that's on the
>> table doesn't tickle my fancy, but it does move toward the rich
>> error description struct I yearn for.
>
>How exactly is errno not rich enough?  What exactly are you intending to
>do with this rich information?

The instance specific info: text for logging, source position info.
It's important that the set of error codes can be extended by the
users of the API.  

Consider multiple_symbol_handler in os/unix/os.c it's calling into
logging implies that alloc and buffer, and logging are all below it in
the layering.  Only alloc ought to be below it - and possibly a call
back into a error hook.

>People have a hard enough time writing code to properly check error
>results.  

And most of it is wrong too. :-).

>Making them more rich isn't going to improve anything if nobody
>is taking advantage of it. 

Parsimony is a virtue.  Logging needs help too.

>> Handling the error continuation is a performance bear.  Establishing
>> and invoking longjmp is usually expensive.
>
>Yeah, it's really unfortunate that setjmp is as it is.  There's a lot less
>expensive ways to get similar functionality.  Really all that's required
>is "unwind the stack", saving registers so they can be restored is a waste
>of time if you're using it for error conditions. 

It's neither here nor there but if compiler writers "get it" then
setjmp/longjmp can be done very efficiently, but they very rarely do.
I've seen setjmp implementations who's only cost was a little chill on
the register aliveness and some data space for tables to delimit the
instruction regions being guarded.

>> Errno is slime since the I can't extend it easily with my errors and
>> a single int is a pretty thin handle to  describe an error.  Those are
>> fixable problems.
>
>There's nothing stopping you from defining your own globals ;)

Yes, maybe in the design of APR.  Just a little richer.

 - ben

Re: [APR] Universal return syntax

Posted by Bill Stoddard <st...@raleigh.ibm.com>.
Ben Hyde wrote:
> 
> Bill Stoddard writes:
> >Eeeek! Maybe I missed the discussion... WHY does NSPR implement threads
> >as fibers? Is it because many OS's don't have decent kernel thread
> >implementations?
> 
> People I trust have told me that an NT thread is a very heavy weight
> object, with a substantial memory hit for each one.  So if you write
> applications with many many threads, say Java programs, you want to
> avoid using them.  The existence of fibers in the NT API would seem
> to suggest that somebody at Microsoft wanted something lighter weight
> badly enough to force the OS guys to implement them.
> 
> The only thing I see threads giving us that fibers don't is compiler
> support for thread local storage.

Hummm, call me a skeptic, but I seriously doubt that an NT thread is so
heavy weight that it would become an issue in web server design. An NT
web server with async I/O and completion ports should be able to support
thousands of concurrent clients quite efficiently with its kernel thread
implementation. 

-- 
Bill Stoddard
stoddard@raleigh.ibm.com

Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Bill Stoddard writes:
>Eeeek! Maybe I missed the discussion... WHY does NSPR implement threads
>as fibers? Is it because many OS's don't have decent kernel thread
>implementations?

People I trust have told me that an NT thread is a very heavy weight
object, with a substantial memory hit for each one.  So if you write
applications with many many threads, say Java programs, you want to
avoid using them.  The existence of fibers in the NT API would seem
to suggest that somebody at Microsoft wanted something lighter weight
badly enough to force the OS guys to implement them.

The only thing I see threads giving us that fibers don't is compiler
support for thread local storage.

  - ben

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Mon, 1 Feb 1999, Bill Stoddard wrote:

> Eeeek! Maybe I missed the discussion... WHY does NSPR implement threads
> as fibers? Is it because many OS's don't have decent kernel thread
> implementations?

The NT-specific port of NSPR uses NT fibers to implement "NSPR threads"... 
and it uses completion ports.  Both for speed. 

NSPR threads themselves are co-operatively multitasked.  They have a
pthread port which multiplexes userland threads on top of pthreads... the
hybrid model similar to NT's fibers.  But this isn't the only choice, you
can go straight pthreads if you want, or straight userland threads.

Dean


Re: [APR] Universal return syntax

Posted by Bill Stoddard <st...@raleigh.ibm.com>.
Dean Gaudet wrote:
> 
> On Mon, 1 Feb 1999, Ben Hyde wrote:
> 
> > Dean Gaudet writes:
> > >> I'm coming up to speed on threads and am ignorant in this area.
> > >> Are you saying that each thread has its own copy of errno?
> > >
> > >Yes.
> >
> > Argh.  I suspect that each fiber does not have a private copy.  - ben
> 
> Didn't someone respond on this issue already?
> 
> NSPR threads have thread local data -- and they're implemented using
> fibers.  So there's a way to do it.

Eeeek! Maybe I missed the discussion... WHY does NSPR implement threads
as fibers? Is it because many OS's don't have decent kernel thread
implementations?

-- 
Bill Stoddard
stoddard@raleigh.ibm.com

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.
On Mon, 1 Feb 1999, Ben Hyde wrote:

> Dean Gaudet writes:
> >> I'm coming up to speed on threads and am ignorant in this area.
> >> Are you saying that each thread has its own copy of errno?
> >
> >Yes.
> 
> Argh.  I suspect that each fiber does not have a private copy.  - ben

Didn't someone respond on this issue already? 

NSPR threads have thread local data -- and they're implemented using
fibers.  So there's a way to do it.

Dean



Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Dean Gaudet writes:
>> I'm coming up to speed on threads and am ignorant in this area.
>> Are you saying that each thread has its own copy of errno?
>
>Yes.

Argh.  I suspect that each fiber does not have a private copy.  - ben

Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Mark - I'm pretty sure I'm agreeing with you below.

Marc Slemko writes:
>On Tue, 26 Jan 1999, Ben Hyde wrote:
>
>> Getting the errno value back on the stack ASAP.
>> 
>> People tend to skip this.  So you get bugs by doing:
>> 
>>     if ( EXCEPTIONAL_VALUE == (result = function(a,b,c))){
>>       report_trouble(... errno ...);
>>       return MY_EXCEPTIONAL_VALUE;
>>     }
>> 
>> Which is just wrong pure and simple.  Once you get
>
>That only holds if your function is speced to return an errno, 

Are you talking about "function" or "report_trouble"?
function: yes.
report_trouble: no.

Report_trouble would have to be even more tightly speced as
never using any sub functions that error.  I'm repeating my self
(but that's common in the musical theater): errno is a second
return value and it is ONLY alive for a very short time.  At other
times it's just an unused register full of noise.

    saved_errno = errno;
    ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, NULL,
                "Opening config file %s (%s)",
                name, (file == NULL) ? strerror(errno) : "successful");
    errno = saved_errno;

> and if the
>errno your code gets makes any sense at all in the larger context.  Often,
>it really doesn't make sense.

Absolutely.

The key point is that the function has to be speced to have an error
return AND what exceptional return value signals that it is alive.
That's the error protocol.  

Be not tempted  to have yet another error protocol that looks so:
  result = function(a,b,c);
  if ( errno != 0 ){ deal with trouble }
It is really error prone.  You always know you've got
confusion at hand when you see:
  errno =  0;

>If you are using hidden things like errno, then you have to be very 
>careful to know what does and doesn't set errno, and always ensure it is
>set properly if it should be set and only check it after a call if it
>should be set.

Yes, you have to spec routines: saying they use the error protocol
and indicating what their exceptional value is.  All other routines
are just "self confident."

Errno is not hidden, it is a second return register.

>The current code doesn't always do that.  

>For example, there are a bunch
>of places in the buff stuff that check if the buff has already been
>marked invalid and, if so, return without setting an errno.

There are an assortment of problems around Buff and it's very
concise spec that make it kind-a hard to use correctly!

Meanwhile, it is a common "design pattern" to have a I/O channel with
operations that never return errors with the two footnotes that if the
channel does breakdown these operations will be effectively a no-op
and the user may want to check the channel status to avoid wasting a
mess of time talking to a ghost.  Buff clearly likes that design
pattern.

 - ben

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Tue, 26 Jan 1999, Ben Hyde wrote:

> The alternate coding style that looks like:
>      error_code = f(&result, ...);
> reduces the chance of this error, yes.  It is a coding
> convention for safety, just like the one above.  It's
> problem is it's neither traditional nor fast.

result = f(&error_code, ...)

where there's the ability to indicate a yes/no "error occured" in result
is faster... but, alas, still requires a stack frame. 

Dean


Re: [APR] Universal return syntax

Posted by Marc Slemko <ma...@worldgate.com>.
On Tue, 26 Jan 1999, Ben Hyde wrote:

> Getting the errno value back on the stack ASAP.
> 
> People tend to skip this.  So you get bugs by doing:
> 
>     if ( EXCEPTIONAL_VALUE == (result = function(a,b,c))){
>       report_trouble(... errno ...);
>       return MY_EXCEPTIONAL_VALUE;
>     }
> 
> Which is just wrong pure and simple.  Once you get

That only holds if your function is speced to return an errno, and if the
errno your code gets makes any sense at all in the larger context.  Often,
it really doesn't make sense.

If you are using hidden things like errno, then you have to be very 
careful to know what does and doesn't set errno, and always ensure it is
set properly if it should be set and only check it after a call if it
should be set.

The current code doesn't always do that.  For example, there are a bunch
of places in the buff stuff that check if the buff has already been
marked invalid and, if so, return without setting an errno.  Which
does (in real life) lead to infinite loops.  Sometime I really need
to find a way to test that fix then commit it...


Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Errno style error handling has a number of pit falls that
require coding conventions to avoid.  It would be bad,
dangerous to pretend these don't exist.

As if you could write:

    (result, error_code) = function(a,b,c)
    if( error_code != NO_ERROR ){
     ...manage trouble...
    }

In the standard C technique a purest might write:

    if ( EXCEPTIONAL_VALUE == (result = function(a,b,c))){
      int error_code = errno;
      report_trouble(... error_code ...);
      errno = error_code;
      return MY_EXCEPTIONAL_VALUE;
    }

Getting the errno value back on the stack ASAP.

People tend to skip this.  So you get bugs by doing:

    if ( EXCEPTIONAL_VALUE == (result = function(a,b,c))){
      report_trouble(... errno ...);
      return MY_EXCEPTIONAL_VALUE;
    }

Which is just wrong pure and simple.  Once you get
this pattern down then you know to fire up your paranoia
every time you see the
    if ( EXCEPTIONAL_VALUE == (result = function(a,b,c))){
       a...

in the code.  You have to grab the errno ASAP since it's
very volatile.  It REALLY is a second return value.

The alternate coding style that looks like:
     error_code = f(&result, ...);
reduces the chance of this error, yes.  It is a coding
convention for safety, just like the one above.  It's
problem is it's neither traditional nor fast.

 - ben

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Tue, 26 Jan 1999, Rodent of Unusual Size wrote:

> Dean Gaudet wrote:
> > 
> > On Mon, 25 Jan 1999, Rodent of Unusual Size wrote:
> > 
> > > them into return values; this frees errno for use by any
> > > other uses in the call stack
> > 
> > That's false of course.  errno is tainted by any libc call.
> > APR presumably will be using some of libc.
> 
> I dispute the claim that it's false.  Consider routine A calling
> routine B.  Routine B does something that sets errno, detects it,
> and returns -1.  errno is now fair game, and the value may be
> lost and no-one will know why B failed.  If B returned the error,
> even if it just copied errno as its return value, errno's volatility
> would be irrelevant.

That's not what your claim said though.  We're agreeing with each other.

> > > or parallel threads without losing
> > > the condition within the current call stack.
> > 
> > errno has no multithread problems, not sure if you're implying
> > it does or not.
> 
> I'm coming up to speed on threads and am ignorant in this area.
> Are you saying that each thread has its own copy of errno?

Yes.

Dean

> I thought it was a single global and hence susceptible to parallel
> processing stomping on it.
> -- 
> #ken    P-)}
> 
> Ken Coar                    <http://Web.Golux.Com/coar/>
> Apache Group member         <http://www.apache.org/>
> "Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>
> 


Re: [APR] Universal return syntax

Posted by Rodent of Unusual Size <Ke...@Golux.Com>.
Dean Gaudet wrote:
> 
> On Mon, 25 Jan 1999, Rodent of Unusual Size wrote:
> 
> > them into return values; this frees errno for use by any
> > other uses in the call stack
> 
> That's false of course.  errno is tainted by any libc call.
> APR presumably will be using some of libc.

I dispute the claim that it's false.  Consider routine A calling
routine B.  Routine B does something that sets errno, detects it,
and returns -1.  errno is now fair game, and the value may be
lost and no-one will know why B failed.  If B returned the error,
even if it just copied errno as its return value, errno's volatility
would be irrelevant.

> > or parallel threads without losing
> > the condition within the current call stack.
> 
> errno has no multithread problems, not sure if you're implying
> it does or not.

I'm coming up to speed on threads and am ignorant in this area.
Are you saying that each thread has its own copy of errno?
I thought it was a single global and hence susceptible to parallel
processing stomping on it.
-- 
#ken    P-)}

Ken Coar                    <http://Web.Golux.Com/coar/>
Apache Group member         <http://www.apache.org/>
"Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.
On Mon, 25 Jan 1999, Rodent of Unusual Size wrote:

> them into return values; this frees errno for use by any
> other uses in the call stack

That's false of course.  errno is tainted by any libc call.
APR presumably will be using some of libc.

> or parallel threads without losing
> the condition within the current call stack.

errno has no multithread problems, not sure if you're implying it does or
not.

Dean


Re: [APR] Universal return syntax

Posted by Rodent of Unusual Size <Ke...@Golux.Com>.
Ben Hyde wrote:
> 
> As a Lisp programmer at heart I can hardly argue that popularity
> of an approach has ever colored much of my decision making, but
> in this case I'd like to hear a little "ode to joy" about why
> #4 makes for prettier, saver, or more fun code.  Somebody?

It's modular; each caller can determine whether to ignore,
return, or handle conditions from things it calls, and it's clear
that the status applies only within the current call stack.  No
globals are being tainted with droppings to spoil later stews.

Separating this from the 'should every function return it'
argument, a well-chosen syntax provides good performance (fits
into a register) and high flexibility.  The lowest level can
play the games of picking up exceptions from errno and turning
them into return values; this frees errno for use by any
other uses in the call stack or parallel threads without losing
the condition within the current call stack.

Of course, remember that I admire the incredibly modular
and flexible return/signal model VMS provides.. :-)
-- 
#ken    P-)}

Ken Coar                    <http://Web.Golux.Com/coar/>
Apache Group member         <http://www.apache.org/>
"Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.
On Mon, 25 Jan 1999, Ben Hyde wrote:

> I'd like to see a rich error description object/struct, a lot of
> unwind via longjmp upon error, the occational exceptional value 
> return, and a hook that let's me get control ASAP on when the
> exception is encountered.
> 
> The current carefully packed error value design that's on the
> table doesn't tickle my fancy, but it does move toward the rich
> error description struct I yearn for.

How exactly is errno not rich enough?  What exactly are you intending to
do with this rich information?

People have a hard enough time writing code to properly check error
results.  Making them more rich isn't going to improve anything if nobody
is taking advantage of it. 

> Handling the error continuation is a performance bear.  Establishing
> and invoking longjmp is usually expensive.

Yeah, it's really unfortunate that setjmp is as it is.  There's a lot less
expensive ways to get similar functionality.  Really all that's required
is "unwind the stack", saving registers so they can be restored is a waste
of time if you're using it for error conditions. 

> Errno is slime since the I can't extend it easily with my errors and
> a single int is a pretty thin handle to  describe an error.  Those are
> fixable problems.

There's nothing stopping you from defining your own globals ;)

Dean



Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
I'd like to see a rich error description object/struct, a lot of
unwind via longjmp upon error, the occational exceptional value 
return, and a hook that let's me get control ASAP on when the
exception is encountered.

The current carefully packed error value design that's on the
table doesn't tickle my fancy, but it does move toward the rich
error description struct I yearn for.

Manoj Kasichainula writes:
>It won't be consistent with how other functions return their error
>codes. 

There are four common techniques used for the error continuation 
in C code.
 1. log and die - very very popular
 2. exceptional return plus out of band (aka -1 with errno) - very popular
 3. longjmp - widely used but only when there is an interpreter nearby
 4. use return value for error code - rarely used.

The current proposal is #4.

As a Lisp programmer at heart I can hardly argue that popularity
of an approach has ever colored much of my decision making, but
in this case I'd like to hear a little "ode to joy" about why
#4 makes for prettier, saver, or more fun code.  Somebody?

I know that #1 is popular because the Unix tool model tends to
encourage error handling at the script level of things.

I know that #2 is popular because:
 a) It is very fast in the typical non-error case.
 b) It lets you unwind the stack without touching the
    error value.

I know it's unpopular because:
 c) people don't bother to check the exceptional return value.
 d) some turkeys set errno on non-exceptional return values.
 e) old errno settings haunt running program and frighten 
    people in the halls.

>> So instead we waste a very useful register (the return register), force
>> the compiler to allocate stack space, spill locals onto and off of the
>> stack around function calls ... all for functions that just don't fail?
>
>We have to pick the right balance between flexibility and
>implementation freedom against performance. What kind of performance
>loss would we get?

Handling the error continuation is a performance bear.  Establishing
and invoking longjmp is usually expensive.  Expecting every API
function to catch two return continuations (the usual and the error
one) is more expensive.  I've never built a system that didn't, in end -
use a little of both.  Some routines throw an exceptional
continuation, others return an exceptional value.  

I usually spec. two standards for how those will get done.  If you
expect the caller of the API function to recover quickly from the
exception return an exceptional value.  Parsers of raw user input for
example.  If the exception is rare then throw it out and don't tax
your callers.

>... But, I really do think that
>most of the functions will need error returns anyway, and the last
>thing I think we want is to create anything that resembles errno.

Yes/No.
I absolutely agree that designing for the error case leaves all
other design approaches in the dust.

Errno: Snobol really is a hoot since it has a error clause on every
statement.  C design, with it's single return value, makes is a pain
to find anyplace easy to put the exceptional return signal.  The
ancestors settled in on fouling the return type of every function's
signature with an exceptional value (sometimes -1, sometimes NULL).
Of course they really wanted to return a second value to the caller
with a description of the error, and hence errno is really just a
second return value.  Since it's used rarely, and it's atomic, you can
put it in a global.  In the end - it's just not that bad a design, it
just requires a little sympathy.

Errno is slime since the I can't extend it easily with my errors and
a single int is a pretty thin handle to  describe an error.  Those are
fixable problems.

>Manoj Kasichainula - manojk at io dot com - http://www.io.com/~manojk/
>"You can get more with a kind word and a 2x4 then just a kind word."

Personally I like to carry those sharpened 4x4 stakes that Buffy uses on TV.

 - ben


Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Sun, 24 Jan 1999, Manoj Kasichainula wrote:

> On Fri, Jan 22, 1999 at 03:00:31PM -0800, Dean Gaudet wrote:
> > On Fri, 22 Jan 1999, Manoj Kasichainula wrote:
> > 
> > > 1. Consistency
> > 
> > char * is just as consistent. 
> 
> It won't be consistent with how other functions return their error
> codes. 

If all the string functions return "char *", it's consistent.  string
functions and i/o functions are different in my opinion. 

> At first thought, I wouldn't think close() needed a return
> value.

Yup, you're not alone -- most people forget to check close()s return
value.

> But it does. Who knows whether we'll need a return value for
> strdup() at some point? 

strdup is a poor example I suppose.  I can come up with any number of
string functions for which there is no conceivable error condition. string
functions are operators for the most part.  If there's a future need for a
return value it's probably because you're extending or changing the
definition of the operator -- and you should be changing the name at that
point.

> > > It's also useful as an alternative to putting asserts in the code,
> > > and we all know how much we love asserts.
> > 
> > So instead we waste a very useful register (the return register), force
> > the compiler to allocate stack space, spill locals onto and off of the
> > stack around function calls ... all for functions that just don't fail?
> 
> We have to pick the right balance between flexibility and
> implementation freedom against performance. What kind of performance
> loss would we get?

Try it, pick a function from apache which uses a lot of string functions. 
Then rewrite all those string functions in the way you think APR should
work.  Compile.  Look at the code.  Time the code.  There's no
substitution for trying it out... I can blow just as much hot air as the
next person :)

> most of the functions will need error returns anyway, and the last
> thing I think we want is to create anything that resembles errno.

I agree errno has its problems.  But I don't think it's the end of the
world either. 

Hey, if we're passing around a "pool *" all over the place, maybe we want
an ap_perrno(p).  I'm half serious.  In many cases the error can be
associated with some other object -- such as a file descriptor.  In that
case it's sufficient to return something which indicates an error
happenned, and provide another function which retrieves the actual error
code. 

Finally:  I take anything which says "like VMS" with a big grain of salt. 
VMS had some cool things, sure.  But that's not in itself a convincing
point. 

What exactly is wrong with unix-style result codes?  NSPR was written that
way, there's no programmatic reason that it can't work. 

Dean


Re: [APR] Universal return syntax

Posted by Manoj Kasichainula <ma...@io.com>.
On Fri, Jan 22, 1999 at 03:00:31PM -0800, Dean Gaudet wrote:
> On Fri, 22 Jan 1999, Manoj Kasichainula wrote:
> 
> > 1. Consistency
> 
> char * is just as consistent. 

It won't be consistent with how other functions return their error
codes. 

> > 2. It would be nice to be able to report unexpected errors to the
> > user, such as out-of-memory errors, and unexpected APR or system bugs.
> 
> There are no unexpected errors of strdup except for out of memory.  The
> same is true of many string functions.

Well, if we have bounded pools, then we'll have two different
out-of-memory conditions. But the point is that unexpected things
happen. At first thought, I wouldn't think close() needed a return
value. But it does. Who knows whether we'll need a return value for
strdup() at some point? 

> > It's also useful as an alternative to putting asserts in the code,
> > and we all know how much we love asserts.
> 
> So instead we waste a very useful register (the return register), force
> the compiler to allocate stack space, spill locals onto and off of the
> stack around function calls ... all for functions that just don't fail?

We have to pick the right balance between flexibility and
implementation freedom against performance. What kind of performance
loss would we get?

Of course, if we're not committed to making the APR API stable and
100% consistent (which is a perfectly legitimate decision to make; we
are working on a web server here, the PR is secondary), then we can
just eliminate the inconvenient cases. But, I really do think that
most of the functions will need error returns anyway, and the last
thing I think we want is to create anything that resembles errno.

-- 
Manoj Kasichainula - manojk at io dot com - http://www.io.com/~manojk/
"You can get more with a kind word and a 2x4 then just a kind word."
  -- Marcus, B5

Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.

On Fri, 22 Jan 1999, Manoj Kasichainula wrote:

> 1. Consistency

char * is just as consistent. 

> 2. It would be nice to be able to report unexpected errors to the
> user, such as out-of-memory errors, and unexpected APR or system bugs.

There are no unexpected errors of strdup except for out of memory.  The
same is true of many string functions.

> It's also useful as an alternative to putting asserts in the code,
> and we all know how much we love asserts.

So instead we waste a very useful register (the return register), force
the compiler to allocate stack space, spill locals onto and off of the
stack around function calls ... all for functions that just don't fail?

I suppose I'd have to see the list of functions this is being proposed
for.  I just don't buy into the pass-by-reference mindset. 

Dean


Re: [APR] Universal return syntax

Posted by Manoj Kasichainula <ma...@io.com>.
On Fri, Jan 22, 1999 at 12:09:45PM -0800, Dean Gaudet wrote:
> I don't see the point, most of the string operations have no failure code
> to diagnose.

1. Consistency

2. It would be nice to be able to report unexpected errors to the
user, such as out-of-memory errors, and unexpected APR or system bugs.
It's also useful as an alternative to putting asserts in the code,
and we all know how much we love asserts.

-- 
Manoj Kasichainula - manojk at io dot com - http://www.io.com/~manojk/
"Tandems are good if you need hardware which sucks reliably, 24x365."
  -- Malcolm Ray.

Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Dean Gaudet writes:
>On Fri, 22 Jan 1999, Ben Hyde wrote:
>
>> Dean Gaudet writes:
>> >I don't see the point, most of the string operations have no failure code
>> >to diagnose.
>> 
>> Routines that never have exceptions ought not be charged the tax of
>> the in-line exception hand waving we must pay now that we have
>> forsworn longjmp, thread destruction, and all the other fun
>> exuberant operations.
>
>I could live with longjmp based exception handling if it's general
>enough. ...

Oh happy day.

I have along standing fear of longjmp since it has been so buggy over
the years.  That fear and some things we had discussed a year ago
about Mozilla's coding conventions had mutated in my mind to the
belief that we had decided to forswear longjmp entirely.  What the
Mozilla conventions actually say is that you can't use C++ exceptions
<http://www.mozilla.org/docs/tplist/catBuild/portable-cpp.html#dont_use_exceptions>

So - way to go.  I'd be very happy to attempt to adopt an exception
handling framework.  I've written a mess of C code under that
style and it's a delight.  The only down side is that setjmp is
usually a disgustingly expensive operations, but at least it's
all in user space.

3rd party libraries will have to do glue to at their interfaces
no matter what error model is adopted.

>Essentially something like this:
>
>    switch (ap_push_exception_handler(p)) {
>    case REGISTERED:
>	break;
>    case OUT_OF_MEMORY:
>	whatever...
>    }
>    ...
>    ap_pop_exception_handler(p);


Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.
On Fri, 22 Jan 1999, Ben Hyde wrote:

> Dean Gaudet writes:
> >I don't see the point, most of the string operations have no failure code
> >to diagnose.
> 
> Routines that never have exceptions ought not be charged the tax of
> the in-line exception hand waving we must pay now that we have
> forsworn longjmp, thread destruction, and all the other fun
> exuberant operations.

I could live with longjmp based exception handling if it's general enough.
The user can screw themselves in 3rd party libraries if they want --
3rd party libraries aren't going to raise apache exceptions unless they
call back into user code.  I just don't want asynchronous cancellation
or signalling.

Essentially something like this:

    switch (ap_push_exception_handler(p)) {
    case REGISTERED:
	break;
    case OUT_OF_MEMORY:
	whatever...
    }
    ...
    ap_pop_exception_handler(p);

The push is just a wrapper around setjmp().  The user has to make sure
they pop before returning.

Dean


Re: [APR] Universal return syntax

Posted by Ben Hyde <bh...@pobox.com>.
Dean Gaudet writes:
>I don't see the point, most of the string operations have no failure code
>to diagnose.

Routines that never have exceptions ought not be charged the tax of
the in-line exception hand waving we must pay now that we have
forsworn longjmp, thread destruction, and all the other fun
exuberant operations.

You have to default to the worse case more often than you'd like.
There is always that other platform that can has an error in this
operation.

API design is too hard and too slow, let's write it in Perl or SNOBOL!

 - ben

Re: [APR] Universal return syntax

Posted by Alexei Kosut <ak...@leland.Stanford.EDU>.
On Fri, 22 Jan 1999, Rodent of Unusual Size wrote:

> One of the aspects of the current APR proposal in apr-function.txt
> is a strict requirement that *all* APR functions return a
> status value (i.e., be declared as returning APRStatus).  This will
> mean lots of 'char **' arguments for string-related operations,
> such as those already in libap.
> 
> I rather expect this to be the source of some discussion.  Anyone
> want to open the ball? :-)  I'm personally in favour of everything
> returning a status value..

Well, it's a nice idea, although sometimes it's nice to have a return
value that's useful at the moment. And you'd always have to check the
return value, which is a pain. So I propose we switch to C++ and use
exceptions ;)

Or Java.

Heck, let's just rewrite the whole server in Lisp.

Ada.

Fortran.

BASIC.

INTERCAL.

-- Alexei Kosut <ak...@stanford.edu> <http://www.stanford.edu/~akosut/>
   Stanford University, Class of 2001 * Apache <http://www.apache.org> *



Re: [APR] Universal return syntax

Posted by Dean Gaudet <dg...@arctic.org>.
I don't see the point, most of the string operations have no failure code
to diagnose.

Dean

On Fri, 22 Jan 1999, Rodent of Unusual Size wrote:

> One of the aspects of the current APR proposal in apr-function.txt
> is a strict requirement that *all* APR functions return a
> status value (i.e., be declared as returning APRStatus).  This will
> mean lots of 'char **' arguments for string-related operations,
> such as those already in libap.
> 
> I rather expect this to be the source of some discussion.  Anyone
> want to open the ball? :-)  I'm personally in favour of everything
> returning a status value..
> -- 
> #ken	P-)}
> 
> Ken Coar                    <http://Web.Golux.Com/coar/>
> Apache Group member         <http://www.apache.org/>
> "Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>
>