Jonathan S. Shapiro | 8 Jul 2007 06:03

IDL issue

An issue has come up in defining the C binding for CapIDL, and I would
like input. The issue is not specific to capabilities.

Any IDL method returns two results: a result (error) code, and a return
value. [There may also be additional OUT parameters, but for my question
we can ignore those.]

The question is: should the C stub return the error code or the return
value?

Concrete example:

  idl:   float f(int arg);
  C:     float f(int arg, IDL_Env *_env);  [return result value]
  C:     result_T f(int arg, float *_retVal, IDL_Env *_env);
         [returns error code]

When the result value is returned, the error code is generally stored
into a dedicated slot within the IDL_Env structure.

In my opinion, returning the error code is better for two reasons:

  1. It leads to more consistent error checking:

       CHECKRESULT(f(arg, &retVal, &idlEnv));
       // where CHECKRESULT is a macro that may cause exceptional
       // control flow, and any code below this point can assume
       // the operation succeeded.

  2. It avoids an initialization problem. Consider the "return result
(Continue reading)

Espen Skoglund | 9 Jul 2007 14:28
Picon
Favicon

Re: IDL issue

[Jonathan S Shapiro]
> The question is: should the C stub return the error code or the
> return value?

> Concrete example:

>   idl:   float f(int arg);
>   C:     float f(int arg, IDL_Env *_env);  [return result value]
>   C:     result_T f(int arg, float *_retVal, IDL_Env *_env);
>          [returns error code]

> When the result value is returned, the error code is generally
> stored into a dedicated slot within the IDL_Env structure.

> In my opinion, returning the error code is better for two reasons:

>   1. It leads to more consistent error checking:
>   2. It avoids an initialization problem.

> Reactions/opinions?

I agree with you.  Returning the error code is more consistent.  Also
it prevents programmers to write code like:

    if (f(arg, &idlEnv) == foo) {}

which does not take the error code into account.  They would have to
write something like, e.g., the following instead:

    if (f(arg, &retVal, &idlEnv) == OK && retVal == foo) {}
(Continue reading)

Neal H. Walfield | 9 Jul 2007 18:10

Re: IDL issue

At Sun, 08 Jul 2007 00:03:10 -0400,
Jonathan S. Shapiro wrote:
>   1. It leads to more consistent error checking:
> 
>        CHECKRESULT(f(arg, &retVal, &idlEnv));
>        // where CHECKRESULT is a macro that may cause exceptional
>        // control flow, and any code below this point can assume
>        // the operation succeeded.
> 
>   2. It avoids an initialization problem. Consider the "return result
>      type" idiom when an exceptional code is returned:
> 
>        float retVal = f(arg, &idlEnv);
>        CHECKRESULT(idlEnv);

I have a preference for the former, however, that may just be
familiarity with the construct.

> For all of these reasons (and some others), Microsoft's DCOM design has
> all interface methods returning an HRESULT, which is basically the error
> code. This may be a matter of convention.

This is similar to the direction POSIX interface has taken in recent
years.  New functions tend to return error codes and not overload
return values.  For instance, ftell, an old function, returns the
position of the passed steam.  If the position is -1, then a failure
occurred.  pthread_create, on the other hand, returns an error code
and the object in an argument.  This approach also has the advantage
that it simplifies code when pthread_t is a struct.

(Continue reading)

Jonathan S. Shapiro | 9 Jul 2007 21:03

Re: IDL issue

On Mon, 2007-07-09 at 18:10 +0200, Neal H. Walfield wrote:
> At Sun, 08 Jul 2007 00:03:10 -0400,
> Jonathan S. Shapiro wrote:
> > I am honestly not sure what to do here, and I would appreciate input.
> > The bottom line, I think, is that *any* failure to check results is
> > potentially fatal in this type of code no matter which way the IDL is
> > generated. Either idiom can be maintained by a careful programmer.
> 
> An interesting counterexample may be that of POSIX file streams.
> Instead of checking after every read or write for an error, the
> programmer may just check if an error occurred at the end of a
> sequence of operations using ferror.  This can greatly simplify the
> code.

Yes. However, note that this trick "works" only because UNIX system
calls have always returned scalars, and all of those scalars have tended
to take the form of mostly-ignorable "status output". I understand why
it seems to work (notably exception of terminal I/O where read/write
lengths really need to be checked), but it doesn't seem to generalize.

--

-- 
Jonathan S. Shapiro, Ph.D.
Managing Director
The EROS Group, LLC
Tom Bachmann | 9 Jul 2007 21:11
Picon

Re: IDL issue


Espen Skoglund wrote:
> The one
> argument I can think of in favour of returning the result value is a
> performance related one.  The architecture calling conventions [...]

These stubs are supposed to be inline anyway, I guess. This wouldn't
matter then.
--
-ness-
Jonathan S. Shapiro | 9 Jul 2007 21:14

Re: IDL issue - struct return vs. cap return

