mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v028 release.
Changelog: - OpenGL (with hardware filter mode support) and SDL video drivers added to Linux port - OpenAL (with speed regulation disable support) and OSS audio drivers added to Linux port [Nach] - SDL input driver (with joypad support) added to Linux port - Emulator pause option added - Added option to select behavior of bsnes when idle: allow input, ignore input or pause emulator - Added support to remap common GUI actions to key/joypad presses on the "Input Configuration" screen - bsnes will now clamp the video output size when it is larger than the screen resolution - GUI library has been enhanced, and renamed to hiro - Fullscreen mode now always centers video, rather than approximates - Fullscreen mode now works correctly on Linux/Openbox - Extra layer of abstraction in src/ui has been removed, as GUI lib unifies all ports anyway - Video, audio and input drivers unified into standard library, named ruby - All custom headers have been merged into a new template library, named nall - Makefile rewritten, vastly improved. Allows quick toggling of compiled-in drivers - Makefile: all object files now placed in /src/obj, binary placed in / - libco greatly enhanced, no longer requires an assembler to build [byuu, blargg, Nach] - libco SJLJ driver added; bsnes should now build on any Unix-derivative now (Solaris, OS X, PS3, etc) [Nach] - Fixed register $213e.d4 PPU1 open bus behavior [zones] - Windows port will not activate screensaver while bsnes is running [Nightcrawler] - Visual C++ target no longer requires stdint.h - And lots more -- mostly code refactoring related
This commit is contained in:
parent
b934ce41d9
commit
dc692754c3
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
libco.win (2008-01-28)
|
||||
authors: Nach, byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "../libco.h"
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local cothread_t co_active_ = 0;
|
||||
|
||||
static void __stdcall co_thunk(void *coentry) {
|
||||
((void (*)(void))coentry)();
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_) {
|
||||
ConvertThreadToFiber(0);
|
||||
co_active_ = GetCurrentFiber();
|
||||
}
|
||||
return co_active_;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
|
||||
if(!co_active_) {
|
||||
ConvertThreadToFiber(0);
|
||||
co_active_ = GetCurrentFiber();
|
||||
}
|
||||
return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
DeleteFiber(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
co_active_ = cothread;
|
||||
SwitchToFiber(cothread);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
libco.ucontext (2007-09-08)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ucontext.h>
|
||||
#include "../libco.h"
|
||||
|
||||
//WARNING: the overhead of POSIX ucontext is very high,
|
||||
//averaging ~450x that of standard subroutine calls.
|
||||
//(tested on FreeBSD 6.2-RELEASE)
|
||||
//By contrast, on the same system, libco_x86's overhead
|
||||
//is ~7.25x standard subroutine calls; or fifty times faster.
|
||||
//
|
||||
//This library only exists for two reasons:
|
||||
//1 - as an initial test for the viability of a ucontext implementation
|
||||
//2 - to demonstrate the power and speed of libco over existing implementations,
|
||||
// such as pth (which defaults to wrapping ucontext on unix targets)
|
||||
//
|
||||
//Use this library only as a *last resort*
|
||||
|
||||
struct cothread_struct {
|
||||
ucontext_t cohandle;
|
||||
void (*coentry)();
|
||||
};
|
||||
|
||||
cothread_t __co_active = 0, __co_primary = 0;
|
||||
void co_entrypoint(cothread_t cothread);
|
||||
void co_init();
|
||||
|
||||
/*****
|
||||
* library functions
|
||||
*****/
|
||||
|
||||
cothread_t co_active() {
|
||||
if(__co_primary == 0)co_init();
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)()) {
|
||||
if(__co_primary == 0)co_init();
|
||||
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
thread->coentry = coentry;
|
||||
getcontext(&thread->cohandle);
|
||||
heapsize += 512;
|
||||
thread->cohandle.uc_stack.ss_sp = (char*)malloc(heapsize);
|
||||
thread->cohandle.uc_stack.ss_size = heapsize;
|
||||
makecontext(&thread->cohandle, (void (*)())co_entrypoint, 1, thread);
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
cothread_struct *thread = (cothread_struct*)cothread;
|
||||
free(thread->cohandle.uc_stack.ss_sp);
|
||||
free(thread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
cothread_struct *active = (cothread_struct*)__co_active;
|
||||
cothread_struct *swap = (cothread_struct*)cothread;
|
||||
__co_active = cothread;
|
||||
swapcontext(&active->cohandle, &swap->cohandle);
|
||||
}
|
||||
|
||||
/*****
|
||||
* internal functions
|
||||
*****/
|
||||
|
||||
void co_entrypoint(cothread_t cothread) {
|
||||
((cothread_struct*)cothread)->coentry();
|
||||
}
|
||||
|
||||
void co_init() {
|
||||
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
thread->coentry = 0;
|
||||
getcontext(&thread->cohandle);
|
||||
__co_active = __co_primary = (cothread_t)thread;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
libco.win (2007-09-08)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
#include "../libco.h"
|
||||
|
||||
struct cothread_struct {
|
||||
void *cohandle;
|
||||
void (*coentry)();
|
||||
};
|
||||
|
||||
cothread_t __co_active = 0, __co_primary = 0;
|
||||
|
||||
void __stdcall co_entryproc(void*);
|
||||
cothread_t co_init();
|
||||
|
||||
/*****
|
||||
* library functions
|
||||
*****/
|
||||
|
||||
cothread_t co_active() {
|
||||
if(__co_primary == 0)co_init();
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)()) {
|
||||
if(__co_primary == 0)co_init();
|
||||
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
s->coentry = coentry;
|
||||
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, (void*)s);
|
||||
return (cothread_t)s;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
cothread_struct *s = (cothread_struct*)cothread;
|
||||
DeleteFiber(s->cohandle);
|
||||
free(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
__co_active = cothread;
|
||||
cothread_struct *s = (cothread_struct*)cothread;
|
||||
SwitchToFiber(s->cohandle);
|
||||
}
|
||||
|
||||
/*****
|
||||
* internal functions
|
||||
*****/
|
||||
|
||||
void __stdcall co_entryproc(void *cothread) {
|
||||
((cothread_struct*)cothread)->coentry();
|
||||
}
|
||||
|
||||
cothread_t co_init() {
|
||||
ConvertThreadToFiber(0);
|
||||
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
s->coentry = 0;
|
||||
s->cohandle = GetCurrentFiber();
|
||||
__co_active = __co_primary = (cothread_t)s;
|
||||
return __co_active;
|
||||
}
|
146
libco.x86-64.asm
146
libco.x86-64.asm
|
@ -1,146 +0,0 @@
|
|||
;*****
|
||||
;libco.x86-64 (2007-12-11)
|
||||
;author: byuu
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform x86-64 implementation of libco
|
||||
;thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;thanks to Lucas Newman and Vas Crabb for assistance with OS X support
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf )
|
||||
;- gcc; mac os x; x86-64
|
||||
;- gcc; linux; x86-64
|
||||
;- gcc; freebsd; x86-64
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- rsp, rbp, rbx, r12, r13, r14, r15
|
||||
;
|
||||
;[volatile registers]
|
||||
;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi
|
||||
;- st0 - st7
|
||||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
;*****
|
||||
;linker-specific name decorations
|
||||
;*****
|
||||
|
||||
%ifdef OSX
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active _co_active
|
||||
%define co_create _co_create
|
||||
%define co_delete _co_delete
|
||||
%define co_switch _co_switch
|
||||
%endif
|
||||
|
||||
bits 64
|
||||
|
||||
section .bss
|
||||
|
||||
align 8
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 8
|
||||
co_active_context dq co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
extern malloc
|
||||
extern free
|
||||
|
||||
global co_active
|
||||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_active:
|
||||
mov rax,[co_active_context wrt rip]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;rdi = heapsize
|
||||
;rsi = coentry
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
;create heap space (stack + context)
|
||||
add rdi,512 ;allocate extra memory for contextual info
|
||||
|
||||
push rdi ;backup volatile registers before malloc call
|
||||
push rsi
|
||||
|
||||
sub rsp,8 ;SSE 16-byte stack alignment
|
||||
call malloc ;rax = malloc(rdi)
|
||||
add rsp,8
|
||||
|
||||
pop rsi ;restore volatile registers
|
||||
pop rdi
|
||||
|
||||
add rdi,rax ;set rdi to point to top of stack heap
|
||||
and rdi,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov qword[rdi-8],0 ;crash if entry point returns
|
||||
mov qword[rdi-16],rsi ;entry point
|
||||
mov qword[rdi-24],0 ;r15
|
||||
mov qword[rdi-32],0 ;r14
|
||||
mov qword[rdi-40],0 ;r13
|
||||
mov qword[rdi-48],0 ;r12
|
||||
mov qword[rdi-56],0 ;rbx
|
||||
mov qword[rdi-64],0 ;rbp
|
||||
sub rdi,64
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [rax],rdi ;*cothread_t = stack heap pointer (rsp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_delete:
|
||||
jmp free ;free(rdi)
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_switch:
|
||||
mov rax,[co_active_context wrt rip] ;backup current context
|
||||
mov [co_active_context wrt rip],rdi ;set new active context
|
||||
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
mov [rax],rsp
|
||||
|
||||
mov rsp,[rdi]
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
pop rbp
|
||||
|
||||
ret
|
155
libco.x86.asm
155
libco.x86.asm
|
@ -1,155 +0,0 @@
|
|||
;*****
|
||||
;libco.x86 (2007-12-11)
|
||||
;author: byuu
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform x86 implementation of libco
|
||||
;thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;thanks to Lucas Newman and Vas Crabb for assistance with OS X support
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- visual c++; windows; x86
|
||||
;- mingw; windows; x86
|
||||
;- gcc; mac os x; x86
|
||||
;- gcc; linux; x86
|
||||
;- gcc; freebsd; x86
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- esp, ebp, edi, esi, ebx
|
||||
;
|
||||
;[volatile registers]
|
||||
;- eax, ecx, edx
|
||||
;- st0 - st7
|
||||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
;*****
|
||||
;linker-specific name decorations
|
||||
;*****
|
||||
|
||||
%ifdef WIN
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active @co_active@0
|
||||
%define co_create @co_create@8
|
||||
%define co_delete @co_delete@4
|
||||
%define co_switch @co_switch@4
|
||||
%endif
|
||||
|
||||
%ifdef OSX
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active _co_active
|
||||
%define co_create _co_create
|
||||
%define co_delete _co_delete
|
||||
%define co_switch _co_switch
|
||||
%endif
|
||||
|
||||
bits 32
|
||||
|
||||
section .bss
|
||||
|
||||
align 4
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 4
|
||||
co_active_context dd co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
extern malloc
|
||||
extern free
|
||||
|
||||
global co_active
|
||||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_active();
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_active:
|
||||
mov eax,[co_active_context]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
|
||||
;ecx = heapsize
|
||||
;edx = coentry
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
;create heap space (stack + context)
|
||||
add ecx,512 ;allocate extra memory for contextual info
|
||||
|
||||
push ecx ;backup volatile registers before malloc call
|
||||
push edx
|
||||
|
||||
push ecx
|
||||
call malloc ;eax = malloc(ecx)
|
||||
add esp,4
|
||||
|
||||
pop edx ;restore volatile registers
|
||||
pop ecx
|
||||
|
||||
add ecx,eax ;set edx to point to top of stack heap
|
||||
and ecx,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov dword[ecx-4],0 ;crash if entry point returns
|
||||
mov dword[ecx-8],edx ;entry point
|
||||
mov dword[ecx-12],0 ;ebp
|
||||
mov dword[ecx-16],0 ;esi
|
||||
mov dword[ecx-20],0 ;edi
|
||||
mov dword[ecx-24],0 ;ebx
|
||||
sub ecx,24
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [eax],ecx ;*cothread_t = stack heap pointer (esp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_delete(cothread_t cothread);
|
||||
;ecx = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_delete:
|
||||
sub esp,8 ;SSE 16-byte stack alignment
|
||||
push ecx
|
||||
call free ;free(ecx)
|
||||
add esp,4+8
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_switch(cothread_t cothread);
|
||||
;ecx = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_switch:
|
||||
mov eax,[co_active_context] ;backup current context
|
||||
mov [co_active_context],ecx ;set new active context
|
||||
|
||||
push ebp
|
||||
push esi
|
||||
push edi
|
||||
push ebx
|
||||
mov [eax],esp
|
||||
|
||||
mov esp,[ecx]
|
||||
pop ebx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
|
||||
ret
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
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
|
||||
#include "../libco.h"
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
sigjmp_buf context;
|
||||
void (*coentry)(void);
|
||||
void *stack;
|
||||
} cothread_struct;
|
||||
|
||||
static thread_local cothread_struct co_primary;
|
||||
static thread_local cothread_struct *creating, *co_running = 0;
|
||||
|
||||
static void springboard(int ignored) {
|
||||
if(sigsetjmp(creating->context, 0)) {
|
||||
co_running->coentry();
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
|
||||
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
if(thread) {
|
||||
struct sigaction handler;
|
||||
struct sigaction old_handler;
|
||||
|
||||
stack_t stack;
|
||||
stack_t old_stack;
|
||||
|
||||
thread->coentry = thread->stack = 0;
|
||||
|
||||
stack.ss_flags = 0;
|
||||
stack.ss_size = size;
|
||||
thread->stack = stack.ss_sp = malloc(size);
|
||||
if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) {
|
||||
handler.sa_handler = springboard;
|
||||
handler.sa_flags = SA_ONSTACK;
|
||||
sigemptyset(&handler.sa_mask);
|
||||
creating = thread;
|
||||
|
||||
if(!sigaction(SIGUSR1, &handler, &old_handler)) {
|
||||
if(!raise(SIGUSR1)) {
|
||||
thread->coentry = coentry;
|
||||
}
|
||||
sigaltstack(&old_stack, 0);
|
||||
sigaction(SIGUSR1, &old_handler, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(thread->coentry != coentry) {
|
||||
co_delete(thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if(!sigsetjmp(co_running->context, 0)) {
|
||||
co_running = (cothread_struct*)cothread;
|
||||
siglongjmp(co_running->context, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
libco.ucontext (2008-01-28)
|
||||
author: Nach
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING: the overhead of POSIX ucontext is very high,
|
||||
* assembly versions of libco or libco_sjlj should be much faster
|
||||
*
|
||||
* This library only exists for two reasons:
|
||||
* 1 - as an initial test for the viability of a ucontext implementation
|
||||
* 2 - to demonstrate the power and speed of libco over existing implementations,
|
||||
* such as pth (which defaults to wrapping ucontext on unix targets)
|
||||
*
|
||||
* Use this library only as a *last resort*
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "../libco.h"
|
||||
#include <stdlib.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local ucontext_t co_primary;
|
||||
static thread_local ucontext_t *co_running = 0;
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
return (cothread_t)co_running;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) {
|
||||
if(!co_running) co_running = &co_primary;
|
||||
ucontext_t *thread = (ucontext_t*)malloc(sizeof(ucontext_t));
|
||||
if(thread) {
|
||||
if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize))) {
|
||||
thread->uc_link = co_running;
|
||||
thread->uc_stack.ss_size = heapsize;
|
||||
makecontext(thread, coentry, 0);
|
||||
} else {
|
||||
co_delete((cothread_t)thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
if(cothread) {
|
||||
if(((ucontext_t*)cothread)->uc_stack.ss_sp) { free(((ucontext_t*)cothread)->uc_stack.ss_sp); }
|
||||
free(cothread);
|
||||
}
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
ucontext_t *old_thread = co_running;
|
||||
co_running = (ucontext_t*)cothread;
|
||||
swapcontext(old_thread, co_running);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
libco.x86-64 (2008-01-28)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "../libco.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local long co_active_buffer[32];
|
||||
static thread_local cothread_t co_active_ = 0;
|
||||
|
||||
static void crash() {
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_) co_active_ = &co_active_buffer;
|
||||
return co_active_;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
cothread_t handle;
|
||||
assert(sizeof(long) == 8);
|
||||
if(!co_active_) co_active_ = &co_active_buffer;
|
||||
size += 128; /* allocate additional space for storage */
|
||||
size &= ~15; /* align stack to 16-byte boundary */
|
||||
|
||||
if(handle = (cothread_t)calloc(size, 1)) {
|
||||
long *p = (long*)((char*)handle + size); /* seek to top of stack */
|
||||
*--p = (long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long)entrypoint; /* start of function */
|
||||
*(long*)handle = (long)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t to) {
|
||||
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
|
||||
register cothread_t from = co_active_;
|
||||
co_active_ = to;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movq %%rsp,(%1) \n\t" /* save old stack pointer */
|
||||
"movq (%0),%%rsp \n\t" /* load new stack pointer */
|
||||
"addq $8,%%rsp \n\t" /* "pop" return address off stack */
|
||||
|
||||
"movq %%rbp, 8(%1) \n\t" /* backup non-volatile registers */
|
||||
"movq %%rbx,16(%1) \n\t"
|
||||
"movq %%r12,24(%1) \n\t"
|
||||
"movq %%r13,32(%1) \n\t"
|
||||
"movq %%r14,40(%1) \n\t"
|
||||
"movq %%r15,48(%1) \n\t"
|
||||
|
||||
"movq 8(%0),%%rbp \n\t" /* restore non-volatile registers */
|
||||
"movq 16(%0),%%rbx \n\t"
|
||||
"movq 24(%0),%%r12 \n\t"
|
||||
"movq 32(%0),%%r13 \n\t"
|
||||
"movq 40(%0),%%r14 \n\t"
|
||||
"movq 48(%0),%%r15 \n\t"
|
||||
|
||||
"jmp *(%2) \n\t" /* jump into "to" thread */
|
||||
: /* no outputs */
|
||||
: "r" (to), "r" (from), "r" (stack)
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
libco.x86 (2008-01-28)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "../libco.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local long co_active_buffer[32];
|
||||
static thread_local cothread_t co_active_ = 0;
|
||||
|
||||
static void crash() {
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
cothread_t co_active() {
|
||||
if(!co_active_) co_active_ = &co_active_buffer;
|
||||
return co_active_;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
|
||||
cothread_t handle;
|
||||
assert(sizeof(long) == 4);
|
||||
if(!co_active_) co_active_ = &co_active_buffer;
|
||||
size += 128; /* allocate additional space for storage */
|
||||
size &= ~15; /* align stack to 16-byte boundary */
|
||||
|
||||
if(handle = (cothread_t)calloc(size, 1)) {
|
||||
long *p = (long*)((char*)handle + size); /* seek to top of stack */
|
||||
*--p = (long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long)entrypoint; /* start of function */
|
||||
*(long*)handle = (long)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle) {
|
||||
free(handle);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
||||
void co_switch(cothread_t to) {
|
||||
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
|
||||
register cothread_t from = co_active_;
|
||||
co_active_ = to;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"movl %%esp,(%1) \n\t" /* save old stack pointer */
|
||||
"movl (%0),%%esp \n\t" /* load new stack pointer */
|
||||
"addl $4,%%esp \n\t" /* "pop" return address off stack */
|
||||
|
||||
"movl %%ebp, 4(%1) \n\t" /* backup non-volatile registers */
|
||||
"movl %%esi, 8(%1) \n\t"
|
||||
"movl %%edi,12(%1) \n\t"
|
||||
"movl %%ebx,16(%1) \n\t"
|
||||
|
||||
"movl 4(%0),%%ebp \n\t" /* restore non-volatile registers */
|
||||
"movl 8(%0),%%esi \n\t"
|
||||
"movl 12(%0),%%edi \n\t"
|
||||
"movl 16(%0),%%ebx \n\t"
|
||||
|
||||
"jmp *(%2) \n\t" /* jump into "to" thread */
|
||||
: /* no outputs */
|
||||
: "r" (to), "r" (from), "r" (stack)
|
||||
);
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
__declspec(naked) __declspec(noinline)
|
||||
static void __fastcall co_swap(register cothread_t to, register cothread_t from) {
|
||||
/* ecx = to, edx = from */
|
||||
__asm {
|
||||
mov [edx],esp
|
||||
mov esp,[ecx]
|
||||
pop eax
|
||||
|
||||
mov [edx+ 4],ebp
|
||||
mov [edx+ 8],esi
|
||||
mov [edx+12],edi
|
||||
mov [edx+16],ebx
|
||||
|
||||
mov ebp,[ecx+ 4]
|
||||
mov esi,[ecx+ 8]
|
||||
mov edi,[ecx+12]
|
||||
mov ebx,[ecx+16]
|
||||
|
||||
jmp eax
|
||||
}
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle) {
|
||||
register cothread_t co_prev_ = co_active_;
|
||||
co_swap(co_active_ = handle, co_prev_);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue