From mboxrd@z Thu Jan 1 00:00:00 1970 MIME-Version: 1.0 In-Reply-To: <3e1162e60909032231h5a2cc329x89744a497052e551@mail.gmail.com> References: <3e1162e60909032118h60620d2cj74791672e5f55a5f@mail.gmail.com> <0084d6ddb9d674fa38925596dabc8d78@quanstro.net> <3e1162e60909032231h5a2cc329x89744a497052e551@mail.gmail.com> Date: Thu, 3 Sep 2009 22:35:35 -0700 Message-ID: <3e1162e60909032235s6e5a67dau6109f30246f255d@mail.gmail.com> From: David Leimbach To: Fans of the OS Plan 9 from Bell Labs <9fans@9fans.net> Content-Type: multipart/alternative; boundary=000e0cd59c969208260472b9dec1 Subject: Re: [9fans] "Blocks" in C Topicbox-Message-UUID: 63b3c554-ead5-11e9-9d60-3106f5b1d025 --000e0cd59c969208260472b9dec1 Content-Type: text/plain; charset=ISO-8859-1 On Thu, Sep 3, 2009 at 10:31 PM, David Leimbach wrote: > > > On Thu, Sep 3, 2009 at 9:44 PM, erik quanstrom wrote: > >> > > that sucker is on the stack. by-by no-execute stack. >> > > how does it get to the stack? is it just copied from >> > > the text segment or is it compiled at run time? >> > > >> > >> > I don't think I posted the whole code, so that's my bad. The X was on >> the >> > stack to begin with as the first X was an automatic variable in a >> function. >> > I'd be a little surprised to find an automatic variable in the text >> > segment, but perhaps that's just my not remembering things properly. >> > (didn't mean that tongue in cheek, I don't think about that stuff much >> > these days, as I've spent the last year or so doing Erlang and Haskell.) >> >> it is the block itself that apple claims is on the stacp >> (your grand centeral reference, p. 38). and i wonder >> how it gets there. is it just copied from the text segment? >> that seems kind of pointless. why not just execute it >> from the text segment? or is it modified (compiled?) >> at run time? >> > > Right, my understanding is that blocks live on the stack, however it > appears that they get copied to a particular queue before being run, either > explicitly or implicitly depending on how it gets submitted. If you use > dispatch_after, it gets copied and released automatically after a certain > amount of time. > > The whole thing is very "eventy". > > Some of the documentation is not terribly explicit about how things get > copied if they do at all. Example is the dispatch_async call, which behaves > based on the queue to which it is submitted, but whether or not a copy > occurs is not mentioned. > > This document goes into more detail: > http://clang.llvm.org/docs/BlockImplementation.txt > > "Block literals may occur within functions where the structure is created > in stack local memory. They may also appear as initialization expressions > for Block variables of global or static local variables. > > When a Block literal expression is evaluated the stack based structure is initialized as follows: > > 1) static descriptor structure is declared and initialized as follows: > 1a) the invoke function pointer is set to a function that takes the Block structure as its first argument and the rest of the arguments (if any) to the Block and executes the Block compound statement. > 1b) the size field is set to the size of the following Block literal structure. > 1c) the copy_helper and dispose_helper function pointers are set to respective helper functions if they are required by the Block literal > 2) a stack (or global) Block literal data structure is created and initialized as follows: > 2a) the isa field is set to the address of the external _NSConcreteStackBlock, which is a block of uninitialized memory supplied in libSystem, or _NSConcreteGlobalBlock if this is a static or file level block literal. > 2) The flags field is set to zero unless there are variables imported into the block that need helper functions for program level Block_copy() and Block_release() operations, in which case the (1<<25) flags bit is set." > > I'm still left feeling somewhat not understanding how it all works :-) > > > Actually, reading on a bit more they deal with the "variable capture" talking about const copies. Automatic storage variables not marked with __block are imported as const copies. The simplest example is that of importing a variable of type int. int x = 10; void (^vv)(void) = ^{ printf("x is %d\n", x); } x = 11; vv(); would be compiled struct __block_literal_2 { void *isa; int flags; int reserved; void (*invoke)(struct __block_literal_2 *); struct __block_descriptor_2 *descriptor; const int x; }; void __block_invoke_2(struct __block_literal_2 *_block) { printf("x is %d\n", _block->x); } static struct __block_descriptor_2 { unsigned long int reserved; unsigned long int Block_size; } __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) }; and struct __block_literal_2 __block_literal_2 = { &_NSConcreteStackBlock, (1<<29), , __block_invoke_2, &__block_descriptor_2, x }; In summary, scalars, structures, unions, and function pointers are generally imported as const copies with no need for helper functions. > >> - erik >> >> > --000e0cd59c969208260472b9dec1 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable

