1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include "base/fiber.hh" 31
| 1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include "base/fiber.hh" 31
|
| 32#if HAVE_VALGRIND 33#include <valgrind/valgrind.h> 34#endif 35
|
32#include <cerrno> 33#include <cstring> 34 35#include "base/logging.hh" 36 37using namespace std; 38 39namespace 40{ 41 42/* 43 * The PrimaryFiber class is a special case that attaches to the currently 44 * executing context. That makes handling the "primary" fiber, aka the one 45 * which most of gem5 is running under, no different than other Fibers. 46 */ 47class PrimaryFiber : public Fiber 48{ 49 public: 50 PrimaryFiber() : Fiber(nullptr, 0) { setStarted(); } 51 void main() { panic("PrimaryFiber main executed.\n"); } 52}; 53 54PrimaryFiber _primaryFiber; 55 56// A pointer to whatever the currently executing Fiber is. 57Fiber *_currentFiber = &_primaryFiber; 58 59// A pointer to the Fiber which is currently being started/initialized. 60Fiber *startingFiber = nullptr; 61 62} // anonymous namespace 63 64void 65Fiber::entryTrampoline() 66{ 67 startingFiber->start(); 68} 69 70Fiber::Fiber(size_t stack_size) : 71 link(primaryFiber()), 72 stack(stack_size ? new uint8_t[stack_size] : nullptr), 73 stackSize(stack_size), started(false), _finished(false)
| 36#include <cerrno> 37#include <cstring> 38 39#include "base/logging.hh" 40 41using namespace std; 42 43namespace 44{ 45 46/* 47 * The PrimaryFiber class is a special case that attaches to the currently 48 * executing context. That makes handling the "primary" fiber, aka the one 49 * which most of gem5 is running under, no different than other Fibers. 50 */ 51class PrimaryFiber : public Fiber 52{ 53 public: 54 PrimaryFiber() : Fiber(nullptr, 0) { setStarted(); } 55 void main() { panic("PrimaryFiber main executed.\n"); } 56}; 57 58PrimaryFiber _primaryFiber; 59 60// A pointer to whatever the currently executing Fiber is. 61Fiber *_currentFiber = &_primaryFiber; 62 63// A pointer to the Fiber which is currently being started/initialized. 64Fiber *startingFiber = nullptr; 65 66} // anonymous namespace 67 68void 69Fiber::entryTrampoline() 70{ 71 startingFiber->start(); 72} 73 74Fiber::Fiber(size_t stack_size) : 75 link(primaryFiber()), 76 stack(stack_size ? new uint8_t[stack_size] : nullptr), 77 stackSize(stack_size), started(false), _finished(false)
|
74{}
| 78{ 79#if HAVE_VALGRIND 80 valgrindStackId = VALGRIND_STACK_REGISTER(stack, stack + stack_size); 81#endif 82}
|
75 76Fiber::Fiber(Fiber *link, size_t stack_size) : 77 link(link), stack(stack_size ? new uint8_t[stack_size] : nullptr), 78 stackSize(stack_size), started(false), _finished(false) 79{} 80 81Fiber::~Fiber() 82{ 83 panic_if(stack && _currentFiber == this, "Fiber stack is in use.");
| 83 84Fiber::Fiber(Fiber *link, size_t stack_size) : 85 link(link), stack(stack_size ? new uint8_t[stack_size] : nullptr), 86 stackSize(stack_size), started(false), _finished(false) 87{} 88 89Fiber::~Fiber() 90{ 91 panic_if(stack && _currentFiber == this, "Fiber stack is in use.");
|
| 92#if HAVE_VALGRIND 93 VALGRIND_STACK_DEREGISTER(valgrindStackId); 94#endif
|
84 delete [] stack; 85} 86 87void 88Fiber::createContext() 89{ 90 // Set up a context for the new fiber, starting it in the trampoline. 91 getcontext(&ctx); 92 ctx.uc_stack.ss_sp = stack; 93 ctx.uc_stack.ss_size = stackSize; 94 ctx.uc_link = nullptr; 95 makecontext(&ctx, &entryTrampoline, 0); 96 97 // Swap to the new context so it can enter its start() function. It 98 // will then swap itself back out and return here. 99 startingFiber = this; 100 panic_if(!_currentFiber, "No active Fiber object."); 101 swapcontext(&_currentFiber->ctx, &ctx); 102 103 // The new context is now ready and about to call main(). 104} 105 106void 107Fiber::start() 108{ 109 // Avoid a dangling pointer. 110 startingFiber = nullptr; 111 112 setStarted(); 113 114 // Swap back to the parent context which is still considered "current", 115 // now that we're ready to go. 116 int ret M5_VAR_USED = swapcontext(&ctx, &_currentFiber->ctx); 117 panic_if(ret == -1, strerror(errno)); 118 119 // Call main() when we're been reactivated for the first time. 120 main(); 121 122 // main has returned, so this Fiber has finished. Switch to the "link" 123 // Fiber. 124 _finished = true; 125 link->run(); 126} 127 128void 129Fiber::run() 130{ 131 panic_if(_finished, "Fiber has already run to completion."); 132 133 // If we're already running this fiber, we're done. 134 if (_currentFiber == this) 135 return; 136 137 if (!started) 138 createContext(); 139 140 // Switch out of the current Fiber's context and this one's in. 141 Fiber *prev = _currentFiber; 142 Fiber *next = this; 143 _currentFiber = next; 144 swapcontext(&prev->ctx, &next->ctx); 145} 146 147Fiber *Fiber::currentFiber() { return _currentFiber; } 148Fiber *Fiber::primaryFiber() { return &_primaryFiber; }
| 95 delete [] stack; 96} 97 98void 99Fiber::createContext() 100{ 101 // Set up a context for the new fiber, starting it in the trampoline. 102 getcontext(&ctx); 103 ctx.uc_stack.ss_sp = stack; 104 ctx.uc_stack.ss_size = stackSize; 105 ctx.uc_link = nullptr; 106 makecontext(&ctx, &entryTrampoline, 0); 107 108 // Swap to the new context so it can enter its start() function. It 109 // will then swap itself back out and return here. 110 startingFiber = this; 111 panic_if(!_currentFiber, "No active Fiber object."); 112 swapcontext(&_currentFiber->ctx, &ctx); 113 114 // The new context is now ready and about to call main(). 115} 116 117void 118Fiber::start() 119{ 120 // Avoid a dangling pointer. 121 startingFiber = nullptr; 122 123 setStarted(); 124 125 // Swap back to the parent context which is still considered "current", 126 // now that we're ready to go. 127 int ret M5_VAR_USED = swapcontext(&ctx, &_currentFiber->ctx); 128 panic_if(ret == -1, strerror(errno)); 129 130 // Call main() when we're been reactivated for the first time. 131 main(); 132 133 // main has returned, so this Fiber has finished. Switch to the "link" 134 // Fiber. 135 _finished = true; 136 link->run(); 137} 138 139void 140Fiber::run() 141{ 142 panic_if(_finished, "Fiber has already run to completion."); 143 144 // If we're already running this fiber, we're done. 145 if (_currentFiber == this) 146 return; 147 148 if (!started) 149 createContext(); 150 151 // Switch out of the current Fiber's context and this one's in. 152 Fiber *prev = _currentFiber; 153 Fiber *next = this; 154 _currentFiber = next; 155 swapcontext(&prev->ctx, &next->ctx); 156} 157 158Fiber *Fiber::currentFiber() { return _currentFiber; } 159Fiber *Fiber::primaryFiber() { return &_primaryFiber; }
|