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