On Mon, 2007-07-09 at 18:10 +0200, Neal H. Walfield wrote:
> At Sun, 08 Jul 2007 00:03:10 -0400,
> Jonathan S. Shapiro wrote:
> 
> > If we choose to adopt the "return the return value" convention, it is
> > still necessary to handle capability returns specially in C, because the
> > caller must say where the incoming capability is to be stored (we cannot
> > get compiler help for this from an unmodified compiler).
> 
> How is this different from returning a struct?  There is a general
> rule of thumb not to return large structs from function calls.
> Instead, the convention is for either the function allocates memory or
> the caller to pass a pointer to a block of allocated memory.

The convention you describe is actually unnecessary, because good
compilers already implement it automatically. If you write something of
the form:

   s = f(...);

where s is some structure type larger than (typically) 2 words, most
calling conventions will automatically rewrite it as:

   f(..., &s);

Many, but not all compilers, will automatically suppress this rewrite
for small, registerizable structs. The convention you describe is mainly
relevant for legacy compilers these days.

But to answer your question:
(Continue reading)

Jonathan S. Shapiro | 9 Jul 2007 21:18

Re: IDL issue

On Mon, 2007-07-09 at 21:11 +0200, Tom Bachmann wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Espen Skoglund wrote:
> > The one
> > argument I can think of in favour of returning the result value is a
> > performance related one.  The architecture calling conventions [...]
> 
> These stubs are supposed to be inline anyway, I guess. This wouldn't
> matter then.

That seems likely to me as well. Note, however, that inlining stubs is
not obviously an optimization...
--

-- 
Jonathan S. Shapiro, Ph.D.
Managing Director
The EROS Group, LLC
Jonathan S. Shapiro | 9 Jul 2007 21:49

Re: IDL issue

On Mon, 2007-07-09 at 14:28 +0200, Espen Skoglund wrote:
> I agree with you.  Returning the error code is more consistent...

I think that this outcome is interesting. So far, we have Shapiro
(Coyotos), Skoglund (L4), Landau (CapROS), Adams (Coyotos), Walfield
(Hurd, L4), and everybody else I have talked to about this agreeing that
returning the error code is the preferred outcome.

Given this, it is interesting (and perhaps unfortunate) that the various
L4 IDL compilers do not agree with us. :-)

> This might eliminate some problems due to sloppy programming.  The one
> argument I can think of in favour of returning the result value is a
> performance related one.  The architecture calling conventions...

Yes, but as Tom Bachmann pointed out, this is not an issue when stubs
are inlined. Inlining stubs seems to be a universal assumption, though
it is probably not an optimization to do this on most architectures.
--

-- 
Jonathan S. Shapiro, Ph.D.
Managing Director
The EROS Group, LLC
Neal H. Walfield | 9 Jul 2007 23:24

Re: IDL issue - struct return vs. cap return

At Mon, 09 Jul 2007 15:14:25 -0400,
Jonathan S. Shapiro wrote:
> 
> On Mon, 2007-07-09 at 18:10 +0200, Neal H. Walfield wrote:
> > At Sun, 08 Jul 2007 00:03:10 -0400,
> > Jonathan S. Shapiro wrote:
> > 
> > > If we choose to adopt the "return the return value" convention, it is
> > > still necessary to handle capability returns specially in C, because the
> > > caller must say where the incoming capability is to be stored (we cannot
> > > get compiler help for this from an unmodified compiler).
> > 
> > How is this different from returning a struct?  There is a general
> > rule of thumb not to return large structs from function calls.
> > Instead, the convention is for either the function allocates memory or
> > the caller to pass a pointer to a block of allocated memory.
> 
> The convention you describe is actually unnecessary, because good
> compilers already implement it automatically. If you write something of
> the form:
> 
>    s = f(...);
> 
> where s is some structure type larger than (typically) 2 words, most
> calling conventions will automatically rewrite it as:
> 
>    f(..., &s);

Are you sure?  This change changes the semantics of the return.  gcc,
for instance, does not do this.  Consider:
(Continue reading)

Neal H. Walfield | 9 Jul 2007 23:42

Re: returning errors

At Mon, 09 Jul 2007 15:49:14 -0400,
Jonathan S. Shapiro wrote:
> 
> On Mon, 2007-07-09 at 14:28 +0200, Espen Skoglund wrote:
> > I agree with you.  Returning the error code is more consistent...
> 
> I think that this outcome is interesting. So far, we have Shapiro
> (Coyotos), Skoglund (L4), Landau (CapROS), Adams (Coyotos), Walfield
> (Hurd, L4), and everybody else I have talked to about this agreeing that
> returning the error code is the preferred outcome.
> 
> Given this, it is interesting (and perhaps unfortunate) that the various
> L4 IDL compilers do not agree with us. :-)

Right, with idl4 and dice (I don't know about magpie), if you want to
know if transmission was successful, you need to check the
environment.  mig always returns an error code.  This variable can be
reused by the object methods to return their own errors--they just
have to be careful to not use the values that the IPC subsystem uses.

At least on the systems that I have worked with, it is rare to call an
IPC stub directly; it is almost always wrapped by a library stub that
at least massages the interface a bit and protects the caller from
having to set up the environment.  This code is usally written by
people in the know.  So, my question is: is this really an issue?

Neal

Gmane