MSVC support for libcontext

This uses the Windows native Fiber API.
This commit is contained in:
Tomasz Wlostowski 2019-03-06 16:19:44 +01:00 committed by Wayne Stambaugh
parent 884ae5a7ff
commit 6cab769f41
3 changed files with 87 additions and 3 deletions

View File

@ -13,6 +13,8 @@
http://www.boost.org/LICENSE_1_0.txt) http://www.boost.org/LICENSE_1_0.txt)
*/ */
#include <stdlib.h>
#include <setjmp.h>
#include <system/libcontext.h> #include <system/libcontext.h>
#if defined(LIBCONTEXT_PLATFORM_windows_i386) && defined(LIBCONTEXT_COMPILER_gcc) #if defined(LIBCONTEXT_PLATFORM_windows_i386) && defined(LIBCONTEXT_COMPILER_gcc)
@ -1268,3 +1270,67 @@ __asm (
); );
#endif #endif
#if defined(LIBCONTEXT_PLATFORM_msvc_x86_64) || defined(LIBCONTEXT_PLATFORM_msvc_i386)
#include <map>
#ifdef __cplusplus
extern "C" {
#endif
#include <windows.h>
namespace libcontext
{
static int threadHasFibers = 0;
struct FiberData
{
intptr_t inValue;
intptr_t outValue;
void(*entry)(intptr_t);
};
static std::map<fcontext_t, FiberData> 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

View File

@ -24,6 +24,8 @@
#if defined(__GNUC__) || defined(__APPLE__) || defined(__FreeBSD__) #if defined(__GNUC__) || defined(__APPLE__) || defined(__FreeBSD__)
#undef LIBCONTEXT_HAS_OWN_STACK
#define LIBCONTEXT_COMPILER_gcc #define LIBCONTEXT_COMPILER_gcc
#if defined(__linux__) || defined(__FreeBSD__) #if defined(__linux__) || defined(__FreeBSD__)
@ -46,7 +48,8 @@
#ifdef _ARCH_PPC64 #ifdef _ARCH_PPC64
#define LIBCONTEXT_PLATFORM_linux_ppc64 #define LIBCONTEXT_PLATFORM_linux_ppc64
#define LIBCONTEXT_CALL_CONVENTION #define LIBCONTEXT_CALL_CONVENTION
#elif defined _ARCH_PPC #endif
#ifdef _ARCH_PPC
#define LIBCONTEXT_PLATFORM_linux_ppc32 #define LIBCONTEXT_PLATFORM_linux_ppc32
#define LIBCONTEXT_CALL_CONVENTION #define LIBCONTEXT_CALL_CONVENTION
#endif #endif
@ -73,6 +76,17 @@
#define LIBCONTEXT_CALL_CONVENTION #define LIBCONTEXT_CALL_CONVENTION
#endif #endif
#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 #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -294,15 +294,19 @@ private:
assert( m_stack == nullptr ); assert( m_stack == nullptr );
// fixme: Clean up stack stuff. Add a guard
size_t stackSize = c_defaultStackSize; 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] ); m_stack.reset( new char[stackSize] );
// align to 16 bytes // 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 // correct the stack size
stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp ); stackSize -= size_t( ( (ptrdiff_t) m_stack.get() + stackSize ) - (ptrdiff_t) sp );
#endif
m_callee = libcontext::make_fcontext( sp, stackSize, callerStub ); m_callee = libcontext::make_fcontext( sp, stackSize, callerStub );
m_running = true; m_running = true;