1 <!-- This file is generated from internal wiki guide by folly/facebook/fibers-update-readme.sh. -->
2 <section class="dex_guide"><h1 class="dex_title">folly::fibers</h1><section class="dex_document"><h1></h1><p class="dex_introduction">folly::fibers is an async C++ framework, which uses fibers for parallelism.</p><h2 id="overview">Overview <a href="#overview" class="headerLink">#</a></h2>
4 <p>Fibers (or coroutines) are lightweight application threads. Multiple fibers can be running on top of a single system thread. Unlike system threads, all the context switching between fibers is happening explicitly. Because of this every such context switch is very fast (~200 million of fiber context switches can be made per second on a single CPU core).</p>
6 <p>folly::fibers implements a task manager (FiberManager), which executes scheduled tasks on fibers. It also provides some fiber-compatible synchronization primitives.</p>
8 <h2 id="basic-example">Basic example <a href="#basic-example" class="headerLink">#</a></h2>
10 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">...</span>
11 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="EventBase">EventBase</span> <span class="no">evb</span><span class="o">;</span>
12 <span class="no">auto</span><span class="o">&</span> <span class="no">fiberManager</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="getFiberManager">getFiberManager</span><span class="o">(</span><span class="no">evb</span><span class="o">);</span>
13 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Baton">Baton</span> <span class="no">baton</span><span class="o">;</span>
15 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([&]()</span> <span class="o">{</span>
16 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Task 1: start"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
17 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="wait">wait</span><span class="o">();</span>
18 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Task 1: after baton.wait()"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
19 <span class="o">});</span>
21 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([&]()</span> <span class="o">{</span>
22 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Task 2: start"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
23 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="post">post</span><span class="o">();</span>
24 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Task 2: after baton.post()"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
25 <span class="o">});</span>
27 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loop">loop</span><span class="o">();</span>
28 <span class="o">...</span></pre></div>
30 <p>This would print:</p>
32 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">Task</span> <span class="mi">1</span><span class="o">:</span> <span class="no">start</span>
33 <span class="no">Task</span> <span class="mi">2</span><span class="o">:</span> <span class="no">start</span>
34 <span class="no">Task</span> <span class="mi">2</span><span class="o">:</span> <span class="no">after</span> <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="post">post</span><span class="o">()</span>
35 <span class="no">Task</span> <span class="mi">1</span><span class="o">:</span> <span class="no">after</span> <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="wait">wait</span><span class="o">()</span></pre></div>
37 <p>It's very important to note that both tasks in this example were executed on the same system thread. Task 1 was suspended by <tt>baton.wait()</tt> call. Task 2 then started and called <tt>baton.post()</tt>, resuming Task 1.</p>
39 <h2 id="features">Features <a href="#features" class="headerLink">#</a></h2>
42 <li>Fibers creation and scheduling is performed by FiberManager</li>
43 <li>Integration with any event-management system (e.g. EventBase)</li>
44 <li>Low-level synchronization primitives (Baton) as well as higher-level primitives built on top of them (await, collectN, mutexes, ... )</li>
45 <li>Synchronization primitives have timeout support</li>
46 <li>Built-in mechanisms for fiber stack-overflow detection</li>
47 <li>Optional fiber-local data (i.e. equivalent of thread locals)</li>
50 <h2 id="non-features">Non-features <a href="#non-features" class="headerLink">#</a></h2>
53 <li>Individual fibers scheduling can't be directly controlled by application</li>
54 <li>FiberManager is not thread-safe (we recommend to keep one FiberManager per thread). Application is responsible for managing it's own threads and distributing load between them</li>
55 <li>We don't support automatic stack size adjustments. Each fiber has a stack of fixed size.</li>
58 <h2 id="why-would-i-not-want-to">Why would I not want to use fibers ? <a href="#why-would-i-not-want-to" class="headerLink">#</a></h2>
60 <p>The only real downside to using fibers is the need to keep a pre-allocated stack for every fiber being run. That either makes you application use a lot of memory (if you have many concurrent tasks and each of them uses large stacks) or creates a risk of stack overflow bugs (if you try to reduce the stack size).</p>
62 <p>We believe these problems can be addressed (and we provide some tooling for that), as fibers library is used in many critical applications at Facebook (mcrouter, TAO, Service Router). However, it's important to be aware of the risks and be ready to deal with stack issues if you decide to use fibers library in your application.</p>
64 <h2 id="what-are-the-alternative">What are the alternatives ? <a href="#what-are-the-alternative" class="headerLink">#</a></h2>
67 <li><a href="https://github.com/facebook/folly/blob/master/folly/futures/" target="_blank">Futures</a> library works great for asynchronous high-level application code. Yet code written using fibers library is generally much simpler and much more efficient (you are not paying the penalty of heap allocation).</li>
68 <li>You can always keep writing your asynchronous code using traditional callback approach. Such code quickly becomes hard to manage and is error-prone. Even though callback approach seems to allow you writing the most efficient code, inefficiency still comes from heap allocations (<tt>std::function</tt>s used for callbacks, context objects to be passed between callbacks etc.)</li>
69 </ul></section><section class="dex_document"><h1>Quick guide</h1><p class="dex_introduction"></p><p>Let's take a look at this basic example:</p>
71 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">...</span>
72 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="EventBase">EventBase</span> <span class="no">evb</span><span class="o">;</span>
73 <span class="no">auto</span><span class="o">&</span> <span class="no">fiberManager</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="getFiberManager">getFiberManager</span><span class="o">(</span><span class="no">evb</span><span class="o">);</span>
74 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Baton">Baton</span> <span class="no">baton</span><span class="o">;</span>
76 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([&]()</span> <span class="o">{</span>
77 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Task: start"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
78 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="wait">wait</span><span class="o">();</span>
79 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Task: after baton.wait()"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
80 <span class="o">});</span>
82 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loop">loop</span><span class="o">();</span>
84 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="post">post</span><span class="o">();</span>
85 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="cout">cout</span> <span class="o"><<</span> <span class="s2">"Baton posted"</span> <span class="o"><<</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="endl">endl</span><span class="o">;</span>
87 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loop">loop</span><span class="o">();</span>
89 <span class="o">...</span></pre></div>
91 <p>This would print:</p>
93 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">Task</span><span class="o">:</span> <span class="no">start</span>
94 <span class="no">Baton</span> <span class="no">posted</span>
95 <span class="no">Task</span><span class="o">:</span> <span class="no">after</span> <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="wait">wait</span><span class="o">()</span></pre></div>
97 <p>What makes fiber-task different from any other task run on e.g. an <tt>folly::EventBase</tt> is the ability to suspend such task, without blocking the system thread. So how do you suspend a fiber-task ?</p>
99 <h3 id="fibers-baton">fibers::Baton <a href="#fibers-baton" class="headerLink">#</a></h3>
101 <p><tt>fibers::Baton</tt> is the core synchronization primitive which is used to suspend a fiber-task and notify when the task may be resumed. <tt>fibers::Baton</tt> supports two basic operations: <tt>wait()</tt> and <tt>post()</tt>. Calling <tt>wait()</tt> on a Baton will suspend current fiber-task until <tt>post()</tt> is called on the same Baton.</p>
103 <p>Please refer to <a href="https://github.com/facebook/folly/blob/master/folly/fibers/Baton.h" target="_blank">Baton</a> for more detailed documentation.</p>
105 <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> <tt>fibers::Baton</tt> is the only native synchronization primitive of folly::fibers library. All other synchronization primitives provided by folly::fibers are built on top of <tt>fibers::Baton</tt>.</div>
107 <h3 id="integrating-with-other-a">Integrating with other asynchronous APIs (callbacks) <a href="#integrating-with-other-a" class="headerLink">#</a></h3>
109 <p>Let's say we have some existing library which provides a classic callback-style asynchronous API.</p>
111 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">void</span> <span class="nf" data-symbol-name="asyncCall">asyncCall</span><span class="o">(</span><span class="no">Request</span> <span class="no">request</span><span class="o">,</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="Function">Function</span><span class="o"><</span><span class="nf" data-symbol-name="void">void</span><span class="o">(</span><span class="no">Response</span><span class="o">)></span> <span class="no">cb</span><span class="o">);</span></pre></div>
113 <p>If we use folly::fibers we can just make an async call from a fiber-task and wait until callback is run:</p>
115 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
116 <span class="o">...</span>
117 <span class="no">Response</span> <span class="no">response</span><span class="o">;</span>
118 <span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-context="fibers" data-symbol-name="Baton">Baton</span> <span class="no">baton</span><span class="o">;</span>
120 <span class="nf" data-symbol-name="asyncCall">asyncCall</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="o">[&](</span><span class="no">Response</span> <span class="no">r</span><span class="o">)</span> <span class="no">mutable</span> <span class="o">{</span>
121 <span class="no">response</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">r</span><span class="o">);</span>
122 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="post">post</span><span class="o">();</span>
123 <span class="o">});</span>
124 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="wait">wait</span><span class="o">();</span>
126 <span class="c">// Now response holds response returned by the async call</span>
127 <span class="o">...</span>
128 <span class="o">}</span></pre></div>
130 <p>Using <tt>fibers::Baton</tt> directly is generally error-prone. To make the task above simpler, folly::fibers provide <tt>fibers::await</tt> function.</p>
132 <p>With <tt>fibers::await</tt>, the code above transforms into:</p>
134 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
135 <span class="o">...</span>
136 <span class="no">auto</span> <span class="no">response</span> <span class="o">=</span> <span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="nf" data-symbol-context="fibers" data-symbol-name="await">await</span><span class="o">([&](</span><span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-context="fibers" data-symbol-name="Promise">Promise</span><span class="o"><</span><span class="no">Response</span><span class="o">></span> <span class="no">promise</span><span class="o">)</span> <span class="o">{</span>
137 <span class="nf" data-symbol-name="asyncCall">asyncCall</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="o">[</span><span class="no">promise</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">promise</span><span class="o">)](</span><span class="no">Response</span> <span class="no">r</span><span class="o">)</span> <span class="no">mutable</span> <span class="o">{</span>
138 <span class="no">promise</span><span class="o">.</span><span class="nf" data-symbol-name="setValue">setValue</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">r</span><span class="o">));</span>
139 <span class="o">});</span>
140 <span class="o">});</span>
142 <span class="c">// Now response holds response returned by the async call</span>
143 <span class="o">...</span>
144 <span class="o">}</span></pre></div>
146 <p>Callback passed to <tt>fibers::await</tt> is executed immediately and then fiber-task is suspended until <tt>fibers::Promise</tt> is fulfilled. When <tt>fibers::Promise</tt> is fulfilled with a value or exception, fiber-task will be resumed and 'fibers::await' returns that value (or throws an exception, if exception was used to fulfill the <tt>Promise</tt>).</p>
148 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
149 <span class="o">...</span>
150 <span class="k">try</span> <span class="o">{</span>
151 <span class="no">auto</span> <span class="no">response</span> <span class="o">=</span> <span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="nf" data-symbol-context="fibers" data-symbol-name="await">await</span><span class="o">([&](</span><span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-context="fibers" data-symbol-name="Promise">Promise</span><span class="o"><</span><span class="no">Response</span><span class="o">></span> <span class="no">promise</span><span class="o">)</span> <span class="o">{</span>
152 <span class="nf" data-symbol-name="asyncCall">asyncCall</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="o">[</span><span class="no">promise</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">promise</span><span class="o">)](</span><span class="no">Response</span> <span class="no">r</span><span class="o">)</span> <span class="no">mutable</span> <span class="o">{</span>
153 <span class="no">promise</span><span class="o">.</span><span class="nf" data-symbol-name="setException">setException</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="runtime_error">runtime_error</span><span class="o">(</span><span class="s2">"Await will re-throw me"</span><span class="o">));</span>
154 <span class="o">});</span>
155 <span class="o">});</span>
156 <span class="nf" data-symbol-name="assert">assert</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span> <span class="c">// We should never get here</span>
157 <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc" data-symbol-name="const">const</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-name="exception">exception</span><span class="o">&</span> <span class="no">e</span><span class="o">)</span> <span class="o">{</span>
158 <span class="nf" data-symbol-name="assert">assert</span><span class="o">(</span><span class="no">e</span><span class="o">.</span><span class="nf" data-symbol-name="what">what</span><span class="o">()</span> <span class="o">==</span> <span class="s2">"Await will re-throw me"</span><span class="o">);</span>
159 <span class="o">}</span>
160 <span class="o">...</span>
161 <span class="o">}</span></pre></div>
163 <p>If <tt>fibers::Promise</tt> is not fulfilled, <tt>fibers::await</tt> will throw a <tt>std::logic_error</tt>.</p>
165 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
166 <span class="o">...</span>
167 <span class="k">try</span> <span class="o">{</span>
168 <span class="no">auto</span> <span class="no">response</span> <span class="o">=</span> <span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="nf" data-symbol-context="fibers" data-symbol-name="await">await</span><span class="o">([&](</span><span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-context="fibers" data-symbol-name="Promise">Promise</span><span class="o"><</span><span class="no">Response</span><span class="o">></span> <span class="no">promise</span><span class="o">)</span> <span class="o">{</span>
169 <span class="c">// We forget about the promise</span>
170 <span class="o">});</span>
171 <span class="nf" data-symbol-name="assert">assert</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span> <span class="c">// We should never get here</span>
172 <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc" data-symbol-name="const">const</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-name="logic_error">logic_error</span><span class="o">&</span> <span class="no">e</span><span class="o">)</span> <span class="o">{</span>
173 <span class="o">...</span>
174 <span class="o">}</span>
175 <span class="o">...</span>
176 <span class="o">}</span></pre></div>
178 <p>Please refer to <a href="https://github.com/facebook/folly/blob/master/folly/fibers/Promise.h" target="_blank">await</a> for more detailed documentation.</p>
180 <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> most of your code written with folly::fibers, won't be using <tt>fibers::Baton</tt> or <tt>fibers::await</tt>. These primitives should only be used to integrate with other asynchronous API which are not fibers-compatible.</div>
182 <h3 id="integrating-with-other-a-1">Integrating with other asynchronous APIs (folly::Future) <a href="#integrating-with-other-a-1" class="headerLink">#</a></h3>
184 <p>Let's say we have some existing library which provides a Future-based asynchronous API.</p>
186 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="Future">Future</span><span class="o"><</span><span class="no">Response</span><span class="o">></span> <span class="nf" data-symbol-name="asyncCallFuture">asyncCallFuture</span><span class="o">(</span><span class="no">Request</span> <span class="no">request</span><span class="o">);</span></pre></div>
188 <p>The good news are, <tt>folly::Future</tt> is already fibers-compatible. You can simply write:</p>
190 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
191 <span class="o">...</span>
192 <span class="no">auto</span> <span class="no">response</span> <span class="o">=</span> <span class="nf" data-symbol-name="asyncCallFuture">asyncCallFuture</span><span class="o">(</span><span class="no">request</span><span class="o">).</span><span class="nf" data-symbol-name="get">get</span><span class="o">();</span>
194 <span class="c">// Now response holds response returned by the async call</span>
195 <span class="o">...</span>
196 <span class="o">}</span></pre></div>
198 <p>Calling <tt>get()</tt> on a <tt>folly::Future</tt> object will only suspend the calling fiber-task. It won't block the system thread, letting it process other tasks.</p>
200 <h2 id="writing-code-with-folly">Writing code with folly::fibers <a href="#writing-code-with-folly" class="headerLink">#</a></h2>
202 <h3 id="building-fibers-compatib">Building fibers-compatible API <a href="#building-fibers-compatib" class="headerLink">#</a></h3>
204 <p>Following the explanations above we may wrap an existing asynchronous API in a function:</p>
206 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">Response</span> <span class="nf" data-symbol-name="fiberCall">fiberCall</span><span class="o">(</span><span class="no">Request</span> <span class="no">request</span><span class="o">)</span> <span class="o">{</span>
207 <span class="k">return</span> <span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="nf" data-symbol-context="fibers" data-symbol-name="await">await</span><span class="o">([&](</span><span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-context="fibers" data-symbol-name="Promise">Promise</span><span class="o"><</span><span class="no">Response</span><span class="o">></span> <span class="no">promise</span><span class="o">)</span> <span class="o">{</span>
208 <span class="nf" data-symbol-name="asyncCall">asyncCall</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="o">[</span><span class="no">promise</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">promise</span><span class="o">)](</span><span class="no">Response</span> <span class="no">r</span><span class="o">)</span> <span class="no">mutable</span> <span class="o">{</span>
209 <span class="no">promise</span><span class="o">.</span><span class="nf" data-symbol-name="setValue">setValue</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">r</span><span class="o">));</span>
210 <span class="o">});</span>
211 <span class="o">});</span>
212 <span class="o">}</span></pre></div>
214 <p>We can then call it from a fiber-task:</p>
216 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
217 <span class="o">...</span>
218 <span class="no">auto</span> <span class="no">response</span> <span class="o">=</span> <span class="nf" data-symbol-name="fiberCall">fiberCall</span><span class="o">(</span><span class="no">request</span><span class="o">);</span>
219 <span class="o">...</span>
220 <span class="o">});</span></pre></div>
222 <p>But what happens if we just call <tt>fiberCall</tt> not from within a fiber-task, but directly from a system thread ? Here another important feature of <tt>fibers::Baton</tt> (and thus all other folly::fibers synchronization primitives built on top of it) comes into play. Calling <tt>wait()</tt> on a <tt>fibers::Baton</tt> within a system thread context just blocks the thread until <tt>post()</tt> is called on the same <tt>folly::Baton</tt>.</p>
224 <p>What this means is that you no longer need to write separate code for synchronous and asynchronous APIs. If you use only folly::fibers synchronization primitives for all blocking calls inside of your synchronous function, it automatically becomes asynchronous when run inside a fiber-task.</p>
226 <h3 id="passing-by-reference">Passing by reference <a href="#passing-by-reference" class="headerLink">#</a></h3>
228 <p>Classic asynchronous APIs (same applies to folly::Future-based APIs) generally rely on copying/moving-in input arguments and often require you to copy/move in some context variables into the callback. E.g.:</p>
230 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">...</span>
231 <span class="no">Context</span> <span class="no">context</span><span class="o">;</span>
233 <span class="nf" data-symbol-name="asyncCall">asyncCall</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="o">[</span><span class="no">request</span><span class="o">,</span> <span class="no">context</span><span class="o">](</span><span class="no">Response</span> <span class="no">response</span><span class="o">)</span> <span class="no">mutable</span> <span class="o">{</span>
234 <span class="nf" data-symbol-name="doSomething">doSomething</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="no">response</span><span class="o">,</span> <span class="no">context</span><span class="o">);</span>
235 <span class="o">});</span>
236 <span class="o">...</span></pre></div>
238 <p>Fibers-compatible APIs look more like synchronous APIs, so you can actually pass input arguments by reference and you don't have to think about passing context at all. E.g.</p>
240 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
241 <span class="o">...</span>
242 <span class="no">Context</span> <span class="no">context</span><span class="o">;</span>
244 <span class="no">auto</span> <span class="no">response</span> <span class="o">=</span> <span class="nf" data-symbol-name="fiberCall">fiberCall</span><span class="o">(</span><span class="no">request</span><span class="o">);</span>
246 <span class="nf" data-symbol-name="doSomething">doSomething</span><span class="o">(</span><span class="no">request</span><span class="o">,</span> <span class="no">response</span><span class="o">,</span> <span class="no">context</span><span class="o">);</span>
247 <span class="o">...</span>
248 <span class="o">});</span></pre></div>
250 <p>Same logic applies to <tt>fibers::await</tt>. Since <tt>fibers::await</tt> call blocks until promise is fulfilled, it's safe to pass everything by reference.</p>
252 <h3 id="limited-stack-space">Limited stack space <a href="#limited-stack-space" class="headerLink">#</a></h3>
254 <p>So should you just run all the code inside a fiber-task ? No exactly.</p>
256 <p>Similarly to system threads, every fiber-task has some stack space assigned to it. Stack usage goes up with the number of nested function calls and objects allocated on the stack. folly::fibers implementation only supports fiber-tasks with fixed stack size. If you want to have many fiber-tasks running concurrently - you need to reduce the amount of stack assigned to each fiber-task, otherwise you may run out of memory.</p>
258 <div class="remarkup-important"><span class="remarkup-note-word">IMPORTANT:</span> If a fiber-task runs out of stack space (e.g. calls a function which does a lot of stack allocations) you program will fail.</div>
260 <p>However if you know that some function never suspends a fiber-task, you can use <tt>fibers::runInMainContext</tt> to safely call it from a fiber-task, without any risk of running out of stack space of the fiber-task.</p>
262 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">Result</span> <span class="nf" data-symbol-name="useALotOfStack">useALotOfStack</span><span class="o">()</span> <span class="o">{</span>
263 <span class="no">char</span> <span class="no">buffer</span><span class="o">[</span><span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span><span class="o">];</span>
264 <span class="o">...</span>
265 <span class="o">}</span>
267 <span class="o">...</span>
268 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
269 <span class="o">...</span>
270 <span class="no">auto</span> <span class="no">result</span> <span class="o">=</span> <span class="nc" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="nf" data-symbol-context="fibers" data-symbol-name="runInMainContext">runInMainContext</span><span class="o">([&]()</span> <span class="o">{</span>
271 <span class="k">return</span> <span class="nf" data-symbol-name="useALotOfStack">useALotOfStack</span><span class="o">();</span>
272 <span class="o">});</span>
273 <span class="o">...</span>
274 <span class="o">});</span>
275 <span class="o">...</span></pre></div>
277 <p><tt>fibers::runInMainContext</tt> will switch to the stack of the system thread (main context), run the functor passed to it and then switch back to the fiber-task stack.</p>
279 <div class="remarkup-important"><span class="remarkup-note-word">IMPORTANT:</span> Make sure you don't do any blocking calls on main context though. It will suspend the whole system thread, not just the fiber-task which was running.</div>
281 <p>Remember that it's fine to use <tt>fibers::runInMainContext</tt> in general purpose functions (those which may be called both from fiber-task and non from fiber-task). When called in non-fiber-task context <tt>fibers::runInMainContext</tt> would simply execute passed functor right away.</p>
283 <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> Besides <tt>fibers::runInMainContext</tt> some other functions in folly::fibers are also executing some of the passed functors on the main context. E.g. functor passes to <tt>fibers::await</tt> is executed on main context, finally-functor passed to <tt>FiberManager::addTaskFinally</tt> is also executed on main context etc. Relying on this can help you avoid extra <tt>fibers::runInMainContext</tt> calls (and avoid extra context switches).</div>
285 <h3 id="using-locks">Using locks <a href="#using-locks" class="headerLink">#</a></h3>
287 <p>Consider the following example:</p>
289 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">...</span>
290 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="EventBase">EventBase</span> <span class="no">evb</span><span class="o">;</span>
291 <span class="no">auto</span><span class="o">&</span> <span class="no">fiberManager</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="getFiberManager">getFiberManager</span><span class="o">(</span><span class="no">evb</span><span class="o">);</span>
292 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="mutex">mutex</span> <span class="no">lock</span><span class="o">;</span>
293 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Baton">Baton</span> <span class="no">baton</span><span class="o">;</span>
295 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([&]()</span> <span class="o">{</span>
296 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="lock_guard">lock_guard</span><span class="o"><</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="mutex">mutex</span><span class="o">></span> <span class="nf" data-symbol-name="lg">lg</span><span class="o">(</span><span class="no">lock</span><span class="o">);</span>
297 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="wait">wait</span><span class="o">();</span>
298 <span class="o">});</span>
300 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([&]()</span> <span class="o">{</span>
301 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="lock_guard">lock_guard</span><span class="o"><</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="mutex">mutex</span><span class="o">></span> <span class="nf" data-symbol-name="lg">lg</span><span class="o">(</span><span class="no">lock</span><span class="o">);</span>
302 <span class="o">});</span>
304 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loop">loop</span><span class="o">();</span>
305 <span class="c">// We won't get here :(</span>
306 <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="post">post</span><span class="o">();</span>
307 <span class="o">...</span></pre></div>
309 <p>First fiber-task will grab a lock and then suspend waiting on a <tt>fibers::Baton</tt>. Then second fiber-task will be run and it will try to grab a lock. Unlike system threads, fiber-task can be only suspended explicitly, so the whole system thread will be blocked waiting on the lock, and we end up with a dead-lock.</p>
311 <p>There're generally two ways we can solve this problem. Ideally we would re-design the program to never not hold any locks when fiber-task is suspended. However if we are absolutely sure we need that lock - folly::fibers library provides some fiber-task-aware lock implementations (e.g.
312 <a href="https://github.com/facebook/folly/blob/master/folly/fibers/TimedMutex.h" target="_blank">TimedMutex</a>).</p></section><section class="dex_document"><h1>APIs</h1><p class="dex_introduction"></p><h2 id="fibers-baton">fibers::Baton <a href="#fibers-baton" class="headerLink">#</a></h2>
314 <p>All of the features of folly::fibers library are actually built on top a single synchronization primitive called Baton. <tt>fibers::Baton</tt> is a fiber-specific version of <tt>folly::Baton</tt>. It only supports two basic operations: <tt>wait()</tt> and <tt>post()</tt>. Whenever <tt>wait()</tt> is called on the Baton, the current thread or fiber-task is suspended, until <tt>post()</tt> is called on the same Baton. <tt>wait()</tt> does not suspend the thread or fiber-task if <tt>post()</tt> was already called on the Baton. Please refer to <a href="https://github.com/facebook/folly/blob/master/folly/fibers/Baton.h" target="_blank">Baton</a> for more detailed documentation.</p>
316 <p>Baton is thread-safe, so <tt>wait()</tt> and <tt>post()</tt> can be (and should be :) ) called from different threads or fiber-tasks.</p>
318 <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> Because Baton transparently works both on threads and fiber-tasks, any synchronization primitive built using it would have the same property. This means that any library with a synchronous API, which uses only <tt>fibers::Baton</tt> for synchronization, becomes asynchronous when used in fiber context.</div>
320 <h3 id="timed-wait">timed_wait() <a href="#timed-wait" class="headerLink">#</a></h3>
322 <p><tt>fibers::Baton</tt> also supports wait with timeout.</p>
324 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([=]()</span> <span class="o">{</span>
325 <span class="no">auto</span> <span class="no">baton</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="make_shared">make_shared</span><span class="o"><</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Baton">Baton</span><span class="o">>();</span>
326 <span class="no">auto</span> <span class="no">result</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="make_shared">make_shared</span><span class="o"><</span><span class="no">Result</span><span class="o">>();</span>
328 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([=]()</span> <span class="o">{</span>
329 <span class="o">*</span><span class="no">result</span> <span class="o">=</span> <span class="nf" data-symbol-name="sendRequest">sendRequest</span><span class="o">(...);</span>
330 <span class="no">baton</span><span class="o">-></span><span class="na" data-symbol-name="post">post</span><span class="o">();</span>
331 <span class="o">});</span>
333 <span class="no">bool</span> <span class="no">success</span> <span class="o">=</span> <span class="no">baton</span><span class="o">.</span><span class="nf" data-symbol-name="timed_wait">timed_wait</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="chrono">chrono</span><span class="o">::</span><span class="na" data-symbol-name="milliseconds">milliseconds</span><span class="o">{</span><span class="mi">10</span><span class="o">});</span>
334 <span class="k">if</span> <span class="o">(</span><span class="no">success</span><span class="o">)</span> <span class="o">{</span>
335 <span class="c">// request successful</span>
336 <span class="o">...</span>
337 <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
338 <span class="c">// handle timeout</span>
339 <span class="o">...</span>
340 <span class="o">}</span>
341 <span class="o">});</span></pre></div>
343 <div class="remarkup-important"><span class="remarkup-note-word">IMPORTANT:</span> unlike <tt>wait()</tt> when using <tt>timed_wait()</tt> API it's generally not safe to pass <tt>fibers::Baton</tt> by reference. You have to make sure that task, which fulfills the Baton is either cancelled in case of timeout, or have shared ownership for the Baton.</div>
345 <h2 id="task-creation">Task creation <a href="#task-creation" class="headerLink">#</a></h2>
347 <h3 id="addtask-addtaskremote">addTask() / addTaskRemote() <a href="#addtask-addtaskremote" class="headerLink">#</a></h3>
349 <p>As you could see from previous examples, the easiest way to create a new fiber-task is to call <tt>addTask()</tt>:</p>
351 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
352 <span class="o">...</span>
353 <span class="o">});</span></pre></div>
355 <p>It is important to remember that <tt>addTask()</tt> is not thread-safe. I.e. it can only be safely called from the the thread, which is running the <tt>folly::FiberManager</tt> loop.</p>
357 <p>If you need to create a fiber-task from a different thread, you have to use <tt>addTaskRemote()</tt>:</p>
359 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="EventBase">EventBase</span> <span class="no">evb</span><span class="o">;</span>
360 <span class="no">auto</span><span class="o">&</span> <span class="no">fiberManager</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="getFiberManager">getFiberManager</span><span class="o">(</span><span class="no">evb</span><span class="o">);</span>
362 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="thread">thread</span> <span class="nf" data-symbol-name="t">t</span><span class="o">([&]()</span> <span class="o">{</span>
363 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTaskRemote">addTaskRemote</span><span class="o">([]()</span> <span class="o">{</span>
364 <span class="o">...</span>
365 <span class="o">});</span>
366 <span class="o">});</span>
368 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loopForever">loopForever</span><span class="o">();</span></pre></div>
370 <h3 id="addtaskfinally">addTaskFinally() <a href="#addtaskfinally" class="headerLink">#</a></h3>
372 <p><tt>addTaskFinally()</tt> is useful when you need to run some code on the main context in the end of a fiber-task.</p>
374 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTaskFinally">addTaskFinally</span><span class="o">(</span>
375 <span class="o">[=]()</span> <span class="o">{</span>
376 <span class="o">...</span>
377 <span class="k">return</span> <span class="no">result</span><span class="o">;</span>
378 <span class="o">},</span>
379 <span class="o">[=](</span><span class="no">Result</span><span class="o">&&</span> <span class="no">result</span><span class="o">)</span> <span class="o">{</span>
380 <span class="nf" data-symbol-name="callUserCallbacks">callUserCallbacks</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">result</span><span class="o">),</span> <span class="o">...)</span>
381 <span class="o">}</span>
382 <span class="o">);</span></pre></div>
384 <p>Of course you could achieve the same by calling <tt>fibers::runInMainContext()</tt>, but <tt>addTaskFinally()</tt> reduces the number of fiber context switches:</p>
386 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([=]()</span> <span class="o">{</span>
387 <span class="o">...</span>
388 <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="runInMainContext">runInMainContext</span><span class="o">([&]()</span> <span class="o">{</span>
389 <span class="c">// Switched to main context</span>
390 <span class="nf" data-symbol-name="callUserCallbacks">callUserCallbacks</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="nf" data-symbol-context="std" data-symbol-name="move">move</span><span class="o">(</span><span class="no">result</span><span class="o">),</span> <span class="o">...)</span>
391 <span class="o">}</span>
392 <span class="c">// Switched back to fiber context</span>
394 <span class="c">// On fiber context we realize there's no more work to be done.</span>
395 <span class="c">// Fiber-task is complete, switching back to main context.</span>
396 <span class="o">});</span></pre></div>
400 <h3 id="addtaskfuture-addtaskrem">addTaskFuture() / addTaskRemoteFuture() <a href="#addtaskfuture-addtaskrem" class="headerLink">#</a></h3>
402 <p><tt>addTask()</tt> and <tt>addTaskRemote()</tt> are creating detached fiber-tasks. If you need to know when fiber-task is complete and/or have some return value for it - <tt>addTaskFuture()</tt> / <tt>addTaskRemoteFuture()</tt> can be used.</p>
404 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="EventBase">EventBase</span> <span class="no">evb</span><span class="o">;</span>
405 <span class="no">auto</span><span class="o">&</span> <span class="no">fiberManager</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="getFiberManager">getFiberManager</span><span class="o">(</span><span class="no">evb</span><span class="o">);</span>
407 <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="thread">thread</span> <span class="nf" data-symbol-name="t">t</span><span class="o">([&]()</span> <span class="o">{</span>
408 <span class="no">auto</span> <span class="no">future1</span> <span class="o">=</span> <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTaskRemoteFuture">addTaskRemoteFuture</span><span class="o">([]()</span> <span class="o">{</span>
409 <span class="o">...</span>
410 <span class="o">});</span>
411 <span class="no">auto</span> <span class="no">future2</span> <span class="o">=</span> <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTaskRemoteFuture">addTaskRemoteFuture</span><span class="o">([]()</span> <span class="o">{</span>
412 <span class="o">...</span>
413 <span class="o">});</span>
415 <span class="no">auto</span> <span class="no">result1</span> <span class="o">=</span> <span class="no">future1</span><span class="o">.</span><span class="nf" data-symbol-name="get">get</span><span class="o">();</span>
416 <span class="no">auto</span> <span class="no">result2</span> <span class="o">=</span> <span class="no">future2</span><span class="o">.</span><span class="nf" data-symbol-name="get">get</span><span class="o">();</span>
417 <span class="o">...</span>
418 <span class="o">});</span>
420 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loopForever">loopForever</span><span class="o">();</span></pre></div>
422 <h2 id="other-synchronization-pr">Other synchronization primitives <a href="#other-synchronization-pr" class="headerLink">#</a></h2>
424 <p>All the listed synchronization primitives are built using <tt>fiber::Baton</tt>. Please check their source code for detailed documentation.</p>
426 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/Promise.h" target="_blank">await</a></p>
428 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/WhenN.h" target="_blank">collectN</a></p>
430 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/WhenN.h" target="_blank">collectAll</a></p>
432 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/WhenN.h" target="_blank">collectAny</a></p>
434 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/ForEach.h" target="_blank">forEach</a></p>
436 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/AddTasks.h" target="_blank">addTasks</a></p>
438 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/TimedMutex.h" target="_blank">TimedMutex</a></p>
440 <p><a href="https://github.com/facebook/folly/blob/master/folly/fibers/TimedMutex.h" target="_blank">TimedRWMutex</a></p></section><section class="dex_document"><h1>Fiber stacks</h1><p class="dex_introduction"></p><p>Similarly to system threads, every fiber-task has some stack space assigned to it. Stack usage goes up with the number of nested function calls and objects allocated on the stack. folly::fibers implementation only supports fiber-tasks with fixed stack size. If you want to have many fiber-tasks running concurrently - you need to reduce the amount of stack assigned to each fiber-task, otherwise you may run out of memory.</p>
442 <h3 id="selecting-stack-size">Selecting stack size <a href="#selecting-stack-size" class="headerLink">#</a></h3>
444 <p>Stack size used for every fiber-task is part of FiberManager configuration. But how do you pick the right stack size ?</p>
446 <p>First of all you need to figure out the maximum number of concurrent fiber-tasks your application may have. E.g. if you are writing a Thrift-service you will probably have a single fiber-task for every request in-fly (but remember that e.g. <tt>fibers::collectAll</tt> and some other synchronization primitives may create extra fiber-tasks). It's very important to get that number first, because if you will at most need 100 concurrent fiber-tasks, even 1MB stacks will result in at most 100MB used for fiber stacks. On the other hand if you need to have 100,000 concurrent fiber-tasks, even 16KB stacks will result in 1.6GB peak memory usage just for fiber stacks.</p>
448 <p>folly::fibers also supports recording stack usage (it can be enabled via <tt>recordStackEvery</tt> option of <tt>FiberManager</tt>). When enabled, the stack of each fiber-task will be filled with magic values. Later linear search can be performed to find the boundary of unused stack space.</p>
450 <h3 id="stack-overflow-detection">Stack overflow detection <a href="#stack-overflow-detection" class="headerLink">#</a></h3>
452 <p>By default every fiber-task stack is allocated with a special guard page next to it (this can be controlled via <tt>useGuardPages</tt> option of <tt>FiberManager</tt>). If a stack overflow happens - this guard page will be accessed, which will result in immediate segmentation fault.</p>
454 <div class="remarkup-important"><span class="remarkup-note-word">IMPORTANT:</span> disabling guard page protection may result in unnoticed stack overflows. Those will inevitably cause memory corruptions, which are usually very hard to debug.</div></section><section class="dex_document"><h1>Event Loops</h1><p class="dex_introduction"></p><p>folly::fibers library doesn't implement it's own event system. Instead it allows <tt>fibers::FiberManager</tt> to work with any other event system by implementing <tt>fibers::LoopController</tt> interface.</p>
456 <h2 id="folly-eventbase-integrat">folly::EventBase integration <a href="#folly-eventbase-integrat" class="headerLink">#</a></h2>
458 <p>The easiest way to create a <tt>fibers::FiberManager</tt> attached to a <tt>folly::EventBase</tt> is by using <tt>fibers::getFiberManager</tt> function:</p>
460 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="EventBase">EventBase</span> <span class="no">evb</span><span class="o">;</span>
461 <span class="no">auto</span><span class="o">&</span> <span class="no">fiberManager</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="getFiberManager">getFiberManager</span><span class="o">(</span><span class="no">evb</span><span class="o">);</span>
463 <span class="no">fiberManager</span><span class="o">.</span><span class="nf" data-symbol-name="addTask">addTask</span><span class="o">([]()</span> <span class="o">{</span>
464 <span class="o">...</span>
465 <span class="o">});</span>
467 <span class="no">evb</span><span class="o">.</span><span class="nf" data-symbol-name="loop">loop</span><span class="o">();</span></pre></div>
469 <p>Such <tt>fibers::FiberManager</tt> will be automatically destroyed, when <tt>folly::EventBase</tt> is destroyed.</p>
471 <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> folly::fibers doesn't support killing fiber-tasks in-flight (for similar reasons you can't kill a thread). If <tt>fibers::FiberManager</tt> has any outstanding fiber-tasks, when <tt>folly::EventBase</tt> is being destroyed, it will keep running the event loop until all those tasks are finished.</div></section><section class="dex_document"><h1>GDB integration</h1><p class="dex_introduction"></p><p>folly::fibers provides some GDB extensions which can be very useful for debugging. To load them simply run the following in GDB console:</p>
473 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">fbload</span> <span class="no">folly_fibers</span></pre></div>
475 <h3 id="find-all-fibermanagers">Find all FiberManagers <a href="#find-all-fibermanagers" class="headerLink">#</a></h3>
477 <p>You can use <tt>$get_fiber_manager_map_evb()</tt> and <tt>$get_fiber_manager_map_vevb()</tt> to get <tt>folly::EventBase</tt> => <tt>fibers::FiberManager</tt> and <tt>folly::VirtualEventBase</tt> => <tt>fibers::FiberManager</tt> mappings respectively:</p>
479 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">fbload</span> <span class="nf" data-symbol-name="stl">stl</span>
480 <span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">p</span> <span class="nv">$get_fiber_manager_map_evb</span><span class="o">()</span>
481 $<span class="mi">2</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="unordered_map">unordered_map</span> <span class="no">with</span> <span class="mi">2</span> <span class="no">elements</span> <span class="o">=</span> <span class="o">{</span>
482 <span class="o">[</span><span class="mh">0x7fffffffda80</span><span class="o">]</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="unique_ptr">unique_ptr</span><span class="o"><</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="FiberManager">FiberManager</span><span class="o">></span> <span class="no">containing</span> <span class="mh">0x7ffff5c22a00</span><span class="o">,</span>
483 <span class="o">[</span><span class="mh">0x7fffffffd850</span><span class="o">]</span> <span class="o">=</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="unique_ptr">unique_ptr</span><span class="o"><</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="FiberManager">FiberManager</span><span class="o">></span> <span class="no">containing</span> <span class="mh">0x7ffff5c22800</span>
484 <span class="o">}</span></pre></div>
486 <p>This will only list <tt>fibers::FiberManager</tt>s created using <tt>fibers::getFiberManager()</tt> function.</p>
488 <h3 id="printing-a-fibermanager">Printing a FiberManager <a href="#printing-a-fibermanager" class="headerLink">#</a></h3>
490 <p>Given a pointer to a <tt>fibers::FiberManager</tt> you can get a list of all its active fibers:</p>
492 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">p</span> <span class="o">*((</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="FiberManager">FiberManager</span><span class="o">*)</span><span class="mh">0x7ffff5c22800</span><span class="o">)</span>
493 $<span class="mi">4</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="FiberManager">FiberManager</span> <span class="o">=</span> <span class="o">{</span>
494 <span class="mh">0x7ffff5d23380</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Fiber">Fiber</span> <span class="o">=</span> <span class="o">{</span>
495 <span class="no">state</span> <span class="o">=</span> <span class="no">Awaiting</span> <span class="no">immediate</span><span class="o">,</span>
496 <span class="no">backtrace</span> <span class="no">available</span> <span class="o">=</span> <span class="kc">true</span>
497 <span class="o">}</span>
498 <span class="o">}</span></pre></div>
500 <p><tt>fiber-print-limit</tt> command can be used to change the maximum number of fibers printed for a <tt>fibers::FiberManager</tt> (default value is 100).</p>
502 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">fiber</span><span class="o">-</span><span class="no">print</span><span class="o">-</span><span class="no">limit</span> <span class="mi">10</span>
503 <span class="k">New</span> <span class="nc" data-symbol-name="fiber">fiber</span> <span class="no">limit</span> <span class="k">for</span> <span class="no">FiberManager</span> <span class="no">printer</span> <span class="no">set</span> <span class="no">to</span> <span class="mi">10</span></pre></div>
505 <h3 id="printing-a-fiber-task">Printing a fiber-task <a href="#printing-a-fiber-task" class="headerLink">#</a></h3>
507 <p>Given a pointer to a <tt>fibers::Fiber</tt>, which is running some fiber-task, you can get its current state:</p>
509 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">p</span> <span class="o">*((</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Fiber">Fiber</span><span class="o">*)</span><span class="mh">0x7ffff5d23380</span><span class="o">)</span>
510 $<span class="mi">5</span> <span class="o">=</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Fiber">Fiber</span> <span class="o">=</span> <span class="o">{</span>
511 <span class="no">state</span> <span class="o">=</span> <span class="no">Awaiting</span> <span class="no">immediate</span><span class="o">,</span>
512 <span class="no">backtrace</span> <span class="no">available</span> <span class="o">=</span> <span class="kc">true</span>
513 <span class="o">}</span></pre></div>
515 <h3 id="activating-a-fiber-task">Activating a fiber-task <a href="#activating-a-fiber-task" class="headerLink">#</a></h3>
517 <p>Every <tt>fibers::Fiber</tt>, which is suspended (and so has its backtrace available), can be activated. To activate a fiber-task you can either use <tt>fiber</tt> GDB command, passing a <tt>fibers::Fiber</tt> pointer to it:</p>
519 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">fiber</span> <span class="mh">0x7ffff5d23380</span>
520 <span class="no">Fiber</span> <span class="mi">140737317581696</span> <span class="no">activated</span><span class="o">.</span> <span class="no">You</span> <span class="no">can</span> <span class="no">call</span> <span class="s1">'bt'</span> <span class="no">now</span><span class="o">.</span></pre></div>
522 <p>or simply call <tt>activate()</tt> on a <tt>fibers::Fiber</tt> object:</p>
524 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="nf" data-symbol-name="p">p</span> <span class="o">((</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="fibers">fibers</span><span class="o">::</span><span class="na" data-symbol-name="Fiber">Fiber</span><span class="o">*)</span><span class="mh">0x7ffff5d23380</span><span class="o">)-></span><span class="na" data-symbol-name="activate">activate</span><span class="o">()</span>
525 $<span class="mi">6</span> <span class="o">=</span> <span class="s2">"Fiber 0x7ffff5d23380 activated. You can call 'bt' now."</span></pre></div>
527 <p>Once fiber-task is activated you can explore its stack using <tt>bt</tt> and <tt>frame</tt> commands, just like a regular thread.</p>
529 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">bt</span>
530 <span class="c">#1 0x00000000005497e9 in folly::fibers::FiberImpl::deactivate() (this=0x7ffff5d233a0)</span>
531 <span class="no">at</span> <span class="no">buck</span><span class="o">-</span><span class="no">out</span><span class="o">/</span><span class="no">dbg</span><span class="o">/</span><span class="no">gen</span><span class="o">/</span><span class="no">folly</span><span class="o">/</span><span class="no">fibers</span><span class="o">/</span><span class="no">fibers_core</span><span class="c">#default,headers/folly/fibers/BoostContextCompatibility.h:105</span>
532 <span class="c">#2 0x000000000054996d in folly::fibers::FiberManager::deactivateFiber(folly::fibers::Fiber*) (this=0x7ffff5c22800, fiber=0x7ffff5d23380)</span>
533 <span class="no">at</span> <span class="no">buck</span><span class="o">-</span><span class="no">out</span><span class="o">/</span><span class="no">dbg</span><span class="o">/</span><span class="no">gen</span><span class="o">/</span><span class="no">folly</span><span class="o">/</span><span class="no">fibers</span><span class="o">/</span><span class="no">fibers_core</span><span class="c">#default,headers/folly/fibers/FiberManagerInternal-inl.h:103</span>
534 <span class="c">#3 0x0000000000548b91 in folly::fibers::Fiber::<lambda()>::operator()(void) (__closure=0x7ffff59ffb20) at folly/fibers/Fiber.cpp:175</span>
535 <span class="c">#4 0x0000000000548d78 in folly::fibers::Fiber::preempt(folly::fibers::Fiber::State) (this=0x7ffff5d23380, state=folly::fibers::Fiber::AWAITING_IMMEDIATE)</span>
536 <span class="no">at</span> <span class="no">folly</span><span class="o">/</span><span class="no">fibers</span><span class="o">/</span><span class="no">Fiber</span><span class="o">.</span><span class="no">cpp</span><span class="o">:</span><span class="mi">185</span>
537 <span class="c">#5 0x000000000043bcc6 in folly::fibers::FiberManager::runInMainContext<FiberManager_nestedFiberManagers_Test::TestBody()::<lambda()>::<lambda()> >(<unknown type in /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0x111bdb>) (this=0x7ffff5c22800, func=<unknown type in /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0x111bdb>)</span>
538 <span class="no">at</span> <span class="no">buck</span><span class="o">-</span><span class="no">out</span><span class="o">/</span><span class="no">dbg</span><span class="o">/</span><span class="no">gen</span><span class="o">/</span><span class="no">folly</span><span class="o">/</span><span class="no">fibers</span><span class="o">/</span><span class="no">fibers_core</span><span class="c">#default,headers/folly/fibers/FiberManagerInternal-inl.h:459</span>
539 <span class="c">#6 0x00000000004300f3 in folly::fibers::runInMainContext<FiberManager_nestedFiberManagers_Test::TestBody()::<lambda()>::<lambda()> >(<unknown type in /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0xf7caa>) (func=<unknown type in /mnt/fio0/andrii/fbsource/fbcode/buck-out/dbg/gen/folly/fibers/test/fibers_test, CU 0x31b, DIE 0xf7caa>)</span>
540 <span class="no">at</span> <span class="no">buck</span><span class="o">-</span><span class="no">out</span><span class="o">/</span><span class="no">dbg</span><span class="o">/</span><span class="no">gen</span><span class="o">/</span><span class="no">folly</span><span class="o">/</span><span class="no">fibers</span><span class="o">/</span><span class="no">fibers_core</span><span class="c">#default,headers/folly/fibers/FiberManagerInternal.h:551</span>
541 <span class="c">#7 0x0000000000422101 in FiberManager_nestedFiberManagers_Test::<lambda()>::operator()(void) const (__closure=0x7ffff5d23450)</span>
542 <span class="no">at</span> <span class="no">folly</span><span class="o">/</span><span class="no">fibers</span><span class="o">/</span><span class="no">test</span><span class="o">/</span><span class="no">FibersTest</span><span class="o">.</span><span class="no">cpp</span><span class="o">:</span><span class="mi">1537</span>
543 <span class="o">...</span></pre></div>
545 <p>To deactivate previously activated fiber-task and switch back to the stack of current thread simply use <tt>fiber-deactivate</tt> GDB command:</p>
547 <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="o">(</span><span class="no">gdb</span><span class="o">)</span> <span class="no">fiber</span><span class="o">-</span><span class="no">deactivate</span>
548 <span class="no">Fiber</span> <span class="no">de</span><span class="o">-</span><span class="no">activated</span><span class="o">.</span></pre></div>
550 <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> For running (i.e. not suspended) fiber-task, you can simply switch to the system thread which owns it and use regular GDB commands for debugging.</div></section></section>