2010-08-09 13:28:56 +00:00
|
|
|
/*
|
|
|
|
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"
|
Update to v094r29 release.
byuu says:
Note: for Windows users, please go to nall/intrinsics.hpp line 60 and
correct the typo from "DISPLAY_WINDOW" to "DISPLAY_WINDOWS" before
compiling, otherwise things won't work at all.
This will be a really major WIP for the core SNES emulation, so please
test as thoroughly as possible.
I rewrote the 65816 CPU core's dispatcher from a jump table to a switch
table. This was so that I could pass class variables as parameters to
opcodes without crazy theatrics.
With that, I killed the regs.r[N] stuff, the flag_t operator|=, &=, ^=
stuff, and all of the template versions of opcodes.
I also removed some stupid pointless flag tests in xcn and pflag that
would always be true.
I sure hope that AWJ is happy with this; because this change was so that
my flag assignments and branch tests won't need to build regs.P into
a full 8-bit variable anymore.
It does of course incur a slight performance hit when you pass in
variables by-value to functions, but it should help with binary size
(and thus cache) by reducing a lot of extra functions. (I know I could
have used template parameters for some things even with a switch table,
but chose not to for the aforementioned reasons.)
Overall, it's about a ~1% speedup from the previous build. The CPU core
instructions were never a bottleneck, but I did want to fix the P flag
building stuff because that really was a dumb mistake v_v'
2015-06-22 13:31:49 +00:00
|
|
|
|
2010-08-09 13:28:56 +00:00
|
|
|
#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
|