Browse Source

simple_threads for win32

David Rose 18 years ago
parent
commit
9ad516cea2

+ 68 - 23
panda/src/pipeline/contextSwitch.c

@@ -89,18 +89,62 @@ switch_to_thread_context(struct ThreadContext *context) {
    _jmp_context.  Then restore back to the original stack pointer. */
    _jmp_context.  Then restore back to the original stack pointer. */
 
 
 #if defined(_M_IX86)
 #if defined(_M_IX86)
-/* Here is own own implementation of setjmp and longjmp for I386, via
+/* Here is our own implementation of setjmp and longjmp for I386, via
    Windows syntax. */
    Windows syntax. */
 
 
-int cs_setjmp(cs_jmp_buf env);
-void cs_longjmp(cs_jmp_buf env);
+/* warning C4731: frame pointer register 'ebp' modified by inline assembly code */
+#pragma warning(disable:4731)
+
+int
+cs_setjmp(cs_jmp_buf env) {
+  __asm {
+    pop ebp;  /* Restore the frame pointer that the compiler pushed */
+
+    pop edx;  /* edx = return address */
+    pop eax;  /* eax = &env */
+    push eax; /* keep &env on the stack; the caller will remove it */
+
+    mov [eax + 0], ebx;
+    mov [eax + 4], edi;
+    mov [eax + 8], esi;
+    mov [eax + 12], ebp;
+    mov [eax + 16], esp;
+    mov [eax + 20], edx;
+
+    fnsave [eax + 24];  /* save floating-point state */
+
+    xor eax,eax;  /* return 0: pass 1 return */
+    jmp edx;      /* this works like ret */
+  }
+}
+
+void
+cs_longjmp(cs_jmp_buf env) {
+  _asm {
+    mov eax, env;
+    
+    mov ebx, [eax + 0];
+    mov edi, [eax + 4];
+    mov esi, [eax + 8];
+    mov ebp, [eax + 12];
+    mov esp, [eax + 16];
+    mov edx, [eax + 20];
+    
+    frstor [eax + 24];  /* restore floating-point state */
+
+    mov eax, 1;   /* return 1 from setjmp: pass 2 return */
+    jmp edx;      /* return from above setjmp call */
+  }
+}
+
 
 
 #elif defined(__i386__)
 #elif defined(__i386__)
-/* Here is own own implementation of setjmp and longjmp for I386, via
+/* Here is our own implementation of setjmp and longjmp for I386, via
    GNU syntax. */
    GNU syntax. */
 
 
 #if defined(IS_LINUX)
 #if defined(IS_LINUX)
-/* On Linux, the underscores are not implicit. */
+/* On Linux, the leading underscores are not implicitly added for C
+   function names. */
 #define cs_setjmp _cs_setjmp
 #define cs_setjmp _cs_setjmp
 #define cs_longjmp _cs_longjmp
 #define cs_longjmp _cs_longjmp
 #endif
 #endif
@@ -113,27 +157,33 @@ __asm__
  "popl %edx\n"
  "popl %edx\n"
  "popl %eax\n"
  "popl %eax\n"
  "pushl %eax\n"
  "pushl %eax\n"
- "movl %ebx,0(%eax)\n"
- "movl %edi,4(%eax)\n"
- "movl %esi,8(%eax)\n"
- "movl %ebp,12(%eax)\n"
- "movl %esp,16(%eax)\n"
- "movl %edx,20(%eax)\n"
+
+ "movl %ebx, 0(%eax)\n"
+ "movl %edi, 4(%eax)\n"
+ "movl %esi, 8(%eax)\n"
+ "movl %ebp, 12(%eax)\n"
+ "movl %esp, 16(%eax)\n"
+ "movl %edx, 20(%eax)\n"
+
  "fnsave 24(%eax)\n"
  "fnsave 24(%eax)\n"
- "xorl %eax,%eax\n"
+
+ "xorl %eax, %eax\n"
  "jmp *%edx\n");
  "jmp *%edx\n");
 
 
 __asm__
 __asm__
 ("_cs_longjmp:\n"
 ("_cs_longjmp:\n"
  "popl %edx\n"
  "popl %edx\n"
  "popl %eax\n"
  "popl %eax\n"
- "movl 0(%eax),%ebx\n"
- "movl 4(%eax),%edi\n"
- "movl 8(%eax),%esi\n"
- "movl 12(%eax),%ebp\n"
- "movl 16(%eax),%esp\n"
- "movl 20(%eax),%edx\n"
+
+ "movl 0(%eax), %ebx\n"
+ "movl 4(%eax), %edi\n"
+ "movl 8(%eax), %esi\n"
+ "movl 12(%eax), %ebp\n"
+ "movl 16(%eax), %esp\n"
+ "movl 20(%eax), %edx\n"
+
  "frstor 24(%eax)\n"
  "frstor 24(%eax)\n"
+
  "mov $1,%eax\n"
  "mov $1,%eax\n"
  "jmp *%edx\n");
  "jmp *%edx\n");
 
 
