resp协议定义, xml定义配置文件
This commit is contained in:
3
NtyCo/core/CMakeLists.txt
Normal file
3
NtyCo/core/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
aux_source_directory(. SRC)
|
||||
|
||||
add_library(nty_core ${SRC})
|
||||
16
NtyCo/core/Makefile
Normal file
16
NtyCo/core/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
CUR_SOURCE = ${wildcard *.c}
|
||||
|
||||
CUR_OBJS = ${patsubst %.c, %.o, $(CUR_SOURCE)}
|
||||
|
||||
all : $(SUB_DIR) $(CUR_OBJS)
|
||||
|
||||
$(SUB_DIR) : ECHO
|
||||
make -C $@
|
||||
|
||||
$(CUR_OBJS) : %.o : %.c
|
||||
$(CC) -c $^ -o $(OBJS_DIR)/$@ $(FLAG)
|
||||
|
||||
ECHO :
|
||||
@echo $(SUB_DIR)
|
||||
353
NtyCo/core/nty_coroutine.c
Executable file
353
NtyCo/core/nty_coroutine.c
Executable file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nty_coroutine.h"
|
||||
|
||||
pthread_key_t global_sched_key;
|
||||
static pthread_once_t sched_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
// https://github.com/halayli/lthread/blob/master/src/lthread.c#L58
|
||||
|
||||
#ifdef _USE_UCONTEXT
|
||||
|
||||
static void
|
||||
_save_stack(nty_coroutine *co) {
|
||||
char* top = co->sched->stack + co->sched->stack_size;
|
||||
char dummy = 0;
|
||||
assert(top - &dummy <= NTY_CO_MAX_STACKSIZE);
|
||||
if (co->stack_size < top - &dummy) {
|
||||
co->stack = realloc(co->stack, top - &dummy);
|
||||
assert(co->stack != NULL);
|
||||
}
|
||||
co->stack_size = top - &dummy;
|
||||
memcpy(co->stack, &dummy, co->stack_size);
|
||||
}
|
||||
|
||||
static void
|
||||
_load_stack(nty_coroutine *co) {
|
||||
memcpy(co->sched->stack + co->sched->stack_size - co->stack_size, co->stack, co->stack_size);
|
||||
}
|
||||
|
||||
static void _exec(void *lt) {
|
||||
nty_coroutine *co = (nty_coroutine*)lt;
|
||||
co->func(co->arg);
|
||||
co->status |= (BIT(NTY_COROUTINE_STATUS_EXITED) | BIT(NTY_COROUTINE_STATUS_FDEOF) | BIT(NTY_COROUTINE_STATUS_DETACH));
|
||||
nty_coroutine_yield(co);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int _switch(nty_cpu_ctx *new_ctx, nty_cpu_ctx *cur_ctx);
|
||||
|
||||
#ifdef __i386__
|
||||
__asm__ (
|
||||
" .text \n"
|
||||
" .p2align 2,,3 \n"
|
||||
".globl _switch \n"
|
||||
"_switch: \n"
|
||||
"__switch: \n"
|
||||
"movl 8(%esp), %edx # fs->%edx \n"
|
||||
"movl %esp, 0(%edx) # save esp \n"
|
||||
"movl %ebp, 4(%edx) # save ebp \n"
|
||||
"movl (%esp), %eax # save eip \n"
|
||||
"movl %eax, 8(%edx) \n"
|
||||
"movl %ebx, 12(%edx) # save ebx,esi,edi \n"
|
||||
"movl %esi, 16(%edx) \n"
|
||||
"movl %edi, 20(%edx) \n"
|
||||
"movl 4(%esp), %edx # ts->%edx \n"
|
||||
"movl 20(%edx), %edi # restore ebx,esi,edi \n"
|
||||
"movl 16(%edx), %esi \n"
|
||||
"movl 12(%edx), %ebx \n"
|
||||
"movl 0(%edx), %esp # restore esp \n"
|
||||
"movl 4(%edx), %ebp # restore ebp \n"
|
||||
"movl 8(%edx), %eax # restore eip \n"
|
||||
"movl %eax, (%esp) \n"
|
||||
"ret \n"
|
||||
);
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
__asm__ (
|
||||
" .text \n"
|
||||
" .p2align 4,,15 \n"
|
||||
".globl _switch \n"
|
||||
".globl __switch \n"
|
||||
"_switch: \n"
|
||||
"__switch: \n"
|
||||
" movq %rsp, 0(%rsi) # save stack_pointer \n"
|
||||
" movq %rbp, 8(%rsi) # save frame_pointer \n"
|
||||
" movq (%rsp), %rax # save insn_pointer \n"
|
||||
" movq %rax, 16(%rsi) \n"
|
||||
" movq %rbx, 24(%rsi) # save rbx,r12-r15 \n"
|
||||
" movq %r12, 32(%rsi) \n"
|
||||
" movq %r13, 40(%rsi) \n"
|
||||
" movq %r14, 48(%rsi) \n"
|
||||
" movq %r15, 56(%rsi) \n"
|
||||
" movq 56(%rdi), %r15 \n"
|
||||
" movq 48(%rdi), %r14 \n"
|
||||
" movq 40(%rdi), %r13 # restore rbx,r12-r15 \n"
|
||||
" movq 32(%rdi), %r12 \n"
|
||||
" movq 24(%rdi), %rbx \n"
|
||||
" movq 8(%rdi), %rbp # restore frame_pointer \n"
|
||||
" movq 0(%rdi), %rsp # restore stack_pointer \n"
|
||||
" movq 16(%rdi), %rax # restore insn_pointer \n"
|
||||
" movq %rax, (%rsp) \n"
|
||||
" ret \n"
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
static void _exec(void *lt) {
|
||||
#if defined(__lvm__) && defined(__x86_64__)
|
||||
__asm__("movq 16(%%rbp), %[lt]" : [lt] "=r" (lt));
|
||||
#endif
|
||||
|
||||
nty_coroutine *co = (nty_coroutine*)lt;
|
||||
co->func(co->arg);
|
||||
co->status |= (BIT(NTY_COROUTINE_STATUS_EXITED) | BIT(NTY_COROUTINE_STATUS_FDEOF) | BIT(NTY_COROUTINE_STATUS_DETACH));
|
||||
#if 1
|
||||
nty_coroutine_yield(co);
|
||||
#else
|
||||
co->ops = 0;
|
||||
_switch(&co->sched->ctx, &co->ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void nty_coroutine_madvise(nty_coroutine *co) {
|
||||
|
||||
size_t current_stack = (co->stack + co->stack_size) - co->ctx.esp;
|
||||
assert(current_stack <= co->stack_size);
|
||||
|
||||
if (current_stack < co->last_stack_size &&
|
||||
co->last_stack_size > co->sched->page_size) {
|
||||
size_t tmp = current_stack + (-current_stack & (co->sched->page_size - 1));
|
||||
assert(madvise(co->stack, co->stack_size-tmp, MADV_DONTNEED) == 0);
|
||||
}
|
||||
co->last_stack_size = current_stack;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
extern int nty_schedule_create(int stack_size);
|
||||
|
||||
|
||||
|
||||
void nty_coroutine_free(nty_coroutine *co) {
|
||||
if (co == NULL) return ;
|
||||
co->sched->spawned_coroutines --;
|
||||
#if 1
|
||||
if (co->stack) {
|
||||
free(co->stack);
|
||||
co->stack = NULL;
|
||||
}
|
||||
#endif
|
||||
if (co) {
|
||||
free(co);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void nty_coroutine_init(nty_coroutine *co) {
|
||||
|
||||
#ifdef _USE_UCONTEXT
|
||||
getcontext(&co->ctx);
|
||||
co->ctx.uc_stack.ss_sp = co->sched->stack;
|
||||
co->ctx.uc_stack.ss_size = co->sched->stack_size;
|
||||
co->ctx.uc_link = &co->sched->ctx;
|
||||
// printf("TAG21\n");
|
||||
makecontext(&co->ctx, (void (*)(void)) _exec, 1, (void*)co);
|
||||
// printf("TAG22\n");
|
||||
#else
|
||||
void **stack = (void **)(co->stack + co->stack_size);
|
||||
|
||||
stack[-3] = NULL;
|
||||
stack[-2] = (void *)co;
|
||||
|
||||
co->ctx.esp = (void*)stack - (4 * sizeof(void*));
|
||||
co->ctx.ebp = (void*)stack - (3 * sizeof(void*));
|
||||
co->ctx.eip = (void*)_exec;
|
||||
#endif
|
||||
co->status = BIT(NTY_COROUTINE_STATUS_READY);
|
||||
|
||||
}
|
||||
|
||||
void nty_coroutine_yield(nty_coroutine *co) {
|
||||
co->ops = 0;
|
||||
#ifdef _USE_UCONTEXT
|
||||
if ((co->status & BIT(NTY_COROUTINE_STATUS_EXITED)) == 0) {
|
||||
_save_stack(co);
|
||||
}
|
||||
swapcontext(&co->ctx, &co->sched->ctx);
|
||||
#else
|
||||
_switch(&co->sched->ctx, &co->ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
int nty_coroutine_resume(nty_coroutine *co) {
|
||||
|
||||
if (co->status & BIT(NTY_COROUTINE_STATUS_NEW)) {
|
||||
nty_coroutine_init(co);
|
||||
}
|
||||
#ifdef _USE_UCONTEXT
|
||||
else {
|
||||
_load_stack(co);
|
||||
}
|
||||
#endif
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
sched->curr_thread = co;
|
||||
#ifdef _USE_UCONTEXT
|
||||
swapcontext(&sched->ctx, &co->ctx);
|
||||
#else
|
||||
_switch(&co->ctx, &co->sched->ctx);
|
||||
nty_coroutine_madvise(co);
|
||||
#endif
|
||||
sched->curr_thread = NULL;
|
||||
|
||||
#if 1
|
||||
if (co->status & BIT(NTY_COROUTINE_STATUS_EXITED)) {
|
||||
if (co->status & BIT(NTY_COROUTINE_STATUS_DETACH)) {
|
||||
nty_coroutine_free(co);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void nty_coroutine_renice(nty_coroutine *co) {
|
||||
co->ops ++;
|
||||
#if 1
|
||||
if (co->ops < 5) return ;
|
||||
#endif
|
||||
TAILQ_INSERT_TAIL(&nty_coroutine_get_sched()->ready, co, ready_next);
|
||||
nty_coroutine_yield(co);
|
||||
}
|
||||
|
||||
|
||||
void nty_coroutine_sleep(uint64_t msecs) {
|
||||
nty_coroutine *co = nty_coroutine_get_sched()->curr_thread;
|
||||
|
||||
if (msecs == 0) {
|
||||
TAILQ_INSERT_TAIL(&co->sched->ready, co, ready_next);
|
||||
nty_coroutine_yield(co);
|
||||
} else {
|
||||
nty_schedule_sched_sleepdown(co, msecs);
|
||||
}
|
||||
}
|
||||
|
||||
void nty_coroutine_detach(void) {
|
||||
nty_coroutine *co = nty_coroutine_get_sched()->curr_thread;
|
||||
co->status |= BIT(NTY_COROUTINE_STATUS_DETACH);
|
||||
}
|
||||
|
||||
static void nty_coroutine_sched_key_destructor(void *data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor(1000))) nty_coroutine_sched_key_creator(void) {
|
||||
assert(pthread_key_create(&global_sched_key, nty_coroutine_sched_key_destructor) == 0);
|
||||
assert(pthread_setspecific(global_sched_key, NULL) == 0);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
// coroutine -->
|
||||
// create
|
||||
//
|
||||
int nty_coroutine_create(nty_coroutine **new_co, proc_coroutine func, void *arg) {
|
||||
|
||||
assert(pthread_once(&sched_key_once, nty_coroutine_sched_key_creator) == 0);
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
|
||||
if (sched == NULL) {
|
||||
nty_schedule_create(0);
|
||||
|
||||
sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
printf("Failed to create scheduler\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
nty_coroutine *co = calloc(1, sizeof(nty_coroutine));
|
||||
if (co == NULL) {
|
||||
printf("Failed to allocate memory for new coroutine\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
#ifdef _USE_UCONTEXT
|
||||
co->stack = NULL;
|
||||
co->stack_size = 0;
|
||||
#else
|
||||
int ret = posix_memalign(&co->stack, getpagesize(), sched->stack_size);
|
||||
if (ret) {
|
||||
printf("Failed to allocate stack for new coroutine\n");
|
||||
free(co);
|
||||
return -3;
|
||||
}
|
||||
co->stack_size = sched->stack_size;
|
||||
#endif
|
||||
co->sched = sched;
|
||||
co->status = BIT(NTY_COROUTINE_STATUS_NEW); //
|
||||
co->id = sched->spawned_coroutines ++;
|
||||
co->func = func;
|
||||
#if CANCEL_FD_WAIT_UINT64
|
||||
co->fd = -1;
|
||||
co->events = 0;
|
||||
#else
|
||||
co->fd_wait = -1;
|
||||
#endif
|
||||
co->arg = arg;
|
||||
co->birth = nty_coroutine_usec_now();
|
||||
*new_co = co;
|
||||
|
||||
TAILQ_INSERT_TAIL(&co->sched->ready, co, ready_next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
389
NtyCo/core/nty_coroutine.h
Executable file
389
NtyCo/core/nty_coroutine.h
Executable file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __NTY_COROUTINE_H__
|
||||
#define __NTY_COROUTINE_H__
|
||||
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define _USE_UCONTEXT
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#ifdef _USE_UCONTEXT
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "nty_queue.h"
|
||||
#include "nty_tree.h"
|
||||
|
||||
#define NTY_CO_MAX_EVENTS (1024*1024)
|
||||
#define NTY_CO_MAX_STACKSIZE (128*1024) // {http: 16*1024, tcp: 4*1024}
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
#define CLEARBIT(x) ~(1 << (x))
|
||||
|
||||
#define CANCEL_FD_WAIT_UINT64 1
|
||||
|
||||
typedef void (*proc_coroutine)(void *);
|
||||
|
||||
|
||||
typedef enum {
|
||||
NTY_COROUTINE_STATUS_WAIT_READ,
|
||||
NTY_COROUTINE_STATUS_WAIT_WRITE,
|
||||
NTY_COROUTINE_STATUS_NEW,
|
||||
NTY_COROUTINE_STATUS_READY,
|
||||
NTY_COROUTINE_STATUS_EXITED,
|
||||
NTY_COROUTINE_STATUS_BUSY,
|
||||
NTY_COROUTINE_STATUS_SLEEPING,
|
||||
NTY_COROUTINE_STATUS_EXPIRED,
|
||||
NTY_COROUTINE_STATUS_FDEOF,
|
||||
NTY_COROUTINE_STATUS_DETACH,
|
||||
NTY_COROUTINE_STATUS_CANCELLED,
|
||||
NTY_COROUTINE_STATUS_PENDING_RUNCOMPUTE,
|
||||
NTY_COROUTINE_STATUS_RUNCOMPUTE,
|
||||
NTY_COROUTINE_STATUS_WAIT_IO_READ,
|
||||
NTY_COROUTINE_STATUS_WAIT_IO_WRITE,
|
||||
NTY_COROUTINE_STATUS_WAIT_MULTI
|
||||
} nty_coroutine_status;
|
||||
|
||||
typedef enum {
|
||||
NTY_COROUTINE_COMPUTE_BUSY,
|
||||
NTY_COROUTINE_COMPUTE_FREE
|
||||
} nty_coroutine_compute_status;
|
||||
|
||||
typedef enum {
|
||||
NTY_COROUTINE_EV_READ,
|
||||
NTY_COROUTINE_EV_WRITE
|
||||
} nty_coroutine_event;
|
||||
|
||||
|
||||
LIST_HEAD(_nty_coroutine_link, _nty_coroutine);
|
||||
TAILQ_HEAD(_nty_coroutine_queue, _nty_coroutine);
|
||||
|
||||
RB_HEAD(_nty_coroutine_rbtree_sleep, _nty_coroutine);
|
||||
RB_HEAD(_nty_coroutine_rbtree_wait, _nty_coroutine);
|
||||
|
||||
|
||||
|
||||
typedef struct _nty_coroutine_link nty_coroutine_link;
|
||||
typedef struct _nty_coroutine_queue nty_coroutine_queue;
|
||||
|
||||
typedef struct _nty_coroutine_rbtree_sleep nty_coroutine_rbtree_sleep;
|
||||
typedef struct _nty_coroutine_rbtree_wait nty_coroutine_rbtree_wait;
|
||||
|
||||
|
||||
#ifndef _USE_UCONTEXT
|
||||
typedef struct _nty_cpu_ctx {
|
||||
void *esp; //
|
||||
void *ebp;
|
||||
void *eip;
|
||||
void *edi;
|
||||
void *esi;
|
||||
void *ebx;
|
||||
void *r1;
|
||||
void *r2;
|
||||
void *r3;
|
||||
void *r4;
|
||||
void *r5;
|
||||
} nty_cpu_ctx;
|
||||
#endif
|
||||
|
||||
///
|
||||
typedef struct _nty_schedule {
|
||||
uint64_t birth;
|
||||
#ifdef _USE_UCONTEXT
|
||||
ucontext_t ctx;
|
||||
#else
|
||||
nty_cpu_ctx ctx;
|
||||
#endif
|
||||
void *stack;
|
||||
size_t stack_size;
|
||||
int spawned_coroutines;
|
||||
uint64_t default_timeout;
|
||||
struct _nty_coroutine *curr_thread;
|
||||
int page_size;
|
||||
|
||||
int poller_fd;
|
||||
int eventfd;
|
||||
struct epoll_event eventlist[NTY_CO_MAX_EVENTS];
|
||||
int nevents;
|
||||
|
||||
int num_new_events;
|
||||
pthread_mutex_t defer_mutex;
|
||||
|
||||
nty_coroutine_queue ready;
|
||||
nty_coroutine_queue defer;
|
||||
|
||||
nty_coroutine_link busy;
|
||||
|
||||
nty_coroutine_rbtree_sleep sleeping;
|
||||
nty_coroutine_rbtree_wait waiting;
|
||||
|
||||
//private
|
||||
|
||||
} nty_schedule;
|
||||
|
||||
typedef struct _nty_coroutine {
|
||||
|
||||
//private
|
||||
|
||||
#ifdef _USE_UCONTEXT
|
||||
ucontext_t ctx;
|
||||
#else
|
||||
nty_cpu_ctx ctx;
|
||||
#endif
|
||||
proc_coroutine func;
|
||||
void *arg;
|
||||
void *data;
|
||||
size_t stack_size;
|
||||
size_t last_stack_size;
|
||||
|
||||
nty_coroutine_status status;
|
||||
nty_schedule *sched;
|
||||
|
||||
uint64_t birth;
|
||||
uint64_t id;
|
||||
#if CANCEL_FD_WAIT_UINT64
|
||||
int fd;
|
||||
unsigned short events; //POLL_EVENT
|
||||
#else
|
||||
int64_t fd_wait;
|
||||
#endif
|
||||
char funcname[64];
|
||||
struct _nty_coroutine *co_join;
|
||||
|
||||
void **co_exit_ptr;
|
||||
void *stack;
|
||||
void *ebp;
|
||||
uint32_t ops;
|
||||
uint64_t sleep_usecs;
|
||||
|
||||
RB_ENTRY(_nty_coroutine) sleep_node;
|
||||
RB_ENTRY(_nty_coroutine) wait_node;
|
||||
|
||||
LIST_ENTRY(_nty_coroutine) busy_next;
|
||||
|
||||
TAILQ_ENTRY(_nty_coroutine) ready_next;
|
||||
TAILQ_ENTRY(_nty_coroutine) defer_next;
|
||||
TAILQ_ENTRY(_nty_coroutine) cond_next;
|
||||
|
||||
TAILQ_ENTRY(_nty_coroutine) io_next;
|
||||
TAILQ_ENTRY(_nty_coroutine) compute_next;
|
||||
|
||||
struct {
|
||||
void *buf;
|
||||
size_t nbytes;
|
||||
int fd;
|
||||
int ret;
|
||||
int err;
|
||||
} io;
|
||||
|
||||
struct _nty_coroutine_compute_sched *compute_sched;
|
||||
int ready_fds;
|
||||
struct pollfd *pfds;
|
||||
nfds_t nfds;
|
||||
} nty_coroutine;
|
||||
|
||||
|
||||
typedef struct _nty_coroutine_compute_sched {
|
||||
#ifdef _USE_UCONTEXT
|
||||
ucontext_t ctx;
|
||||
#else
|
||||
nty_cpu_ctx ctx;
|
||||
#endif
|
||||
nty_coroutine_queue coroutines;
|
||||
|
||||
nty_coroutine *curr_coroutine;
|
||||
|
||||
pthread_mutex_t run_mutex;
|
||||
pthread_cond_t run_cond;
|
||||
|
||||
pthread_mutex_t co_mutex;
|
||||
LIST_ENTRY(_nty_coroutine_compute_sched) compute_next;
|
||||
|
||||
nty_coroutine_compute_status compute_status;
|
||||
} nty_coroutine_compute_sched;
|
||||
|
||||
extern pthread_key_t global_sched_key;
|
||||
static inline nty_schedule *nty_coroutine_get_sched(void) {
|
||||
return pthread_getspecific(global_sched_key);
|
||||
}
|
||||
|
||||
static inline uint64_t nty_coroutine_diff_usecs(uint64_t t1, uint64_t t2) {
|
||||
return t2-t1;
|
||||
}
|
||||
|
||||
static inline uint64_t nty_coroutine_usec_now(void) {
|
||||
struct timeval t1 = {0, 0};
|
||||
gettimeofday(&t1, NULL);
|
||||
|
||||
return t1.tv_sec * 1000000 + t1.tv_usec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int nty_epoller_create(void);
|
||||
|
||||
|
||||
void nty_schedule_cancel_event(nty_coroutine *co);
|
||||
void nty_schedule_sched_event(nty_coroutine *co, int fd, nty_coroutine_event e, uint64_t timeout);
|
||||
|
||||
void nty_schedule_desched_sleepdown(nty_coroutine *co);
|
||||
void nty_schedule_sched_sleepdown(nty_coroutine *co, uint64_t msecs);
|
||||
|
||||
nty_coroutine* nty_schedule_desched_wait(int fd);
|
||||
void nty_schedule_sched_wait(nty_coroutine *co, int fd, unsigned short events, uint64_t timeout);
|
||||
|
||||
void nty_schedule_run(void);
|
||||
|
||||
int nty_epoller_ev_register_trigger(void);
|
||||
int nty_epoller_wait(struct timespec t);
|
||||
int nty_coroutine_resume(nty_coroutine *co);
|
||||
void nty_coroutine_free(nty_coroutine *co);
|
||||
int nty_coroutine_create(nty_coroutine **new_co, proc_coroutine func, void *arg);
|
||||
void nty_coroutine_yield(nty_coroutine *co);
|
||||
|
||||
void nty_coroutine_sleep(uint64_t msecs);
|
||||
|
||||
|
||||
int nty_socket(int domain, int type, int protocol);
|
||||
int nty_accept(int fd, struct sockaddr *addr, socklen_t *len);
|
||||
ssize_t nty_recv(int fd, void *buf, size_t len, int flags);
|
||||
ssize_t nty_send(int fd, const void *buf, size_t len, int flags);
|
||||
int nty_close(int fd);
|
||||
int nty_poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
int nty_connect(int fd, struct sockaddr *name, socklen_t namelen);
|
||||
|
||||
ssize_t nty_sendto(int fd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
ssize_t nty_recvfrom(int fd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
|
||||
|
||||
#define COROUTINE_HOOK
|
||||
|
||||
#ifdef COROUTINE_HOOK
|
||||
|
||||
|
||||
typedef int (*socket_t)(int domain, int type, int protocol);
|
||||
extern socket_t socket_f;
|
||||
|
||||
typedef int(*connect_t)(int, const struct sockaddr *, socklen_t);
|
||||
extern connect_t connect_f;
|
||||
|
||||
typedef ssize_t(*read_t)(int, void *, size_t);
|
||||
extern read_t read_f;
|
||||
|
||||
|
||||
typedef ssize_t(*recv_t)(int sockfd, void *buf, size_t len, int flags);
|
||||
extern recv_t recv_f;
|
||||
|
||||
typedef ssize_t(*recvfrom_t)(int sockfd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
extern recvfrom_t recvfrom_f;
|
||||
|
||||
typedef ssize_t(*write_t)(int, const void *, size_t);
|
||||
extern write_t write_f;
|
||||
|
||||
typedef ssize_t(*send_t)(int sockfd, const void *buf, size_t len, int flags);
|
||||
extern send_t send_f;
|
||||
|
||||
typedef ssize_t(*sendto_t)(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
extern sendto_t sendto_f;
|
||||
|
||||
typedef int(*accept_t)(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
extern accept_t accept_f;
|
||||
|
||||
// new-syscall
|
||||
typedef int(*close_t)(int);
|
||||
extern close_t close_f;
|
||||
|
||||
|
||||
int init_hook(void);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
typedef int(*fcntl_t)(int __fd, int __cmd, ...);
|
||||
extern fcntl_t fcntl_f;
|
||||
|
||||
typedef int (*getsockopt_t)(int sockfd, int level, int optname,
|
||||
void *optval, socklen_t *optlen);
|
||||
extern getsockopt_t getsockopt_f;
|
||||
|
||||
typedef int (*setsockopt_t)(int sockfd, int level, int optname,
|
||||
const void *optval, socklen_t optlen);
|
||||
extern setsockopt_t setsockopt_f;
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
75
NtyCo/core/nty_epoll.c
Normal file
75
NtyCo/core/nty_epoll.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
#include "nty_coroutine.h"
|
||||
|
||||
|
||||
int nty_epoller_create(void) {
|
||||
return epoll_create(1024);
|
||||
}
|
||||
|
||||
int nty_epoller_wait(struct timespec t) {
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
return epoll_wait(sched->poller_fd, sched->eventlist, NTY_CO_MAX_EVENTS, t.tv_sec*1000.0 + t.tv_nsec/1000000.0);
|
||||
}
|
||||
|
||||
int nty_epoller_ev_register_trigger(void) {
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
|
||||
if (!sched->eventfd) {
|
||||
sched->eventfd = eventfd(0, EFD_NONBLOCK);
|
||||
assert(sched->eventfd != -1);
|
||||
}
|
||||
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = sched->eventfd;
|
||||
int ret = epoll_ctl(sched->poller_fd, EPOLL_CTL_ADD, sched->eventfd, &ev);
|
||||
|
||||
assert(ret != -1);
|
||||
}
|
||||
|
||||
|
||||
589
NtyCo/core/nty_queue.h
Normal file
589
NtyCo/core/nty_queue.h
Normal file
@@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NTY_QUEUE_H__
|
||||
#define __NTY_QUEUE_H__
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
/* Store the last 2 places the queue element or head was altered */
|
||||
struct qm_trace {
|
||||
char * lastfile;
|
||||
int lastline;
|
||||
char * prevfile;
|
||||
int prevline;
|
||||
};
|
||||
|
||||
#define TRACEBUF struct qm_trace trace;
|
||||
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
|
||||
|
||||
#define QMD_TRACE_HEAD(head) do { \
|
||||
(head)->trace.prevline = (head)->trace.lastline; \
|
||||
(head)->trace.prevfile = (head)->trace.lastfile; \
|
||||
(head)->trace.lastline = __LINE__; \
|
||||
(head)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TRACE_ELEM(elem) do { \
|
||||
(elem)->trace.prevline = (elem)->trace.lastline; \
|
||||
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
||||
(elem)->trace.lastline = __LINE__; \
|
||||
(elem)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define QMD_TRACE_ELEM(elem)
|
||||
#define QMD_TRACE_HEAD(head)
|
||||
#define TRACEBUF
|
||||
#define TRASHIT(x)
|
||||
#endif /* QUEUE_MACRO_DEBUG */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked List declarations.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != NULL; \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_INIT(head) do { \
|
||||
SLIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
|
||||
SLIST_NEXT((slistelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
|
||||
SLIST_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if (SLIST_FIRST((head)) == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = SLIST_FIRST((head)); \
|
||||
while (SLIST_NEXT(curelm, field) != (elm)) \
|
||||
curelm = SLIST_NEXT(curelm, field); \
|
||||
SLIST_REMOVE_AFTER(curelm, field); \
|
||||
} \
|
||||
TRASHIT((elm)->field.sle_next); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_AFTER(elm, field) do { \
|
||||
SLIST_NEXT(elm, field) = \
|
||||
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first;/* first element */ \
|
||||
struct type **stqh_last;/* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_CONCAT(head1, head2) do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for((var) = STAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define STAILQ_INIT(head) do { \
|
||||
STAILQ_FIRST((head)) = NULL; \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_NEXT((tqelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
STAILQ_NEXT((elm), field) = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_LAST(head, type, field) \
|
||||
(STAILQ_EMPTY((head)) ? \
|
||||
NULL : \
|
||||
((struct type *)(void *) \
|
||||
((char *)((head)->stqh_last) - __offsetof(struct type, field))))
|
||||
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
if (STAILQ_FIRST((head)) == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = STAILQ_FIRST((head)); \
|
||||
while (STAILQ_NEXT(curelm, field) != (elm)) \
|
||||
curelm = STAILQ_NEXT(curelm, field); \
|
||||
STAILQ_REMOVE_AFTER(head, curelm, field); \
|
||||
} \
|
||||
TRASHIT((elm)->field.stqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if ((STAILQ_FIRST((head)) = \
|
||||
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT(elm, field) = \
|
||||
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_SWAP(head1, head2, type) do { \
|
||||
struct type *swap_first = STAILQ_FIRST(head1); \
|
||||
struct type **swap_last = (head1)->stqh_last; \
|
||||
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_FIRST(head2) = swap_first; \
|
||||
(head2)->stqh_last = swap_last; \
|
||||
if (STAILQ_EMPTY(head1)) \
|
||||
(head1)->stqh_last = &STAILQ_FIRST(head1); \
|
||||
if (STAILQ_EMPTY(head2)) \
|
||||
(head2)->stqh_last = &STAILQ_FIRST(head2); \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* List declarations.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_LIST_CHECK_HEAD(head, field) do { \
|
||||
if (LIST_FIRST((head)) != NULL && \
|
||||
LIST_FIRST((head))->field.le_prev != \
|
||||
&LIST_FIRST((head))) \
|
||||
panic("Bad list head %p first->prev != head", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
|
||||
if (LIST_NEXT((elm), field) != NULL && \
|
||||
LIST_NEXT((elm), field)->field.le_prev != \
|
||||
&((elm)->field.le_next)) \
|
||||
panic("Bad link elm %p next->prev != elm", (elm)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_LIST_CHECK_PREV(elm, field) do { \
|
||||
if (*(elm)->field.le_prev != (elm)) \
|
||||
panic("Bad link elm %p prev->next != elm", (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_LIST_CHECK_HEAD(head, field)
|
||||
#define QMD_LIST_CHECK_NEXT(elm, field)
|
||||
#define QMD_LIST_CHECK_PREV(elm, field)
|
||||
#endif /* (_KERNEL && INVARIANTS) */
|
||||
|
||||
|
||||
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
QMD_LIST_CHECK_NEXT(listelm, field); \
|
||||
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
|
||||
LIST_NEXT((listelm), field)->field.le_prev = \
|
||||
&LIST_NEXT((elm), field); \
|
||||
LIST_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
QMD_LIST_CHECK_PREV(listelm, field); \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
LIST_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
QMD_LIST_CHECK_HEAD((head), field); \
|
||||
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
|
||||
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
|
||||
LIST_FIRST((head)) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
QMD_LIST_CHECK_NEXT(elm, field); \
|
||||
QMD_LIST_CHECK_PREV(elm, field); \
|
||||
if (LIST_NEXT((elm), field) != NULL) \
|
||||
LIST_NEXT((elm), field)->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
|
||||
TRASHIT((elm)->field.le_next); \
|
||||
TRASHIT((elm)->field.le_prev); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_SWAP(head1, head2, type, field) do { \
|
||||
struct type *swap_tmp = LIST_FIRST((head1)); \
|
||||
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
|
||||
LIST_FIRST((head2)) = swap_tmp; \
|
||||
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
|
||||
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Tail queue declarations.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
|
||||
if (!TAILQ_EMPTY(head) && \
|
||||
TAILQ_FIRST((head))->field.tqe_prev != \
|
||||
&TAILQ_FIRST((head))) \
|
||||
panic("Bad tailq head %p first->prev != head", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
|
||||
if (*(head)->tqh_last != NULL) \
|
||||
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
|
||||
if (TAILQ_NEXT((elm), field) != NULL && \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev != \
|
||||
&((elm)->field.tqe_next)) \
|
||||
panic("Bad link elm %p next->prev != elm", (elm)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
|
||||
if (*(elm)->field.tqe_prev != (elm)) \
|
||||
panic("Bad link elm %p prev->next != elm", (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_TAILQ_CHECK_HEAD(head, field)
|
||||
#define QMD_TAILQ_CHECK_TAIL(head, headname)
|
||||
#define QMD_TAILQ_CHECK_NEXT(elm, field)
|
||||
#define QMD_TAILQ_CHECK_PREV(elm, field)
|
||||
#endif /* (_KERNEL && INVARIANTS) */
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
QMD_TRACE_HEAD(head1); \
|
||||
QMD_TRACE_HEAD(head2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_INIT(head) do { \
|
||||
TAILQ_FIRST((head)) = NULL; \
|
||||
(head)->tqh_last = &TAILQ_FIRST((head)); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_NEXT(listelm, field); \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else { \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} \
|
||||
TAILQ_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
QMD_TRACE_ELEM(&listelm->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_PREV(listelm, field); \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
TAILQ_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
QMD_TRACE_ELEM(&listelm->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_HEAD(head, field); \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
|
||||
TAILQ_FIRST((head))->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_FIRST((head)) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_TAIL(head, field); \
|
||||
TAILQ_NEXT((elm), field) = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
QMD_TAILQ_CHECK_NEXT(elm, field); \
|
||||
QMD_TAILQ_CHECK_PREV(elm, field); \
|
||||
if ((TAILQ_NEXT((elm), field)) != NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else { \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} \
|
||||
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
|
||||
TRASHIT((elm)->field.tqe_next); \
|
||||
TRASHIT((elm)->field.tqe_prev); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_SWAP(head1, head2, type, field) do { \
|
||||
struct type *swap_first = (head1)->tqh_first; \
|
||||
struct type **swap_last = (head1)->tqh_last; \
|
||||
(head1)->tqh_first = (head2)->tqh_first; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
(head2)->tqh_first = swap_first; \
|
||||
(head2)->tqh_last = swap_last; \
|
||||
if ((swap_first = (head1)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head1)->tqh_first; \
|
||||
else \
|
||||
(head1)->tqh_last = &(head1)->tqh_first; \
|
||||
if ((swap_first = (head2)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head2)->tqh_first; \
|
||||
else \
|
||||
(head2)->tqh_last = &(head2)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
369
NtyCo/core/nty_schedule.c
Normal file
369
NtyCo/core/nty_schedule.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "nty_coroutine.h"
|
||||
|
||||
|
||||
|
||||
#define FD_KEY(f,e) (((int64_t)(f) << (sizeof(int32_t) * 8)) | e)
|
||||
#define FD_EVENT(f) ((int32_t)(f))
|
||||
#define FD_ONLY(f) ((f) >> ((sizeof(int32_t) * 8)))
|
||||
|
||||
|
||||
static inline int nty_coroutine_sleep_cmp(nty_coroutine *co1, nty_coroutine *co2) {
|
||||
if (co1->sleep_usecs < co2->sleep_usecs) {
|
||||
return -1;
|
||||
}
|
||||
if (co1->sleep_usecs == co2->sleep_usecs) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int nty_coroutine_wait_cmp(nty_coroutine *co1, nty_coroutine *co2) {
|
||||
#if CANCEL_FD_WAIT_UINT64
|
||||
if (co1->fd < co2->fd) return -1;
|
||||
else if (co1->fd == co2->fd) return 0;
|
||||
else return 1;
|
||||
#else
|
||||
if (co1->fd_wait < co2->fd_wait) {
|
||||
return -1;
|
||||
}
|
||||
if (co1->fd_wait == co2->fd_wait) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE(_nty_coroutine_rbtree_sleep, _nty_coroutine, sleep_node, nty_coroutine_sleep_cmp);
|
||||
RB_GENERATE(_nty_coroutine_rbtree_wait, _nty_coroutine, wait_node, nty_coroutine_wait_cmp);
|
||||
|
||||
|
||||
|
||||
void nty_schedule_sched_sleepdown(nty_coroutine *co, uint64_t msecs) {
|
||||
uint64_t usecs = msecs * 1000u;
|
||||
|
||||
nty_coroutine *co_tmp = RB_FIND(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co);
|
||||
if (co_tmp != NULL) {
|
||||
RB_REMOVE(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co_tmp);
|
||||
}
|
||||
|
||||
co->sleep_usecs = nty_coroutine_diff_usecs(co->sched->birth, nty_coroutine_usec_now()) + usecs;
|
||||
|
||||
while (msecs) {
|
||||
co_tmp = RB_INSERT(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co);
|
||||
if (co_tmp) {
|
||||
printf("1111 sleep_usecs %"PRIu64"\n", co->sleep_usecs);
|
||||
co->sleep_usecs ++;
|
||||
continue;
|
||||
}
|
||||
co->status |= BIT(NTY_COROUTINE_STATUS_SLEEPING);
|
||||
break;
|
||||
}
|
||||
|
||||
//yield
|
||||
}
|
||||
|
||||
void nty_schedule_desched_sleepdown(nty_coroutine *co) {
|
||||
if (co->status & BIT(NTY_COROUTINE_STATUS_SLEEPING)) {
|
||||
RB_REMOVE(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co);
|
||||
|
||||
co->status &= CLEARBIT(NTY_COROUTINE_STATUS_SLEEPING);
|
||||
co->status |= BIT(NTY_COROUTINE_STATUS_READY);
|
||||
co->status &= CLEARBIT(NTY_COROUTINE_STATUS_EXPIRED);
|
||||
}
|
||||
}
|
||||
|
||||
nty_coroutine *nty_schedule_search_wait(int fd) {
|
||||
nty_coroutine find_it = {0};
|
||||
find_it.fd = fd;
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
|
||||
nty_coroutine *co = RB_FIND(_nty_coroutine_rbtree_wait, &sched->waiting, &find_it);
|
||||
co->status = 0;
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
nty_coroutine* nty_schedule_desched_wait(int fd) {
|
||||
|
||||
nty_coroutine find_it = {0};
|
||||
find_it.fd = fd;
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
|
||||
nty_coroutine *co = RB_FIND(_nty_coroutine_rbtree_wait, &sched->waiting, &find_it);
|
||||
if (co != NULL) {
|
||||
RB_REMOVE(_nty_coroutine_rbtree_wait, &co->sched->waiting, co);
|
||||
}
|
||||
co->status = 0;
|
||||
nty_schedule_desched_sleepdown(co);
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
void nty_schedule_sched_wait(nty_coroutine *co, int fd, unsigned short events, uint64_t timeout) {
|
||||
|
||||
if (co->status & BIT(NTY_COROUTINE_STATUS_WAIT_READ) ||
|
||||
co->status & BIT(NTY_COROUTINE_STATUS_WAIT_WRITE)) {
|
||||
printf("Unexpected event. lt id %"PRIu64" fd %"PRId32" already in %"PRId32" state\n",
|
||||
co->id, co->fd, co->status);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (events & POLLIN) {
|
||||
co->status |= NTY_COROUTINE_STATUS_WAIT_READ;
|
||||
} else if (events & POLLOUT) {
|
||||
co->status |= NTY_COROUTINE_STATUS_WAIT_WRITE;
|
||||
} else {
|
||||
printf("events : %d\n", events);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
co->fd = fd;
|
||||
co->events = events;
|
||||
nty_coroutine *co_tmp = RB_INSERT(_nty_coroutine_rbtree_wait, &co->sched->waiting, co);
|
||||
|
||||
assert(co_tmp == NULL);
|
||||
|
||||
//printf("timeout --> %"PRIu64"\n", timeout);
|
||||
if (timeout == 1) return ; //Error
|
||||
|
||||
nty_schedule_sched_sleepdown(co, timeout);
|
||||
|
||||
}
|
||||
|
||||
void nty_schedule_cancel_wait(nty_coroutine *co) {
|
||||
RB_REMOVE(_nty_coroutine_rbtree_wait, &co->sched->waiting, co);
|
||||
}
|
||||
|
||||
void nty_schedule_free(nty_schedule *sched) {
|
||||
if (sched->poller_fd > 0) {
|
||||
close(sched->poller_fd);
|
||||
}
|
||||
if (sched->eventfd > 0) {
|
||||
close(sched->eventfd);
|
||||
}
|
||||
if (sched->stack != NULL) {
|
||||
free(sched->stack);
|
||||
}
|
||||
|
||||
free(sched);
|
||||
|
||||
assert(pthread_setspecific(global_sched_key, NULL) == 0);
|
||||
}
|
||||
|
||||
int nty_schedule_create(int stack_size) {
|
||||
|
||||
int sched_stack_size = stack_size ? stack_size : NTY_CO_MAX_STACKSIZE;
|
||||
|
||||
nty_schedule *sched = (nty_schedule*)calloc(1, sizeof(nty_schedule));
|
||||
if (sched == NULL) {
|
||||
printf("Failed to initialize scheduler\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(pthread_setspecific(global_sched_key, sched) == 0);
|
||||
|
||||
sched->poller_fd = nty_epoller_create();
|
||||
if (sched->poller_fd == -1) {
|
||||
printf("Failed to initialize epoller\n");
|
||||
nty_schedule_free(sched);
|
||||
return -2;
|
||||
}
|
||||
|
||||
nty_epoller_ev_register_trigger();
|
||||
|
||||
sched->stack_size = sched_stack_size;
|
||||
sched->page_size = getpagesize();
|
||||
|
||||
#ifdef _USE_UCONTEXT
|
||||
int ret = posix_memalign(&sched->stack, sched->page_size, sched->stack_size);
|
||||
assert(ret == 0);
|
||||
#else
|
||||
sched->stack = NULL;
|
||||
bzero(&sched->ctx, sizeof(nty_cpu_ctx));
|
||||
#endif
|
||||
|
||||
sched->spawned_coroutines = 0;
|
||||
sched->default_timeout = 3000000u;
|
||||
|
||||
RB_INIT(&sched->sleeping);
|
||||
RB_INIT(&sched->waiting);
|
||||
|
||||
sched->birth = nty_coroutine_usec_now();
|
||||
|
||||
TAILQ_INIT(&sched->ready);
|
||||
TAILQ_INIT(&sched->defer);
|
||||
LIST_INIT(&sched->busy);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static nty_coroutine *nty_schedule_expired(nty_schedule *sched) {
|
||||
|
||||
uint64_t t_diff_usecs = nty_coroutine_diff_usecs(sched->birth, nty_coroutine_usec_now());
|
||||
nty_coroutine *co = RB_MIN(_nty_coroutine_rbtree_sleep, &sched->sleeping);
|
||||
if (co == NULL) return NULL;
|
||||
|
||||
if (co->sleep_usecs <= t_diff_usecs) {
|
||||
RB_REMOVE(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co);
|
||||
return co;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int nty_schedule_isdone(nty_schedule *sched) {
|
||||
return (RB_EMPTY(&sched->waiting) &&
|
||||
LIST_EMPTY(&sched->busy) &&
|
||||
RB_EMPTY(&sched->sleeping) &&
|
||||
TAILQ_EMPTY(&sched->ready));
|
||||
}
|
||||
|
||||
static uint64_t nty_schedule_min_timeout(nty_schedule *sched) {
|
||||
uint64_t t_diff_usecs = nty_coroutine_diff_usecs(sched->birth, nty_coroutine_usec_now());
|
||||
uint64_t min = sched->default_timeout;
|
||||
|
||||
nty_coroutine *co = RB_MIN(_nty_coroutine_rbtree_sleep, &sched->sleeping);
|
||||
if (!co) return min;
|
||||
|
||||
min = co->sleep_usecs;
|
||||
if (min > t_diff_usecs) {
|
||||
return min - t_diff_usecs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nty_schedule_epoll(nty_schedule *sched) {
|
||||
|
||||
sched->num_new_events = 0;
|
||||
|
||||
struct timespec t = {0, 0};
|
||||
uint64_t usecs = nty_schedule_min_timeout(sched);
|
||||
if (usecs && TAILQ_EMPTY(&sched->ready)) {
|
||||
t.tv_sec = usecs / 1000000u;
|
||||
if (t.tv_sec != 0) {
|
||||
t.tv_nsec = (usecs % 1000u) * 1000u;
|
||||
} else {
|
||||
t.tv_nsec = usecs * 1000u;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nready = 0;
|
||||
while (1) {
|
||||
nready = nty_epoller_wait(t);
|
||||
if (nready == -1) {
|
||||
if (errno == EINTR) continue;
|
||||
else assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sched->nevents = 0;
|
||||
sched->num_new_events = nready;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nty_schedule_run(void) {
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) return ;
|
||||
|
||||
while (!nty_schedule_isdone(sched)) {
|
||||
|
||||
// 1. expired --> sleep rbtree
|
||||
nty_coroutine *expired = NULL;
|
||||
while ((expired = nty_schedule_expired(sched)) != NULL) {
|
||||
nty_coroutine_resume(expired);
|
||||
}
|
||||
// 2. ready queue
|
||||
nty_coroutine *last_co_ready = TAILQ_LAST(&sched->ready, _nty_coroutine_queue);
|
||||
while (!TAILQ_EMPTY(&sched->ready)) {
|
||||
nty_coroutine *co = TAILQ_FIRST(&sched->ready);
|
||||
TAILQ_REMOVE(&co->sched->ready, co, ready_next);
|
||||
|
||||
if (co->status & BIT(NTY_COROUTINE_STATUS_FDEOF)) {
|
||||
nty_coroutine_free(co);
|
||||
break;
|
||||
}
|
||||
|
||||
nty_coroutine_resume(co);
|
||||
if (co == last_co_ready) break;
|
||||
}
|
||||
|
||||
// 3. wait rbtree
|
||||
nty_schedule_epoll(sched);
|
||||
while (sched->num_new_events) {
|
||||
int idx = --sched->num_new_events;
|
||||
struct epoll_event *ev = sched->eventlist+idx;
|
||||
|
||||
int fd = ev->data.fd;
|
||||
int is_eof = ev->events & EPOLLHUP;
|
||||
if (is_eof) errno = ECONNRESET;
|
||||
|
||||
nty_coroutine *co = nty_schedule_search_wait(fd);
|
||||
if (co != NULL) {
|
||||
if (is_eof) {
|
||||
co->status |= BIT(NTY_COROUTINE_STATUS_FDEOF);
|
||||
}
|
||||
nty_coroutine_resume(co);
|
||||
}
|
||||
|
||||
is_eof = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nty_schedule_free(sched);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
672
NtyCo/core/nty_socket.c
Executable file
672
NtyCo/core/nty_socket.c
Executable file
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nty_coroutine.h"
|
||||
|
||||
|
||||
|
||||
static uint32_t nty_pollevent_2epoll( short events )
|
||||
{
|
||||
uint32_t e = 0;
|
||||
if( events & POLLIN ) e |= EPOLLIN;
|
||||
if( events & POLLOUT ) e |= EPOLLOUT;
|
||||
if( events & POLLHUP ) e |= EPOLLHUP;
|
||||
if( events & POLLERR ) e |= EPOLLERR;
|
||||
if( events & POLLRDNORM ) e |= EPOLLRDNORM;
|
||||
if( events & POLLWRNORM ) e |= EPOLLWRNORM;
|
||||
return e;
|
||||
}
|
||||
static short nty_epollevent_2poll( uint32_t events )
|
||||
{
|
||||
short e = 0;
|
||||
if( events & EPOLLIN ) e |= POLLIN;
|
||||
if( events & EPOLLOUT ) e |= POLLOUT;
|
||||
if( events & EPOLLHUP ) e |= POLLHUP;
|
||||
if( events & EPOLLERR ) e |= POLLERR;
|
||||
if( events & EPOLLRDNORM ) e |= POLLRDNORM;
|
||||
if( events & EPOLLWRNORM ) e |= POLLWRNORM;
|
||||
return e;
|
||||
}
|
||||
/*
|
||||
* nty_poll_inner --> 1. sockfd--> epoll, 2 yield, 3. epoll x sockfd
|
||||
* fds :
|
||||
*/
|
||||
|
||||
static int nty_poll_inner(struct pollfd *fds, nfds_t nfds, int timeout) {
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
return poll(fds, nfds, timeout);
|
||||
}
|
||||
if (timeout < 0)
|
||||
{
|
||||
timeout = INT_MAX;
|
||||
}
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
printf("scheduler not exit!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nty_coroutine *co = sched->curr_thread;
|
||||
|
||||
int i = 0;
|
||||
for (i = 0;i < nfds;i ++) {
|
||||
|
||||
struct epoll_event ev;
|
||||
ev.events = nty_pollevent_2epoll(fds[i].events);
|
||||
ev.data.fd = fds[i].fd;
|
||||
epoll_ctl(sched->poller_fd, EPOLL_CTL_ADD, fds[i].fd, &ev);
|
||||
|
||||
co->events = fds[i].events;
|
||||
nty_schedule_sched_wait(co, fds[i].fd, fds[i].events, timeout);
|
||||
}
|
||||
nty_coroutine_yield(co);
|
||||
|
||||
for (i = 0;i < nfds;i ++) {
|
||||
|
||||
struct epoll_event ev;
|
||||
ev.events = nty_pollevent_2epoll(fds[i].events);
|
||||
ev.data.fd = fds[i].fd;
|
||||
epoll_ctl(sched->poller_fd, EPOLL_CTL_DEL, fds[i].fd, &ev);
|
||||
|
||||
nty_schedule_desched_wait(fds[i].fd);
|
||||
}
|
||||
|
||||
return nfds;
|
||||
}
|
||||
|
||||
|
||||
int nty_socket(int domain, int type, int protocol) {
|
||||
|
||||
int fd = socket(domain, type, protocol);
|
||||
if (fd == -1) {
|
||||
printf("Failed to create a new socket\n");
|
||||
return -1;
|
||||
}
|
||||
int ret = fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
close(ret);
|
||||
return -1;
|
||||
}
|
||||
int reuse = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
//nty_accept
|
||||
//return failed == -1, success > 0
|
||||
|
||||
int nty_accept(int fd, struct sockaddr *addr, socklen_t *len) {
|
||||
int sockfd = -1;
|
||||
int timeout = 1;
|
||||
nty_coroutine *co = nty_coroutine_get_sched()->curr_thread;
|
||||
|
||||
while (1) {
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
nty_poll_inner(&fds, 1, timeout);
|
||||
|
||||
sockfd = accept(fd, addr, len);
|
||||
if (sockfd < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
continue;
|
||||
} else if (errno == ECONNABORTED) {
|
||||
printf("accept : ECONNABORTED\n");
|
||||
|
||||
} else if (errno == EMFILE || errno == ENFILE) {
|
||||
printf("accept : EMFILE || ENFILE\n");
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
int reuse = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
|
||||
int nty_connect(int fd, struct sockaddr *name, socklen_t namelen) {
|
||||
|
||||
int ret = 0;
|
||||
|
||||
while (1) {
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
ret = connect(fd, name, namelen);
|
||||
if (ret == 0) break;
|
||||
|
||||
if (ret == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS)) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//recv
|
||||
// add epoll first
|
||||
//
|
||||
ssize_t nty_recv(int fd, void *buf, size_t len, int flags) {
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
int ret = recv(fd, buf, len, flags);
|
||||
if (ret < 0) {
|
||||
//if (errno == EAGAIN) return ret;
|
||||
if (errno == ECONNRESET) return -1;
|
||||
//printf("recv error : %d, ret : %d\n", errno, ret);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t nty_send(int fd, const void *buf, size_t len, int flags) {
|
||||
|
||||
int sent = 0;
|
||||
|
||||
int ret = send(fd, ((char*)buf)+sent, len-sent, flags);
|
||||
if (ret == 0) return ret;
|
||||
if (ret > 0) sent += ret;
|
||||
|
||||
while (sent < len) {
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
ret = send(fd, ((char*)buf)+sent, len-sent, flags);
|
||||
//printf("send --> len : %d\n", ret);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
sent += ret;
|
||||
}
|
||||
|
||||
if (ret <= 0 && sent == 0) return ret;
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
|
||||
ssize_t nty_sendto(int fd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen) {
|
||||
|
||||
|
||||
int sent = 0;
|
||||
|
||||
while (sent < len) {
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
int ret = sendto(fd, ((char*)buf)+sent, len-sent, flags, dest_addr, addrlen);
|
||||
if (ret <= 0) {
|
||||
if (errno == EAGAIN) continue;
|
||||
else if (errno == ECONNRESET) {
|
||||
return ret;
|
||||
}
|
||||
printf("send errno : %d, ret : %d\n", errno, ret);
|
||||
assert(0);
|
||||
}
|
||||
sent += ret;
|
||||
}
|
||||
return sent;
|
||||
|
||||
}
|
||||
|
||||
ssize_t nty_recvfrom(int fd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen) {
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
int ret = recvfrom(fd, buf, len, flags, src_addr, addrlen);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) return ret;
|
||||
if (errno == ECONNRESET) return 0;
|
||||
|
||||
printf("recv error : %d, ret : %d\n", errno, ret);
|
||||
assert(0);
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int nty_close(int fd) {
|
||||
#if 0
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
|
||||
nty_coroutine *co = sched->curr_thread;
|
||||
if (co) {
|
||||
TAILQ_INSERT_TAIL(&nty_coroutine_get_sched()->ready, co, ready_next);
|
||||
co->status |= BIT(NTY_COROUTINE_STATUS_FDEOF);
|
||||
}
|
||||
#endif
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
|
||||
#ifdef COROUTINE_HOOK
|
||||
|
||||
socket_t socket_f = NULL;
|
||||
|
||||
read_t read_f = NULL;
|
||||
recv_t recv_f = NULL;
|
||||
recvfrom_t recvfrom_f = NULL;
|
||||
|
||||
write_t write_f = NULL;
|
||||
send_t send_f = NULL;
|
||||
sendto_t sendto_f = NULL;
|
||||
|
||||
accept_t accept_f = NULL;
|
||||
close_t close_f = NULL;
|
||||
connect_t connect_f = NULL;
|
||||
|
||||
|
||||
int init_hook(void) {
|
||||
|
||||
socket_f = (socket_t)dlsym(RTLD_NEXT, "socket");
|
||||
|
||||
read_f = (read_t)dlsym(RTLD_NEXT, "read");
|
||||
recv_f = (recv_t)dlsym(RTLD_NEXT, "recv");
|
||||
recvfrom_f = (recvfrom_t)dlsym(RTLD_NEXT, "recvfrom");
|
||||
|
||||
write_f = (write_t)dlsym(RTLD_NEXT, "write");
|
||||
send_f = (send_t)dlsym(RTLD_NEXT, "send");
|
||||
sendto_f = (sendto_t)dlsym(RTLD_NEXT, "sendto");
|
||||
|
||||
accept_f = (accept_t)dlsym(RTLD_NEXT, "accept");
|
||||
close_f = (close_t)dlsym(RTLD_NEXT, "close");
|
||||
connect_f = (connect_t)dlsym(RTLD_NEXT, "connect");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int socket(int domain, int type, int protocol) {
|
||||
|
||||
if (!socket_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return socket_f(domain, type, protocol);
|
||||
}
|
||||
|
||||
int fd = socket_f(domain, type, protocol);
|
||||
if (fd == -1) {
|
||||
printf("Failed to create a new socket\n");
|
||||
return -1;
|
||||
}
|
||||
int ret = fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
close(ret);
|
||||
return -1;
|
||||
}
|
||||
int reuse = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
ssize_t read(int fd, void *buf, size_t count) {
|
||||
|
||||
if (!read_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return read_f(fd, buf, count);
|
||||
}
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
int ret = read_f(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
//if (errno == EAGAIN) return ret;
|
||||
if (errno == ECONNRESET) return -1;
|
||||
//printf("recv error : %d, ret : %d\n", errno, ret);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t recv(int fd, void *buf, size_t len, int flags) {
|
||||
|
||||
if (!recv_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return recv_f(fd, buf, len, flags);
|
||||
}
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
int ret = recv_f(fd, buf, len, flags);
|
||||
if (ret < 0) {
|
||||
//if (errno == EAGAIN) return ret;
|
||||
if (errno == ECONNRESET) return -1;
|
||||
//printf("recv error : %d, ret : %d\n", errno, ret);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t recvfrom(int fd, void *buf, size_t len, int flags,
|
||||
struct sockaddr *src_addr, socklen_t *addrlen) {
|
||||
|
||||
if (!recvfrom_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return recvfrom_f(fd, buf, len, flags, src_addr, addrlen);
|
||||
}
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
int ret = recvfrom_f(fd, buf, len, flags, src_addr, addrlen);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) return ret;
|
||||
if (errno == ECONNRESET) return 0;
|
||||
|
||||
printf("recv error : %d, ret : %d\n", errno, ret);
|
||||
assert(0);
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t count) {
|
||||
|
||||
if (!write_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return write_f(fd, buf, count);
|
||||
}
|
||||
|
||||
int sent = 0;
|
||||
|
||||
int ret = write_f(fd, ((char*)buf)+sent, count-sent);
|
||||
if (ret == 0) return ret;
|
||||
if (ret > 0) sent += ret;
|
||||
|
||||
while (sent < count) {
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
ret = write_f(fd, ((char*)buf)+sent, count-sent);
|
||||
//printf("send --> len : %d\n", ret);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
sent += ret;
|
||||
}
|
||||
|
||||
if (ret <= 0 && sent == 0) return ret;
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
|
||||
ssize_t send(int fd, const void *buf, size_t len, int flags) {
|
||||
|
||||
if (!send_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return send_f(fd, buf, len, flags);
|
||||
}
|
||||
|
||||
int sent = 0;
|
||||
|
||||
int ret = send_f(fd, ((char*)buf)+sent, len-sent, flags);
|
||||
if (ret == 0) return ret;
|
||||
if (ret > 0) sent += ret;
|
||||
|
||||
while (sent < len) {
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
ret = send_f(fd, ((char*)buf)+sent, len-sent, flags);
|
||||
//printf("send --> len : %d\n", ret);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
sent += ret;
|
||||
}
|
||||
|
||||
if (ret <= 0 && sent == 0) return ret;
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen) {
|
||||
|
||||
if (!sendto_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return sendto_f(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
}
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = sockfd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
int ret = sendto_f(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN) return ret;
|
||||
if (errno == ECONNRESET) return 0;
|
||||
|
||||
printf("recv error : %d, ret : %d\n", errno, ret);
|
||||
assert(0);
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
int accept(int fd, struct sockaddr *addr, socklen_t *len) {
|
||||
|
||||
if (!accept_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return accept_f(fd, addr, len);
|
||||
}
|
||||
|
||||
int sockfd = -1;
|
||||
int timeout = 1;
|
||||
nty_coroutine *co = nty_coroutine_get_sched()->curr_thread;
|
||||
|
||||
while (1) {
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN | POLLERR | POLLHUP;
|
||||
nty_poll_inner(&fds, 1, timeout);
|
||||
|
||||
sockfd = accept_f(fd, addr, len);
|
||||
if (sockfd < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
continue;
|
||||
} else if (errno == ECONNABORTED) {
|
||||
printf("accept : ECONNABORTED\n");
|
||||
|
||||
} else if (errno == EMFILE || errno == ENFILE) {
|
||||
printf("accept : EMFILE || ENFILE\n");
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
close(sockfd);
|
||||
return -1;
|
||||
}
|
||||
int reuse = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
int close(int fd) {
|
||||
|
||||
if (!close_f) init_hook();
|
||||
|
||||
return close_f(fd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int connect(int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
|
||||
if (!connect_f) init_hook();
|
||||
|
||||
nty_schedule *sched = nty_coroutine_get_sched();
|
||||
if (sched == NULL) {
|
||||
return connect_f(fd, addr, addrlen);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
while (1) {
|
||||
|
||||
struct pollfd fds;
|
||||
fds.fd = fd;
|
||||
fds.events = POLLOUT | POLLERR | POLLHUP;
|
||||
nty_poll_inner(&fds, 1, 1);
|
||||
|
||||
ret = connect_f(fd, addr, addrlen);
|
||||
if (ret == 0) break;
|
||||
|
||||
if (ret == -1 && (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == EINPROGRESS)) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
754
NtyCo/core/nty_tree.h
Normal file
754
NtyCo/core/nty_tree.h
Normal file
@@ -0,0 +1,754 @@
|
||||
/*
|
||||
* Author : WangBoJing , email : 1989wangbojing@gmail.com
|
||||
*
|
||||
* Copyright Statement:
|
||||
* --------------------
|
||||
* This software is protected by Copyright and the information contained
|
||||
* herein is confidential. The software may not be copied and the information
|
||||
* contained herein may not be used or disclosed except with the written
|
||||
* permission of Author. (C) 2017
|
||||
*
|
||||
*
|
||||
|
||||
**** ***** *****
|
||||
*** * ** ***
|
||||
*** * * * **
|
||||
* ** * * ** **
|
||||
* ** * * ** *
|
||||
* ** * ** ** *
|
||||
* ** * *** **
|
||||
* ** * *********** ***** ***** ** ****
|
||||
* ** * ** ** ** ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** ** * ** ** **
|
||||
* ** * ** * * ** ** **
|
||||
* ** * ** ** * ** * ** **
|
||||
* *** ** * * ** * ** **
|
||||
* *** ** * ** * * ** **
|
||||
* ** ** * ** ** * ** **
|
||||
* ** ** * * ** * ** **
|
||||
***** * **** * ***** ****
|
||||
*
|
||||
*
|
||||
*****
|
||||
****
|
||||
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NTY_TREE_H__
|
||||
#define __NTY_TREE_H__
|
||||
|
||||
|
||||
#define SPLAY_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sph_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define SPLAY_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define SPLAY_INIT(root) do { \
|
||||
(root)->sph_root = NULL; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *spe_left; /* left element */ \
|
||||
struct type *spe_right; /* right element */ \
|
||||
}
|
||||
|
||||
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
|
||||
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
|
||||
#define SPLAY_ROOT(head) (head)->sph_root
|
||||
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
|
||||
|
||||
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
|
||||
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
(head)->sph_root = tmp; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKLEFT(head, tmp, field) do { \
|
||||
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
|
||||
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
|
||||
tmp = (head)->sph_root; \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
|
||||
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
|
||||
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
|
||||
|
||||
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
|
||||
void name##_SPLAY(struct name *, struct type *); \
|
||||
void name##_SPLAY_MINMAX(struct name *, int); \
|
||||
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
|
||||
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_FIND(struct name *head, struct type *elm) { \ \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return(NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) \
|
||||
return (head->sph_root); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_NEXT(struct name *head, struct type *elm) { \
|
||||
name##_SPLAY(head, elm); \
|
||||
if (SPLAY_RIGHT(elm, field) != NULL) { \
|
||||
elm = SPLAY_RIGHT(elm, field); \
|
||||
while (SPLAY_LEFT(elm, field) != NULL) { \
|
||||
elm = SPLAY_LEFT(elm, field); \
|
||||
} \
|
||||
} else \
|
||||
elm = NULL; \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
static __inline struct type * \
|
||||
name##_SPLAY_MIN_MAX(struct name *head, int val) { \
|
||||
name##_SPLAY_MINMAX(head, val); \
|
||||
return (SPLAY_ROOT(head)); \
|
||||
}
|
||||
|
||||
/* Main splay operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define SPLAY_GENERATE(name, type, field, cmp) \
|
||||
struct type * \
|
||||
name##_SPLAY_INSERT(struct name *head, struct type *elm) { \
|
||||
if (SPLAY_EMPTY(head)) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
|
||||
} else { \
|
||||
int __comp; \
|
||||
name##_SPLAY(head, elm); \
|
||||
__comp = (cmp)(elm, (head)->sph_root); \
|
||||
if(__comp < 0) { \
|
||||
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
|
||||
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_LEFT((head)->sph_root, field) = NULL; \
|
||||
} else if (__comp > 0) { \
|
||||
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
SPLAY_LEFT(elm, field) = (head)->sph_root; \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
|
||||
} else \
|
||||
return ((head)->sph_root); \
|
||||
} \
|
||||
(head)->sph_root = (elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
struct type * \
|
||||
name##_SPLAY_REMOVE(struct name *head, struct type *elm) { \
|
||||
struct type *__tmp; \
|
||||
if (SPLAY_EMPTY(head)) \
|
||||
return (NULL); \
|
||||
name##_SPLAY(head, elm); \
|
||||
if ((cmp)(elm, (head)->sph_root) == 0) { \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
|
||||
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
|
||||
} else { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
|
||||
name##_SPLAY(head, elm); \
|
||||
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
name##_SPLAY(struct name *head, struct type *elm) { \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
int __comp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) {\
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if ((cmp)(elm, __tmp) > 0){ \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
} \
|
||||
\
|
||||
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
|
||||
{ \
|
||||
struct type __node, *__left, *__right, *__tmp; \
|
||||
\
|
||||
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
|
||||
__left = __right = &__node; \
|
||||
\
|
||||
while (1) { \
|
||||
if (__comp < 0) { \
|
||||
__tmp = SPLAY_LEFT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp < 0){ \
|
||||
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
|
||||
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKLEFT(head, __right, field); \
|
||||
} else if (__comp > 0) { \
|
||||
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
|
||||
if (__tmp == NULL) \
|
||||
break; \
|
||||
if (__comp > 0) { \
|
||||
SPLAY_ROTATE_LEFT(head, __tmp, field); \
|
||||
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
|
||||
break; \
|
||||
} \
|
||||
SPLAY_LINKRIGHT(head, __left, field); \
|
||||
} \
|
||||
} \
|
||||
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
|
||||
}
|
||||
|
||||
#define SPLAY_NEGINF -1
|
||||
#define SPLAY_INF 1
|
||||
|
||||
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
|
||||
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
|
||||
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
|
||||
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
|
||||
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
|
||||
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
|
||||
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
|
||||
|
||||
#define SPLAY_FOREACH(x, name, head) \
|
||||
for ((x) = SPLAY_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = SPLAY_NEXT(name, head, x))
|
||||
|
||||
|
||||
|
||||
|
||||
/* Macros that define a red-black tree */
|
||||
#define RB_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *rbh_root; /* root of the tree */ \
|
||||
}
|
||||
|
||||
#define RB_INITIALIZER(root) \
|
||||
{ NULL }
|
||||
|
||||
#define RB_INIT(root) do { \
|
||||
(root)->rbh_root = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define RB_BLACK 0
|
||||
#define RB_RED 1
|
||||
|
||||
#define RB_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *rbe_left; /* left element */ \
|
||||
struct type *rbe_right; /* right element */ \
|
||||
struct type *rbe_parent; /* parent element */ \
|
||||
int rbe_color; /* node color */ \
|
||||
}
|
||||
|
||||
#define RB_LEFT(elm, field) (elm)->field.rbe_left
|
||||
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
|
||||
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
|
||||
#define RB_COLOR(elm, field) (elm)->field.rbe_color
|
||||
#define RB_ROOT(head) (head)->rbh_root
|
||||
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
|
||||
|
||||
#define RB_SET(elm, parent, field) do { \
|
||||
RB_PARENT(elm, field) = parent; \
|
||||
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
|
||||
RB_COLOR(elm, field) = RB_RED; \
|
||||
} while (0)
|
||||
|
||||
#define RB_SET_BLACKRED(black, red, field) do { \
|
||||
RB_COLOR(black, field) = RB_BLACK; \
|
||||
RB_COLOR(red, field) = RB_RED; \
|
||||
} while (0)
|
||||
|
||||
#ifndef RB_AUGMENT
|
||||
#define RB_AUGMENT(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
|
||||
(tmp) = RB_RIGHT(elm, field); \
|
||||
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
|
||||
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
|
||||
} \
|
||||
RB_AUGMENT(elm); \
|
||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
} else \
|
||||
(head)->rbh_root = (tmp); \
|
||||
RB_LEFT(tmp, field) = (elm); \
|
||||
RB_PARENT(elm, field) = (tmp); \
|
||||
RB_AUGMENT(tmp); \
|
||||
if ((RB_PARENT(tmp, field))) \
|
||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
|
||||
(tmp) = RB_LEFT(elm, field); \
|
||||
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
|
||||
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
|
||||
} \
|
||||
RB_AUGMENT(elm); \
|
||||
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
|
||||
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
|
||||
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
|
||||
} else \
|
||||
(head)->rbh_root = (tmp); \
|
||||
RB_RIGHT(tmp, field) = (elm); \
|
||||
RB_PARENT(elm, field) = (tmp); \
|
||||
RB_AUGMENT(tmp); \
|
||||
if ((RB_PARENT(tmp, field))) \
|
||||
RB_AUGMENT(RB_PARENT(tmp, field)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define RB_PROTOTYPE(name, type, field, cmp) \
|
||||
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
|
||||
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
|
||||
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
|
||||
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
|
||||
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
|
||||
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
|
||||
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_FIND(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
|
||||
attr struct type *name##_RB_NEXT(struct type *); \
|
||||
attr struct type *name##_RB_PREV(struct type *); \
|
||||
attr struct type *name##_RB_MINMAX(struct name *, int); \
|
||||
|
||||
/* Main rb operation.
|
||||
* Moves node close to the key of elm to top
|
||||
*/
|
||||
#define RB_GENERATE(name, type, field, cmp) \
|
||||
RB_GENERATE_INTERNAL(name, type, field, cmp,)
|
||||
#define RB_GENERATE_STATIC(name, type, field, cmp) \
|
||||
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
|
||||
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
|
||||
attr void \
|
||||
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) { \
|
||||
struct type *parent, *gparent, *tmp; \
|
||||
while ((parent = RB_PARENT(elm, field)) != NULL && \
|
||||
RB_COLOR(parent, field) == RB_RED) { \
|
||||
gparent = RB_PARENT(parent, field); \
|
||||
if (parent == RB_LEFT(gparent, field)) { \
|
||||
tmp = RB_RIGHT(gparent, field); \
|
||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
elm = gparent; \
|
||||
continue; \
|
||||
} \
|
||||
if (RB_RIGHT(parent, field) == elm) { \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||
tmp = parent; \
|
||||
parent = elm; \
|
||||
elm = tmp; \
|
||||
} \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
|
||||
} else { \
|
||||
tmp = RB_LEFT(gparent, field); \
|
||||
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_COLOR(tmp, field) = RB_BLACK; \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
elm = gparent; \
|
||||
continue; \
|
||||
} \
|
||||
if (RB_LEFT(parent, field) == elm) { \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||
tmp = parent; \
|
||||
parent = elm; \
|
||||
elm = tmp; \
|
||||
} \
|
||||
RB_SET_BLACKRED(parent, gparent, field); \
|
||||
RB_ROTATE_LEFT(head, gparent, tmp, field); \
|
||||
} \
|
||||
} \
|
||||
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
|
||||
} \
|
||||
\
|
||||
attr void \
|
||||
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp; \
|
||||
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
|
||||
elm != RB_ROOT(head)) { \
|
||||
if (RB_LEFT(parent, field) == elm) { \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_SET_BLACKRED(tmp, parent, field); \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
} \
|
||||
if ((RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
||||
(RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
elm = parent; \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
} else { \
|
||||
if (RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
|
||||
struct type *oleft; \
|
||||
if ((oleft = RB_LEFT(tmp, field)) \
|
||||
!= NULL) \
|
||||
RB_COLOR(oleft, field) = RB_BLACK; \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
RB_ROTATE_RIGHT(head, tmp, oleft, field); \
|
||||
tmp = RB_RIGHT(parent, field); \
|
||||
} \
|
||||
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
|
||||
RB_COLOR(parent, field) = RB_BLACK; \
|
||||
if (RB_RIGHT(tmp, field)) \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
|
||||
RB_ROTATE_LEFT(head, parent, tmp, field); \
|
||||
elm = RB_ROOT(head); \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
if (RB_COLOR(tmp, field) == RB_RED) { \
|
||||
RB_SET_BLACKRED(tmp, parent, field); \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
} \
|
||||
if ((RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
|
||||
(RB_RIGHT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
elm = parent; \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
} else { \
|
||||
if (RB_LEFT(tmp, field) == NULL || \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
|
||||
struct type *oright; \
|
||||
if ((oright = RB_RIGHT(tmp, field)) \
|
||||
!= NULL) \
|
||||
RB_COLOR(oright, field) = RB_BLACK; \
|
||||
RB_COLOR(tmp, field) = RB_RED; \
|
||||
RB_ROTATE_LEFT(head, tmp, oright, field); \
|
||||
tmp = RB_LEFT(parent, field); \
|
||||
} \
|
||||
RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
|
||||
RB_COLOR(parent, field) = RB_BLACK; \
|
||||
if (RB_LEFT(tmp, field)) \
|
||||
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
|
||||
RB_ROTATE_RIGHT(head, parent, tmp, field); \
|
||||
elm = RB_ROOT(head); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (elm) \
|
||||
RB_COLOR(elm, field) = RB_BLACK; \
|
||||
} \
|
||||
\
|
||||
attr struct type * \
|
||||
name##_RB_REMOVE(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *child, *parent, *old = elm; \
|
||||
int color; \
|
||||
if (RB_LEFT(elm, field) == NULL) \
|
||||
child = RB_RIGHT(elm, field); \
|
||||
else if (RB_RIGHT(elm, field) == NULL) \
|
||||
child = RB_LEFT(elm, field); \
|
||||
else { \
|
||||
struct type *left; \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
while ((left = RB_LEFT(elm, field)) != NULL) \
|
||||
elm = left; \
|
||||
child = RB_RIGHT(elm, field); \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
color = RB_COLOR(elm, field); \
|
||||
if (child) \
|
||||
RB_PARENT(child, field) = parent; \
|
||||
if (parent) { \
|
||||
if (RB_LEFT(parent, field) == elm) \
|
||||
RB_LEFT(parent, field) = child; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = child; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = child; \
|
||||
if (RB_PARENT(elm, field) == old) \
|
||||
parent = elm; \
|
||||
(elm)->field = (old)->field; \
|
||||
if (RB_PARENT(old, field)) { \
|
||||
if (RB_LEFT(RB_PARENT(old, field), field) == old) \
|
||||
RB_LEFT(RB_PARENT(old, field), field) = elm; \
|
||||
else \
|
||||
RB_RIGHT(RB_PARENT(old, field), field) = elm; \
|
||||
RB_AUGMENT(RB_PARENT(old, field)); \
|
||||
} else \
|
||||
RB_ROOT(head) = elm; \
|
||||
RB_PARENT(RB_LEFT(old, field), field) = elm; \
|
||||
if (RB_RIGHT(old, field)) \
|
||||
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
|
||||
if (parent) { \
|
||||
left = parent; \
|
||||
do { \
|
||||
RB_AUGMENT(left); \
|
||||
} while ((left = RB_PARENT(left, field)) != NULL); \
|
||||
} \
|
||||
goto color; \
|
||||
} \
|
||||
parent = RB_PARENT(elm, field); \
|
||||
color = RB_COLOR(elm, field); \
|
||||
if (child) \
|
||||
RB_PARENT(child, field) = parent; \
|
||||
if (parent) { \
|
||||
if (RB_LEFT(parent, field) == elm) \
|
||||
RB_LEFT(parent, field) = child; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = child; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = child; \
|
||||
color: \
|
||||
if (color == RB_BLACK) \
|
||||
name##_RB_REMOVE_COLOR(head, parent, child); \
|
||||
return (old); \
|
||||
} \
|
||||
\
|
||||
/* Inserts a node into the RB tree */ \
|
||||
attr struct type * \
|
||||
name##_RB_INSERT(struct name *head, struct type *elm) { \
|
||||
struct type *tmp; \
|
||||
struct type *parent = NULL; \
|
||||
int comp = 0; \
|
||||
tmp = RB_ROOT(head); \
|
||||
while (tmp) { \
|
||||
parent = tmp; \
|
||||
comp = (cmp)(elm, parent); \
|
||||
if (comp < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
RB_SET(elm, parent, field); \
|
||||
if (parent != NULL) { \
|
||||
if (comp < 0) \
|
||||
RB_LEFT(parent, field) = elm; \
|
||||
else \
|
||||
RB_RIGHT(parent, field) = elm; \
|
||||
RB_AUGMENT(parent); \
|
||||
} else \
|
||||
RB_ROOT(head) = elm; \
|
||||
name##_RB_INSERT_COLOR(head, elm); \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
/* Finds the node with the same key as elm */ \
|
||||
attr struct type * \
|
||||
name##_RB_FIND(struct name *head, struct type *elm) { \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
int comp; \
|
||||
while (tmp) { \
|
||||
comp = cmp(elm, tmp); \
|
||||
if (comp < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
return (NULL); \
|
||||
} \
|
||||
\
|
||||
/* Finds the first node greater than or equal to the search key */ \
|
||||
attr struct type * \
|
||||
name##_RB_NFIND(struct name *head, struct type *elm) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
struct type *res = NULL; \
|
||||
int comp; \
|
||||
while (tmp) { \
|
||||
comp = cmp(elm, tmp); \
|
||||
if (comp < 0) { \
|
||||
res = tmp; \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
} \
|
||||
else if (comp > 0) \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
else \
|
||||
return (tmp); \
|
||||
} \
|
||||
return (res); \
|
||||
} \
|
||||
\
|
||||
/* ARGSUSED */ \
|
||||
attr struct type * \
|
||||
name##_RB_NEXT(struct type *elm) \
|
||||
{ \
|
||||
if (RB_RIGHT(elm, field)) { \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
while (RB_LEFT(elm, field)) \
|
||||
elm = RB_LEFT(elm, field); \
|
||||
} else { \
|
||||
if (RB_PARENT(elm, field) && \
|
||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
else { \
|
||||
while (RB_PARENT(elm, field) && \
|
||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
} \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
/* ARGSUSED */ \
|
||||
attr struct type * \
|
||||
name##_RB_PREV(struct type *elm) \
|
||||
{ \
|
||||
if (RB_LEFT(elm, field)) { \
|
||||
elm = RB_LEFT(elm, field); \
|
||||
while (RB_RIGHT(elm, field)) \
|
||||
elm = RB_RIGHT(elm, field); \
|
||||
} else { \
|
||||
if (RB_PARENT(elm, field) && \
|
||||
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
else { \
|
||||
while (RB_PARENT(elm, field) && \
|
||||
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
elm = RB_PARENT(elm, field); \
|
||||
} \
|
||||
} \
|
||||
return (elm); \
|
||||
} \
|
||||
\
|
||||
attr struct type * \
|
||||
name##_RB_MINMAX(struct name *head, int val) \
|
||||
{ \
|
||||
struct type *tmp = RB_ROOT(head); \
|
||||
struct type *parent = NULL; \
|
||||
while (tmp) { \
|
||||
parent = tmp; \
|
||||
if (val < 0) \
|
||||
tmp = RB_LEFT(tmp, field); \
|
||||
else \
|
||||
tmp = RB_RIGHT(tmp, field); \
|
||||
} \
|
||||
return (parent); \
|
||||
}
|
||||
|
||||
#define RB_NEGINF -1
|
||||
#define RB_INF 1
|
||||
|
||||
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
|
||||
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
|
||||
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
|
||||
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
|
||||
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
|
||||
#define RB_PREV(name, x, y) name##_RB_PREV(y)
|
||||
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
|
||||
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
|
||||
|
||||
#define RB_FOREACH(x, name, head) \
|
||||
for ((x) = RB_MIN(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = name##_RB_NEXT(x))
|
||||
|
||||
#define RB_FOREACH_FROM(x, name, y) \
|
||||
for ((x) = (y); \
|
||||
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_SAFE(x, name, head, y) \
|
||||
for ((x) = RB_MIN(name, head); \
|
||||
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_REVERSE(x, name, head) \
|
||||
for ((x) = RB_MAX(name, head); \
|
||||
(x) != NULL; \
|
||||
(x) = name##_RB_PREV(x))
|
||||
|
||||
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
|
||||
for ((x) = (y); \
|
||||
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
|
||||
for ((x) = RB_MAX(name, head); \
|
||||
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
|
||||
(x) = (y))
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user