mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add ucontext
coroutine implementation for generic fallback.
This commit is contained in:
parent
a84a99ffab
commit
6c6bf9ffcb
13 changed files with 211 additions and 174 deletions
|
@ -917,8 +917,10 @@ strlcat.$(OBJEXT): {$(VPATH)}strlcat.c
|
||||||
strlcpy.$(OBJEXT): {$(VPATH)}strlcpy.c
|
strlcpy.$(OBJEXT): {$(VPATH)}strlcpy.c
|
||||||
strstr.$(OBJEXT): {$(VPATH)}strstr.c
|
strstr.$(OBJEXT): {$(VPATH)}strstr.c
|
||||||
nt.$(OBJEXT): {$(VPATH)}nt.c
|
nt.$(OBJEXT): {$(VPATH)}nt.c
|
||||||
|
|
||||||
|
COROUTINE_SRC = $(COROUTINE_H:.h=).$(ASMEXT)
|
||||||
.coroutine_obj $(COROUTINE_OBJ): \
|
.coroutine_obj $(COROUTINE_OBJ): \
|
||||||
{$(VPATH)}$(COROUTINE_H:.h=).$(ASMEXT) \
|
{$(VPATH)}$(COROUTINE_SRC:/ucontext/Context.S=/ucontext/Context.c) \
|
||||||
$(COROUTINE_H:/Context.h=/.time)
|
$(COROUTINE_H:/Context.h=/.time)
|
||||||
$(COROUTINE_H:/Context.h=/.time):
|
$(COROUTINE_H:/Context.h=/.time):
|
||||||
$(Q) $(MAKEDIRS) $(@D)
|
$(Q) $(MAKEDIRS) $(@D)
|
||||||
|
|
|
@ -2263,7 +2263,7 @@ AS_CASE(["$rb_cv_fiber_coroutine"], [yes|''], [
|
||||||
AS_CASE(["$ac_cv_sizeof_voidp"],
|
AS_CASE(["$ac_cv_sizeof_voidp"],
|
||||||
[8], [ rb_cv_fiber_coroutine=amd64 ],
|
[8], [ rb_cv_fiber_coroutine=amd64 ],
|
||||||
[4], [ rb_cv_fiber_coroutine=x86 ],
|
[4], [ rb_cv_fiber_coroutine=x86 ],
|
||||||
[*], [ rb_cv_fiber_coroutine= ]
|
[*], [ rb_cv_fiber_coroutine= ]
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[*86-linux], [
|
[*86-linux], [
|
||||||
|
@ -2282,7 +2282,7 @@ AS_CASE(["$rb_cv_fiber_coroutine"], [yes|''], [
|
||||||
rb_cv_fiber_coroutine=ppc64le
|
rb_cv_fiber_coroutine=ppc64le
|
||||||
],
|
],
|
||||||
[*], [
|
[*], [
|
||||||
rb_cv_fiber_coroutine=
|
rb_cv_fiber_coroutine=ucontext
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
AC_MSG_RESULT(${rb_cv_fiber_coroutine:-no})
|
AC_MSG_RESULT(${rb_cv_fiber_coroutine:-no})
|
||||||
|
|
8
cont.c
8
cont.c
|
@ -187,7 +187,7 @@ struct rb_fiber_struct {
|
||||||
#if FIBER_USE_NATIVE
|
#if FIBER_USE_NATIVE
|
||||||
#if defined(FIBER_USE_COROUTINE)
|
#if defined(FIBER_USE_COROUTINE)
|
||||||
#define FIBER_ALLOCATE_STACK
|
#define FIBER_ALLOCATE_STACK
|
||||||
coroutine_context context;
|
struct coroutine_context context;
|
||||||
void *ss_sp;
|
void *ss_sp;
|
||||||
size_t ss_size;
|
size_t ss_size;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
@ -802,7 +802,7 @@ cont_restore_thread(rb_context_t *cont)
|
||||||
#if FIBER_USE_NATIVE
|
#if FIBER_USE_NATIVE
|
||||||
#if defined(FIBER_USE_COROUTINE)
|
#if defined(FIBER_USE_COROUTINE)
|
||||||
static COROUTINE
|
static COROUTINE
|
||||||
fiber_entry(coroutine_context * from, coroutine_context * to)
|
fiber_entry(struct coroutine_context * from, struct coroutine_context * to)
|
||||||
{
|
{
|
||||||
rb_fiber_start();
|
rb_fiber_start();
|
||||||
}
|
}
|
||||||
|
@ -914,7 +914,7 @@ fiber_initialize_machine_stack_context(rb_fiber_t *fib, size_t size)
|
||||||
ptr = fiber_machine_stack_alloc(size);
|
ptr = fiber_machine_stack_alloc(size);
|
||||||
fib->ss_sp = ptr;
|
fib->ss_sp = ptr;
|
||||||
fib->ss_size = size;
|
fib->ss_size = size;
|
||||||
coroutine_initialize(&fib->context, fiber_entry, ptr+size, size);
|
coroutine_initialize(&fib->context, fiber_entry, ptr, size);
|
||||||
sec->machine.stack_start = (VALUE*)(ptr + STACK_DIR_UPPER(0, size));
|
sec->machine.stack_start = (VALUE*)(ptr + STACK_DIR_UPPER(0, size));
|
||||||
sec->machine.stack_maxsize = size - RB_PAGE_SIZE;
|
sec->machine.stack_maxsize = size - RB_PAGE_SIZE;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
@ -1530,7 +1530,7 @@ root_fiber_alloc(rb_thread_t *th)
|
||||||
|
|
||||||
#if FIBER_USE_NATIVE
|
#if FIBER_USE_NATIVE
|
||||||
#if defined(FIBER_USE_COROUTINE)
|
#if defined(FIBER_USE_COROUTINE)
|
||||||
coroutine_initialize(&fib->context, NULL, NULL, 0);
|
coroutine_initialize_main(&fib->context);
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
/* setup fib_handle for root Fiber */
|
/* setup fib_handle for root Fiber */
|
||||||
if (fib->fib_handle == 0) {
|
if (fib->fib_handle == 0) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
|
||||||
# Restore callee stack pointer
|
# Restore callee stack pointer
|
||||||
movq (%rsi), %rsp
|
movq (%rsi), %rsp
|
||||||
|
|
||||||
# Restore callee stack
|
# Restore callee state
|
||||||
popq %r15
|
popq %r15
|
||||||
popq %r14
|
popq %r14
|
||||||
popq %r13
|
popq %r13
|
||||||
|
|
|
@ -10,35 +10,32 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __attribute__((noreturn)) void
|
#define COROUTINE __attribute__((noreturn)) void
|
||||||
|
|
||||||
enum {COROUTINE_REGISTERS = 6};
|
enum {COROUTINE_REGISTERS = 6};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef COROUTINE(* coroutine_start)(coroutine_context *from, coroutine_context *self);
|
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->stack_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize(
|
||||||
coroutine_context *context,
|
struct coroutine_context *context,
|
||||||
coroutine_start start,
|
coroutine_start start,
|
||||||
void *stack_pointer,
|
void *stack,
|
||||||
size_t stack_size
|
size_t size
|
||||||
) {
|
) {
|
||||||
/* Force 16-byte alignment */
|
assert(start && stack && size >= 1024);
|
||||||
context->stack_pointer = (void**)((uintptr_t)stack_pointer & ~0xF);
|
|
||||||
|
|
||||||
if (!start) {
|
// Stack grows down. Force 16-byte alignment.
|
||||||
assert(!context->stack_pointer);
|
char * top = (char*)stack + size;
|
||||||
/* We are main coroutine for this thread */
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*--context->stack_pointer = NULL;
|
*--context->stack_pointer = NULL;
|
||||||
*--context->stack_pointer = (void*)start;
|
*--context->stack_pointer = (void*)start;
|
||||||
|
@ -47,13 +44,9 @@ static inline void coroutine_initialize(
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target);
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
context->stack_pointer = NULL;
|
context->stack_pointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,34 +10,32 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __attribute__((noreturn)) void
|
#define COROUTINE __attribute__((noreturn)) void
|
||||||
|
|
||||||
enum {COROUTINE_REGISTERS = 8};
|
enum {COROUTINE_REGISTERS = 8};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef COROUTINE(* coroutine_start)(coroutine_context *from, coroutine_context *self);
|
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->stack_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize(
|
||||||
coroutine_context *context,
|
struct coroutine_context *context,
|
||||||
coroutine_start start,
|
coroutine_start start,
|
||||||
void *stack_pointer,
|
void *stack,
|
||||||
size_t stack_size
|
size_t size
|
||||||
) {
|
) {
|
||||||
context->stack_pointer = (void**)stack_pointer;
|
assert(start && stack && size >= 1024);
|
||||||
|
|
||||||
if (!start) {
|
// Stack grows down. Force 16-byte alignment.
|
||||||
assert(!context->stack_pointer);
|
char * top = (char*)stack + size;
|
||||||
/* We are main coroutine for this thread */
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*--context->stack_pointer = (void*)start;
|
*--context->stack_pointer = (void*)start;
|
||||||
|
|
||||||
|
@ -45,12 +43,8 @@ static inline void coroutine_initialize(
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target);
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,35 +10,32 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __attribute__((noreturn)) void
|
#define COROUTINE __attribute__((noreturn)) void
|
||||||
|
|
||||||
enum {COROUTINE_REGISTERS = 0xb0 / 8};
|
enum {COROUTINE_REGISTERS = 0xb0 / 8};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef COROUTINE(* coroutine_start)(coroutine_context *from, coroutine_context *self);
|
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->stack_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize(
|
||||||
coroutine_context *context,
|
struct coroutine_context *context,
|
||||||
coroutine_start start,
|
coroutine_start start,
|
||||||
void *stack_pointer,
|
void *stack,
|
||||||
size_t stack_size
|
size_t size
|
||||||
) {
|
) {
|
||||||
/* Force 16-byte alignment */
|
assert(start && stack && size >= 1024);
|
||||||
context->stack_pointer = (void**)((uintptr_t)stack_pointer & ~0xF);
|
|
||||||
|
|
||||||
if (!start) {
|
// Stack grows down. Force 16-byte alignment.
|
||||||
assert(!context->stack_pointer);
|
char * top = (char*)stack + size;
|
||||||
/* We are main coroutine for this thread */
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->stack_pointer -= COROUTINE_REGISTERS;
|
context->stack_pointer -= COROUTINE_REGISTERS;
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
|
@ -46,12 +43,8 @@ static inline void coroutine_initialize(
|
||||||
context->stack_pointer[0xa0 / 8] = (void*)start;
|
context->stack_pointer[0xa0 / 8] = (void*)start;
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target);
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __attribute__((noreturn)) void
|
#define COROUTINE __attribute__((noreturn)) void
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -15,27 +11,28 @@ enum {
|
||||||
+ 4 /* space for fiber_entry() to store the link register */
|
+ 4 /* space for fiber_entry() to store the link register */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef COROUTINE(* coroutine_start)(coroutine_context *from, coroutine_context *self);
|
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->stack_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize(
|
||||||
coroutine_context *context,
|
struct coroutine_context *context,
|
||||||
coroutine_start start,
|
coroutine_start start,
|
||||||
void *stack_pointer,
|
void *stack,
|
||||||
size_t stack_size
|
size_t size
|
||||||
) {
|
) {
|
||||||
/* Force 16-byte alignment */
|
assert(start && stack && size >= 1024);
|
||||||
context->stack_pointer = (void**)((uintptr_t)stack_pointer & ~0xF);
|
|
||||||
|
|
||||||
if (!start) {
|
// Stack grows down. Force 16-byte alignment.
|
||||||
assert(!context->stack_pointer);
|
char * top = (char*)stack + size;
|
||||||
/* We are main coroutine for this thread */
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->stack_pointer -= COROUTINE_REGISTERS;
|
context->stack_pointer -= COROUTINE_REGISTERS;
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
|
@ -44,13 +41,9 @@ static inline void coroutine_initialize(
|
||||||
context->stack_pointer[18] = ((char*)start) + 8;
|
context->stack_pointer[18] = ((char*)start) + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target);
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
context->stack_pointer = NULL;
|
context->stack_pointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
16
coroutine/ucontext/Context.c
Normal file
16
coroutine/ucontext/Context.c
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the "Coroutine" project and released under the MIT License.
|
||||||
|
*
|
||||||
|
* Created by Samuel Williams on 24/6/2019.
|
||||||
|
* Copyright, 2019, by Samuel Williams. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Context.h"
|
||||||
|
|
||||||
|
void coroutine_trampoline(void * _start, void * _context)
|
||||||
|
{
|
||||||
|
coroutine_start start = _start;
|
||||||
|
struct coroutine_context * context = _context;
|
||||||
|
|
||||||
|
start(context->from, context);
|
||||||
|
}
|
66
coroutine/ucontext/Context.h
Normal file
66
coroutine/ucontext/Context.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the "Coroutine" project and released under the MIT License.
|
||||||
|
*
|
||||||
|
* Created by Samuel Williams on 24/6/2019.
|
||||||
|
* Copyright, 2019, by Samuel Williams. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
#define COROUTINE __attribute__((noreturn)) void
|
||||||
|
|
||||||
|
struct coroutine_context
|
||||||
|
{
|
||||||
|
ucontext_t state;
|
||||||
|
struct coroutine_context * from;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
|
COROUTINE coroutine_trampoline(void * _start, void * _context);
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->from = NULL;
|
||||||
|
getcontext(&context->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void coroutine_initialize(
|
||||||
|
struct coroutine_context *context,
|
||||||
|
coroutine_start start,
|
||||||
|
void *stack,
|
||||||
|
size_t size
|
||||||
|
) {
|
||||||
|
assert(start && stack && size >= 1024);
|
||||||
|
|
||||||
|
coroutine_initialize_main(context);
|
||||||
|
|
||||||
|
context->state.uc_stack.ss_size = size;
|
||||||
|
// Despite what it's called, this is not actually a stack pointer. It points to the address of the stack allocation (the lowest address).
|
||||||
|
context->state.uc_stack.ss_sp = (char*)stack;
|
||||||
|
context->state.uc_stack.ss_flags = 0;
|
||||||
|
context->state.uc_link = NULL;
|
||||||
|
|
||||||
|
makecontext(&context->state, (void(*)(void))coroutine_trampoline, 2, (void*)start, (void*)context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target)
|
||||||
|
{
|
||||||
|
struct coroutine_context * previous = target->from;
|
||||||
|
|
||||||
|
target->from = current;
|
||||||
|
swapcontext(¤t->state, &target->state);
|
||||||
|
target->from = previous;
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
|
{
|
||||||
|
context->state.uc_stack.ss_sp = NULL;
|
||||||
|
context->state.uc_stack.ss_size = 0;
|
||||||
|
context->from = NULL;
|
||||||
|
}
|
|
@ -10,53 +10,47 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __declspec(noreturn) void __fastcall
|
#define COROUTINE __declspec(noreturn) void __fastcall
|
||||||
|
|
||||||
/* This doesn't include thread information block */
|
/* This doesn't include thread information block */
|
||||||
enum {COROUTINE_REGISTERS = 4};
|
enum {COROUTINE_REGISTERS = 4};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef void(__fastcall * coroutine_start)(coroutine_context *from, coroutine_context *self);
|
typedef void(__fastcall * coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->stack_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize(
|
||||||
coroutine_context *context,
|
struct coroutine_context *context,
|
||||||
coroutine_start start,
|
coroutine_start start,
|
||||||
void *stack_pointer,
|
void *stack,
|
||||||
size_t stack_size
|
size_t size
|
||||||
) {
|
) {
|
||||||
context->stack_pointer = (void**)stack_pointer;
|
assert(start && stack && size >= 1024);
|
||||||
|
|
||||||
if (!start) {
|
// Stack grows down. Force 16-byte alignment.
|
||||||
assert(!context->stack_pointer);
|
char * top = (char*)stack + size;
|
||||||
/* We are main coroutine for this thread */
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*--context->stack_pointer = (void*)start;
|
*--context->stack_pointer = (void*)start;
|
||||||
|
|
||||||
/* Windows Thread Information Block */
|
/* Windows Thread Information Block */
|
||||||
*--context->stack_pointer = 0; /* fs:[0] */
|
*--context->stack_pointer = 0; /* fs:[0] */
|
||||||
*--context->stack_pointer = (void*)stack_pointer; /* fs:[4] */
|
*--context->stack_pointer = (void*)top; /* fs:[4] */
|
||||||
*--context->stack_pointer = (void*)((char *)stack_pointer - stack_size); /* fs:[8] */
|
*--context->stack_pointer = (void*)stack; /* fs:[8] */
|
||||||
|
|
||||||
context->stack_pointer -= COROUTINE_REGISTERS;
|
context->stack_pointer -= COROUTINE_REGISTERS;
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * __fastcall coroutine_transfer(coroutine_context * current, coroutine_context * target);
|
struct coroutine_context * __fastcall coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,10 +10,6 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __declspec(noreturn) void
|
#define COROUTINE __declspec(noreturn) void
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -21,29 +17,30 @@ enum {
|
||||||
COROUTINE_XMM_REGISTERS = 1+10*2,
|
COROUTINE_XMM_REGISTERS = 1+10*2,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef void(* coroutine_start)(coroutine_context *from, coroutine_context *self);
|
typedef void(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
|
||||||
|
|
||||||
void coroutine_trampoline();
|
void coroutine_trampoline();
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
coroutine_context *context,
|
context->stack_pointer = NULL;
|
||||||
coroutine_start start,
|
}
|
||||||
void *stack_pointer,
|
|
||||||
size_t stack_size
|
|
||||||
) {
|
|
||||||
/* Force 16-byte alignment */
|
|
||||||
context->stack_pointer = (void**)((uintptr_t)stack_pointer & ~0xF);
|
|
||||||
|
|
||||||
if (!start) {
|
static inline void coroutine_initialize(
|
||||||
assert(!context->stack_pointer);
|
struct coroutine_context *context,
|
||||||
/* We are main coroutine for this thread */
|
coroutine_start start,
|
||||||
return;
|
void *stack,
|
||||||
}
|
size_t size
|
||||||
|
) {
|
||||||
|
assert(start && stack && size >= 1024);
|
||||||
|
|
||||||
|
// Stack grows down. Force 16-byte alignment.
|
||||||
|
char * top = (char*)stack + size;
|
||||||
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
|
|
||||||
/* Win64 ABI requires space for arguments */
|
/* Win64 ABI requires space for arguments */
|
||||||
context->stack_pointer -= 4;
|
context->stack_pointer -= 4;
|
||||||
|
@ -55,20 +52,16 @@ static inline void coroutine_initialize(
|
||||||
|
|
||||||
/* Windows Thread Information Block */
|
/* Windows Thread Information Block */
|
||||||
/* *--context->stack_pointer = 0; */ /* gs:[0x00] is not used */
|
/* *--context->stack_pointer = 0; */ /* gs:[0x00] is not used */
|
||||||
*--context->stack_pointer = (void*)stack_pointer; /* gs:[0x08] */
|
*--context->stack_pointer = (void*)top; /* gs:[0x08] */
|
||||||
*--context->stack_pointer = (void*)((char *)stack_pointer - stack_size); /* gs:[0x10] */
|
*--context->stack_pointer = (void*)stack; /* gs:[0x10] */
|
||||||
|
|
||||||
context->stack_pointer -= COROUTINE_REGISTERS;
|
context->stack_pointer -= COROUTINE_REGISTERS;
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
memset(context->stack_pointer - COROUTINE_XMM_REGISTERS, 0, sizeof(void*) * COROUTINE_XMM_REGISTERS);
|
memset(context->stack_pointer - COROUTINE_XMM_REGISTERS, 0, sizeof(void*) * COROUTINE_XMM_REGISTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target);
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,35 +10,32 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define COROUTINE __attribute__((noreturn, fastcall)) void
|
#define COROUTINE __attribute__((noreturn, fastcall)) void
|
||||||
|
|
||||||
enum {COROUTINE_REGISTERS = 4};
|
enum {COROUTINE_REGISTERS = 4};
|
||||||
|
|
||||||
typedef struct
|
struct coroutine_context
|
||||||
{
|
{
|
||||||
void **stack_pointer;
|
void **stack_pointer;
|
||||||
} coroutine_context;
|
};
|
||||||
|
|
||||||
typedef COROUTINE(* coroutine_start)(coroutine_context *from, coroutine_context *self) __attribute__((fastcall));
|
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self) __attribute__((fastcall));
|
||||||
|
|
||||||
|
static inline void coroutine_initialize_main(struct coroutine_context * context) {
|
||||||
|
context->stack_pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void coroutine_initialize(
|
static inline void coroutine_initialize(
|
||||||
coroutine_context *context,
|
struct coroutine_context *context,
|
||||||
coroutine_start start,
|
coroutine_start start,
|
||||||
void *stack_pointer,
|
void *stack,
|
||||||
size_t stack_size
|
size_t size
|
||||||
) {
|
) {
|
||||||
/* Force 16-byte alignment */
|
assert(start && stack && size >= 1024);
|
||||||
context->stack_pointer = (void**)((uintptr_t)stack_pointer & ~0xF);
|
|
||||||
|
|
||||||
if (!start) {
|
// Stack grows down. Force 16-byte alignment.
|
||||||
assert(!context->stack_pointer);
|
char * top = (char*)stack + size;
|
||||||
/* We are main coroutine for this thread */
|
context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*--context->stack_pointer = NULL;
|
*--context->stack_pointer = NULL;
|
||||||
*--context->stack_pointer = (void*)start;
|
*--context->stack_pointer = (void*)start;
|
||||||
|
@ -47,13 +44,9 @@ static inline void coroutine_initialize(
|
||||||
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context * coroutine_transfer(coroutine_context * current, coroutine_context * target) __attribute__((fastcall));
|
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target) __attribute__((fastcall));
|
||||||
|
|
||||||
static inline void coroutine_destroy(coroutine_context * context)
|
static inline void coroutine_destroy(struct coroutine_context * context)
|
||||||
{
|
{
|
||||||
context->stack_pointer = NULL;
|
context->stack_pointer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue