Topic: P0099 suggestion: Minimal support for


Author: Oliver Kowalke <oliver.kowalke@gmail.com>
Date: Mon, 12 Oct 2015 20:07:47 +0200
Raw View
--001a11403bb21aa65e0521ec365f
Content-Type: text/plain; charset=UTF-8

2015-10-12 19:40 GMT+02:00 Nicol Bolas <jmckesson@gmail.com>:

With `execution_context`, it's easy. If the value is NULL, then that's the
> first time `current` has been called on that thread.
>

it is not NULL - the main thread or any other thread represents an
execution-context


> All threads start on an execution context which is not a fiber (even if
> your thread function immediately starts a fiber, there is an execution
> context under it that is not a fiber).
>

you have to understand that a fiber or a stackful coroutine can be
represented by one or two execution_contexts
in the case of fibers the main-thread can be tracked as fiber (main-fiber)


> If you start up fiber1 on that context, then the thread_local gets filled
> in with fiber1, and fiber1's parent context is updated.
> Now, let's say that fiber1 decides that it needs to do some fiber
> processing of its own. So it starts up fiber2. When it does so, it's parent
> context becomes fiber1, and the thread_local is updated to be fiber2.
> That's fine.
> What happens if fiber2 yields? The thread_local stores fiber2, so it can
> get at the parent execution context and resumes it. But what happens to the
> thread_local variable?
>

- fibers are agnostic of their predecessor and successor
- a fiber can not yield, a fiber uses symmetric context switching -
symmetric context switching requires that a target is given to the switch
operation


> And there is no reason why fibers should be prohibited from starting
> fibers of their own, or from starting non-fiber contexts that *themselves*
> start fibers of their own.
>

it is not prohibited


> So long as there is no way to transform an execution_context into a fiber
> (if it is indeed from a fiber), then merely having a thread_local will not
> help you.
>

a fiber is represented by a execution_context


> I have a function. Its process of execution will take multiple iterations
> of the main program's loop. I don't want to start up a thread or anything
> for it. I want it to execute at a specific time and place in the loop, but
> I want it to be able to wait on things that will happen many loops from now.
>
> There are no "values" to be "yielded" (or at least, not in that sense).
> This could be anything from a scene animation system in a videogame to
> animating the positions of a GUI in motion (moving a widget from one
> location to another to another, in a sequence). Asymmetric coroutines have
> plenty of uses.
>
> Take the GUI-in-motion example. Normally, you'd have to code this in a
> very weird way. With asymmetric coroutines, it looks like this:
>
> {
>   auto anim = widget->AnimateMoveTo(location1);
>   while(!anim)
>     coroutine::yield();
> }
>
> {
>   auto anim = widget->AnimateMoveTo(location2);
>   auto anim2 = widget2->AnimateMoveTo(location3);
>   while(!anim && !anim2)
>     coroutine::yield();
> }
>
> That code is extremely easy to read, understand, reason about, modify, and
> maintain. No threading, synchronization, or anything else needs to be
> involved.
>
> I don't want Boost.Coroutine2 and its not-at-all-asymmetric coroutines.


boost.coroutine2 implements asymmetric coroutines - I don't know why you
insist that it doesn't
an asymmetric coroutine is characterized that it provides two operations
for context switching - one operation to resume and one operation to suspend
the case of boost.coroutine2 is a little bit special - the two operations
are separated into to coroutine types which do always occur in a pair, e.g.
the counter-part (suspend-op) is synthesized by the library


> I don't want Boost.Fiber and its scheduler. I just want a function that
> executes for a bit, then returns. When it's done, it's done. At the end of
> the day, it's a very simple concept.
>
> The fact that many other languages offer asymmetric coroutines should at
> least prove their utility. Not all coroutines sit there and wait on other
> coroutines.
>

 you can easily build your own coroutine-API/library utilizing
execution_context

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

