16bbc0262SSergey Makeev // The MIT License (MIT) 26bbc0262SSergey Makeev // 36bbc0262SSergey Makeev // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev 46bbc0262SSergey Makeev // 56bbc0262SSergey Makeev // Permission is hereby granted, free of charge, to any person obtaining a copy 66bbc0262SSergey Makeev // of this software and associated documentation files (the "Software"), to deal 76bbc0262SSergey Makeev // in the Software without restriction, including without limitation the rights 86bbc0262SSergey Makeev // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 96bbc0262SSergey Makeev // copies of the Software, and to permit persons to whom the Software is 106bbc0262SSergey Makeev // furnished to do so, subject to the following conditions: 116bbc0262SSergey Makeev // 126bbc0262SSergey Makeev // The above copyright notice and this permission notice shall be included in 136bbc0262SSergey Makeev // all copies or substantial portions of the Software. 146bbc0262SSergey Makeev // 156bbc0262SSergey Makeev // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 166bbc0262SSergey Makeev // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 176bbc0262SSergey Makeev // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 186bbc0262SSergey Makeev // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 196bbc0262SSergey Makeev // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 206bbc0262SSergey Makeev // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 216bbc0262SSergey Makeev // THE SOFTWARE. 226bbc0262SSergey Makeev 236bbc0262SSergey Makeev #pragma once 246bbc0262SSergey Makeev 256bbc0262SSergey Makeev #ifndef __MT_FIBER_DEFAULT__ 266bbc0262SSergey Makeev #define __MT_FIBER_DEFAULT__ 276bbc0262SSergey Makeev 286bbc0262SSergey Makeev #include "MTAtomic.h" 296bbc0262SSergey Makeev 306bbc0262SSergey Makeev namespace MT 316bbc0262SSergey Makeev { 326bbc0262SSergey Makeev FiberGetSelf()33feebdc7dSs.makeev_local inline void* FiberGetSelf() 34feebdc7dSs.makeev_local { 35feebdc7dSs.makeev_local MW_BOOL isThreadAFiber = ::IsThreadAFiber(); 36feebdc7dSs.makeev_local if (isThreadAFiber == 0) 37feebdc7dSs.makeev_local { 38feebdc7dSs.makeev_local // GetCurrentFiber() return invalid values is current thread is not fiber. 39feebdc7dSs.makeev_local return nullptr; 40feebdc7dSs.makeev_local } 41feebdc7dSs.makeev_local 42feebdc7dSs.makeev_local //This function is equal to GetCurrentFiber() macro 43feebdc7dSs.makeev_local void* pFiber = (void*)ReadTeb(MW_CURRENT_FIBER_OFFSET); 44feebdc7dSs.makeev_local return pFiber; 45feebdc7dSs.makeev_local } 46feebdc7dSs.makeev_local 47feebdc7dSs.makeev_local 486bbc0262SSergey Makeev // 496bbc0262SSergey Makeev // Fibers implementation using system fibers 506bbc0262SSergey Makeev // Beware! Windows Fibers are wasteful use of Virtual Memory space for the stack. ( 1Mb reserved for each Fiber ) 516bbc0262SSergey Makeev // 526bbc0262SSergey Makeev class Fiber 536bbc0262SSergey Makeev { 546bbc0262SSergey Makeev void* funcData; 556bbc0262SSergey Makeev TThreadEntryPoint func; 566bbc0262SSergey Makeev 576bbc0262SSergey Makeev void* fiber; 586bbc0262SSergey Makeev FiberFuncInternal(void * pFiber)596bbc0262SSergey Makeev static void __stdcall FiberFuncInternal(void* pFiber) 606bbc0262SSergey Makeev { 616bbc0262SSergey Makeev Fiber* self = (Fiber*)pFiber; 626bbc0262SSergey Makeev self->func(self->funcData); 636bbc0262SSergey Makeev } 646bbc0262SSergey Makeev CleanUp()653d930776Ss.makeev_local void CleanUp() 663d930776Ss.makeev_local { 673d930776Ss.makeev_local if (fiber) 683d930776Ss.makeev_local { 693d930776Ss.makeev_local // Do not destroy fibers created using ::ConvertThreadToFiberEx 703d930776Ss.makeev_local if (func != nullptr) 713d930776Ss.makeev_local { 723d930776Ss.makeev_local ::DeleteFiber(fiber); 733d930776Ss.makeev_local } 74*d8cd6e1fSTsarevich Dmitry else 75*d8cd6e1fSTsarevich Dmitry { 76*d8cd6e1fSTsarevich Dmitry ::ConvertFiberToThread(); 77*d8cd6e1fSTsarevich Dmitry } 783d930776Ss.makeev_local fiber = nullptr; 793d930776Ss.makeev_local } 803d930776Ss.makeev_local } 813d930776Ss.makeev_local 826bbc0262SSergey Makeev public: 836bbc0262SSergey Makeev 842e846c40SSergey Makeev MT_NOCOPYABLE(Fiber); 852e846c40SSergey Makeev Fiber()866bbc0262SSergey Makeev Fiber() 876bbc0262SSergey Makeev : fiber(nullptr) 886bbc0262SSergey Makeev { 896bbc0262SSergey Makeev } 906bbc0262SSergey Makeev ~Fiber()916bbc0262SSergey Makeev ~Fiber() 926bbc0262SSergey Makeev { 933d930776Ss.makeev_local CleanUp(); 946bbc0262SSergey Makeev } 956bbc0262SSergey Makeev 966bbc0262SSergey Makeev CreateFromCurrentThreadAndRun(TThreadEntryPoint entryPoint,void * userData)97ae5bbefbSs.makeev_local void CreateFromCurrentThreadAndRun(TThreadEntryPoint entryPoint, void *userData) 986bbc0262SSergey Makeev { 996bbc0262SSergey Makeev MT_ASSERT(fiber == nullptr, "Fiber already created"); 1006bbc0262SSergey Makeev 1016bbc0262SSergey Makeev func = nullptr; 1026bbc0262SSergey Makeev funcData = nullptr; 1036bbc0262SSergey Makeev 1043d930776Ss.makeev_local void* fiberSelf = FiberGetSelf(); 1053d930776Ss.makeev_local if (fiberSelf != nullptr) 1063d930776Ss.makeev_local { 1073d930776Ss.makeev_local fiber = fiberSelf; 1083d930776Ss.makeev_local } else 1093d930776Ss.makeev_local { 11087ecbf38Ss.makeev fiber = ::ConvertThreadToFiberEx(nullptr, MW_FIBER_FLAG_FLOAT_SWITCH); 1116bbc0262SSergey Makeev MT_ASSERT(fiber != nullptr, "Can't create fiber"); 1123d930776Ss.makeev_local } 11302d170cfSs.makeev_local 11402d170cfSs.makeev_local entryPoint(userData); 1153d930776Ss.makeev_local 1163d930776Ss.makeev_local CleanUp(); 1176bbc0262SSergey Makeev } 1186bbc0262SSergey Makeev 1196bbc0262SSergey Makeev Create(size_t stackSize,TThreadEntryPoint entryPoint,void * userData)1206bbc0262SSergey Makeev void Create(size_t stackSize, TThreadEntryPoint entryPoint, void* userData) 1216bbc0262SSergey Makeev { 1226bbc0262SSergey Makeev MT_ASSERT(fiber == nullptr, "Fiber already created"); 1236bbc0262SSergey Makeev 1246bbc0262SSergey Makeev func = entryPoint; 1256bbc0262SSergey Makeev funcData = userData; 1266bbc0262SSergey Makeev fiber = ::CreateFiber( stackSize, FiberFuncInternal, this ); 1276bbc0262SSergey Makeev MT_ASSERT(fiber != nullptr, "Can't create fiber"); 1286bbc0262SSergey Makeev } 1296bbc0262SSergey Makeev 130d7cf17b1Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD SetName(const char * fiberName)131d7cf17b1Ss.makeev_local void SetName(const char* fiberName) 132d7cf17b1Ss.makeev_local { 133d7cf17b1Ss.makeev_local MT_UNUSED(fiberName); 134d7cf17b1Ss.makeev_local } 135d7cf17b1Ss.makeev_local #endif 136d7cf17b1Ss.makeev_local SwitchTo(Fiber & from,Fiber & to)1376bbc0262SSergey Makeev static void SwitchTo(Fiber & from, Fiber & to) 1386bbc0262SSergey Makeev { 13987ecbf38Ss.makeev MT_USED_IN_ASSERT(from); 14087ecbf38Ss.makeev 1416bbc0262SSergey Makeev HardwareFullMemoryBarrier(); 1426bbc0262SSergey Makeev 1436bbc0262SSergey Makeev MT_ASSERT(from.fiber != nullptr, "Invalid from fiber"); 1446bbc0262SSergey Makeev MT_ASSERT(to.fiber != nullptr, "Invalid to fiber"); 1456bbc0262SSergey Makeev 14687ecbf38Ss.makeev ::SwitchToFiber( (void*)to.fiber ); 1476bbc0262SSergey Makeev } 1486bbc0262SSergey Makeev 1496bbc0262SSergey Makeev 1506bbc0262SSergey Makeev }; 1516bbc0262SSergey Makeev 1526bbc0262SSergey Makeev } 1536bbc0262SSergey Makeev 1546bbc0262SSergey Makeev #endif 155