base: use setjmp to speed up fiber
[gem5.git] / src / base / fiber.hh
index 5f7285b297551de2c9c7222aa3547fcef82f2004..be8937f18f6b23c2d8983c3e299854eb0d1fadc1 100644 (file)
@@ -23,8 +23,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabe Black
  */
 
 #ifndef __BASE_FIBER_HH__
 #include <ucontext.h>
 #endif
 
+// Avoid fortify source for longjmp to work between ucontext stacks.
+#pragma push_macro("__USE_FORTIFY_LEVEL")
+#undef __USE_FORTIFY_LEVEL
+#include <setjmp.h>
+#pragma pop_macro("__USE_FORTIFY_LEVEL")
+
 #include <cstddef>
 #include <cstdint>
 
+#include "config/have_valgrind.hh"
+
 /**
  * This class represents a fiber, which is a light weight sort of thread which
  * is cooperatively scheduled and runs sequentially with other fibers, swapping
 class Fiber
 {
   public:
+    /**
+     * @ingroup api_fiber
+     */
     const static size_t DefaultStackSize = 0x50000;
 
-    /// stack_size is the size of the stack available to this fiber.
-    /// link points to another fiber which will start executing when this
-    /// fiber's main function returns.
+    /**
+     * @param Link points to another fiber which will start executing when this
+     *     fiber's main function returns.
+     * @param stack_size is the size of the stack available to this fiber.
+     *
+     * @ingroup api_fiber
+     * @{
+     */
     Fiber(size_t stack_size=DefaultStackSize);
     Fiber(Fiber *link, size_t stack_size=DefaultStackSize);
+    /** @} */ // end of api_fiber
 
+    /**
+     * @ingroup api_fiber
+     */
     virtual ~Fiber();
 
-    /// Start executing the fiber represented by this object. This function
-    /// will "return" when the current fiber is switched back to later on.
+    /**
+     * Start executing the fiber represented by this object. This function
+     * will "return" when the current fiber is switched back to later on.
+     *
+     * @ingroup api_fiber
+     */
     void run();
 
-    /// Returns whether the "main" function of this fiber has finished.
-    ///
+    /**
+     * Returns whether the "main" function of this fiber has finished.
+     *
+     * @ingroup api_fiber
+     */
     bool finished() const { return _finished; };
 
-    /// Get a pointer to the current running Fiber.
-    ///
+    /**
+     * Returns whether the "main" function of this fiber has started.
+     *
+     * @ingroup api_fiber
+     */
+    bool started() const { return _started; };
+
+    /**
+     * Get a pointer to the current running Fiber.
+     *
+     * @ingroup api_fiber
+     */
     static Fiber *currentFiber();
-    /// Get a pointer to the primary Fiber.
-    /// This Fiber represents the thread of execution started by the OS, and
-    /// which has a Fiber attached to it after the fact.
+
+    /**
+     * Get a pointer to the primary Fiber.
+     * This Fiber represents the thread of execution started by the OS, and
+     * which has a Fiber attached to it after the fact.
+     *
+     * @ingroup api_fiber
+     */
     static Fiber *primaryFiber();
 
   protected:
-    /// This method is called when this fiber is first run. Override it to
-    /// give your fiber something to do. When main returns, the fiber will
-    /// mark itself as finished and switch to its link fiber.
+    /**
+     * This method is called when this fiber is first run. Override it to
+     * give your fiber something to do. When main returns, the fiber will
+     * mark itself as finished and switch to its link fiber.
+     */
     virtual void main() = 0;
 
-    void setStarted() { started = true; }
+    void setStarted() { _started = true; }
 
   private:
     static void entryTrampoline();
     void start();
 
     ucontext_t ctx;
+    // ucontext is slow in swapcontext. Here we use _setjmp/_longjmp to avoid
+    // the additional signals for speed up.
+    jmp_buf jmp;
+
     Fiber *link;
 
     // The stack for this context, or a nullptr if allocated elsewhere.
-    uint8_t *stack;
+    void *stack;
     size_t stackSize;
+    void *guardPage;
+    size_t guardPageSize;
+#if HAVE_VALGRIND
+    unsigned valgrindStackId;
+#endif
 
-    bool started;
+    bool _started;
     bool _finished;
     void createContext();
 };