--001a11403bb21aa65e0521ec365f
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_extra"><div class=3D"gmail_quote">2015=
-10-12 19:40 GMT+02:00 Nicol Bolas <span dir=3D"ltr">&lt;<a href=3D"mailto:=
jmckesson@gmail.com" target=3D"_blank">jmckesson@gmail.com</a>&gt;</span>:<=
br><br><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-=
left:1px #ccc solid;padding-left:1ex"><span class=3D""></span><div>With `ex=
ecution_context`, it&#39;s easy. If the value is NULL, then that&#39;s the =
first time `current` has been called on that thread. </div></blockquote><di=
v><br></div><div>it is not NULL - the main thread or any other thread repre=
sents an execution-context<br></div><div>=C2=A0</div><blockquote class=3D"g=
mail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-l=
eft:1ex"><div>All threads start on an execution context which is not a fibe=
r (even if your thread function immediately starts a fiber, there is an exe=
cution context under it that is not a fiber).</div></blockquote><div><br></=
div><div>you have to understand that a fiber or a stackful coroutine can be=
 represented by one or two execution_contexts<br></div><div>in the case of =
fibers the main-thread can be tracked as fiber (main-fiber)<br></div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><div> If you start up fiber1 on =
that context, then the thread_local gets filled in with fiber1, and fiber1&=
#39;s parent context is updated.<br>Now, let&#39;s say that fiber1 decides =
that it needs to do some fiber processing of its own. So it starts up fiber=
2. When it does so, it&#39;s parent context becomes fiber1, and the thread_=
local is updated to be fiber2. That&#39;s fine.<br>What happens if fiber2 y=
ields? The thread_local stores fiber2, so it can get at the parent executio=
n context and resumes it. But what happens to the thread_local variable?<br=
></div></blockquote><div><br></div><div>- fibers are agnostic of their pred=
ecessor and successor <br></div><div>- a fiber can not yield, a fiber uses =
symmetric context switching - symmetric context switching requires that a t=
arget is given to the switch operation<br></div><div>=C2=A0</div><div></div=
><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1=
px #ccc solid;padding-left:1ex"><div>And there is no reason why fibers shou=
ld be prohibited from starting fibers of their own, or from starting non-fi=
ber contexts that <i>themselves</i> start fibers of their own.<br></div></b=
lockquote><div><br></div><div>it is not prohibited<br></div><div>=C2=A0</di=
v><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:=
1px #ccc solid;padding-left:1ex"><div>So long as there is no way to transfo=
rm an execution_context into a fiber (if it is indeed from a fiber), then m=
erely having a thread_local will not help you.<br></div></blockquote><div><=
br></div><div>a fiber is represented by a execution_context<br></div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;bo=
rder-left:1px #ccc solid;padding-left:1ex"><span class=3D""></span>I have a=
 function. Its process of execution will take multiple iterations of the ma=
in program&#39;s loop. I don&#39;t want to start up a thread or anything fo=
r it. I want it to execute at a specific time and place in the loop, but I =
want it to be able to wait on things that will happen many loops from now.<=
br><br>There are no &quot;values&quot; to be &quot;yielded&quot; (or at lea=
st, not in that sense). This could be anything from a scene animation syste=
m in a videogame to animating the positions of a GUI in motion (moving a wi=
dget from one location to another to another, in a sequence). Asymmetric co=
routines have plenty of uses.<br><br>Take the GUI-in-motion example. Normal=
ly, you&#39;d have to code this in a very weird way. With asymmetric corout=
ines, it looks like this:<br><br><div style=3D"background-color:rgb(250,250=
,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px;wor=
d-wrap:break-word"><code><div><span style=3D"color:#660">{</span><span styl=
e=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">auto</span><s=
pan style=3D"color:#000"> anim </span><span style=3D"color:#660">=3D</span>=
<span style=3D"color:#000"> widget</span><span style=3D"color:#660">-&gt;</=
span><span style=3D"color:#606">AnimateMoveTo</span><span style=3D"color:#6=
60">(</span><span style=3D"color:#000">location1</span><span style=3D"color=
:#660">);</span><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D=
"color:#008">while</span><span style=3D"color:#660">(!</span><span style=3D=
"color:#000">anim</span><span style=3D"color:#660">)</span><span style=3D"c=
olor:#000"><br>=C2=A0 =C2=A0 coroutine</span><span style=3D"color:#660">::<=
/span><span style=3D"color:#008">yield</span><span style=3D"color:#660">();=
</span><span style=3D"color:#000"><br></span><span style=3D"color:#660">}</=
span><span style=3D"color:#000"><br><br></span><span style=3D"color:#660">{=
</span><span style=3D"color:#000"><br>=C2=A0 </span><span style=3D"color:#0=
08">auto</span><span style=3D"color:#000"> anim </span><span style=3D"color=
:#660">=3D</span><span style=3D"color:#000"> widget</span><span style=3D"co=
lor:#660">-&gt;</span><span style=3D"color:#606">AnimateMoveTo</span><span =
style=3D"color:#660">(</span><span style=3D"color:#000">location2</span><sp=
an style=3D"color:#660">);</span><span style=3D"color:#000"><br>=C2=A0 </sp=
an><span style=3D"color:#008">auto</span><span style=3D"color:#000"> anim2 =
</span><span style=3D"color:#660">=3D</span><span style=3D"color:#000"> wid=
get2</span><span style=3D"color:#660">-&gt;</span><span style=3D"color:#606=
">AnimateMoveTo</span><span style=3D"color:#660">(</span><span style=3D"col=
or:#000">location3</span><span style=3D"color:#660">);</span><span style=3D=
"color:#000"><br>=C2=A0 </span><span style=3D"color:#008">while</span><span=
 style=3D"color:#660">(!</span><span style=3D"color:#000">anim </span><span=
 style=3D"color:#660">&amp;&amp;</span><span style=3D"color:#000"> </span><=
span style=3D"color:#660">!</span><span style=3D"color:#000">anim2</span><s=
pan style=3D"color:#660">)</span><span style=3D"color:#000"><br>=C2=A0 =C2=
=A0 coroutine</span><span style=3D"color:#660">::</span><span style=3D"colo=
r:#008">yield</span><span style=3D"color:#660">();</span><span style=3D"col=
or:#000"><br></span><span style=3D"color:#660">}</span><span style=3D"color=
:#000"><br></span></div></code></div><br>That code is extremely easy to rea=
d, understand, reason about, modify, and maintain. No threading, synchroniz=
ation, or anything else needs to be involved.<br><br>I don&#39;t want Boost=
..Coroutine2 and its not-at-all-asymmetric coroutines.</blockquote><div><br>=
</div><div>boost.coroutine2 implements asymmetric coroutines - I don&#39;t =
know why you insist that it doesn&#39;t<br></div><div>an asymmetric corouti=
ne is characterized that it provides two operations for context switching -=
 one operation to resume and one operation to suspend<br></div><div>the cas=
e of boost.coroutine2 is a little bit special - the two operations are sepa=
rated into to coroutine types which do always occur in a pair, e.g.<br></di=
v><div>the counter-part (suspend-op) is synthesized by the library <br></di=
v><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 =
..8ex;border-left:1px #ccc solid;padding-left:1ex"> I don&#39;t want Boost.F=
iber and its scheduler. I just want a function that executes for a bit, the=
n returns. When it&#39;s done, it&#39;s done. At the end of the day, it&#39=
;s a very simple concept.<br><br>The fact that many other languages offer a=
symmetric coroutines should at least prove their utility. Not all coroutine=
s sit there and wait on other coroutines.<br></blockquote></div><br></div><=
div class=3D"gmail_extra">=C2=A0you can easily build your own coroutine-API=
/library utilizing execution_context<br></div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--001a11403bb21aa65e0521ec365f--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 12 Oct 2015 13:27:30 -0700 (PDT)
Raw View
------=_Part_5050_1863004027.1444681650356
Content-Type: multipart/alternative;
 boundary="----=_Part_5051_270390137.1444681650357"

------=_Part_5051_270390137.1444681650357
Content-Type: text/plain; charset=UTF-8

On Monday, October 12, 2015 at 2:08:10 PM UTC-4, Oliver Kowalke wrote:
>
> 2015-10-12 19:40 GMT+02:00 Nicol Bolas <jmck...@gmail.com <javascript:>>:
>
> With `execution_context`, it's easy. If the value is NULL, then that's the
>> first time `current` has been called on that thread.
>>
>
> it is not NULL - the main thread or any other thread represents an
> execution-context
>
>
>> All threads start on an execution context which is not a fiber (even if
>> your thread function immediately starts a fiber, there is an execution
>> context under it that is not a fiber).
>>
>
> you have to understand that a fiber or a stackful coroutine can be
> represented by one or two execution_contexts
> in the case of fibers the main-thread can be tracked as fiber (main-fiber)
>
>
>> If you start up fiber1 on that context, then the thread_local gets filled
>> in with fiber1, and fiber1's parent context is updated.
>> Now, let's say that fiber1 decides that it needs to do some fiber
>> processing of its own. So it starts up fiber2. When it does so, it's parent
>> context becomes fiber1, and the thread_local is updated to be fiber2.
>> That's fine.
>> What happens if fiber2 yields? The thread_local stores fiber2, so it can
>> get at the parent execution context and resumes it. But what happens to the
>> thread_local variable?
>>
>
> - fibers are agnostic of their predecessor and successor
> - a fiber can not yield, a fiber uses symmetric context switching -
> symmetric context switching requires that a target is given to the switch
> operation
>

OK, the entire rest of your post is based on what may be a misuse of
terminology on my part. When I said "fiber", what I meant was "the
construct giving me the functionality I asked for". I based this on Gor's
use of the term; I assumed that when he said "fiber", he meant something
that gave me the functionality I was asking for, and he described it as
such.

Whether that matches your definition of what a "fiber" is or not (since the
definition of these terms is far from universal), I can't say.

Therefore, forget everything I said. So that we are all clear on what words
mean, I will define the term *fully asymetric coroutine* as follows:

*A stackful coroutine that can halt its execution, returning control to
whichever execution context resumed it.*

That is the behavior I want to be able to build atop `execution_context`.
So here's what I said again, using proper terminology:

----

There's a problem here. It's about how that thread_local gets updated.

With `execution_context`, it's easy. Initially, its an `execution_context`
that represents the initial path of execution for the thread. Anytime the
user resumes an execution context, the thread_local is updated accordingly.

The problem with fa_coroutine (the prospective type implementing a fully
asymetric coroutine atop an `execution_context`) mirroring that process is
this.

All threads start on an execution context which is not a fa_coroutine (even
if your thread function immediately starts a fa_coroutine, there is an
execution context under it that is not a fa_coroutine). So the thread_local
must be empty. If you start up fa_co1 on that context, then the
thread_local gets filled in with fa_co1, and fa_co1's parent context is
updated.

Now, let's say that fa_co1 decides that it needs to do some fa_coroutine
processing of its own. So it starts up fa_co2. When it does so, its parent
context becomes fa_co1, and the thread_local is updated to be fa_co2.
That's fine.

What happens when fa_co2 yields? The thread_local stores fa_co2, so it can
get at the parent execution context and resumes it. But what happens to the
thread_local variable?

Because fa_co2 was executed from a fa_coroutine, when you return, the
thread_local needs to be set to that fa_co. But... we have no way of
knowing that fa_co2 was launched from a fa_coroutine. And there's no reason
to assume that it was. There is no way to convert an execution_context into
a fa_coroutine, remember? So there's no way to even test that.

And there is no reason why fa_coroutines should be prohibited from starting
fa_coroutines of their own, or from starting non-fa_coroutine contexts that
themselves start fa_coroutines of their own.

So long as there is no way to transform an execution_context into a
fa_coroutine (if it is indeed from a fa_coroutine), then merely having a
thread_local will not help you.

----

I believe this can be resolved, though it requires some effort:

class fa_coroutine
{
    //The caller can be either a naked execution_context or another
fa_coroutine.
    //Ignore the fact that this isn't legal. You get the general idea.
    std::variant<execution_context, fa_coroutine> caller;
    std::aligned_storage_t<sizeof(execution_context), alignof(
execution_context) ec_data;

    execution_context *get_context() {return static_cast<execution_context>(
ec_data);}

    static thread_local std::optional<fa_coroutine> current_fa_co;

public:
    //copying, construction, etc as expected.

    void operator()()
    {
        if(current_fa_co)
            caller = *current_fa_co
        else
            caller = execution_context::current();

        current_fa_co = *this;
        get_context()();
    }

    struct update_current_fac
    {
        execution_context operator()(execution_context caller)
        {
            current_fa_co = nullopt;
            return caller;
        }

        execution_context operator()(fa_coroutine caller)
        {
            //The caller's caller may be a fa_coroutine or not. The
            //current fa_coroutine must be updated to match.
            fa_coroutine *new_caller = get<fa_coroutine>(&caller.caller)
            if(new_caller)
                current_fa_co = *new_caller
            else
                current_fa_co = nullopt;

            //Deliberately bypass fa_coroutine's operator().
            return *caller.get_context()
        }
    }

    static void yield_current()
    {
        Expects(current_fa_co);
        execution_context ec = visit(current_fa_co->caller,
            update_current_fac);
        ec(); //Actual yield.
    }

    friend struct update_current_fac;
};

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_5051_270390137.1444681650357
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On Monday, October 12, 2015 at 2:08:10 PM UTC-4, Oliver Kowalke wrote:<bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><div class=3D=
"gmail_quote">2015-10-12 19:40 GMT+02:00 Nicol Bolas <span dir=3D"ltr">&lt;=
<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"enw4AYkH=
DgAJ" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;javascript:&#39;;ret=
urn true;" onclick=3D"this.href=3D&#39;javascript:&#39;;return true;">jmck.=
...@gmail.com</a>&gt;</span>:<br><br><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span></=
span><div>With `execution_context`, it&#39;s easy. If the value is NULL, th=
en that&#39;s the first time `current` has been called on that thread. </di=
v></blockquote><div><br></div><div>it is not NULL - the main thread or any =
other thread represents an execution-context<br></div><div>=C2=A0</div><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #c=
cc solid;padding-left:1ex"><div>All threads start on an execution context w=
hich is not a fiber (even if your thread function immediately starts a fibe=
r, there is an execution context under it that is not a fiber).</div></bloc=
kquote><div><br></div><div>you have to understand that a fiber or a stackfu=
l coroutine can be represented by one or two execution_contexts<br></div><d=
iv>in the case of fibers the main-thread can be tracked as fiber (main-fibe=
r)<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div> If you st=
art up fiber1 on that context, then the thread_local gets filled in with fi=
ber1, and fiber1&#39;s parent context is updated.<br>Now, let&#39;s say tha=
t fiber1 decides that it needs to do some fiber processing of its own. So i=
t starts up fiber2. When it does so, it&#39;s parent context becomes fiber1=
, and the thread_local is updated to be fiber2. That&#39;s fine.<br>What ha=
ppens if fiber2 yields? The thread_local stores fiber2, so it can get at th=
e parent execution context and resumes it. But what happens to the thread_l=
ocal variable?<br></div></blockquote><div><br></div><div>- fibers are agnos=
tic of their predecessor and successor <br></div><div>- a fiber can not yie=
ld, a fiber uses symmetric context switching - symmetric context switching =
requires that a target is given to the switch operation<br></div></div></di=
v></div></blockquote><div><br>OK, the entire rest of your post is based on =
what may be a misuse of terminology on my part. When I said &quot;fiber&quo=
t;, what I meant was &quot;the construct giving me the functionality I aske=
d for&quot;. I based this on Gor&#39;s use of the term; I assumed that when=
 he said &quot;fiber&quot;, he meant something that gave me the functionali=
ty I was asking for, and he described it as such.<br><br>Whether that match=
es your definition of what a &quot;fiber&quot; is or not (since the definit=
ion of these terms is far from universal), I can&#39;t say.<br><br>Therefor=
e, forget everything I said. So that we are all clear on what words mean, I=
 will define the term <u>fully asymetric coroutine</u> as follows:<br><br><=
u>A stackful coroutine that can halt its execution, returning control to wh=
ichever execution context resumed it.</u><br><br>That is the behavior I wan=
t to be able to build atop `execution_context`. So here&#39;s what I said a=
gain, using proper terminology:<br><br>----<br><br>There&#39;s a problem he=
re. It&#39;s about how that thread_local gets updated.<br><br>With `executi=
on_context`, it&#39;s easy. Initially, its an `execution_context` that repr=
esents the initial path of execution for the thread. Anytime the user resum=
es an execution context, the thread_local is updated accordingly.<br><br>Th=
e problem with fa_coroutine (the prospective type implementing a fully asym=
etric coroutine atop an `execution_context`) mirroring that process is this=
..<br><br>All threads start on an execution context which is not a fa_corout=
ine (even if your thread function immediately starts a fa_coroutine, there =
is an execution context under it that is not a fa_coroutine). So the thread=
_local must be empty. If you start up fa_co1 on that context, then the thre=
ad_local gets filled in with fa_co1, and fa_co1&#39;s parent context is upd=
ated.<br><br>Now, let&#39;s say that fa_co1 decides that it needs to do som=
e fa_coroutine processing of its own. So it starts up fa_co2. When it does =
so, its parent context becomes fa_co1, and the thread_local is updated to b=
e fa_co2. That&#39;s fine.<br><br>What happens when fa_co2 yields? The thre=
ad_local stores fa_co2, so it can get at the parent execution context and r=
esumes it. But what happens to the thread_local variable?<br><br>Because fa=
_co2 was executed from a fa_coroutine, when you return, the thread_local ne=
eds to be set to that fa_co. But... we have no way of knowing that fa_co2 w=
as launched from a fa_coroutine. And there&#39;s no reason to assume that i=
t was. There is no way to convert an execution_context into a fa_coroutine,=
 remember? So there&#39;s no way to even test that.<br><br>And there is no =
reason why fa_coroutines should be prohibited from starting fa_coroutines o=
f their own, or from starting non-fa_coroutine contexts that themselves sta=
rt fa_coroutines of their own.<br><br>So long as there is no way to transfo=
rm an execution_context into a fa_coroutine (if it is indeed from a fa_coro=
utine), then merely having a thread_local will not help you.<br><br>----<br=
><br>I believe this can be resolved, though it requires some effort:<br><br=
><div class=3D"prettyprint" style=3D"background-color: rgb(250, 250, 250); =
border-color: rgb(187, 187, 187); border-style: solid; border-width: 1px; w=
ord-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettyp=
rint"><span style=3D"color: #008;" class=3D"styled-by-prettify">class</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> fa_coroutine<br=
></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =
</span><span style=3D"color: #800;" class=3D"styled-by-prettify">//The call=
er can be either a naked execution_context or another fa_coroutine.</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =
</span><span style=3D"color: #800;" class=3D"styled-by-prettify">//Ignore t=
he fact that this isn&#39;t legal. You get the general idea.</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 std</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify">variant</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">&lt;</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">execution_context</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> fa_coroutine</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">caller</span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"><br>=C2=A0 =C2=A0 std</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">aligned_storage_t</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">sizeof</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">execution_context</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">),</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify=
">alignof</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">execution_=
context</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> ec_data</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>=C2=A0 =C2=A0 e=
xecution_context </span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">*</span><span style=3D"color: #000;" class=3D"styled-by-prettify">ge=
t_context</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><span styl=
e=3D"color: #008;" class=3D"styled-by-prettify">return</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">static_cast</span><span style=3D"color: =
#080;" class=3D"styled-by-prettify">&lt;execution_context&gt;</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">ec_data</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">);}</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br><br>=C2=A0 =C2=A0 </span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">static</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> thread_local std</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify">optional</span><span style=3D"color:=
 #080;" class=3D"styled-by-prettify">&lt;fa_coroutine&gt;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> current_fa_co</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">public</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">:</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #=
800;" class=3D"styled-by-prettify">//copying, construction, etc as expected=
..</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br><br>=
=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">operator</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">()()</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">if</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">current_fa_co=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"st=
yled-by-prettify">caller</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">*</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">current_fa_co<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">else</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">caller</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify"> execution_context</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">current</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 <br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 current_fa_co </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">*</sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">this</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 get_context</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">()();</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br>=C2=A0 =C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><=
br><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by=
-prettify">struct</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> update_current_fac<br>=C2=A0 =C2=A0 </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 execution_context =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">operator</=
span><span style=3D"color: #660;" class=3D"styled-by-prettify">()(</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">execution_context <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">caller</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0=
 =C2=A0 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">{<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 current_fa_co </span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> nullopt</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #008;" class=3D"styled-by-prettify">caller</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span=
 style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
 <br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 execution_context </span><span style=3D"co=
lor: #008;" class=3D"styled-by-prettify">operator</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">()(</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">fa_coroutine </span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">caller</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 </span><span style=3D"color: #800;" class=3D"styled-by-prettify"=
>//The caller&#39;s caller may be a fa_coroutine or not. The</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #800;" class=3D"styled-by=
-prettify">//current fa_coroutine must be updated to match.</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 fa_coroutine </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">*</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">new_caller </span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
get</span><span style=3D"color: #080;" class=3D"styled-by-prettify">&lt;fa_=
coroutine&gt;</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(&amp;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">c=
aller</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">caller</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by=
-prettify">if</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">new_ca=
ller</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 current_fa_co </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">*</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify">new_caller<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">els=
e</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 current_fa_co </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> nullopt</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 <br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </sp=
an><span style=3D"color: #800;" class=3D"styled-by-prettify">//Deliberately=
 bypass fa_coroutine&#39;s operator().</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">return</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">*</span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">caller</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify">get_context</span><span style=3D"color: #660;"=
 class=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 <br>=C2=A0 =C2=A0 <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">static</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">void</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> yield_current</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">()</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 <=
/span><span style=3D"color: #606;" class=3D"styled-by-prettify">Expects</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify">current_fa_co</span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 execution_context ec </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> visit</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">curre=
nt_fa_co</span><span style=3D"color: #660;" class=3D"styled-by-prettify">-&=
gt;</span><span style=3D"color: #008;" class=3D"styled-by-prettify">caller<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 update_current_fac</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 ec</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">();</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color=
: #800;" class=3D"styled-by-prettify">//Actual yield.</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 <br>=C2=A0 =C2=
=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">friend=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">struct</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> update_current_fac</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">};</span></div></code></div>=
<br></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_5051_270390137.1444681650357--
------=_Part_5050_1863004027.1444681650356--

.