-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathresume_with.tex
68 lines (53 loc) · 3.08 KB
/
resume_with.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
\abschnitt{inject function into suspended fiber}\label{resumewith}
Sometimes it is useful to inject a new function (for instance, to throw an
exception or assign the synthesized fiber to the caller as described in
\nameref{fiberreturn}) into a suspended fiber. For this purpose
\anyresumewith may be called, passing the function \cpp{fn()} to execute.
\cppfl{suspender}
The \resumewith call at line 11 injects function \cpp{fn()} into
fiber \cpp{f} as if the \resume call at line 3 had directly
called \cpp{fn()}.
Like an \entryfn passed to \fiber, \cpp{fn()} must accept
\cpp{std::fiber\_context&&} and return\\
\fiber. The \fiber instance returned by \cpp{fn()} will, in turn, be returned
to \cpp{f}'s lambda by the \resume at line 3.
In the example below, suppose that code running on the program's main fiber
calls \resume (line 12), thereby entering the first lambda. This is the point
at which \cpp{m} is synthesized and passed into the lambda at line 2.
Suppose further that after doing some work (line 4), the lambda calls
\cpp{m.resume()}, thereby switching back to the main fiber. The lambda remains
suspended in the call to \cpp{m.resume()} at line 5.
At line 18 the main fiber calls \cpp{f.resume\_with()} where the passed lambda
accepts \cpp{fiber\_context &&}. That new lambda is called on the fiber of the suspended
lambda. It is as if the \cpp{m.resume()} call at line 8 directly called the second
lambda.
The function passed to \resumewith has almost the same range of possibilities as
any function called on \thefiber{\cpp{f}}. Its special invocation
matters when control leaves it in either of two ways:
\begin{enumerate}
\item If it throws an exception, that exception unwinds all previous stack
entries in that fiber (such as the first lambda's) as well, back to
a matching \cpp{catch} clause.\footnote{As stated
in \nameref{exceptions}, if there is no matching \cpp{catch}
clause in that fiber, \cpp{std::terminate()} is called.}
\item If the function returns, the returned \fiber instance is returned by
the suspended \anyresume call.
\end{enumerate}
\cppfl{ontop}
The \cpp{f.resume\_with(<lambda>)} call at line 18 passes control to the second
lambda on the fiber of the first lambda.
As usual, \resumewith synthesizes a \fiber instance representing the calling
fiber, passed into the lambda as \cpp{m}. This particular lambda returns \cpp{m}
unchanged at line 21; thus that \cpp{m} instance is returned by the \resume call
at line 8.
Finally, the first lambda returns at line 10 the \cpp{m} variable updated at
line 8, switching back to the main fiber.
One case worth pointing out is when you call \anyresumewith on a
\fiber that has not yet been resumed for the first time:
\cppfl{initial_resume_with}
In this situation, \cpp{injected()} is called with a \fiber instance
representing the caller of \resumewith. When \cpp{injected()} eventually
returns that (or some other) \fiber instance, the returned\\
\fiber instance is passed into \cpp{topfunc()} as its \cpp{prev} parameter.
\zs{Member function \anyresumewith allows you to inject a
function into a suspended fiber.}