You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

199 lines
4.9 KiB

// Copyright 2018 Sen Han 00hnes@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ACO_H
#define ACO_H
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#define ACO_VERSION_MAJOR 1
#define ACO_VERSION_MINOR 2
#define ACO_VERSION_PATCH 0
#ifdef ACO_USE_VALGRIND
#include <valgrind/valgrind.h>
#endif
#ifdef __i386__
#define ACO_REG_IDX_RETADDR 0
#define ACO_REG_IDX_SP 1
#define ACO_REG_IDX_FPU 6
#elif __x86_64__
#define ACO_REG_IDX_RETADDR 4
#define ACO_REG_IDX_SP 5
#define ACO_REG_IDX_FPU 8
#else
#error "platform no support yet"
#endif
typedef struct {
void* ptr;
size_t sz;
size_t valid_sz;
// max copy size in bytes
size_t max_cpsz;
// copy from share stack to this save stack
size_t ct_save;
// copy from this save stack to share stack
size_t ct_restore;
} aco_save_stack_t;
struct aco_s__;
typedef struct aco_s__ aco_t;
typedef struct {
void* ptr;
size_t sz;
void* align_highptr;
void* align_retptr;
size_t align_validsz;
size_t align_limit;
aco_t* owner;
char guard_page_enabled;
void* real_ptr;
size_t real_sz;
#ifdef ACO_USE_VALGRIND
unsigned long valgrind_stk_id;
#endif
} aco_share_stack_t;
typedef void (*aco_cofuncp_t)(void);
struct aco_s__{
// cpu registers' state
#ifdef __i386__
#ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
void* reg[6];
#else
void* reg[8];
#endif
#elif __x86_64__
#ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
void* reg[8];
#else
void* reg[9];
#endif
#else
#error "platform no support yet"
#endif
aco_t* main_co;
void* arg;
char is_end;
aco_cofuncp_t fp;
aco_save_stack_t save_stack;
aco_share_stack_t* share_stack;
};
#define aco_likely(x) (__builtin_expect(!!(x), 1))
#define aco_unlikely(x) (__builtin_expect(!!(x), 0))
#define aco_assert(EX) ((aco_likely(EX))?((void)0):(abort()))
#define aco_assertptr(ptr) ((aco_likely((ptr) != NULL))?((void)0):(abort()))
#define aco_assertalloc_bool(b) do { \
if(aco_unlikely(!(b))){ \
fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
abort(); \
} \
} while(0)
#define aco_assertalloc_ptr(ptr) do { \
if(aco_unlikely((ptr) == NULL)){ \
fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
abort(); \
} \
} while(0)
extern void aco_runtime_test();
extern void aco_thread_init(aco_cofuncp_t last_word_co_fp);
// TODO: plan to use regparm(0) (fastcall) in Sys V ABI intel386
// to accelerate acosw and copystack(-8bytes), and PR is welcome :)
extern void* acosw(aco_t* from_co, aco_t* to_co); // asm
extern void aco_save_fpucw_mxcsr(void* p); // asm
extern void aco_funcp_protector_asm(); // asm
extern void aco_funcp_protector();
extern aco_share_stack_t* aco_share_stack_new(size_t sz);
aco_share_stack_t* aco_share_stack_new2(size_t sz, char guard_page_enabled);
extern void aco_share_stack_destroy(aco_share_stack_t* sstk);
extern aco_t* aco_create(
aco_t* main_co,
aco_share_stack_t* share_stack,
size_t save_stack_sz,
aco_cofuncp_t fp, void* arg
);
// aco's Global Thread Local Storage variable `co`
extern __thread aco_t* aco_gtls_co;
extern void aco_resume(aco_t* resume_co);
//extern void aco_yield1(aco_t* yield_co);
#define aco_yield1(yield_co) do { \
aco_assertptr((yield_co)); \
aco_assertptr((yield_co)->main_co); \
acosw((yield_co), (yield_co)->main_co); \
} while(0)
#define aco_yield() do { \
aco_yield1(aco_gtls_co); \
} while(0)
#define aco_get_arg() (aco_gtls_co->arg)
#define aco_get_co() ({(void)0; aco_gtls_co;})
#define aco_co() ({(void)0; aco_gtls_co;})
extern void aco_destroy(aco_t* co);
#define aco_is_main_co(co) ({((co)->main_co) == NULL;})
#define aco_exit1(co) do { \
(co)->is_end = 1; \
aco_assert((co)->share_stack->owner == (co)); \
(co)->share_stack->owner = NULL; \
(co)->share_stack->align_validsz = 0; \
aco_yield1((co)); \
aco_assert(0); \
} while(0)
#define aco_exit() do { \
aco_exit1(aco_gtls_co); \
} while(0)
#endif