On Thu, Sep 3, 2009 at 10:31 PM, David L= eimbach <leimy2k@= gmail.com> wrote:


On Thu= , Sep 3, 2009 at 9:44 PM, erik quanstrom <quanstro@quanstro.net>= ; wrote:
> > that sucker is on the stack. =A0by-by no-execute stack.
> > how does it get to the stack? =A0is it just copied from
> > the text segment or is it compiled at run time?
> >
>
> I don't think I posted the whole code, so that's my bad. =A0Th= e X was on the
> stack to begin with as the first X was an automatic variable in a func= tion.
> =A0I'd be a little surprised to find an automatic variable in the = text
> segment, but perhaps that's just my not remembering things properl= y.
> =A0(didn't mean that tongue in cheek, I don't think about that= stuff much
> these days, as I've spent the last year or so doing Erlang and Has= kell.)

it is the block itself that apple claims is on the stacp
(your grand centeral reference, p. 38). =A0and i wonder
how it gets there. =A0is it just copied from the text segment?
that seems kind of pointless. =A0why not just execute it
from the text segment? =A0or is it modified (compiled?)
at run time?

Right, my unde= rstanding is that blocks live on the stack, however it appears that they ge= t copied to a particular queue before being run, either explicitly or impli= citly depending on how it gets submitted. =A0If you use dispatch_after, it = gets copied and released automatically after a certain amount of time.

The whole thing is very "eventy".
<= br>
Some of the documentation is not terribly explicit about how = things get copied if they do at all. =A0Example is the dispatch_async call,= which behaves based on the queue to which it is submitted, but whether or = not a copy occurs is not mentioned.

This document goes into more detail:
"Block literals may occur within functions = where the structure is created in stack local memory. They may also appear= as initialization expressions for Block variables of global or static loca= l variables.
When a Block literal expression is evaluat=
ed the stack based structure is initialized as follows:

1) static descriptor structure is declared and initialized as follows:
1a) the invoke function pointer is set to a function that takes the Block s=
tructure as its first argument and the rest of the arguments (if any) to th=
e Block and executes the Block compound statement.
1b) the size field is set to the size of the following Block literal struct=
ure.
1c) the copy_helper and dispose_helper function pointers are set to respect=
ive helper functions if they are required by the Block literal
2) a stack (or global) Block literal data structure is created and initiali=
zed as follows:
2a) the isa field is set to the address of the external _NSConcreteStackBlo=
ck, which is a block of uninitialized memory supplied in libSystem, or _NSC=
oncreteGlobalBlock if this is a static or file level block literal.
2) The flags field is set to zero unless there are variables imported into =
the block that need helper functions for program level Block_copy() and Blo=
ck_release() operations, in which case the (1<<25) flags bit is set.&=
quot;
I'm still left=
 feeling somewhat not understanding how it all works :-)
= =A0

Actually, reading on a bit = more they deal with the "variable capture" talking about const co= pies.

Automatic storage variables not marked with __block are imported as const c=
opies.

The simplest example is that of importing a variable of type int.

   int x =3D 10;
   void (^vv)(void) =3D ^{ printf("x is %d\n", x); }
   x =3D 11;
   vv();

would be compiled

struct __block_literal_2 {
    void *isa;
    int flags;
    int reserved;=20
    void (*invoke)(struct __block_literal_2 *);
    struct __block_descriptor_2 *descriptor;
    const int x;
};

void __block_invoke_2(struct __block_literal_2 *_block) {
    printf("x is %d\n", _block->x);
}

static struct __block_descriptor_2 {
    unsigned long int reserved;
    unsigned long int Block_size;
} __block_descriptor_2 =3D { 0, sizeof(struct __block_literal_2) };

and

  struct __block_literal_2 __block_literal_2 =3D {
	&_NSConcreteStackBlock,
	(1<<29), <uninitialized>,
	__block_invoke_2,
	&__block_descriptor_2,
        x
   };

In summary, scalars, structures, unions, and function pointers are generall=
y imported as const copies with no need for helper functions.

=A0

- erik



--000e0cd59c969208260472b9dec1--