fiber.hh revision 12787
112787Sgabeblack@google.com/*
212787Sgabeblack@google.com * Copyright 2018 Google, Inc.
312787Sgabeblack@google.com *
412787Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
512787Sgabeblack@google.com * modification, are permitted provided that the following conditions are
612787Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
712787Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
812787Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
912787Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1012787Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1112787Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1212787Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1312787Sgabeblack@google.com * this software without specific prior written permission.
1412787Sgabeblack@google.com *
1512787Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612787Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712787Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812787Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912787Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012787Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112787Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212787Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312787Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412787Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512787Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612787Sgabeblack@google.com *
2712787Sgabeblack@google.com * Authors: Gabe Black
2812787Sgabeblack@google.com */
2912787Sgabeblack@google.com
3012787Sgabeblack@google.com#ifndef __BASE_FIBER_HH__
3112787Sgabeblack@google.com#define __BASE_FIBER_HH__
3212787Sgabeblack@google.com
3312787Sgabeblack@google.com#include <ucontext.h>
3412787Sgabeblack@google.com
3512787Sgabeblack@google.com#include <cstddef>
3612787Sgabeblack@google.com#include <cstdint>
3712787Sgabeblack@google.com
3812787Sgabeblack@google.com/**
3912787Sgabeblack@google.com * This class represents a fiber, which is a light weight sort of thread which
4012787Sgabeblack@google.com * is cooperatively scheduled and runs sequentially with other fibers, swapping
4112787Sgabeblack@google.com * in and out of a single actual thread of execution.
4212787Sgabeblack@google.com *
4312787Sgabeblack@google.com * To define your own threads, create a subclass of Fiber and override its
4412787Sgabeblack@google.com * main() function to do what you want your fiber to do. You can start it by
4512787Sgabeblack@google.com * calling its run() method which will stop your execution and start the other
4612787Sgabeblack@google.com * fiber in your place.
4712787Sgabeblack@google.com *
4812787Sgabeblack@google.com * If your main() function ends, that fiber will automatically switch to either
4912787Sgabeblack@google.com * the primary fiber, or to a particular fiber you specified at construction
5012787Sgabeblack@google.com * time, and your fiber is considered finished.
5112787Sgabeblack@google.com */
5212787Sgabeblack@google.com
5312787Sgabeblack@google.comclass Fiber
5412787Sgabeblack@google.com{
5512787Sgabeblack@google.com  public:
5612787Sgabeblack@google.com    const static size_t DefaultStackSize = 0x50000;
5712787Sgabeblack@google.com
5812787Sgabeblack@google.com    /// stack_size is the size of the stack available to this fiber.
5912787Sgabeblack@google.com    /// link points to another fiber which will start executing when this
6012787Sgabeblack@google.com    /// fiber's main function returns.
6112787Sgabeblack@google.com    Fiber(size_t stack_size=DefaultStackSize);
6212787Sgabeblack@google.com    Fiber(Fiber *link, size_t stack_size=DefaultStackSize);
6312787Sgabeblack@google.com
6412787Sgabeblack@google.com    virtual ~Fiber();
6512787Sgabeblack@google.com
6612787Sgabeblack@google.com    /// Start executing the fiber represented by this object. This function
6712787Sgabeblack@google.com    /// will "return" when the current fiber is switched back to later on.
6812787Sgabeblack@google.com    void run();
6912787Sgabeblack@google.com
7012787Sgabeblack@google.com    /// Returns whether the "main" function of this fiber has finished.
7112787Sgabeblack@google.com    ///
7212787Sgabeblack@google.com    bool finished() const { return _finished; };
7312787Sgabeblack@google.com
7412787Sgabeblack@google.com    /// Get a pointer to the current running Fiber.
7512787Sgabeblack@google.com    ///
7612787Sgabeblack@google.com    static Fiber *currentFiber();
7712787Sgabeblack@google.com    /// Get a pointer to the primary Fiber.
7812787Sgabeblack@google.com    /// This Fiber represents the thread of execution started by the OS, and
7912787Sgabeblack@google.com    /// which has a Fiber attached to it after the fact.
8012787Sgabeblack@google.com    static Fiber *primaryFiber();
8112787Sgabeblack@google.com
8212787Sgabeblack@google.com  protected:
8312787Sgabeblack@google.com    /// This method is called when this fiber is first run. Override it to
8412787Sgabeblack@google.com    /// give your fiber something to do. When main returns, the fiber will
8512787Sgabeblack@google.com    /// mark itself as finished and switch to its link fiber.
8612787Sgabeblack@google.com    virtual void main() = 0;
8712787Sgabeblack@google.com
8812787Sgabeblack@google.com    void setStarted() { started = true; }
8912787Sgabeblack@google.com
9012787Sgabeblack@google.com  private:
9112787Sgabeblack@google.com    static void entryTrampoline();
9212787Sgabeblack@google.com    void start();
9312787Sgabeblack@google.com
9412787Sgabeblack@google.com    ucontext_t ctx;
9512787Sgabeblack@google.com    Fiber *link;
9612787Sgabeblack@google.com
9712787Sgabeblack@google.com    // The stack for this context, or a nullptr if allocated elsewhere.
9812787Sgabeblack@google.com    uint8_t *stack;
9912787Sgabeblack@google.com    size_t stackSize;
10012787Sgabeblack@google.com
10112787Sgabeblack@google.com    bool started;
10212787Sgabeblack@google.com    bool _finished;
10312787Sgabeblack@google.com    void createContext();
10412787Sgabeblack@google.com};
10512787Sgabeblack@google.com
10612787Sgabeblack@google.com#endif // __BASE_FIBER_HH__
107