diff --git a/panda/src/pipeline/contextSwitch.c b/panda/src/pipeline/contextSwitch.c index 0749754adf..8f0abbf562 100644 --- a/panda/src/pipeline/contextSwitch.c +++ b/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. */ #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. */ -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__) -/* 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. */ #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_longjmp _cs_longjmp #endif @@ -113,27 +157,33 @@ __asm__ "popl %edx\n" "popl %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" - "xorl %eax,%eax\n" + + "xorl %eax, %eax\n" "jmp *%edx\n"); __asm__ ("_cs_longjmp:\n" "popl %edx\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" + "mov $1,%eax\n" "jmp *%edx\n"); @@ -149,11 +199,6 @@ __asm__ this directory. */ #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 /* CS_JB_SP */ diff --git a/panda/src/pipeline/contextSwitch.h b/panda/src/pipeline/contextSwitch.h index 01d15f2fde..275e25e9e9 100644 --- a/panda/src/pipeline/contextSwitch.h +++ b/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 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. This will be safe than the system version, since who knows what that one's really doing? */ diff --git a/panda/src/pipeline/threadSimpleImpl.cxx b/panda/src/pipeline/threadSimpleImpl.cxx index 14165d6b15..1d5c58c9b7 100644 --- a/panda/src/pipeline/threadSimpleImpl.cxx +++ b/panda/src/pipeline/threadSimpleImpl.cxx @@ -24,6 +24,11 @@ #include "threadSimpleManager.h" #include "thread.h" +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this; //////////////////////////////////////////////////////////////////// @@ -45,7 +50,14 @@ ThreadSimpleImpl(Thread *parent_obj) : // We allocate the requested stack size, plus an additional tiny // buffer to allow room for the code to access values on the // 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. _manager = ThreadSimpleManager::get_global_ptr(); @@ -64,7 +76,13 @@ ThreadSimpleImpl:: } nassertv(_status != S_running); - free(_stack); + if (_stack != (void *)NULL) { +#ifdef WIN32 + VirtualFree(_stack, 0, MEM_RELEASE); +#else + free(_stack); +#endif + } } ////////////////////////////////////////////////////////////////////