Re: IDL issue - struct return vs. cap return

"Neal H. Walfield" <[email protected]>
Newsgroups gmane.os.hurd.l4
Message-ID <87644tz2x4.wl%[email protected]>
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:

  #include <string.h>
  #include <stdio.h>
  
  struct foo
  {
    char *p;
    char s[100000];
  };
  
  struct foo bar (void)
  {
    struct foo foo;
    foo.p = foo.s;
    return foo;
  }
  
  int
  main ()
  {
    struct foo foo;
    foo.p = foo.s;
  
    printf ("before: %x\n", foo.p);
    foo = bar ();
    printf ("after: %x\n", foo.p);
  }

  $ ./foo
  before: 7339c5c8
  after: 7336b848

(Having a pointer to an internal member is not an uncommon practice.
If you have a struct and a number of variable size elements whose size
you know at allocation, but not compile, time, you can allocate them
with a single call to malloc to save a bit of CPU and storage overhead
plus get a bit of locality.)

> 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.

I don't completely buy the legacy argument.  When the struct is
returned, the pointer needs to be updated, however, the compiler
doesn't know that memcpy isn't enough.  When returning a struct, you
need to be careful in a similar way to which you have to be careful
when dealing with opaque references.

> Because cap_t is a reference, you basically have two options if you want
> to return a cap_t from an IDL procedure:
> 
>   1. Use a well-known return location, e.g. capability register 2.
>   2. Call the capability location allocator from inside the stub, as
>      in:
> 
>      f() {
>       cap_t _retVal = alloc_cap_location();
>       DO_SYSCALL_HERE(_retVal);
>       return _retVal;
>     }

3. The caller provides the address of the slot in which the function
   should store the capability.  (You want this for the same reasons
   you may not necessarily want a function to call malloc.)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.