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
3312846Sgiacomo.travaglini@arm.com// ucontext functions (like getcontext, setcontext etc) have been marked
3412846Sgiacomo.travaglini@arm.com// as deprecated and are hence hidden in latest macOS releases.
3512846Sgiacomo.travaglini@arm.com// By defining _XOPEN_SOURCE we make them available at compilation time.
3612846Sgiacomo.travaglini@arm.com#if defined(__APPLE__) && defined(__MACH__)
3712846Sgiacomo.travaglini@arm.com#define _XOPEN_SOURCE 600
3812787Sgabeblack@google.com#include <ucontext.h>
3912846Sgiacomo.travaglini@arm.com#undef _XOPEN_SOURCE
4012846Sgiacomo.travaglini@arm.com#else
4112846Sgiacomo.travaglini@arm.com#include <ucontext.h>
4212846Sgiacomo.travaglini@arm.com#endif
4312787Sgabeblack@google.com
4412787Sgabeblack@google.com#include <cstddef>
4512787Sgabeblack@google.com#include <cstdint>
4612787Sgabeblack@google.com
4712920Sgabeblack@google.com#include "config/have_valgrind.hh"
4812920Sgabeblack@google.com
4912787Sgabeblack@google.com/**
5012787Sgabeblack@google.com * This class represents a fiber, which is a light weight sort of thread which
5112787Sgabeblack@google.com * is cooperatively scheduled and runs sequentially with other fibers, swapping
5212787Sgabeblack@google.com * in and out of a single actual thread of execution.
5312787Sgabeblack@google.com *
5412787Sgabeblack@google.com * To define your own threads, create a subclass of Fiber and override its
5512787Sgabeblack@google.com * main() function to do what you want your fiber to do. You can start it by
5612787Sgabeblack@google.com * calling its run() method which will stop your execution and start the other
5712787Sgabeblack@google.com * fiber in your place.
5812787Sgabeblack@google.com *
5912787Sgabeblack@google.com * If your main() function ends, that fiber will automatically switch to either
6012787Sgabeblack@google.com * the primary fiber, or to a particular fiber you specified at construction
6112787Sgabeblack@google.com * time, and your fiber is considered finished.
6212787Sgabeblack@google.com */
6312787Sgabeblack@google.com
6412787Sgabeblack@google.comclass Fiber
6512787Sgabeblack@google.com{
6612787Sgabeblack@google.com  public:
6712787Sgabeblack@google.com    const static size_t DefaultStackSize = 0x50000;
6812787Sgabeblack@google.com
6912787Sgabeblack@google.com    /// stack_size is the size of the stack available to this fiber.
7012787Sgabeblack@google.com    /// link points to another fiber which will start executing when this
7112787Sgabeblack@google.com    /// fiber's main function returns.
7212787Sgabeblack@google.com    Fiber(size_t stack_size=DefaultStackSize);
7312787Sgabeblack@google.com    Fiber(Fiber *link, size_t stack_size=DefaultStackSize);
7412787Sgabeblack@google.com
7512787Sgabeblack@google.com    virtual ~Fiber();
7612787Sgabeblack@google.com
7712787Sgabeblack@google.com    /// Start executing the fiber represented by this object. This function
7812787Sgabeblack@google.com    /// will "return" when the current fiber is switched back to later on.
7912787Sgabeblack@google.com    void run();
8012787Sgabeblack@google.com
8112787Sgabeblack@google.com    /// Returns whether the "main" function of this fiber has finished.
8212787Sgabeblack@google.com    ///
8312787Sgabeblack@google.com    bool finished() const { return _finished; };
8412787Sgabeblack@google.com
8514042Sgiacomo.travaglini@arm.com    /// Returns whether the "main" function of this fiber has started.
8614042Sgiacomo.travaglini@arm.com    ///
8714042Sgiacomo.travaglini@arm.com    bool started() const { return _started; };
8814042Sgiacomo.travaglini@arm.com
8912787Sgabeblack@google.com    /// Get a pointer to the current running Fiber.
9012787Sgabeblack@google.com    ///
9112787Sgabeblack@google.com    static Fiber *currentFiber();
9212787Sgabeblack@google.com    /// Get a pointer to the primary Fiber.
9312787Sgabeblack@google.com    /// This Fiber represents the thread of execution started by the OS, and
9412787Sgabeblack@google.com    /// which has a Fiber attached to it after the fact.
9512787Sgabeblack@google.com    static Fiber *primaryFiber();
9612787Sgabeblack@google.com
9712787Sgabeblack@google.com  protected:
9812787Sgabeblack@google.com    /// This method is called when this fiber is first run. Override it to
9912787Sgabeblack@google.com    /// give your fiber something to do. When main returns, the fiber will
10012787Sgabeblack@google.com    /// mark itself as finished and switch to its link fiber.
10112787Sgabeblack@google.com    virtual void main() = 0;
10212787Sgabeblack@google.com
10314042Sgiacomo.travaglini@arm.com    void setStarted() { _started = true; }
10412787Sgabeblack@google.com
10512787Sgabeblack@google.com  private:
10612787Sgabeblack@google.com    static void entryTrampoline();
10712787Sgabeblack@google.com    void start();
10812787Sgabeblack@google.com
10912787Sgabeblack@google.com    ucontext_t ctx;
11012787Sgabeblack@google.com    Fiber *link;
11112787Sgabeblack@google.com
11212787Sgabeblack@google.com    // The stack for this context, or a nullptr if allocated elsewhere.
11313435Sgabeblack@google.com    void *stack;
11412787Sgabeblack@google.com    size_t stackSize;
11513435Sgabeblack@google.com    void *guardPage;
11613435Sgabeblack@google.com    size_t guardPageSize;
11712920Sgabeblack@google.com#if HAVE_VALGRIND
11812920Sgabeblack@google.com    unsigned valgrindStackId;
11912920Sgabeblack@google.com#endif
12012787Sgabeblack@google.com
12114042Sgiacomo.travaglini@arm.com    bool _started;
12212787Sgabeblack@google.com    bool _finished;
12312787Sgabeblack@google.com    void createContext();
12412787Sgabeblack@google.com};
12512787Sgabeblack@google.com
12612787Sgabeblack@google.com#endif // __BASE_FIBER_HH__
127