init push
This commit is contained in:
3
deps/easy/src/thread/CMakeLists.txt
vendored
Normal file
3
deps/easy/src/thread/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
easy_add_objects(thread
|
||||
easy_uthread.c
|
||||
)
|
||||
259
deps/easy/src/thread/easy_uthread.c
vendored
Normal file
259
deps/easy/src/thread/easy_uthread.c
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OceanBase
|
||||
* OceanBase CE is licensed under Mulan PubL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
||||
* You may obtain a copy of Mulan PubL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PubL v2 for more details.
|
||||
*/
|
||||
|
||||
#include "easy_atomic.h"
|
||||
#include "thread/easy_uthread.h"
|
||||
#include <signal.h>
|
||||
|
||||
__thread easy_uthread_control_t* easy_uthread_var = NULL;
|
||||
|
||||
static easy_uthread_t* easy_uthread_alloc(easy_uthread_start_pt* fn, void* args, int stack_size);
|
||||
static void easy_uthread_start(uint32_t y, uint32_t x);
|
||||
static void easy_uthread_context_switch(ucontext_t* from, ucontext_t* to);
|
||||
|
||||
void easy_uthread_init(easy_uthread_control_t* control)
|
||||
{
|
||||
if (easy_uthread_var == NULL) {
|
||||
easy_uthread_var = control;
|
||||
memset(easy_uthread_var, 0, sizeof(easy_uthread_control_t));
|
||||
easy_list_init(&easy_uthread_var->runqueue);
|
||||
easy_list_init(&easy_uthread_var->thread_list);
|
||||
}
|
||||
}
|
||||
|
||||
void easy_uthread_destroy()
|
||||
{
|
||||
easy_uthread_t *t, *t2;
|
||||
|
||||
if (!easy_uthread_var)
|
||||
return;
|
||||
|
||||
easy_list_for_each_entry_safe(t, t2, &easy_uthread_var->thread_list, thread_list_node)
|
||||
{
|
||||
easy_pool_destroy(t->pool);
|
||||
}
|
||||
|
||||
easy_uthread_var = NULL;
|
||||
}
|
||||
|
||||
void easy_uthread_stop()
|
||||
{
|
||||
if (easy_uthread_var) {
|
||||
easy_uthread_var->stoped = 1;
|
||||
}
|
||||
}
|
||||
|
||||
easy_uthread_t* easy_uthread_create(easy_uthread_start_pt* start_routine, void* args, int stack_size)
|
||||
{
|
||||
easy_uthread_t* t;
|
||||
|
||||
if (!easy_uthread_var)
|
||||
return NULL;
|
||||
|
||||
if ((t = easy_uthread_alloc(start_routine, args, stack_size)) == NULL)
|
||||
return NULL;
|
||||
|
||||
easy_uthread_var->thread_count++;
|
||||
easy_list_add_tail(&t->thread_list_node, &easy_uthread_var->thread_list);
|
||||
|
||||
easy_uthread_ready(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void easy_uthread_exit(int val)
|
||||
{
|
||||
easy_uthread_var->exit_value = val;
|
||||
easy_uthread_var->running->exiting = 1;
|
||||
easy_uthread_switch();
|
||||
}
|
||||
|
||||
void easy_uthread_switch()
|
||||
{
|
||||
easy_uthread_var->running->errcode = 0;
|
||||
easy_uthread_needstack(0);
|
||||
easy_uthread_context_switch(&easy_uthread_var->running->context, &easy_uthread_var->context);
|
||||
}
|
||||
|
||||
easy_uthread_t* easy_uthread_current()
|
||||
{
|
||||
return (easy_uthread_var ? easy_uthread_var->running : NULL);
|
||||
}
|
||||
|
||||
int easy_uthread_get_errcode()
|
||||
{
|
||||
if (easy_uthread_var && easy_uthread_var->running)
|
||||
return easy_uthread_var->running->errcode;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void easy_uthread_set_errcode(easy_uthread_t* t, int errcode)
|
||||
{
|
||||
t->errcode = (errcode & 0xff);
|
||||
}
|
||||
|
||||
void easy_uthread_needstack(int n)
|
||||
{
|
||||
easy_uthread_t* t;
|
||||
|
||||
t = easy_uthread_var->running;
|
||||
|
||||
if ((char*)&t <= (char*)t->stk || (char*)&t - (char*)t->stk < 256 + n) {
|
||||
fprintf(stderr, "uthread stack overflow: &t=%p tstk=%p n=%d\n", &t, t->stk, 256 + n);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void easy_uthread_ready(easy_uthread_t* t)
|
||||
{
|
||||
if (t) {
|
||||
t->ready = 1;
|
||||
easy_list_add_tail(&t->runqueue_node, &easy_uthread_var->runqueue);
|
||||
}
|
||||
}
|
||||
|
||||
int easy_uthread_yield()
|
||||
{
|
||||
int n;
|
||||
|
||||
n = easy_uthread_var->nswitch;
|
||||
easy_uthread_ready(easy_uthread_var->running);
|
||||
easy_uthread_switch();
|
||||
return easy_uthread_var->nswitch - n - 1;
|
||||
}
|
||||
|
||||
int easy_uthread_scheduler()
|
||||
{
|
||||
easy_uthread_t* t;
|
||||
|
||||
while (easy_uthread_var->stoped == 0) {
|
||||
if (easy_uthread_var->thread_count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (easy_list_empty(&easy_uthread_var->runqueue)) {
|
||||
fprintf(stderr, "no runnable user thread! (%d)\n", easy_uthread_var->thread_count);
|
||||
easy_uthread_var->exit_value = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// first entry
|
||||
t = easy_list_entry(easy_uthread_var->runqueue.next, easy_uthread_t, runqueue_node);
|
||||
easy_list_del(&t->runqueue_node);
|
||||
|
||||
t->ready = 0;
|
||||
easy_uthread_var->running = t;
|
||||
easy_uthread_var->nswitch++;
|
||||
|
||||
easy_uthread_context_switch(&easy_uthread_var->context, &t->context);
|
||||
easy_uthread_var->running = NULL;
|
||||
|
||||
if (t->exiting) {
|
||||
easy_list_del(&t->thread_list_node);
|
||||
easy_uthread_var->thread_count--;
|
||||
easy_pool_destroy(t->pool);
|
||||
}
|
||||
}
|
||||
|
||||
return easy_uthread_var->exit_value;
|
||||
}
|
||||
|
||||
void easy_uthread_print(int sig)
|
||||
{
|
||||
easy_uthread_t* t;
|
||||
char* extra;
|
||||
|
||||
fprintf(stderr, "uthread list:\n");
|
||||
easy_list_for_each_entry(t, &easy_uthread_var->thread_list, thread_list_node)
|
||||
{
|
||||
if (t == easy_uthread_var->running)
|
||||
extra = " (running)";
|
||||
else if (t->ready)
|
||||
extra = " (ready)";
|
||||
else
|
||||
extra = "";
|
||||
|
||||
fprintf(stderr, "%6d %s\n", t->id, extra);
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static easy_uthread_t* easy_uthread_alloc(easy_uthread_start_pt* fn, void* args, int stack_size)
|
||||
{
|
||||
easy_uthread_t* t;
|
||||
easy_pool_t* pool;
|
||||
int size;
|
||||
sigset_t zero;
|
||||
uint32_t x, y;
|
||||
uint64_t z;
|
||||
|
||||
size = sizeof(easy_uthread_t) + stack_size;
|
||||
|
||||
if ((pool = easy_pool_create(size)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((t = (easy_uthread_t*)easy_pool_alloc(pool, size)) == NULL)
|
||||
goto error_exit;
|
||||
|
||||
memset(t, 0, sizeof(easy_uthread_t));
|
||||
t->pool = pool;
|
||||
t->stk = (unsigned char*)(t + 1);
|
||||
t->stksize = stack_size;
|
||||
t->id = ++easy_uthread_var->gid;
|
||||
t->startfn = fn;
|
||||
t->startargs = args;
|
||||
|
||||
/* do a reasonable initialization */
|
||||
memset(&t->context, 0, sizeof(t->context));
|
||||
sigemptyset(&zero);
|
||||
sigprocmask(SIG_BLOCK, &zero, &t->context.uc_sigmask);
|
||||
|
||||
/* must initialize with current context */
|
||||
if (getcontext(&t->context) < 0)
|
||||
goto error_exit;
|
||||
|
||||
/* call makecontext to do the real work. */
|
||||
t->context.uc_stack.ss_sp = t->stk;
|
||||
t->context.uc_stack.ss_size = t->stksize;
|
||||
z = (unsigned long)t;
|
||||
y = (uint32_t)z;
|
||||
x = (uint32_t)(z >> 32);
|
||||
|
||||
makecontext(&t->context, (void (*)())easy_uthread_start, 2, y, x);
|
||||
|
||||
return t;
|
||||
error_exit:
|
||||
|
||||
if (pool)
|
||||
easy_pool_destroy(pool);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void easy_uthread_start(uint32_t y, uint32_t x)
|
||||
{
|
||||
uint64_t z;
|
||||
|
||||
z = x;
|
||||
z <<= 32;
|
||||
z |= y;
|
||||
easy_uthread_t* t = (easy_uthread_t*)(long)z;
|
||||
t->startfn(t->startargs);
|
||||
easy_uthread_exit(0);
|
||||
}
|
||||
|
||||
static void easy_uthread_context_switch(ucontext_t* from, ucontext_t* to)
|
||||
{
|
||||
if (swapcontext(from, to) < 0) {
|
||||
fprintf(stderr, "swapcontext failed.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
102
deps/easy/src/thread/easy_uthread.h
vendored
Normal file
102
deps/easy/src/thread/easy_uthread.h
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OceanBase
|
||||
* OceanBase CE is licensed under Mulan PubL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
||||
* You may obtain a copy of Mulan PubL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PubL v2 for more details.
|
||||
*/
|
||||
|
||||
#ifndef EASY_UTHREAD_H
|
||||
#define EASY_UTHREAD_H
|
||||
|
||||
#include "util/easy_pool.h"
|
||||
#include "easy_list.h"
|
||||
#include <ucontext.h>
|
||||
|
||||
EASY_CPP_START
|
||||
|
||||
#define EASY_UTHREAD_STACK (65536 - sizeof(easy_pool_t))
|
||||
|
||||
typedef void(easy_uthread_start_pt)(void* args);
|
||||
typedef struct easy_uthread_t easy_uthread_t;
|
||||
typedef struct easy_uthread_control_t easy_uthread_control_t;
|
||||
|
||||
struct easy_uthread_t {
|
||||
easy_list_t runqueue_node;
|
||||
easy_list_t thread_list_node;
|
||||
easy_pool_t* pool;
|
||||
easy_uthread_start_pt* startfn;
|
||||
void* startargs;
|
||||
|
||||
uint32_t id;
|
||||
int8_t exiting;
|
||||
int8_t ready;
|
||||
int8_t errcode;
|
||||
uint32_t stksize;
|
||||
unsigned char* stk;
|
||||
ucontext_t context;
|
||||
};
|
||||
|
||||
struct easy_uthread_control_t {
|
||||
int gid;
|
||||
int nswitch;
|
||||
int16_t stoped;
|
||||
int16_t thread_count;
|
||||
int exit_value;
|
||||
easy_list_t runqueue;
|
||||
easy_list_t thread_list;
|
||||
easy_uthread_t* running;
|
||||
ucontext_t context;
|
||||
};
|
||||
|
||||
void easy_uthread_init(easy_uthread_control_t* control);
|
||||
void easy_uthread_destroy();
|
||||
easy_uthread_t* easy_uthread_create(easy_uthread_start_pt* start, void* args, int stack_size);
|
||||
easy_uthread_t* easy_uthread_current();
|
||||
int easy_uthread_yield();
|
||||
int easy_uthread_scheduler();
|
||||
void easy_uthread_stop();
|
||||
void easy_uthread_ready(easy_uthread_t* t);
|
||||
void easy_uthread_switch();
|
||||
void easy_uthread_needstack(int n);
|
||||
void easy_uthread_ready(easy_uthread_t* t);
|
||||
void easy_uthread_print(int sig);
|
||||
int easy_uthread_get_errcode();
|
||||
void easy_uthread_set_errcode(easy_uthread_t* t, int errcode);
|
||||
|
||||
//////////////////////
|
||||
#define EASY_UTHREAD_RUN_MAIN(main_name) \
|
||||
static int easy_uthread_stacksize = 0; \
|
||||
static int easy_uthread_argc; \
|
||||
static char** easy_uthread_argv; \
|
||||
static void easy_uthread_mainstart(void* v) \
|
||||
{ \
|
||||
main_name(easy_uthread_argc, easy_uthread_argv); \
|
||||
} \
|
||||
int main(int argc, char** argv) \
|
||||
{ \
|
||||
int ret; \
|
||||
struct sigaction sa, osa; \
|
||||
easy_uthread_control_t control; \
|
||||
memset(&sa, 0, sizeof sa); \
|
||||
sa.sa_handler = easy_uthread_print; \
|
||||
sa.sa_flags = SA_RESTART; \
|
||||
sigaction(SIGQUIT, &sa, &osa); \
|
||||
easy_uthread_argc = argc; \
|
||||
easy_uthread_argv = argv; \
|
||||
if (easy_uthread_stacksize == 0) \
|
||||
easy_uthread_stacksize = 256 * 1024; \
|
||||
easy_uthread_init(&control); \
|
||||
easy_uthread_create(easy_uthread_mainstart, NULL, easy_uthread_stacksize); \
|
||||
ret = easy_uthread_scheduler(); \
|
||||
easy_uthread_destroy(); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
EASY_CPP_END
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user