@@ -149,11 +199,6 @@ __asm__
    this directory. */
    this directory. */
 #define CS_JB_SP 9
 #define CS_JB_SP 9
 
 
-#elif defined(WIN32)
-/* We have determined this value empirically, via test_setjmp.cxx in
-   this directory. */
-#define CS_JB_SP 4
-
 #endif
 #endif
 
 
 #endif  /* CS_JB_SP */
 #endif  /* CS_JB_SP */

+ 1 - 1
panda/src/pipeline/contextSwitch.h

@@ -49,7 +49,7 @@ struct ThreadContext {
    it claims to be adopted by Posix).  So we have to fall back to
    it claims to be adopted by Posix).  So we have to fall back to
    setjmp() / longjmp() in its absence.  This is a hackier solution. */
    setjmp() / longjmp() in its absence.  This is a hackier solution. */
 
 
-#if defined(__i386__)
+#if defined(_M_IX86) || defined(__i386__)
 /* Maybe we can implement our own setjmp/longjmp in assembly code.
 /* Maybe we can implement our own setjmp/longjmp in assembly code.
    This will be safe than the system version, since who knows what
    This will be safe than the system version, since who knows what
    that one's really doing? */
    that one's really doing? */

+ 20 - 2
panda/src/pipeline/threadSimpleImpl.cxx

@@ -24,6 +24,11 @@
 #include "threadSimpleManager.h"
 #include "threadSimpleManager.h"
 #include "thread.h"
 #include "thread.h"
 
 
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
 ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this;
 ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -45,7 +50,14 @@ ThreadSimpleImpl(Thread *parent_obj) :
   // We allocate the requested stack size, plus an additional tiny
   // We allocate the requested stack size, plus an additional tiny
   // buffer to allow room for the code to access values on the
   // buffer to allow room for the code to access values on the
   // currently executing stack frame at the time we switch the stack.
   // currently executing stack frame at the time we switch the stack.
-  _stack = (unsigned char *)malloc(_stack_size + 0x100);
+  size_t alloc_size = _stack_size + 0x100;
+
+#ifdef WIN32
+  _stack = (unsigned char *)VirtualAlloc(NULL, alloc_size, MEM_COMMIT | MEM_RESERVE,
+                                         PAGE_EXECUTE_READWRITE);
+#else
+  _stack = (unsigned char *)malloc(alloc_size);
+#endif
 
 
   // Save this pointer for convenience.
   // Save this pointer for convenience.
   _manager = ThreadSimpleManager::get_global_ptr();
   _manager = ThreadSimpleManager::get_global_ptr();
@@ -64,7 +76,13 @@ ThreadSimpleImpl::
   }
   }
   nassertv(_status != S_running);
   nassertv(_status != S_running);
 
 
-  free(_stack);
+  if (_stack != (void *)NULL) {
+#ifdef WIN32
+    VirtualFree(_stack, 0, MEM_RELEASE);
+#else  
+    free(_stack);
+#endif
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////