← Back to team overview

kicad-developers team mailing list archive

[PATCH 7/9] MSVC support for libcontext

 

This uses the Windows native Fiber API.
---
 common/system/libcontext.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++
 include/system/libcontext.h  | 16 ++++++++++-
 include/tool/coroutine.h     |  8 ++++--
 3 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/common/system/libcontext.cpp b/common/system/libcontext.cpp
index f6f83ceae..57478f12c 100644
--- a/common/system/libcontext.cpp
+++ b/common/system/libcontext.cpp
@@ -13,6 +13,8 @@
             http://www.boost.org/LICENSE_1_0.txt)
 
 */
+#include <stdlib.h>
+#include <setjmp.h>
 #include <system/libcontext.h>
 
 #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 <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
diff --git a/include/system/libcontext.h b/include/system/libcontext.h
index 8045fa2b7..dfa323dcd 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 7be173adb..60144ebc0 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;

References