From fc862fbfcc3e05b5b74b7057d7288cc58d3c79a6 Mon Sep 17 00:00:00 2001 From: Not6 Date: Sun, 15 Oct 2017 20:21:24 +0200 Subject: [PATCH] update libco --- libretro/libco/amd64.c | 63 +++++++++-------- libretro/libco/armeabi.c | 28 +++++--- libretro/libco/fiber.c | 13 ++++ libretro/libco/libco.c | 37 ++++++---- libretro/libco/libco.h | 75 ++++++++++++++++---- libretro/libco/psp2.c | 113 ++++++++++++++++++++++++++++++ libretro/libco/retro_common_api.h | 108 ++++++++++++++++++++++++++++ libretro/libco/scefiber.c | 96 +++++++++++++++++++++++++ libretro/libco/sjlj.c | 12 ++-- 9 files changed, 476 insertions(+), 69 deletions(-) create mode 100644 libretro/libco/psp2.c create mode 100644 libretro/libco/retro_common_api.h create mode 100644 libretro/libco/scefiber.c diff --git a/libretro/libco/amd64.c b/libretro/libco/amd64.c index 21d5990..2494415 100644 --- a/libretro/libco/amd64.c +++ b/libretro/libco/amd64.c @@ -5,7 +5,7 @@ */ #define LIBCO_C -#include "libco.h" +#include #include #include @@ -21,12 +21,10 @@ static thread_local long long co_active_buffer[64]; static thread_local cothread_t co_active_handle = 0; #ifndef CO_USE_INLINE_ASM static void (*co_swap)(cothread_t, cothread_t) = 0; -#else -void co_swap(cothread_t, cothread_t); #endif #ifdef _WIN32 -//ABI: Win64 +/* ABI: Win64 */ static unsigned char co_swap_function[] = { 0x48, 0x89, 0x22, /* mov [rdx],rsp */ 0x48, 0x8b, 0x21, /* mov rsp,[rcx] */ @@ -83,7 +81,7 @@ void co_init(void) sizeof(co_swap_function), PAGE_EXECUTE_READWRITE, &old_privileges); } #else -//ABI: SystemV +/* ABI: SystemV */ #ifndef CO_USE_INLINE_ASM static unsigned char co_swap_function[] = { 0x48, 0x89, 0x26, /* mov [rsi],rsp */ @@ -115,29 +113,7 @@ void co_init(void) mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC); } #else -__asm__( -".intel_syntax noprefix\n" -".globl co_swap \n" -"co_swap: \n" -".globl _co_swap \n" /* OSX ABI is different from Linux. */ -"_co_swap: \n" -"mov [rsi],rsp \n" -"mov [rsi+0x08],rbp \n" -"mov [rsi+0x10],rbx \n" -"mov [rsi+0x18],r12 \n" -"mov [rsi+0x20],r13 \n" -"mov [rsi+0x28],r14 \n" -"mov [rsi+0x30],r15 \n" -"mov rsp,[rdi] \n" -"mov rbp,[rdi+0x08] \n" -"mov rbx,[rdi+0x10] \n" -"mov r12,[rdi+0x18] \n" -"mov r13,[rdi+0x20] \n" -"mov r14,[rdi+0x28] \n" -"mov r15,[rdi+0x30] \n" -"ret \n" -".att_syntax \n" -); +void co_init(void) {} #endif #endif @@ -186,11 +162,42 @@ void co_delete(cothread_t handle) free(handle); } +#ifndef CO_USE_INLINE_ASM void co_switch(cothread_t handle) { register cothread_t co_previous_handle = co_active_handle; co_swap(co_active_handle = handle, co_previous_handle); } +#else +#ifdef __APPLE__ +#define ASM_PREFIX "_" +#else +#define ASM_PREFIX "" +#endif +__asm__( +".intel_syntax noprefix \n" +".globl " ASM_PREFIX "co_switch \n" +ASM_PREFIX "co_switch: \n" +"mov rsi, [rip+" ASM_PREFIX "co_active_handle]\n" +"mov [rsi],rsp \n" +"mov [rsi+0x08],rbp \n" +"mov [rsi+0x10],rbx \n" +"mov [rsi+0x18],r12 \n" +"mov [rsi+0x20],r13 \n" +"mov [rsi+0x28],r14 \n" +"mov [rsi+0x30],r15 \n" +"mov [rip+" ASM_PREFIX "co_active_handle], rdi\n" +"mov rsp,[rdi] \n" +"mov rbp,[rdi+0x08] \n" +"mov rbx,[rdi+0x10] \n" +"mov r12,[rdi+0x18] \n" +"mov r13,[rdi+0x20] \n" +"mov r14,[rdi+0x28] \n" +"mov r15,[rdi+0x30] \n" +"ret \n" +".att_syntax \n" +); +#endif #ifdef __cplusplus } diff --git a/libretro/libco/armeabi.c b/libretro/libco/armeabi.c index 1457c27..6128f3f 100644 --- a/libretro/libco/armeabi.c +++ b/libretro/libco/armeabi.c @@ -11,7 +11,7 @@ #include #include -#ifndef IOS +#ifndef __APPLE__ #include #endif @@ -23,6 +23,22 @@ static thread_local uint32_t co_active_buffer[64]; static thread_local cothread_t co_active_handle; asm ( +#if defined(__thumb2__) + ".thumb\n" + ".align 2\n" + ".globl co_switch_arm\n" + ".globl _co_switch_arm\n" + "co_switch_arm:\n" + "_co_switch_arm:\n" + " mov r3, sp\n" + " stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\n" + " stmia r1!, {r3, lr}\n" + " ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n" + " ldmfd r0!, { r3 }\n" + " mov sp, r3\n" + " ldmfd r0!, { r3 }\n" + " mov pc, r3\n" +#else ".arm\n" ".align 4\n" ".globl co_switch_arm\n" @@ -31,22 +47,17 @@ asm ( "_co_switch_arm:\n" " stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n" " ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n" +#endif ); /* ASM */ void co_switch_arm(cothread_t handle, cothread_t current); -static void crash(void) -{ - /* Called only if cothread_t entrypoint returns. */ - assert(0); -} - cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { size = (size + 1023) & ~1023; cothread_t handle = 0; -#if HAVE_POSIX_MEMALIGN >= 1 +#if defined(__APPLE__) || HAVE_POSIX_MEMALIGN >= 1 if (posix_memalign(&handle, 1024, size + 256) < 0) return 0; #else @@ -66,6 +77,7 @@ cothread_t co_create(unsigned int size, void (*entrypoint)(void)) ptr[5] = 0; /* r9 */ ptr[6] = 0; /* r10 */ ptr[7] = 0; /* r11 */ + /* Align stack to 64-bit */ ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */ ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */ return handle; diff --git a/libretro/libco/fiber.c b/libretro/libco/fiber.c index 90ba115..9e63089 100644 --- a/libretro/libco/fiber.c +++ b/libretro/libco/fiber.c @@ -26,7 +26,11 @@ cothread_t co_active(void) { if(!co_active_) { +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH); +#else ConvertThreadToFiber(0); +#endif co_active_ = GetCurrentFiber(); } return co_active_; @@ -36,10 +40,19 @@ cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) { if(!co_active_) { +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH); +#else ConvertThreadToFiber(0); +#endif co_active_ = GetCurrentFiber(); } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + return (cothread_t)CreateFiberEx(heapsize, heapsize, FIBER_FLAG_FLOAT_SWITCH, co_thunk, (void*)coentry); +#else return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry); +#endif } void co_delete(cothread_t cothread) diff --git a/libretro/libco/libco.c b/libretro/libco/libco.c index 63126d3..4cc65b2 100644 --- a/libretro/libco/libco.c +++ b/libretro/libco/libco.c @@ -4,18 +4,31 @@ license: public domain */ -#if defined(__GNUC__) && defined(__i386__) || (defined(_MSC_VER) && defined(_M_IX86)) - #include "x86.c" -#elif defined(__GNUC__) && defined(__amd64__) || (defined(_MSC_VER) && defined(_M_AMD64)) - #include "amd64.c" -#elif defined(__GNUC__) && defined(_ARCH_PPC) - #include "ppc.c" -#elif defined(__GNUC__) && (defined(__ARM_EABI__) || defined(__arm__)) - #include "armeabi.c" -#elif defined(__GNUC__) - #include "sjlj.c" -#elif defined(_MSC_VER) - #include "fiber.c" +#if defined _MSC_VER + #include + #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + #include "fiber.c" + #elif defined _M_IX86 + #include "x86.c" + #elif defined _M_AMD64 + #include "amd64.c" + #else + #include "fiber.c" + #endif +#elif defined __GNUC__ + #if defined __i386__ + #include "x86.c" + #elif defined __amd64__ + #include "amd64.c" + #elif defined _ARCH_PPC + #include "ppc.c" + #elif defined VITA + #include "scefiber.c" + #elif defined(__ARM_EABI__) || defined(__arm__) + #include "armeabi.c" + #else + #include "sjlj.c" + #endif #else #error "libco: unsupported processor, compiler or operating system" #endif diff --git a/libretro/libco/libco.h b/libretro/libco/libco.h index deb954f..1599cb2 100644 --- a/libretro/libco/libco.h +++ b/libretro/libco/libco.h @@ -1,12 +1,30 @@ -/* - libco - version: 0.16 (2010-12-24) - license: public domain -*/ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (libco.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ #ifndef LIBCO_H #define LIBCO_H +#include + #ifdef LIBCO_C #ifdef LIBCO_MP #define thread_local __thread @@ -15,20 +33,47 @@ #endif #endif -#ifdef __cplusplus -extern "C" { -#endif +RETRO_BEGIN_DECLS typedef void* cothread_t; -cothread_t co_active(); -cothread_t co_create(unsigned int, void (*)(void)); -void co_delete(cothread_t); -void co_switch(cothread_t); +/** + * co_active: + * + * Gets the currently active context. + * + * Returns: active context. + **/ +cothread_t co_active(void); -#ifdef __cplusplus -} -#endif +/** + * co_create: + * @int : stack size + * @funcptr : thread entry function callback + * + * Create a co_thread. + * + * Returns: cothread if successful, otherwise NULL. + */ +cothread_t co_create(unsigned int, void (*)(void)); + +/** + * co_delete: + * @cothread : cothread object + * + * Frees a co_thread. + */ +void co_delete(cothread_t cothread); + +/** + * co_switch: + * @cothread : cothread object to switch to + * + * Do a context switch to @cothread. + */ +void co_switch(cothread_t cothread); + +RETRO_END_DECLS /* ifndef LIBCO_H */ #endif diff --git a/libretro/libco/psp2.c b/libretro/libco/psp2.c new file mode 100644 index 0000000..eaf9b7a --- /dev/null +++ b/libretro/libco/psp2.c @@ -0,0 +1,113 @@ +/* +libco.arm (2015-06-18) +license: public domain +*/ + +#define LIBCO_C +#include "libco.h" + +#include +#include +#include +#include +#include +#include + +#define FOUR_KB_ALIGN(x) align(x, 12) +#define MB_ALIGN(x) align(x, 20) + +#ifdef __cplusplus +extern "C" { +#endif + + static inline int align(int x, int n) + { + return (((x >> n) + 1) << n); + } + + static thread_local unsigned long co_active_buffer[64]; + static thread_local cothread_t co_active_handle = 0; + static void(*co_swap)(cothread_t, cothread_t) = 0; + static int block; + static uint32_t co_swap_function[] = { + 0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */ + 0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */ + 0xe12fff1e, /* bx lr */ + }; + + void co_init() + { + int ret; + void *base; + + block = sceKernelAllocMemBlockForVM("libco", + MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function))); + if (block < 0) + return; + + /* get base address */ + ret = sceKernelGetMemBlockBase(block, &base); + if (ret < 0) + return; + + /* set domain to be writable by user */ + ret = sceKernelOpenVMDomain(); + if (ret < 0) + return; + + memcpy(base, co_swap_function, sizeof co_swap_function); + + /* set domain back to read-only */ + ret = sceKernelCloseVMDomain(); + if (ret < 0) + return; + + /* flush icache */ + ret = sceKernelSyncVMDomain(block, base, + MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function))); + if (ret < 0) + return; + + co_swap = (void(*)(cothread_t, cothread_t))base; + } + + cothread_t co_active(void) + { + if (!co_active_handle) co_active_handle = &co_active_buffer; + return co_active_handle; + } + + cothread_t co_create(unsigned int size, void(*entrypoint)(void)) + { + unsigned long* handle = 0; + if (!co_swap) + co_init(); + if (!co_active_handle) co_active_handle = &co_active_buffer; + size += 256; + size &= ~15; + + if ((handle = (unsigned long*)malloc(size))) + { + unsigned long* p = (unsigned long*)((unsigned char*)handle + size); + handle[8] = (unsigned long)p; + handle[9] = (unsigned long)entrypoint; + } + + return handle; + } + + void co_delete(cothread_t handle) + { + free(handle); + sceKernelFreeMemBlock(block); + } + + void co_switch(cothread_t handle) + { + cothread_t co_previous_handle = co_active_handle; + co_swap(co_active_handle = handle, co_previous_handle); + } + +#ifdef __cplusplus +} +#endif diff --git a/libretro/libco/retro_common_api.h b/libretro/libco/retro_common_api.h new file mode 100644 index 0000000..659f90d --- /dev/null +++ b/libretro/libco/retro_common_api.h @@ -0,0 +1,108 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_common_api.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H +#define _LIBRETRO_COMMON_RETRO_COMMON_API_H + +/* +This file is designed to normalize the libretro-common compiling environment +for public API headers. This should be leaner than a normal compiling environment, +since it gets #included into other project's sources. +*/ + +/* ------------------------------------ */ + +/* +Ordinarily we want to put #ifdef __cplusplus extern "C" in C library +headers to enable them to get used by c++ sources. +However, we want to support building this library as C++ as well, so a +special technique is called for. +*/ + +#define RETRO_BEGIN_DECLS +#define RETRO_END_DECLS + +#ifdef __cplusplus + +#ifdef CXX_BUILD +/* build wants everything to be built as c++, so no extern "C" */ +#else +#undef RETRO_BEGIN_DECLS +#undef RETRO_END_DECLS +#define RETRO_BEGIN_DECLS extern "C" { +#define RETRO_END_DECLS } +#endif + +#else + +/* header is included by a C source file, so no extern "C" */ + +#endif + +/* +IMO, this non-standard ssize_t should not be used. +However, it's a good example of how to handle something like this. +*/ +#ifdef _MSC_VER +#ifndef HAVE_SSIZE_T +#define HAVE_SSIZE_T +#if defined(_WIN64) +typedef __int64 ssize_t; +#elif defined(_WIN32) +typedef int ssize_t; +#endif +#endif +#elif defined(__MACH__) +#include +#endif + +#ifdef _WIN32 +#define STRING_REP_INT64 "%I64d" +#define STRING_REP_UINT64 "%I64u" +#define STRING_REP_USIZE "%Iu" +#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L && !defined(VITA) && !defined(WIIU) +#define STRING_REP_INT64 "%lld" +#define STRING_REP_UINT64 "%llu" +#define STRING_REP_USIZE "%zu" +#else +#define STRING_REP_INT64 "%lld" +#define STRING_REP_UINT64 "%llu" +#define STRING_REP_USIZE "%lu" +#endif + +/* +I would like to see retro_inline.h moved in here; possibly boolean too. + +rationale: these are used in public APIs, and it is easier to find problems +and write code that works the first time portably when theyre included uniformly +than to do the analysis from scratch each time you think you need it, for each feature. + +Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h, +then you should pay the price everywhere, so you can see how much grief it will cause. + +Of course, another school of thought is that you should do as little damage as possible +in as few places as possible... +*/ + + +/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */ +#endif diff --git a/libretro/libco/scefiber.c b/libretro/libco/scefiber.c new file mode 100644 index 0000000..a233bec --- /dev/null +++ b/libretro/libco/scefiber.c @@ -0,0 +1,96 @@ +/* + libco.win (2016-09-06) + authors: frangarcj + license: public domain +*/ + +#define LIBCO_C +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static thread_local cothread_t co_active_ = 0; + +typedef struct SceFiber { + char reserved[128]; +} SceFiber __attribute__( ( aligned ( 8 ) ) ) ; + +int32_t _sceFiberInitializeImpl(SceFiber* fiber, char* name, void* entry, uint32_t argOnInitialize, void* addrContext, int32_t sizeContext, void* params); + +int32_t sceFiberFinalize(SceFiber* fiber); + +int32_t sceFiberRun(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun); + +int32_t sceFiberSwitch(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun); + +int32_t sceFiberReturnToThread(uint32_t argOnReturn, uint32_t* argOnRun); + +void co_thunk(uint32_t argOnInitialize, uint32_t argOnRun) +{ + ((void (*)(void))argOnInitialize)(); +} + +cothread_t co_active(void) +{ + if(!co_active_) + { + sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER); + co_active_ = (cothread_t)1; + } + return co_active_; +} + +cothread_t co_create(unsigned int heapsize, void (*coentry)(void)) +{ + SceFiber* tailFiber = malloc(sizeof(SceFiber)); + char * m_contextBuffer = malloc(sizeof(char)*heapsize); + if(!co_active_) + { + sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER); + co_active_ = (cothread_t)1; + } + + //_sceFiberInitializeImpl + int ret = _sceFiberInitializeImpl(tailFiber, "tailFiber", co_thunk, (uint32_t)coentry, (void*) m_contextBuffer, heapsize, NULL); + if(ret==0){ + return (cothread_t)tailFiber; + }else{ + return (cothread_t)ret; + } + +} + +void co_delete(cothread_t cothread) +{ + if(cothread == (cothread_t)1){ + return; + } + sceFiberFinalize((SceFiber*)cothread); +} + +void co_switch(cothread_t cothread) +{ + + uint32_t argOnReturn = 0; + if(cothread == (cothread_t)1){ + co_active_ = cothread; + sceFiberReturnToThread(0, NULL); + }else{ + SceFiber* theFiber = (SceFiber*)cothread; + if(co_active_ == (cothread_t)1){ + co_active_ = cothread; + sceFiberRun(theFiber, 0, &argOnReturn); + }else{ + co_active_ = cothread; + sceFiberSwitch(theFiber, 0, &argOnReturn); + } + } +} + +#ifdef __cplusplus +} +#endif diff --git a/libretro/libco/sjlj.c b/libretro/libco/sjlj.c index f074714..bb65136 100644 --- a/libretro/libco/sjlj.c +++ b/libretro/libco/sjlj.c @@ -53,12 +53,12 @@ cothread_t co_create(unsigned int size, void (*coentry)(void)) if(thread) { - struct sigaction handler; - struct sigaction old_handler; - stack_t stack; stack_t old_stack; + struct sigaction handler = {{0}}; + struct sigaction old_handler = {{0}}; + thread->coentry = thread->stack = 0; stack.ss_flags = 0; @@ -68,7 +68,7 @@ cothread_t co_create(unsigned int size, void (*coentry)(void)) if(stack.ss_sp && !sigaltstack(&stack, &old_stack)) { handler.sa_handler = springboard; - handler.sa_flags = SA_ONSTACK; + handler.sa_flags = SA_ONSTACK; sigemptyset(&handler.sa_mask); creating = thread; @@ -93,7 +93,7 @@ cothread_t co_create(unsigned int size, void (*coentry)(void)) void co_delete(cothread_t cothread) { - if(cothread) + if (cothread) { if(((cothread_struct*)cothread)->stack) free(((cothread_struct*)cothread)->stack); @@ -103,7 +103,7 @@ void co_delete(cothread_t cothread) void co_switch(cothread_t cothread) { - if(!sigsetjmp(co_running->context, 0)) + if (!sigsetjmp(co_running->context, 0)) { co_running = (cothread_struct*)cothread; siglongjmp(co_running->context, 1);