diff --git a/common/system/libcontext.cpp b/common/system/libcontext.cpp index f6f83ceaef..57478f12c2 100644 --- a/common/system/libcontext.cpp +++ b/common/system/libcontext.cpp @@ -13,6 +13,8 @@ http://www.boost.org/LICENSE_1_0.txt) */ +#include +#include #include #if defined(LIBCONTEXT_PLATFORM_windows_i386) && defined(LIBCONTEXT_COMPILER_gcc) @@ -1268,3 +1270,67 @@ __asm ( ); #endif + +#if defined(LIBCONTEXT_PLATFORM_msvc_x86_64) || defined(LIBCONTEXT_PLATFORM_msvc_i386) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +namespace libcontext +{ + +static int threadHasFibers = 0; + +struct FiberData +{ + intptr_t inValue; + intptr_t outValue; + void(*entry)(intptr_t); +}; + +static std::map fiberParams; + +static void fiberEntry(LPVOID params) +{ + auto ctx = (fcontext_t) GetCurrentFiber(); + auto& d = fiberParams[ctx]; + d.entry(d.inValue); +} + +fcontext_t LIBCONTEXT_CALL_CONVENTION make_fcontext(void* sp, size_t size, void(*fn)(intptr_t)) +{ + if (!threadHasFibers) + { + ConvertThreadToFiber(nullptr); + threadHasFibers = 1; + } + + fcontext_t ctx = CreateFiber(size, (LPFIBER_START_ROUTINE) fiberEntry, nullptr ); + fiberParams[ctx].entry = fn; + + return ctx; +} + +intptr_t LIBCONTEXT_CALL_CONVENTION jump_fcontext(fcontext_t* ofc, fcontext_t nfc, + intptr_t vp, bool preserve_fpu) +{ + auto current = (void*)GetCurrentFiber(); + fiberParams[current].outValue = vp; + *ofc = GetCurrentFiber(); + fiberParams[nfc].inValue = vp; + SwitchToFiber(nfc); + return fiberParams[*ofc].outValue; +} + +}; // namespace libcontext + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/system/libcontext.h b/include/system/libcontext.h index 8045fa2b78..dfa323dcd3 100644 --- a/include/system/libcontext.h +++ b/include/system/libcontext.h @@ -24,6 +24,8 @@ #if defined(__GNUC__) || defined(__APPLE__) || defined(__FreeBSD__) + #undef LIBCONTEXT_HAS_OWN_STACK + #define LIBCONTEXT_COMPILER_gcc #if defined(__linux__) || defined(__FreeBSD__) @@ -46,7 +48,8 @@ #ifdef _ARCH_PPC64 #define LIBCONTEXT_PLATFORM_linux_ppc64 #define LIBCONTEXT_CALL_CONVENTION - #elif defined _ARCH_PPC + #endif + #ifdef _ARCH_PPC #define LIBCONTEXT_PLATFORM_linux_ppc32 #define LIBCONTEXT_CALL_CONVENTION #endif @@ -73,6 +76,17 @@ #define LIBCONTEXT_CALL_CONVENTION #endif #endif +#elif defined (_MSC_VER) + +#define LIBCONTEXT_HAS_OWN_STACK + +#define LIBCONTEXT_CALL_CONVENTION __cdecl + +#if defined(_WIN64) + #define LIBCONTEXT_PLATFORM_msvc_x86_64 +#elif defined(_WIN32) + #define LIBCONTEXT_PLATFORM_msvc_i386 +#endif #endif #ifdef __cplusplus diff --git a/include/tool/coroutine.h b/include/tool/coroutine.h index 7be173adb1..60144ebc0b 100644 --- a/include/tool/coroutine.h +++ b/include/tool/coroutine.h @@ -294,15 +294,19 @@ private: assert( m_stack == nullptr ); - // fixme: Clean up stack stuff. Add a guard size_t stackSize = c_defaultStackSize; + void* sp = nullptr; + + #ifndef LIBCONTEXT_HAS_OWN_STACK + // fixme: Clean up stack stuff. Add a guard m_stack.reset( new char[stackSize] ); // align to 16 bytes - void* sp = (void*)((((ptrdiff_t) m_stack.get()) + stackSize - 0xf) & (~0x0f)); + sp = (void*)((((ptrdiff_t) m_stack.get()) + stackSize - 0xf) & (~0x0f)); // correct the stack size stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp ); + #endif m_callee = libcontext::make_fcontext( sp, stackSize, callerStub ); m_running = true;