change libco to use an msvc-compiled dll so that it doesnt get wrecked whenever the .net GC process suspends a thread in a coroutine. cant figure out how to get that same code working compiled by mingw32.
This commit is contained in:
parent
8cdcae462d
commit
f3b6afa5ad
|
@ -51,6 +51,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
|
||||||
|
|
||||||
public class BGInfo
|
public class BGInfo
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Is the layer even enabled?
|
||||||
|
/// </summary>
|
||||||
|
public bool Enabled { get { return Bpp != 0; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// screen and tiledata register values
|
/// screen and tiledata register values
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -112,11 +112,13 @@ namespace BizHawk.MultiClient
|
||||||
allocate(256, 256);
|
allocate(256, 256);
|
||||||
gd.RenderTilesToScreen(pixelptr, stride / 4, 8, 0);
|
gd.RenderTilesToScreen(pixelptr, stride / 4, 8, 0);
|
||||||
}
|
}
|
||||||
if (selection == "BG1" || selection == "BG2" || selection == "BG3" /*|| selection == "BG4"*/)
|
if (selection == "BG1" || selection == "BG2" || selection == "BG3" || selection == "BG4")
|
||||||
{
|
{
|
||||||
int bgnum = int.Parse(selection.Substring(2));
|
int bgnum = int.Parse(selection.Substring(2));
|
||||||
var si = gd.ScanScreenInfo();
|
var si = gd.ScanScreenInfo();
|
||||||
var bg = si.BG[bgnum];
|
var bg = si.BG[bgnum];
|
||||||
|
if (bg.Enabled)
|
||||||
|
{
|
||||||
var dims = bg.ScreenSizeInPixels;
|
var dims = bg.ScreenSizeInPixels;
|
||||||
allocate(dims.Width, dims.Height);
|
allocate(dims.Width, dims.Height);
|
||||||
int numPixels = dims.Width * dims.Height;
|
int numPixels = dims.Width * dims.Height;
|
||||||
|
@ -128,6 +130,7 @@ namespace BizHawk.MultiClient
|
||||||
gd.Paletteize(pixelptr, 0, 0, numPixels);
|
gd.Paletteize(pixelptr, 0, 0, numPixels);
|
||||||
gd.Colorize(pixelptr, 0, numPixels);
|
gd.Colorize(pixelptr, 0, numPixels);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bmp != null)
|
if (bmp != null)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
rm bsnes/obj/*.o
|
|
@ -1,4 +1,6 @@
|
||||||
cd bsnes
|
cd bsnes
|
||||||
|
export BIZWINCFLAGS="-I. -O3 -masm=intel -DLIBCO_IMPORT -DLIBCO_MSVC"
|
||||||
|
export TARGET_LIBSNES_LIBDEPS="-L ../libco_msvc_win32/release/ -llibco_msvc_win32"
|
||||||
profile=compatibility platform=win target=libsnes make -e -j
|
profile=compatibility platform=win target=libsnes make -e -j
|
||||||
cd ..
|
cd ..
|
||||||
cp bsnes/out/snes.dll ../BizHawk.MultiClient/output
|
cp bsnes/out/snes.dll ../BizHawk.MultiClient/output
|
|
@ -9,12 +9,16 @@ target := ui
|
||||||
# options += console
|
# options += console
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
c := $(compiler) -std=gnu99
|
c := $(compiler) -std=gnu99 $(BIZWINCFLAGS)
|
||||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||||
flags := -I. -O3 -fomit-frame-pointer
|
flags := -I. -O3 -fomit-frame-pointer
|
||||||
link :=
|
link :=
|
||||||
objects := libco
|
objects := libco
|
||||||
|
|
||||||
|
ifneq ($(BIZWINCFLAGS),)
|
||||||
|
flags := $(BIZWINCFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
# profile-guided optimization mode
|
# profile-guided optimization mode
|
||||||
# pgo := instrument
|
# pgo := instrument
|
||||||
# pgo := optimize
|
# pgo := optimize
|
||||||
|
|
|
@ -4,8 +4,12 @@
|
||||||
license: public domain
|
license: public domain
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__GNUC__) && defined(__i386__)
|
#if (defined(__ARM_EABI__) || defined(__ARMCC_VERSION) )
|
||||||
|
#include "sjlj-multi.c"
|
||||||
|
#elif defined(__GNUC__) && defined(__i386__)
|
||||||
|
#if !defined(LIBCO_MSVC)
|
||||||
#include "x86.c"
|
#include "x86.c"
|
||||||
|
#endif
|
||||||
#elif defined(__GNUC__) && defined(__amd64__)
|
#elif defined(__GNUC__) && defined(__amd64__)
|
||||||
#include "amd64.c"
|
#include "amd64.c"
|
||||||
#elif defined(__GNUC__) && defined(_ARCH_PPC)
|
#elif defined(__GNUC__) && defined(_ARCH_PPC)
|
||||||
|
|
|
@ -20,11 +20,20 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void* cothread_t;
|
typedef void* cothread_t;
|
||||||
|
typedef void (*coentry_t)(void);
|
||||||
|
|
||||||
cothread_t co_active();
|
#if defined(LIBCO_IMPORT)
|
||||||
cothread_t co_create(unsigned int, void (*)(void));
|
#define LIBCO_IMPORTDECL __declspec(dllimport)
|
||||||
void co_delete(cothread_t);
|
#elif defined(LIBCO_EXPORT)
|
||||||
void co_switch(cothread_t);
|
#define LIBCO_IMPORTDECL __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define LIBCO_IMPORTDECL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LIBCO_IMPORTDECL cothread_t co_active();
|
||||||
|
LIBCO_IMPORTDECL cothread_t co_create(unsigned int, coentry_t);
|
||||||
|
LIBCO_IMPORTDECL void co_delete(cothread_t);
|
||||||
|
LIBCO_IMPORTDECL void co_switch(cothread_t);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
#define LIBCO_C
|
||||||
|
#include "libco.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
jmp_buf context;
|
||||||
|
coentry_t coentry;
|
||||||
|
void *stack;
|
||||||
|
unsigned long seh_frame, stack_top, stack_bottom;
|
||||||
|
cothread_t caller;
|
||||||
|
} cothread_struct;
|
||||||
|
|
||||||
|
static thread_local cothread_struct co_primary;
|
||||||
|
static thread_local cothread_struct *co_running = 0;
|
||||||
|
|
||||||
|
//-------------------
|
||||||
|
#if defined(_MSC_VER) || defined(MINGW32)
|
||||||
|
|
||||||
|
__declspec(dllimport) cothread_t os_co_create();
|
||||||
|
__declspec(dllimport) void os_pre_setjmp(cothread_t target);
|
||||||
|
__declspec(dllimport) void os_pre_longjmp(cothread_struct* rec);
|
||||||
|
|
||||||
|
#elif defined(__ARM_EABI__) || defined(__ARMCC_VERSION)
|
||||||
|
|
||||||
|
//http://sourceware.org/cgi-bin/cvsweb.cgi/src/newlib/libc/machine/arm/setjmp.S?rev=1.5&content-type=text/x-cvsweb-markup&cvsroot=src
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
#ifdef LIBCO_ARM_JUMBLED
|
||||||
|
int r8,r9,r10,r11,lr,r4,r5,r6,r7,sp;
|
||||||
|
#else
|
||||||
|
int r4,r5,r6,r7,r8,r9,r10,fp;
|
||||||
|
#ifndef LIBCO_ARM_NOIP
|
||||||
|
int ip;
|
||||||
|
#endif
|
||||||
|
int sp,lr;
|
||||||
|
#endif
|
||||||
|
} _JUMP_BUFFER;
|
||||||
|
|
||||||
|
static void os_co_create(cothread_struct* rec, unsigned int size, coentry_t coentry)
|
||||||
|
{
|
||||||
|
_JUMP_BUFFER* jb = (_JUMP_BUFFER*)&rec->context;
|
||||||
|
|
||||||
|
jb->sp = (unsigned long)rec->stack + size - 4;
|
||||||
|
jb->lr = (unsigned long)coentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_pre_setjmp(cothread_t target)
|
||||||
|
{
|
||||||
|
cothread_struct* rec = (cothread_struct*)target;
|
||||||
|
rec->caller = co_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_pre_longjmp(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "sjlj-multi: unsupported processor, compiler or operating system"
|
||||||
|
#endif
|
||||||
|
//-------------------
|
||||||
|
|
||||||
|
cothread_t co_active()
|
||||||
|
{
|
||||||
|
if(!co_running) co_running = &co_primary;
|
||||||
|
return (cothread_t)co_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
cothread_t co_create(unsigned int size, void (*coentry)(void))
|
||||||
|
{
|
||||||
|
cothread_struct *thread;
|
||||||
|
|
||||||
|
if(!co_running) co_running = &co_primary;
|
||||||
|
|
||||||
|
thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||||
|
if(thread)
|
||||||
|
{
|
||||||
|
thread->coentry = coentry;
|
||||||
|
thread->stack = malloc(size);
|
||||||
|
{
|
||||||
|
setjmp(thread->context);
|
||||||
|
os_co_create(thread,size,coentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cothread_t)thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void co_delete(cothread_t cothread)
|
||||||
|
{
|
||||||
|
if(cothread)
|
||||||
|
{
|
||||||
|
if(((cothread_struct*)cothread)->stack)
|
||||||
|
{
|
||||||
|
free(((cothread_struct*)cothread)->stack);
|
||||||
|
}
|
||||||
|
free(cothread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void co_switch(cothread_t cothread)
|
||||||
|
{
|
||||||
|
os_pre_setjmp(cothread);
|
||||||
|
if(!setjmp(co_running->context))
|
||||||
|
{
|
||||||
|
co_running = (cothread_struct*)cothread;
|
||||||
|
os_pre_longjmp(co_running);
|
||||||
|
longjmp(co_running->context,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -24,7 +24,7 @@ else ifeq ($(platform),osx)
|
||||||
ar rcs out/libsnes.a $(objects)
|
ar rcs out/libsnes.a $(objects)
|
||||||
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(objects)
|
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(objects)
|
||||||
else ifeq ($(platform),win)
|
else ifeq ($(platform),win)
|
||||||
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(objects)
|
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(objects) $(TARGET_LIBSNES_LIBDEPS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
|
|
@ -126,7 +126,31 @@ void snes_set_cartridge_basename(const char *basename) {
|
||||||
interface.basename = basename;
|
interface.basename = basename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
static jmp_buf buf;
|
||||||
|
|
||||||
|
void second(void) {
|
||||||
|
printf("second\n"); // prints
|
||||||
|
longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
void first(void) {
|
||||||
|
second();
|
||||||
|
printf("first\n"); // does not print
|
||||||
|
}
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
if ( ! setjmp(buf) ) {
|
||||||
|
first(); // when executed, setjmp returns 0
|
||||||
|
} else { // when longjmp jumps back, setjmp returns 1
|
||||||
|
printf("main\n"); // prints
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void snes_init(void) {
|
void snes_init(void) {
|
||||||
|
test();
|
||||||
SNES::interface = &interface;
|
SNES::interface = &interface;
|
||||||
SNES::system.init();
|
SNES::system.init();
|
||||||
SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad);
|
SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad);
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
libco.sjlj (2008-01-28)
|
||||||
|
author: Nach
|
||||||
|
license: public domain
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note this was designed for UNIX systems. Based on ideas expressed in a paper
|
||||||
|
* by Ralf Engelschall.
|
||||||
|
* For SJLJ on other systems, one would want to rewrite springboard() and
|
||||||
|
* co_create() and hack the jmb_buf stack pointer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LIBCO_C
|
||||||
|
#define LIBCO_EXPORT
|
||||||
|
#include "../bsnes/libco/libco.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
jmp_buf context;
|
||||||
|
coentry_t coentry;
|
||||||
|
void *stack;
|
||||||
|
unsigned long seh_frame, stack_top, stack_bottom;
|
||||||
|
cothread_t caller;
|
||||||
|
} cothread_struct;
|
||||||
|
|
||||||
|
static thread_local cothread_struct co_primary;
|
||||||
|
static thread_local cothread_struct *co_running = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//links of interest
|
||||||
|
//http://connect.microsoft.com/VisualStudio/feedback/details/100319/really-wierd-behaviour-in-crt-io-coupled-with-some-inline-assembly
|
||||||
|
//http://en.wikipedia.org/wiki/Thread_Information_Block
|
||||||
|
//http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/72093e46-4524-4f54-9f36-c7e8a309d1db/ //FS warning
|
||||||
|
|
||||||
|
|
||||||
|
#define WINVER 0x0400
|
||||||
|
#define _WIN32_WINNT 0x0400
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#pragma warning(disable:4733)
|
||||||
|
#pragma warning(disable:4311)
|
||||||
|
|
||||||
|
static void capture_fs(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
__asm mov eax, dword ptr fs:[0];
|
||||||
|
__asm mov temp, eax;
|
||||||
|
rec->seh_frame = temp;
|
||||||
|
__asm mov eax, dword ptr fs:[4];
|
||||||
|
__asm mov temp, eax;
|
||||||
|
rec->stack_top = temp;
|
||||||
|
__asm mov eax, dword ptr fs:[8];
|
||||||
|
__asm mov temp, eax;
|
||||||
|
rec->stack_bottom = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_fs(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
temp = rec->seh_frame;
|
||||||
|
__asm mov eax, temp;
|
||||||
|
__asm mov dword ptr fs:[0], eax
|
||||||
|
temp = rec->stack_top;
|
||||||
|
__asm mov eax, temp;
|
||||||
|
__asm mov dword ptr fs:[4], eax
|
||||||
|
temp = rec->stack_bottom;
|
||||||
|
__asm mov eax, temp;
|
||||||
|
__asm mov dword ptr fs:[8], eax
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_co_wrapper()
|
||||||
|
{
|
||||||
|
cothread_struct* rec = (cothread_struct*)co_active();
|
||||||
|
//__try
|
||||||
|
//{
|
||||||
|
rec->coentry();
|
||||||
|
//}
|
||||||
|
//__except(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
//{
|
||||||
|
// //unhandled win32 exception in coroutine.
|
||||||
|
// //this coroutine will now be suspended permanently and control will be yielded to caller, for lack of anything better to do.
|
||||||
|
// //perhaps the process should just terminate.
|
||||||
|
// for(;;)
|
||||||
|
// {
|
||||||
|
// //dead coroutine
|
||||||
|
// co_switch(rec->caller);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_co_create(cothread_struct* rec, unsigned int size, coentry_t coentry)
|
||||||
|
{
|
||||||
|
_JUMP_BUFFER* jb = (_JUMP_BUFFER*)&rec->context;
|
||||||
|
cothread_struct temp;
|
||||||
|
|
||||||
|
jb->Esp = (unsigned long)rec->stack + size - 4;
|
||||||
|
jb->Eip = (unsigned long)os_co_wrapper;
|
||||||
|
|
||||||
|
rec->stack_top = jb->Esp + 4;
|
||||||
|
rec->stack_bottom = (unsigned long)rec->stack;
|
||||||
|
|
||||||
|
//wild assumption about SEH frame.. seems to work
|
||||||
|
capture_fs(&temp);
|
||||||
|
rec->seh_frame = temp.seh_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_pre_setjmp(cothread_t target)
|
||||||
|
{
|
||||||
|
cothread_struct* rec = (cothread_struct*)target;
|
||||||
|
capture_fs(co_running);
|
||||||
|
rec->caller = co_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_pre_longjmp(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
restore_fs(rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport) cothread_t co_active()
|
||||||
|
{
|
||||||
|
if(!co_running) co_running = &co_primary;
|
||||||
|
return (cothread_t)co_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport) cothread_t co_create(unsigned int size, void (*coentry)(void))
|
||||||
|
{
|
||||||
|
cothread_struct *thread;
|
||||||
|
|
||||||
|
if(!co_running) co_running = &co_primary;
|
||||||
|
|
||||||
|
thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||||
|
if(thread)
|
||||||
|
{
|
||||||
|
thread->coentry = coentry;
|
||||||
|
thread->stack = malloc(size);
|
||||||
|
{
|
||||||
|
setjmp(thread->context);
|
||||||
|
os_co_create(thread,size,coentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cothread_t)thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport) void co_delete(cothread_t cothread)
|
||||||
|
{
|
||||||
|
if(cothread)
|
||||||
|
{
|
||||||
|
if(((cothread_struct*)cothread)->stack)
|
||||||
|
{
|
||||||
|
free(((cothread_struct*)cothread)->stack);
|
||||||
|
}
|
||||||
|
free(cothread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(dllexport) void co_switch(cothread_t cothread)
|
||||||
|
{
|
||||||
|
os_pre_setjmp(cothread);
|
||||||
|
if(!setjmp(co_running->context))
|
||||||
|
{
|
||||||
|
co_running = (cothread_struct*)cothread;
|
||||||
|
os_pre_longjmp(co_running);
|
||||||
|
longjmp(co_running->context,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||||
|
# Visual Studio 2005
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libco_msvc", "libco_msvc_win32.vcproj", "{C5D03072-BBF9-4DED-8CE6-5467736251BF}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C5D03072-BBF9-4DED-8CE6-5467736251BF}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{C5D03072-BBF9-4DED-8CE6-5467736251BF}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{C5D03072-BBF9-4DED-8CE6-5467736251BF}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{C5D03072-BBF9-4DED-8CE6-5467736251BF}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,187 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="8.00"
|
||||||
|
Name="libco_msvc_win32"
|
||||||
|
ProjectGUID="{C5D03072-BBF9-4DED-8CE6-5467736251BF}"
|
||||||
|
RootNamespace="libco_msvc_win32"
|
||||||
|
Keyword="Win32Proj"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="2"
|
||||||
|
CharacterSet="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
CommandLine=""
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBCO_MSVC_EXPORTS"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="3"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="true"
|
||||||
|
DebugInformationFormat="4"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
LinkIncremental="2"
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
SubSystem="2"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManifestTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAppVerifierTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
CommandLine="copy $(TargetPath) ..\..\BizHawk.MultiClient\output"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="2"
|
||||||
|
CharacterSet="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
CommandLine=""
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBCO_MSVC_EXPORTS"
|
||||||
|
RuntimeLibrary="2"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
Detect64BitPortabilityProblems="true"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
LinkIncremental="1"
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
SubSystem="2"
|
||||||
|
OptimizeReferences="2"
|
||||||
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManifestTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAppVerifierTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
CommandLine="copy $(TargetPath) ..\..\BizHawk.MultiClient\output"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<File
|
||||||
|
RelativePath=".\libco_msvc_win32.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\readme.txt"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,11 @@
|
||||||
|
* Why does this exist?
|
||||||
|
|
||||||
|
Because zeromus can't figure out how to successfully compile this code in mingw32.
|
||||||
|
My efforts are in trying-to-port-to-mingw-win32.c; I don't know why it isn't working.
|
||||||
|
|
||||||
|
* Why do we need this code?
|
||||||
|
|
||||||
|
Because libco needs to be a bit more properly win32 in order for it to get used from .net code.
|
||||||
|
.net throws exceptions in each thread when it needs to suspend them for GC.
|
||||||
|
Those exceptions get garbled without more proper win32 stack frame setup, and the process terminates.
|
||||||
|
Additionally, you wont be able to debug very well from callbacks out of a coroutine into c# without this.
|
|
@ -0,0 +1,178 @@
|
||||||
|
//links of interest
|
||||||
|
//http://connect.microsoft.com/VisualStudio/feedback/details/100319/really-wierd-behaviour-in-crt-io-coupled-with-some-inline-assembly
|
||||||
|
//http://en.wikipedia.org/wiki/Thread_Information_Block
|
||||||
|
//http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/72093e46-4524-4f54-9f36-c7e8a309d1db/ //FS warning
|
||||||
|
|
||||||
|
#define LIBCO_C
|
||||||
|
#define LIBCO_EXPORT
|
||||||
|
#include "../bsnes/libco/libco.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*coentry_t)(void);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
jmp_buf context;
|
||||||
|
coentry_t coentry;
|
||||||
|
void *stack;
|
||||||
|
unsigned long seh_frame, stack_top, stack_bottom;
|
||||||
|
cothread_t caller;
|
||||||
|
} cothread_struct;
|
||||||
|
|
||||||
|
static thread_local cothread_struct co_primary;
|
||||||
|
static thread_local cothread_struct *co_running = 0;
|
||||||
|
|
||||||
|
#define WINVER 0x0400
|
||||||
|
#define _WIN32_WINNT 0x0400
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
typedef struct __JUMP_BUFFER {
|
||||||
|
unsigned long Ebp;
|
||||||
|
unsigned long Ebx;
|
||||||
|
unsigned long Edi;
|
||||||
|
unsigned long Esi;
|
||||||
|
unsigned long Esp;
|
||||||
|
unsigned long Eip;
|
||||||
|
unsigned long Registration;
|
||||||
|
unsigned long TryLevel;
|
||||||
|
unsigned long Cookie;
|
||||||
|
unsigned long UnwindFunc;
|
||||||
|
unsigned long UnwindData[6];
|
||||||
|
} _JUMP_BUFFER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma warning(disable:4733)
|
||||||
|
#pragma warning(disable:4311)
|
||||||
|
|
||||||
|
static void capture_fs(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
asm(
|
||||||
|
"mov %0, dword ptr fs:[0];"
|
||||||
|
"mov %1, dword ptr fs:[4];"
|
||||||
|
"mov %2, dword ptr fs:[8];"
|
||||||
|
:"=r"(rec->seh_frame), "=r"(rec->stack_top), "=r"(rec->stack_bottom)
|
||||||
|
:
|
||||||
|
:
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_fs(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
asm(
|
||||||
|
"mov dword ptr fs:[0], %0;"
|
||||||
|
"mov dword ptr fs:[4], %1;"
|
||||||
|
"mov dword ptr fs:[8], %2;"
|
||||||
|
:
|
||||||
|
:"r"(rec->seh_frame), "r"(rec->stack_top), "r"(rec->stack_bottom)
|
||||||
|
:
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_co_wrapper()
|
||||||
|
{
|
||||||
|
cothread_struct* rec = (cothread_struct*)co_active();
|
||||||
|
//__try
|
||||||
|
//{
|
||||||
|
rec->coentry();
|
||||||
|
//}
|
||||||
|
//__except(EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
//{
|
||||||
|
// //unhandled win32 exception in coroutine.
|
||||||
|
// //this coroutine will now be suspended permanently and control will be yielded to caller, for lack of anything better to do.
|
||||||
|
// //perhaps the process should just terminate.
|
||||||
|
// for(;;)
|
||||||
|
// {
|
||||||
|
// //dead coroutine
|
||||||
|
// co_switch(rec->caller);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_co_create(cothread_struct* rec, unsigned int size, coentry_t coentry)
|
||||||
|
{
|
||||||
|
_JUMP_BUFFER* jb = (_JUMP_BUFFER*)&rec->context;
|
||||||
|
cothread_struct temp;
|
||||||
|
|
||||||
|
jb->Esp = (unsigned long)rec->stack + size - 4;
|
||||||
|
jb->Eip = (unsigned long)os_co_wrapper;
|
||||||
|
|
||||||
|
rec->stack_top = jb->Esp + 4;
|
||||||
|
rec->stack_bottom = (unsigned long)rec->stack;
|
||||||
|
|
||||||
|
//wild assumption about SEH frame.. seems to work
|
||||||
|
capture_fs(&temp);
|
||||||
|
rec->seh_frame = temp.seh_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_pre_setjmp(cothread_t target)
|
||||||
|
{
|
||||||
|
cothread_struct* rec = (cothread_struct*)target;
|
||||||
|
capture_fs(co_running);
|
||||||
|
rec->caller = co_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_pre_longjmp(cothread_struct* rec)
|
||||||
|
{
|
||||||
|
restore_fs(rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
cothread_t co_active()
|
||||||
|
{
|
||||||
|
if(!co_running) co_running = &co_primary;
|
||||||
|
return (cothread_t)co_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cothread_t co_create(unsigned int size, void (*coentry)(void))
|
||||||
|
{
|
||||||
|
cothread_struct *thread;
|
||||||
|
|
||||||
|
if(!co_running) co_running = &co_primary;
|
||||||
|
|
||||||
|
thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||||
|
if(thread)
|
||||||
|
{
|
||||||
|
thread->coentry = coentry;
|
||||||
|
thread->stack = malloc(size);
|
||||||
|
{
|
||||||
|
setjmp(thread->context);
|
||||||
|
os_co_create(thread,size,coentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (cothread_t)thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void co_delete(cothread_t cothread)
|
||||||
|
{
|
||||||
|
if(cothread)
|
||||||
|
{
|
||||||
|
if(((cothread_struct*)cothread)->stack)
|
||||||
|
{
|
||||||
|
free(((cothread_struct*)cothread)->stack);
|
||||||
|
}
|
||||||
|
free(cothread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void co_switch(cothread_t cothread)
|
||||||
|
{
|
||||||
|
os_pre_setjmp(cothread);
|
||||||
|
if(!setjmp(co_running->context))
|
||||||
|
{
|
||||||
|
co_running = (cothread_struct*)cothread;
|
||||||
|
os_pre_longjmp(co_running);
|
||||||
|
longjmp(co_running->context,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Reference in New Issue