l4-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: IDL issue - struct return vs. cap return


From: Neal H. Walfield
Subject: Re: IDL issue - struct return vs. cap return
Date: Mon, 09 Jul 2007 23:24:07 +0200
User-agent: Wanderlust/2.14.0 (Africa) SEMI/1.14.6 (Maruoka) FLIM/1.14.6 (Marutamachi) APEL/10.6 Emacs/21.4 (i386-pc-linux-gnu) MULE/5.0 (SAKAKI)

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]