add NtyCo as submodule & 搭建设计ebpf主从同步代码框架

This commit is contained in:
1iaan
2026-01-28 12:05:28 +00:00
parent 226f9a510f
commit fe257cafec
49 changed files with 249 additions and 8922 deletions

2
.gitignore vendored
View File

@@ -4,6 +4,8 @@
*.o
*.a
/ebpf/libbpf-bootstrap
kvstore
testcase

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "NtyCo"]
path = NtyCo
url = https://github.com/wangbojing/NtyCo.git

View File

@@ -3,11 +3,12 @@ CC = gcc
CFLAGS = -g -DJEMALLOC_NO_DEMANGLE
NET_SRCS = ntyco.c proactor.c reactor.c kvstore.c
KV_SRCS = kvs_array_bin.c kvs_rbtree_bin.c kvs_hash_bin.c kvs_rw_tools.c kvs_protocol_resp.c kvs_oplog.c kvs_slave.c
KV_SRCS = kvs_array_bin.c kvs_rbtree_bin.c kvs_hash_bin.c kvs_rw_tools.c kvs_protocol_resp.c kvs_slave.c
MEM_SRCS = ./memory/mempool.c ./memory/alloc_dispatch.c
COMMON_SRCS = ./common/config.c ./diskuring/diskuring.c
DUMP_SRCS = ./dump/kvs_snapshot.c ./dump/kvs_oplog.c
SRCS = $(NET_SRCS) $(KV_SRCS) $(MEM_SRCS) $(COMMON_SRCS)
SRCS = $(NET_SRCS) $(KV_SRCS) $(MEM_SRCS) $(COMMON_SRCS) $(DUMP_SRCS)
INC = -I./NtyCo/core/ -I/usr/include/libxml2 -I./
LIBDIRS = -L./NtyCo/

1
NtyCo Submodule

Submodule NtyCo added at 72ab5fd04f

4
NtyCo/.gitignore vendored
View File

@@ -1,4 +0,0 @@
_build/
bin/
objs/
lib/

View File

@@ -1,94 +0,0 @@
CC = gcc
ECHO = echo
SUB_DIR = core/
SAMPLE_DIR = sample/
ROOT_DIR = $(shell pwd)
OBJS_DIR = $(ROOT_DIR)/objs
BIN_DIR = $(ROOT_DIR)/bin
BIN = nty_server nty_client nty_bench nty_server_mulcore hook_tcpserver nty_http_server nty_mysql_client nty_mysql_oper nty_websocket_server nty_http_server_mulcore ntyco_httpd nty_rediscli
LIB = libntyco.a
FLAG = -lpthread -O3 -ldl -I $(ROOT_DIR)/core
THIRDFLAG = -lcrypto -lssl -lmysqlclient -lhiredis -I /usr/include/mysql/ -I /usr/local/include/hiredis/
CUR_SOURCE = ${wildcard *.c}
CUR_OBJS = ${patsubst %.c, %.o, %(CUR_SOURCE)}
export CC BIN_DIR OBJS_DIR ROOT_IDR FLAG BIN ECHO EFLAG
all : check_objs check_bin $(SUB_DIR) $(LIB)
.PHONY : all
bin: $(SAMPLE_DIR) $(BIN)
# lib: $(SUB_DIR) $(LIB)
$(SUB_DIR) : ECHO
make -C $@
#DEBUG : ECHO
# make -C bin
ECHO :
@echo $(SUB_DIR)
check_objs:
if [ ! -d "objs" ]; then \
mkdir -p objs; \
fi
check_bin:
if [ ! -d "bin" ]; then \
mkdir -p bin; \
fi
nty_server : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_server.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
nty_client : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_client.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
nty_bench : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_bench.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
nty_server_mulcore : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_server_mulcore.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
nty_http_server : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_http_server.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
nty_websocket_server : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_websocket_server.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG)
nty_mysql_client : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_mysql_client.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG)
nty_mysql_oper : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_mysql_oper.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG)
nty_rediscli : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_rediscli.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG)
hook_tcpserver: $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/hook_tcpserver.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
nty_http_server_mulcore : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/nty_http_server_mulcore.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
ntyco_httpd : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o $(SAMPLE_DIR)/ntyco_httpd.c
$(CC) -o $(BIN_DIR)/$@ $^ $(FLAG)
libntyco.a : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o
ar rcs $@ $^
clean :
rm -rf $(BIN_DIR)/* $(OBJS_DIR)/* libntyco.a

View File

@@ -1,75 +0,0 @@
## NtyCo
#### coroutine
[实现原理](https://github.com/wangbojing/NtyCo/wiki/NtyCo%E7%9A%84%E5%AE%9E%E7%8E%B0)
[配套视频讲解](https://it.0voice.com/p/t_pc/goods_pc_detail/goods_detail/course_2QFAeORw45TjJA1y9tq8CmdVJTQ)
## details
#### coroutine FSM
![](http://bojing.wang/wp-content/uploads/2018/08/status_machine.png)
#### storage structure (ready, wait, sleep, status)
![](http://bojing.wang/wp-content/uploads/2018/08/6.1.png)
#### nty_server process
![](https://cos.0voice.com/nty_server_uml.png)
#### compile
```
编译ntyco的core文件与编译libntyco.a的静态库
$ make
// 编译sample
$ make bin
```
#### err info
```
nty_mysql_oper.c:8:19: fatal error: mysql.h: No such file or directory
解决方案:
# sudo apt-get install libmysqlclient-dev
nty_rediscli.c:11:21: fatal error: hiredis.h: No such file or directory
解决方案:
需要编译安装hiredis: https://github.com/redis/hiredis
```
#### server
```
$ ./bin/nty_server
```
#### client
```
./bin/nty_client
```
#### mul_process, mul_core
```
$ ./bin/nty_server_mulcore
```
#### websocket
```
$ ./bin/nty_websocket_server
```
#### bench
```
$ ./bin/nty_bench
```
![](http://bojing.wang/wp-content/uploads/2018/08/nty_bench_ntyco.png)
![](http://bojing.wang/wp-content/uploads/2018/08/nty_bench_nginx.png)
#### http server
```
$ ./bin/nty_http_server_mulcore
```
![](http://bojing.wang/wp-content/uploads/2018/08/ntyco_ab.png)![](http://bojing.wang/wp-content/uploads/2018/08/nginx_ab.png)
##### [对应视频讲解](https://ke.qq.com/course/2705727?tuin=1bf84273)

View File

@@ -1,3 +0,0 @@
aux_source_directory(. SRC)
add_library(nty_core ${SRC})

View File

@@ -1,16 +0,0 @@
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)

View File

@@ -1,353 +0,0 @@
/*
* 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;
}

View File

@@ -1,389 +0,0 @@
/*
* 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

View File

@@ -1,75 +0,0 @@
/*
* 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);
}

View File

@@ -1,589 +0,0 @@
/*
* 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

View File

@@ -1,369 +0,0 @@
/*
* 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 ;
}

View File

@@ -1,672 +0,0 @@
/*
* 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

View File

@@ -1,754 +0,0 @@
/*
* 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

Binary file not shown.

View File

@@ -1,20 +0,0 @@
#!/usr/bin/perl -Tw
use strict;
use CGI;
my($cgi) = new CGI;
print $cgi->header('text/html');
print $cgi->start_html(-title => "Example CGI script",
-BGCOLOR => 'red');
print $cgi->h1("CGI Example");
print $cgi->p, "This is an example of CGI\n";
print $cgi->p, "Parameters given to this script:\n";
print "<UL>\n";
foreach my $param ($cgi->param)
{
print "<LI>", "$param ", $cgi->param($param), "\n";
}
print "</UL>";
print $cgi->end_html, "\n";

View File

@@ -1,15 +0,0 @@
#!/usr/bin/perl -Tw
use strict;
use CGI;
my($cgi) = new CGI;
print $cgi->header;
my($color) = "blue";
$color = $cgi->param('color') if defined $cgi->param('color');
print $cgi->start_html(-title => uc($color),
-BGCOLOR => $color);
print $cgi->h1("This is $color");
print $cgi->end_html;

View File

@@ -1,11 +0,0 @@
<HTML>
<TITLE>Index</TITLE>
<BODY>
<P>Welcome to J. David's webserver.
<H1>CGI demo
<FORM ACTION="color.cgi" METHOD="POST">
Enter a color: <INPUT TYPE="text" NAME="color">
<INPUT TYPE="submit">
</FORM>
</BODY>
</HTML>

View File

@@ -1,15 +0,0 @@
aux_source_directory(. SRC)
# 编译不过的,先放这里
set(NOT_COMPILE )
foreach(FILE_PATH ${SRC})
string(REGEX REPLACE ".+/(.+)\\..*" "\\1" FILE_NAME ${FILE_PATH})
list(FIND NOT_COMPILE ${FILE_NAME} RESULT)
if(${RESULT} EQUAL -1)
message(${FILE_NAME})
add_executable(${FILE_NAME} ${FILE_PATH})
target_link_libraries(${FILE_NAME} nty_core ${LIBS})
endif()
endforeach()

View File

@@ -1,16 +0,0 @@
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)

View File

@@ -1,84 +0,0 @@
#include "nty_coroutine.h"
#include <arpa/inet.h>
void server_reader(void *arg) {
int fd = *(int *)arg;
int ret = 0;
while (1) {
char buf[1024] = {0};
ret = recv(fd, buf, 1024, 0);
if (ret > 0) {
printf("read from server: %.*s\n", ret, buf);
ret = send(fd, buf, strlen(buf), 0);
if (ret == -1) {
close(fd);
break;
}
} else if (ret == 0) {
close(fd);
break;
}
}
}
void server(void *arg) {
unsigned short port = *(unsigned short *)arg;
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return ;
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in));
listen(fd, 20);
printf("listen port : %d\n", port);
while (1) {
socklen_t len = sizeof(struct sockaddr_in);
int cli_fd = accept(fd, (struct sockaddr*)&remote, &len);
nty_coroutine *read_co;
nty_coroutine_create(&read_co, server_reader, &cli_fd);
}
}
int main(int argc, char *argv[]) {
int port = atoi(argv[1]);
nty_coroutine *co = NULL;
nty_coroutine_create(&co, server, &port);
nty_schedule_run();
}

View File

@@ -1,727 +0,0 @@
/*
* 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
*
*
**** ***** *****
*** * ** ***
*** * * * **
* ** * * ** **
* ** * * ** *
* ** * ** ** *
* ** * *** **
* ** * *********** ***** ***** ** ****
* ** * ** ** ** ** ** **
* ** * ** ** * ** * **
* ** * ** * * ** ** **
* ** * ** ** * ** * **
* ** * ** * * ** ** **
* ** * ** ** * ** ** **
* ** * ** ** * ** ** **
* ** * ** * * ** ** **
* ** * ** ** * ** * ** **
* *** ** * * ** * ** **
* *** ** * ** * * ** **
* ** ** * ** ** * ** **
* ** ** * * ** * ** **
***** * **** * ***** ****
*
*
*****
****
*
*/
/*
* (C) Radim Kolar 1997-2004
* This is free software, see GNU Public License version 2 for
* details.
*
* Simple forking WWW Server benchmark:
*
* Usage:
* webbench --help
*
* Return codes:
* 0 - sucess
* 1 - benchmark failed (server is not on-line)
* 2 - bad param
* 3 - internal error, fork failed
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "nty_coroutine.h"
#define ENABLE_NTYCO 1
#define MAX_BUFFER_LENGTH 1024
#define write(a, b, c) nty_send(a, b, c, 0)
#define send(a, b, c, d) nty_send(a, b, c, d)
#define read(a, b, c) nty_recv(a, b, c, 0)
#define recv(a, b, c, d) nty_recv(a, b, c, d)
#define connect(a, b, c) nty_connect(a, b, c)
#define socket(a, b, c) nty_socket(a, b, c)
#define close(a) nty_close(a)
#define accept(a, b, c) nty_accept(a, b, c)
int Socket(const char *host, int clientPort)
{
int sock;
unsigned long inaddr;
struct sockaddr_in ad;
struct hostent *hp;
memset(&ad, 0, sizeof(ad));
ad.sin_family = AF_INET;
inaddr = inet_addr(host);
if (inaddr != INADDR_NONE)
memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
else
{
hp = gethostbyname(host);
if (hp == NULL)
return -1;
memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
}
ad.sin_port = htons(clientPort);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
return sock;
if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)
return -1;
return sock;
}
#include <unistd.h>
#include <sys/param.h>
#include <rpc/types.h>
#include <getopt.h>
#include <strings.h>
#include <time.h>
#include <signal.h>
/* values */
volatile int timerexpired=0;
int speed=0;
int failed=0;
int bytes=0;
/* globals */
int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */
/* Allow: GET, HEAD, OPTIONS, TRACE */
#define METHOD_GET 0
#define METHOD_HEAD 1
#define METHOD_OPTIONS 2
#define METHOD_TRACE 3
#define PROGRAM_VERSION "1.5"
int method=METHOD_GET;
int clients=1;
#if ENABLE_NTYCO
// clients --> fork num
// nreqs --> http request
// socket --> io num
// socket per fork --> sockets / client
// request per socket --> request / sockets
int nreqs = 0;
int sockets = 0;
#endif
int force=0;
int force_reload=0;
int proxyport=80;
char *proxyhost=NULL;
int benchtime=30;
/* internal */
int mypipe[2];
char host[MAXHOSTNAMELEN];
#define REQUEST_SIZE 2048
char request[REQUEST_SIZE] = {0};
static const struct option long_options[]=
{
{"force",no_argument,&force,1},
{"reload",no_argument,&force_reload,1},
{"time",required_argument,NULL,'t'},
{"help",no_argument,NULL,'?'},
{"http09",no_argument,NULL,'9'},
{"http10",no_argument,NULL,'1'},
{"http11",no_argument,NULL,'2'},
{"get",no_argument,&method,METHOD_GET},
{"head",no_argument,&method,METHOD_HEAD},
{"options",no_argument,&method,METHOD_OPTIONS},
{"trace",no_argument,&method,METHOD_TRACE},
{"version",no_argument,NULL,'V'},
{"proxy",required_argument,NULL,'p'},
{"clients",required_argument,NULL,'c'},
{NULL,0,NULL,0}
};
/* prototypes */
static void benchcore(const char* host,const int port, const char *request);
static int bench(void);
static void build_request(const char *url);
static void alarm_handler(int signal)
{
timerexpired=1;
}
static void usage(void)
{
fprintf(stderr,
"webbench [option]... URL\n"
" -f|--force Don't wait for reply from server.\n"
" -r|--reload Send reload request - Pragma: no-cache.\n"
" -t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n"
" -n|--request <num> Sum of requestion\n"
" -s|--socket <num> Sum of socket\n"
" -p|--proxy <server:port> Use proxy server for request.\n"
" -c|--clients <n> Run <n> HTTP clients at once. Default one.\n"
" -9|--http09 Use HTTP/0.9 style requests.\n"
" -1|--http10 Use HTTP/1.0 protocol.\n"
" -2|--http11 Use HTTP/1.1 protocol.\n"
" --get Use GET request method.\n"
" --head Use HEAD request method.\n"
" --options Use OPTIONS request method.\n"
" --trace Use TRACE request method.\n"
" -?|-h|--help This information.\n"
" -V|--version Display program version.\n"
);
};
int main(int argc, char *argv[])
{
int opt=0;
int options_index=0;
char *tmp=NULL;
if(argc==1)
{
usage();
return 2;
}
while((opt=getopt_long(argc,argv,"912Vfrt:p:n:s:c:?h",long_options,&options_index))!=EOF )
{
switch(opt)
{
case 0 : break;
case 'f': force=1;break;
case 'r': force_reload=1;break;
case '9': http10=0;break;
case '1': http10=1;break;
case '2': http10=2;break;
case 'V': printf(PROGRAM_VERSION"\n");exit(0);
case 't': benchtime=atoi(optarg);break;
case 'p':
/* proxy server parsing server:port */
tmp=strrchr(optarg,':');
proxyhost=optarg;
if(tmp==NULL)
{
break;
}
if(tmp==optarg)
{
fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);
return 2;
}
if(tmp==optarg+strlen(optarg)-1)
{
fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);
return 2;
}
*tmp='\0';
proxyport=atoi(tmp+1);break;
case ':':
case 'h':
case '?': usage();return 2;break;
case 'c': clients=atoi(optarg);break;
#if ENABLE_NTYCO
case 'n': nreqs=atoi(optarg);break;
case 's': sockets=atoi(optarg);break;
#endif
}
}
if(optind==argc) {
fprintf(stderr,"webbench: Missing URL!\n");
usage();
return 2;
}
if(clients==0) clients=1;
if(benchtime==0) benchtime=60;
#if ENABLE_NTYCO
if (clients > 10) clients = 10;
if (nreqs < 1000) nreqs = 1000;
//if (sockets < clients) sockets = clients;
if (sockets % clients != 0) sockets = sockets / clients * clients;
#endif
/* Copyright */
fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n"
"Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n"
);
build_request(argv[optind]);
/* print bench info */
printf("\nBenchmarking: ");
switch(method)
{
case METHOD_GET:
default:
printf("GET");break;
case METHOD_OPTIONS:
printf("OPTIONS");break;
case METHOD_HEAD:
printf("HEAD");break;
case METHOD_TRACE:
printf("TRACE");break;
}
printf(" %s",argv[optind]);
switch(http10)
{
case 0: printf(" (using HTTP/0.9)");break;
case 2: printf(" (using HTTP/1.1)");break;
}
printf("\n");
if(clients==1) printf("1 client");
else
printf("%d clients",clients);
printf(", running %d sec", benchtime);
if(force) printf(", early socket close");
if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport);
if(force_reload) printf(", forcing reload");
printf(".\n");
return bench();
}
void build_request(const char *url)
{
char tmp[10];
int i;
bzero(host,MAXHOSTNAMELEN);
bzero(request,REQUEST_SIZE);
if(force_reload && proxyhost!=NULL && http10<1) http10=1;
if(method==METHOD_HEAD && http10<1) http10=1;
if(method==METHOD_OPTIONS && http10<2) http10=2;
if(method==METHOD_TRACE && http10<2) http10=2;
switch(method)
{
default:
case METHOD_GET: strcpy(request,"GET");break;
case METHOD_HEAD: strcpy(request,"HEAD");break;
case METHOD_OPTIONS: strcpy(request,"OPTIONS");break;
case METHOD_TRACE: strcpy(request,"TRACE");break;
}
strcat(request," ");
if(NULL==strstr(url,"://"))
{
fprintf(stderr, "\n%s: is not a valid URL.\n",url);
exit(2);
}
if(strlen(url)>1500)
{
fprintf(stderr,"URL is too long.\n");
exit(2);
}
if(proxyhost==NULL)
if (0!=strncasecmp("http://",url,7))
{ fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");
exit(2);
}
/* protocol/host delimiter */
i=strstr(url,"://")-url+3;
/* printf("%d\n",i); */
if(strchr(url+i,'/')==NULL) {
fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");
exit(2);
}
if(proxyhost==NULL)
{
/* get port from hostname */
if(index(url+i,':')!=NULL &&
index(url+i,':')<index(url+i,'/'))
{
strncpy(host,url+i,strchr(url+i,':')-url-i);
bzero(tmp,10);
strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);
/* printf("tmp=%s\n",tmp); */
proxyport=atoi(tmp);
if(proxyport==0) proxyport=80;
} else
{
strncpy(host,url+i,strcspn(url+i,"/"));
}
// printf("Host=%s\n",host);
strcat(request+strlen(request),url+i+strcspn(url+i,"/"));
} else
{
// printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport);
strcat(request,url);
}
if(http10==1)
strcat(request," HTTP/1.0");
else if (http10==2)
strcat(request," HTTP/1.1");
strcat(request,"\r\n");
if(http10>0)
strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n");
if(proxyhost==NULL && http10>0)
{
strcat(request,"Host: ");
strcat(request,host);
strcat(request,"\r\n");
}
if(force_reload && proxyhost!=NULL)
{
strcat(request,"Pragma: no-cache\r\n");
}
if(http10>1)
strcat(request,"Connection: close\r\n");
/* add empty line at end */
if(http10>0) strcat(request,"\r\n");
// printf("Req=%s\n",request);
}
/* vraci system rc error kod */
static int bench(void)
{
int i,j,k;
pid_t pid=0;
FILE *f;
#if ENABLE_NTYCO == 0
/* check avaibility of target server */
i=Socket(proxyhost==NULL?host:proxyhost,proxyport);
if(i<0) {
fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");
return 1;
}
close(i);
#endif
/* create pipe */
if(pipe(mypipe))
{
perror("pipe failed.");
return 3;
}
/* not needed, since we have alarm() in childrens */
/* wait 4 next system clock tick */
/*
cas=time(NULL);
while(time(NULL)==cas)
sched_yield();
*/
printf("bench enter\n");
/* fork childs */
for(i=0;i<clients;i++)
{
pid=fork();
if(pid <= (pid_t) 0)
{
/* child process or error*/
sleep(1); /* make childs faster */
break;
}
}
if( pid< (pid_t) 0)
{
fprintf(stderr,"problems forking worker no. %d\n",i);
perror("fork failed.");
return 3;
}
if(pid== (pid_t) 0)
{
/* I am a child */
if(proxyhost==NULL)
benchcore(host,proxyport,request);
else
benchcore(proxyhost,proxyport,request);
/* write results to pipe */
f=fdopen(mypipe[1],"w");
if(f==NULL)
{
perror("open pipe for writing failed.");
return 3;
}
/* fprintf(stderr,"Child - %d %d\n",speed,failed); */
fprintf(f,"%d %d %d\n",speed,failed,bytes);
fclose(f);
return 0;
} else
{
f=fdopen(mypipe[0],"r");
if(f==NULL)
{
perror("open pipe for reading failed.");
return 3;
}
setvbuf(f,NULL,_IONBF,0);
speed=0;
failed=0;
bytes=0;
while(1)
{
pid=fscanf(f,"%d %d %d",&i,&j,&k);
if(pid<2)
{
fprintf(stderr,"Some of our childrens died.\n");
break;
}
speed+=i;
failed+=j;
bytes+=k;
/* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */
if(--clients==0) break;
}
fclose(f);
printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n",
(int)((speed+failed)/(benchtime/60.0f)),
(int)(bytes/(float)benchtime),
speed,
failed);
}
return i;
}
struct serv_host {
const char *host;
const int port;
const char *req;
};
int testok(char *response) {
if (response == NULL) return -1;
char* p;
char* q;
p = strchr(response, '\n');
*p = '\0';
if(NULL != (q = strstr(response, "200 OK")))
return 1;
else
return 0;
}
int send_buffer(int sockfd, char *buffer, int length) {
int idx = 0;
while (idx < length) {
int count = 0;
if ((idx+MAX_BUFFER_LENGTH) < length) {
count = send(sockfd, buffer+idx, MAX_BUFFER_LENGTH, 0);
} else {
count = send(sockfd, buffer+idx, length-idx, 0);
}
if (count < 0) break;
idx += count;
}
return idx;
}
int recv_buffer(int sockfd, char *buffer, int length, int *ret) {
int idx = 0;
while (1) {
int count = recv(sockfd, buffer+idx, MAX_BUFFER_LENGTH, 0);
//printf("sockfd : %d, recv_buffer --> %d\n", sockfd, count);
if (count < 0) {
*ret = -1;
break;
} else if (count == 0) {
*ret = 0;
close(sockfd);
break;
} else {
//printf("sockfd : %d, recv_buffer --> %d\n", sockfd, count);
idx += count;
}
}
if (idx > 0) *ret = 1;
return idx;
}
void httprequest_commit(void *arg) {
char buf[1500] = {0};
struct serv_host *shost = (struct serv_host *)arg;
int slen = strlen(shost->req);
int idx = 0;
for (idx = 0;idx < (nreqs / sockets);idx ++) {
int s = Socket(shost->host, shost->port);
if (s < 0) {
failed ++;
continue ;
}
if (slen != send(s, shost->req, slen, 0)) {
failed ++;
close(s);
continue;
}
memset(buf, 0, 1500);
#if ENABLE_NTYCO
int ret = 0;
int rlen = recv_buffer(s, buf, 1500, &ret);
#else
int rlen = recv(s, buf, 1500, 0);
#endif
if (ret < 0) {
failed ++;
} else {
if (testok(buf)) {
speed ++;
} else {
failed ++;
}
bytes += rlen;
}
}
return ;
}
void benchcore(const char *host,const int port,const char *req)
{
int rlen;
char buf[1500];
int s,i;
struct sigaction sa;
/* setup alarm signal handler */
sa.sa_handler=alarm_handler;
sa.sa_flags=0;
if(sigaction(SIGALRM,&sa,NULL))
exit(3);
alarm(benchtime);
#if ENABLE_NTYCO
//int i = 0;
nty_coroutine *co = NULL;
struct serv_host shost = {host, port, req};
for (i = 0;i < sockets / clients;i ++) {
nty_coroutine_create(&co, httprequest_commit, &shost);
}
nty_schedule_run();
#else
rlen=strlen(req);
nexttry:while(1)
{
if(timerexpired)
{
if(failed>0)
{
/* fprintf(stderr,"Correcting failed by signal\n"); */
failed--;
}
return;
}
s=Socket(host,port);
if(s<0) { failed++;continue;}
if(rlen!=write(s, req, rlen)) {failed++;close(s);continue;}
#if ENABLE_NTYCO
if(http10==0)
close(s);
#else
if(http10==0)
if(shutdown(s,1)) { failed++;close(s);continue;}
#endif
if(force==0)
{
/* read all available data from socket */
while(1)
{
if(timerexpired) break;
i=read(s,buf,1500);
/* fprintf(stderr,"%d\n",i); */
if(i<0)
{
failed++;
close(s);
goto nexttry;
}
else
if(i==0) break;
else
bytes+=i;
}
}
if(close(s)) {failed++;continue;}
speed++;
}
#endif
}

View File

@@ -1,111 +0,0 @@
/*
* 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"
#include <arpa/inet.h>
#define NTY_SERVER_IPADDR "127.0.0.1"
#define NTY_SERVER_PORT 9096
int init_client(void) {
int clientfd = nty_socket(AF_INET, SOCK_STREAM, 0);
if (clientfd <= 0) {
printf("socket failed\n");
return -1;
}
struct sockaddr_in serveraddr = {0};
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(NTY_SERVER_PORT);
serveraddr.sin_addr.s_addr = inet_addr(NTY_SERVER_IPADDR);
int result = nty_connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if (result != 0) {
printf("connect failed\n");
return -2;
}
return clientfd;
}
void client(void *arg) {
int clientfd = init_client();
char *buffer = "ntyco_client\r\n";
while (1) {
int length = nty_send(clientfd, buffer, strlen(buffer), 0);
printf("echo length : %d\n", length);
sleep(1);
}
}
int main(int argc, char *argv[]) {
nty_coroutine *co = NULL;
nty_coroutine_create(&co, client, NULL);
nty_schedule_run(); //run
return 0;
}

View File

@@ -1,745 +0,0 @@
/*
* 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 <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <sys/syscall.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/poll.h>
#define __USE_GNU
#include <sched.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#define MAX_CLIENT_NUM 1000000
#define TOTALFDS 16
typedef struct _shm_area {
int totalfds[TOTALFDS];
char cpu_lb[TOTALFDS];
//mtx : default 0
// 1 : lock -- del epoll
// 2 : lock -- del complete
// 3 : unlock -- add
// 0 : unlock -- add complete
int accept_mtx;
} shm_area;
static shm_area *global_shmaddr = NULL;
static int global_shmid = -1;
int cpu_size = 0;
int accept_disable = 1000;
int enable_accept = 1;
pid_t self_id = 0;
unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) {
unsigned long prev;
volatile unsigned int *_ptr = (volatile unsigned int *)(addr);
switch (size) {
case 1: {
__asm__ volatile (
"lock; cmpxchgb %b1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 2: {
__asm__ volatile (
"lock; cmpxchgw %w1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 4: {
__asm__ volatile (
"lock; cmpxchg %1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
}
return prev;
}
int atomic_add(volatile int *value, int add)
{
__asm__ volatile (
"lock;"
" addl %0, %1; "
: "+r" (add) : "m" (*value) : "cc", "memory");
return add;
}
int atomic_sub(volatile int *value, int sub)
{
__asm__ volatile (
"lock;"
" subl %0, %1; "
: "+r" (sub) : "m" (*value) : "cc", "memory");
return sub;
}
#define ISspace(x) isspace((int)(x))
#define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n"
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define ENABLE_NTYCO 0
#if ENABLE_NTYCO
#define socket nty_socket
#define accept nty_accept
#define recv(a, b, c, d) nty_recv(a, b, c, d)
#define send(a, b, c, d) nty_send(a, b, c, d)
#define MAX_BUFFER_LENGTH 1024
#endif
#define INC_COUNTFD do { \
atomic_add(&global_shmaddr->totalfds[self_id % cpu_size], 1); \
} while (0)
#define DEC_COUNTFD do { \
atomic_sub(&global_shmaddr->totalfds[self_id % cpu_size], 1); \
} while (0)
int get_countfd(void) {
return global_shmaddr->totalfds[self_id % cpu_size];
}
int max_countfd(void) {
int count = -1;
int i = 0;
for (i = 0;i < cpu_size;i ++) {
if (count < global_shmaddr->totalfds[i]) {
count = global_shmaddr->totalfds[i];
}
}
return count;
}
int min_countfd(void) {
int count = 0xffffffff;
int i = 0;
for (i = 0;i < cpu_size;i ++) {
if (count > global_shmaddr->totalfds[i]) {
count = global_shmaddr->totalfds[i];
}
}
return count;
}
int compare_out_countfd(void) {
int current = get_countfd();
int min = min_countfd();
if ((current * 7 / 8) > min) {
return 1;
} else {
return 0;
}
}
int compare_in_countfd(void) {
int current = get_countfd();
int max = max_countfd();
if ((current * 8 / 7) < max) {
return 1;
} else {
return 0;
}
}
void print_countfds(void) {
int i = 0;
for (i = 0;i < cpu_size;i ++) {
printf("%5d : %5d ", i, global_shmaddr->totalfds[i]);
}
printf("\n");
}
void lock_accept(void) {
global_shmaddr->cpu_lb[self_id % cpu_size] = 1;
int count = 0xffffffff;
int i = 0;
for (i = 0;i < cpu_size;i ++) {
if (count > global_shmaddr->totalfds[i]) {
count = global_shmaddr->totalfds[i];
}
}
for (i = 0;i < cpu_size;i ++) {
if (count == global_shmaddr->totalfds[i]) {
global_shmaddr->cpu_lb[i] = 3;
}
}
}
char read_accept(void) {
return global_shmaddr->cpu_lb[self_id % cpu_size];
}
void write_accept(char state) { //0, 1, 2, 3
global_shmaddr->cpu_lb[self_id % cpu_size] = state;
}
int lock(void) {
return cmpxchg(&global_shmaddr->accept_mtx, 0, 1, 4); //zero:success, non-zero:failed
}
void unlock(void) {
global_shmaddr->accept_mtx = 0;
}
void accept_request(int fd, int epfd);
void bad_request(int);
void cat(int);
void cannot_execute(int);
void error_die(const char *);
void execute_cgi(int, const char *, const char *, const char *);
int get_line(int, char *, int);
void headers(int);
void not_found(int);
void serve_file(int);
int startup(u_short *);
void unimplemented(int);
ssize_t nsend(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) {
#if 0
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN | POLLERR | POLLHUP;
poll(&fds, 1, -1);
#endif
ret = send(fd, ((char*)buf)+sent, len-sent, flags);
//printf("send --> len : %d\n", ret);
if (ret <= 0) {
if (errno == EAGAIN) continue;
break;
}
sent += ret;
}
if (ret <= 0 && sent == 0) return ret;
return sent;
}
static int ntySetNonblock(int fd) {
int flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return flags;
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) return -1;
return 0;
}
static int ntySetReUseAddr(int fd) {
int reuse = 1;
return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}
/**********************************************************************/
/* A request has caused a call to accept() on the server port to
* return. Process the request appropriately.
* Parameters: the socket connected to the client */
/**********************************************************************/
void accept_request(int fd, int epfd)
{
int client = fd;
char buf[1024];
size_t numchars;
char method[16];
char url[32];
char path[64];
size_t i, j;
struct stat st;
int cgi = 0; /* becomes true if server decides this is a CGI
* program */
char *query_string = NULL;
numchars = recv(client, buf, sizeof(buf), 0);
if (numchars == -1) {
//printf("recv errno : %d\n", errno);
if (errno == ECONNRESET) {
close(client);
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client;
epoll_ctl(epfd, EPOLL_CTL_DEL, client, &ev);
DEC_COUNTFD;
}
} else if (numchars == 0) {
close(client);
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client;
epoll_ctl(epfd, EPOLL_CTL_DEL, client, &ev);
DEC_COUNTFD;
} else {
//printf("recv numchars : %ld\n", numchars);
}
//serve_file(client, path);
}
#if 0
#define HTML_PAGE "<HTML> \
<TITLE>Index</TITLE> \
<BODY> \
<P>Welcome to J. David's webserver.\
<H1>CGI demo \
<FORM ACTION=\"color.cgi\" METHOD=\"POST\">\
Enter a color: <INPUT TYPE=\"text\" NAME=\"color\">\
<INPUT TYPE=\"submit\">\
</FORM>\
</BODY>\
</HTML>"
#else
#define HTML_PAGE "<!DOCTYPE html> \
<html> \
<head> \
<title>Welcome to nginx!</title> \
<style> \
body { \
width: 35em;\
margin: 0 auto;\
font-family: Tahoma, Verdana, Arial, sans-serif;\
}\
</style>\
</head>\
<body>\
<h1>Welcome to nginx!</h1>\
<p>If you see this page, the nginx web server is successfully installed and\
working. Further configuration is required.</p>\
\
<p>For online documentation and support please refer to\
<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\
Commercial support is available at\
<a href=\"http://nginx.com/\">nginx.com</a>.</p>\
\
<p><em>Thank you for using nginx.</em></p>\
</body>\
</html>"
#endif
void cat(int client)
{
//char buf[1024] = HTML_PAGE;
int ret = send(client, HTML_PAGE, strlen(HTML_PAGE), 0);
if (ret == -1) {
printf("send : errno : %d\n", errno);
} else {
printf("cat send ret : %d\n", ret);
}
}
void error_die(const char *sc)
{
printf("%s\n", sc);
exit(1);
}
void headers(int client)
{
char buf[1024] = {0};
char content[128] = {0};
sprintf(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, SERVER_STRING);
strcat(buf, "Content-Type: text/html\r\n");
#if 0
strcat(buf, "Transfer-Encoding: chunked\r\n");
#else
sprintf(content, "Content-Length: %ld\r\n", strlen(HTML_PAGE));
strcat(buf, content);
#endif
strcat(buf, "\r\n");
strcat(buf, HTML_PAGE);
int ret = send(client, buf, strlen(buf), 0);
if (ret == -1) {
printf("send : errno : %d\n", errno);
} else {
//printf("headers send ret : %d\n", ret);
}
}
/**********************************************************************/
/* Send a regular file to the client. Use headers, and report
* errors to client if they occur.
* Parameters: a pointer to a file structure produced from the socket
* file descriptor
* the name of the file to serve */
/**********************************************************************/
void serve_file(int client)
{
headers(client);
//cat(client);
}
#define MAX_EPOLLSIZE 10240
void server(void *arg) {
int fd = *(int *)arg;
int epfd = epoll_create(1);
struct epoll_event events[MAX_EPOLLSIZE];
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
int acc = 1; //
while (1) {
#if 0
char lock = read_accept();
if (lock == 1) { //lock
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev);
write_accept(2); //add complete
} else if (acc == 0 && lock == 3) {
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
write_accept(0);
}
#endif
int nready = epoll_wait(epfd, events, MAX_EPOLLSIZE, 1);
if (nready == -1) {
if (errno == EINTR) {
printf("errno : EINTR\n");
continue;
}
continue;
}
int i = 0;
for (i = 0;i < nready;i ++) {
int sockfd = events[i].data.fd;
if (sockfd == fd) {
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
#if 0
if (get_countfd() % accept_disable == 999) {
lock_accept();
acc = 0;
}
char lock = read_accept();
if (lock != 0 && lock != 3) continue;
#endif
if (lock()) {
continue;
}
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
unlock();
if (clientfd < 0) {
if (errno == EAGAIN) {
//printf("accept : EAGAIN\n");
continue;
} else if (errno == ECONNABORTED) {
printf("accept : ECONNABORTED\n");
} else if (errno == EMFILE || errno == ENFILE) {
printf("accept : EMFILE || ENFILE\n");
}
return ;
}
INC_COUNTFD;
ntySetNonblock(clientfd);
ntySetReUseAddr(clientfd);
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);
}
else if (events[i].events & EPOLLIN) {
accept_request(sockfd, epfd);
#if 1
//struct epoll_event ev;
ev.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;
ev.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
//close(sockfd);
#endif
}
else if (events[i].events & EPOLLOUT) {
serve_file(sockfd);
//close(sockfd);
//struct epoll_event ev;
ev.events = EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR;
ev.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
DEC_COUNTFD;
}
else if (events[i].events & (EPOLLHUP|EPOLLRDHUP|EPOLLERR)) {
close(sockfd);
printf(" EPOLLHUP | EPOLLRDHUP\n");
//struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
ev.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, &ev);
DEC_COUNTFD;
}
}
// print_countfds();
}
}
int mulcore_entry(int begin_port) {
int i = 0;
unsigned short base_port = begin_port;
unsigned short *port = calloc(1, sizeof(unsigned short));
*port = base_port;
server(port);
}
int process_bind(int fd) {
int num = sysconf(_SC_NPROCESSORS_CONF);
self_id = syscall(__NR_gettid);
//printf("selfid --> %d\n", self_id);
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(self_id % num, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
server(&fd);
//mulcore_entry(9000);
}
int init_shmvalue(int num) {
global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600);
if (global_shmid < 0) {
perror("shmget failed\n");
return -1;
}
global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0);
if (global_shmaddr == (shm_area*)-1) {
perror("shmat addr error");
return -1;
}
memset(global_shmaddr->totalfds, 0, TOTALFDS * sizeof(int));
memset(global_shmaddr->cpu_lb, 0, TOTALFDS * sizeof(char));
global_shmaddr->accept_mtx = 0;
}
int main(int argc, char *argv[]) {
short port = 9000;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name);
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return -1;
ntySetNonblock(fd);
ntySetReUseAddr(fd);
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in));
listen(fd, 20);
int num = sysconf(_SC_NPROCESSORS_CONF);
cpu_size = num;
init_shmvalue(num);
int i = 0;
pid_t pid=0;
for(i = 0;i < num;i ++) {
pid=fork();
if(pid <= (pid_t) 0)
{
usleep(1);
break;
}
}
#if 1
if (pid > 0) {
printf("ntyco_httpd server running ...\n");
getchar();
} else if (pid == 0) {
process_bind(fd);
}
#else
INC_COUNTFD;
INC_COUNTFD;
print_countfds();
#endif
}

View File

@@ -1,634 +0,0 @@
/*
* 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
*
*
**** ***** *****
*** * ** ***
*** * * * **
* ** * * ** **
* ** * * ** *
* ** * ** ** *
* ** * *** **
* ** * *********** ***** ***** ** ****
* ** * ** ** ** ** ** **
* ** * ** ** * ** * **
* ** * ** * * ** ** **
* ** * ** ** * ** * **
* ** * ** * * ** ** **
* ** * ** ** * ** ** **
* ** * ** ** * ** ** **
* ** * ** * * ** ** **
* ** * ** ** * ** * ** **
* *** ** * * ** * ** **
* *** ** * ** * * ** **
* ** ** * ** ** * ** **
* ** ** * * ** * ** **
***** * **** * ***** ****
*
*
*****
****
*
*/
/* J. David's webserver */
/* This is a simple webserver.
* Created November 1999 by J. David Blackstone.
* CSE 4344 (Network concepts), Prof. Zeigler
* University of Texas at Arlington
*/
/* This program compiles for Sparc Solaris 2.6.
* To compile for Linux:
* 1) Comment out the #include <pthread.h> line.
* 2) Comment out the line that defines the variable newthread.
* 3) Comment out the two lines that run pthread_create().
* 4) Uncomment the line that runs accept_request().
* 5) Remove -lsocket from the Makefile.
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <sys/stat.h>
#include <pthread.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdint.h>
#define ISspace(x) isspace((int)(x))
#define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n"
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define ENABLE_NTYCO 1
#if ENABLE_NTYCO
#include "nty_coroutine.h"
#define socket nty_socket
#define accept nty_accept
#define recv(a, b, c, d) nty_recv(a, b, c, d)
#define send(a, b, c, d) nty_send(a, b, c, d)
#define MAX_BUFFER_LENGTH 1024
#endif
void accept_request(void *);
void bad_request(int);
void cat(int, FILE *);
void cannot_execute(int);
void error_die(const char *);
void execute_cgi(int, const char *, const char *, const char *);
int get_line(int, char *, int);
void headers(int, const char *);
void not_found(int);
void serve_file(int, const char *);
int startup(u_short *);
void unimplemented(int);
int readline(char* allbuf,int level,char* linebuf){
int len = strlen(allbuf);
for (;level < len; ++level) {
if(allbuf[level]=='\r' && allbuf[level+1]=='\n')
return level+2;
else
*(linebuf++) = allbuf[level];
}
return -1;
}
/**********************************************************************/
/* A request has caused a call to accept() on the server port to
* return. Process the request appropriately.
* Parameters: the socket connected to the client */
/**********************************************************************/
void accept_request(void *arg)
{
int *pclient = (int*)arg;
int client = *pclient;
char buf[1024];
size_t numchars;
char method[255];
char url[255];
char path[512];
size_t i, j;
struct stat st;
int cgi = 0; /* becomes true if server decides this is a CGI
* program */
char *query_string = NULL;
numchars = nty_recv(client, buf, sizeof(buf), 0);
i = 0; j = 0;
while (!ISspace(buf[i]) && (i < sizeof(method) - 1))
{
method[i] = buf[i];
i++;
}
j=i;
method[i] = '\0';
if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
{
unimplemented(client);
return;
}
if (strcasecmp(method, "POST") == 0)
cgi = 1;
i = 0;
while (ISspace(buf[j]) && (j < numchars))
j++;
while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < numchars))
{
url[i] = buf[j];
i++; j++;
}
url[i] = '\0';
if (strcasecmp(method, "GET") == 0)
{
query_string = url;
while ((*query_string != '?') && (*query_string != '\0'))
query_string++;
if (*query_string == '?')
{
cgi = 1;
*query_string = '\0';
query_string++;
}
}
sprintf(path, "htdocs%s", url);
if (path[strlen(path) - 1] == '/')
strcat(path, "index.html");
if (stat(path, &st) == -1) {
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
not_found(client);
}
else
{
if ((st.st_mode & S_IFMT) == S_IFDIR)
strcat(path, "/index.html");
if ((st.st_mode & S_IXUSR) ||
(st.st_mode & S_IXGRP) ||
(st.st_mode & S_IXOTH) )
cgi = 1;
cgi = 0;
if (!cgi)
serve_file(client, path);
else
execute_cgi(client, path, method, query_string);
}
nty_close(client);
free(pclient);
}
/**********************************************************************/
/* Inform the client that a request it has made has a problem.
* Parameters: client socket */
/**********************************************************************/
void bad_request(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "Content-type: text/html\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "<P>Your browser sent a bad request, ");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "such as a POST without a Content-Length.\r\n");
send(client, buf, sizeof(buf), 0);
}
/**********************************************************************/
/* Put the entire contents of a file out on a socket. This function
* is named after the UNIX "cat" command, because it might have been
* easier just to do something like pipe, fork, and exec("cat").
* Parameters: the client socket descriptor
* FILE pointer for the file to cat */
/**********************************************************************/
void cat(int client, FILE *resource)
{
char buf[1024];
char *ch = fgets(buf, sizeof(buf), resource);
while (!feof(resource))
{
send(client, buf, strlen(buf), 0);
ch = fgets(buf, sizeof(buf), resource);
}
}
/**********************************************************************/
/* Inform the client that a CGI script could not be executed.
* Parameter: the client socket descriptor. */
/**********************************************************************/
void cannot_execute(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<P>Error prohibited CGI execution.\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
/* Print out an error message with perror() (for system errors; based
* on value of errno, which indicates system call errors) and exit the
* program indicating an error. */
/**********************************************************************/
void error_die(const char *sc)
{
perror(sc);
exit(1);
}
/**********************************************************************/
/* Execute a CGI script. Will need to set environment variables as
* appropriate.
* Parameters: client socket descriptor
* path to the CGI script */
/**********************************************************************/
void execute_cgi(int client, const char *path,
const char *method, const char *query_string)
{
char buf[1024];
int cgi_output[2];
int cgi_input[2];
pid_t pid;
int status;
int i;
char c;
int numchars = 1;
int content_length = -1;
buf[0] = 'A'; buf[1] = '\0';
if (strcasecmp(method, "GET") == 0)
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
else if (strcasecmp(method, "POST") == 0) /*POST*/
{
numchars = get_line(client, buf, sizeof(buf));
while ((numchars > 0) && strcmp("\n", buf))
{
buf[15] = '\0';
if (strcasecmp(buf, "Content-Length:") == 0)
content_length = atoi(&(buf[16]));
numchars = get_line(client, buf, sizeof(buf));
}
if (content_length == -1) {
bad_request(client);
return;
}
}
else/*HEAD or other*/
{
}
if (pipe(cgi_output) < 0) {
cannot_execute(client);
return;
}
if (pipe(cgi_input) < 0) {
cannot_execute(client);
return;
}
if ( (pid = fork()) < 0 ) {
cannot_execute(client);
return;
}
sprintf(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
if (pid == 0) /* child: CGI script */
{
char meth_env[255];
char query_env[255];
char length_env[255];
dup2(cgi_output[1], STDOUT);
dup2(cgi_input[0], STDIN);
close(cgi_output[0]);
close(cgi_input[1]);
sprintf(meth_env, "REQUEST_METHOD=%s", method);
putenv(meth_env);
if (strcasecmp(method, "GET") == 0) {
sprintf(query_env, "QUERY_STRING=%s", query_string);
putenv(query_env);
}
else { /* POST */
sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
putenv(length_env);
}
execl(path, "", NULL);
exit(0);
} else { /* parent */
close(cgi_output[1]);
close(cgi_input[0]);
if (strcasecmp(method, "POST") == 0)
for (i = 0; i < content_length; i++) {
recv(client, &c, 1, 0);
int len = write(cgi_input[1], &c, 1);
}
while (read(cgi_output[0], &c, 1) > 0)
send(client, &c, 1, 0);
close(cgi_output[0]);
close(cgi_input[1]);
waitpid(pid, &status, 0);
}
}
/**********************************************************************/
/* Get a line from a socket, whether the line ends in a newline,
* carriage return, or a CRLF combination. Terminates the string read
* with a null character. If no newline indicator is found before the
* end of the buffer, the string is terminated with a null. If any of
* the above three line terminators is read, the last character of the
* string will be a linefeed and the string will be terminated with a
* null character.
* Parameters: the socket descriptor
* the buffer to save the data in
* the size of the buffer
* Returns: the number of bytes stored (excluding null) */
/**********************************************************************/
int get_line(int sock, char *buf, int size)
{
int i = 0;
char c = '\0';
int n;
while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}
/**********************************************************************/
/* Return the informational HTTP headers about a file. */
/* Parameters: the socket to print the headers on
* the name of the file */
/**********************************************************************/
void headers(int client, const char *filename)
{
char buf[1024];
(void)filename; /* could use filename to determine file type */
strcpy(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
strcpy(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
strcpy(buf, "\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
/* Give a client a 404 not found status message. */
/**********************************************************************/
void not_found(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "your request because the resource specified\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "is unavailable or nonexistent.\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
/* Send a regular file to the client. Use headers, and report
* errors to client if they occur.
* Parameters: a pointer to a file structure produced from the socket
* file descriptor
* the name of the file to serve */
/**********************************************************************/
void serve_file(int client, const char *filename)
{
FILE *resource = NULL;
int numchars = 1;
char buf[1024];
#if (ENABLE_NTYCO == 0)
buf[0] = 'A'; buf[1] = '\0';
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
#endif
resource = fopen(filename, "r");
if (resource == NULL)
not_found(client);
else
{
headers(client, filename);
cat(client, resource);
}
fclose(resource);
}
/**********************************************************************/
/* This function starts the process of listening for web connections
* on a specified port. If the port is 0, then dynamically allocate a
* port and modify the original port variable to reflect the actual
* port.
* Parameters: pointer to variable containing the port to connect on
* Returns: the socket */
/**********************************************************************/
int startup(u_short *port)
{
int httpd = 0;
int on = 1;
struct sockaddr_in name;
httpd = socket(PF_INET, SOCK_STREAM, 0);
if (httpd == -1)
error_die("socket");
memset(&name, 0, sizeof(name));
name.sin_family = AF_INET;
name.sin_port = htons(*port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if ((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
{
error_die("setsockopt failed");
}
if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
error_die("bind");
if (*port == 0) /* if dynamically allocating a port */
{
socklen_t namelen = sizeof(name);
if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
error_die("getsockname");
*port = ntohs(name.sin_port);
}
if (listen(httpd, 5) < 0)
error_die("listen");
return(httpd);
}
/**********************************************************************/
/* Inform the client that the requested web method has not been
* implemented.
* Parameter: the client socket */
/**********************************************************************/
void unimplemented(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</TITLE></HEAD>\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
void server(void *arg)
{
int server_sock = -1;
u_short port = 4000;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name);
server_sock = startup(&port);
printf("httpd running on port %d\n", port);
while (1)
{
int *client_sock = (int *)malloc(sizeof(int));
*client_sock = accept(server_sock,
(struct sockaddr *)&client_name,
&client_name_len);
if (*client_sock == -1)
error_die("accept");
/* accept_request(&client_sock); */
#if 1 //ENABLE_NTYCO
printf(" %d.%d.%d.%d:%d clientfd:%d --> New Client Connected \n",
*(unsigned char*)(&client_name.sin_addr.s_addr), *((unsigned char*)(&client_name.sin_addr.s_addr)+1),
*((unsigned char*)(&client_name.sin_addr.s_addr)+2), *((unsigned char*)(&client_name.sin_addr.s_addr)+3),
client_name.sin_port, *client_sock);
nty_coroutine *read_co;
nty_coroutine_create(&read_co, accept_request, client_sock);
#else
pthread_t newthread;
if (pthread_create(&newthread , NULL, (void *)accept_request, (void *)(intptr_t)client_sock) != 0)
perror("pthread_create");
#endif
}
nty_close(server_sock);
return ;
}
int main(int argc, char *argv[]) {
nty_coroutine *co = NULL;
nty_coroutine_create(&co, server, 0); ////////no run
nty_schedule_run(); //run
return 0;
}

View File

@@ -1,891 +0,0 @@
/*
* 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 <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sysinfo.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define __USE_GNU
#include <sched.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include "nty_coroutine.h"
static int global_shmid = -1;
static int global_semid = -1;
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
typedef struct _shm_area {
int total;
int accept_lock;
struct timeval tv_begin;
} shm_area;
static shm_area *global_shmaddr = NULL;
#define MAX_CLIENT_NUM 1000000
struct timeval* get_shm_timevalue(void);
void set_shm_timevalue(struct timeval *tv);
int add_shmvalue(void);
int sub_shmvalue(void);
int init_shmvalue(void);
int lock_accept_mutex(void);
int unlock_accept_mutex(void);
unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) {
unsigned long prev;
volatile unsigned int *_ptr = (volatile unsigned int *)(addr);
switch (size) {
case 1: {
__asm__ volatile (
"lock; cmpxchgb %b1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 2: {
__asm__ volatile (
"lock; cmpxchgw %w1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 4: {
__asm__ volatile (
"lock; cmpxchg %1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
}
return prev;
}
#define ISspace(x) isspace((int)(x))
#define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n"
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define ENABLE_NTYCO 1
#if ENABLE_NTYCO
#define socket nty_socket
#define accept nty_accept
#define recv(a, b, c, d) nty_recv(a, b, c, d)
#define send(a, b, c, d) nty_send(a, b, c, d)
#define close(a) nty_close(a)
#define MAX_BUFFER_LENGTH 1024
#endif
void accept_request(void *);
void bad_request(int);
void cat(int, FILE *);
void cannot_execute(int);
void error_die(const char *);
void execute_cgi(int, const char *, const char *, const char *);
int get_line(int, char *, int);
void headers(int, const char *);
void not_found(int);
void serve_file(int, const char *);
int startup(u_short *);
void unimplemented(int);
int readline(char* allbuf, int level, char* linebuf) {
int len = strlen(allbuf);
for (;level < len; ++level) {
if(allbuf[level]=='\r' && allbuf[level+1]=='\n')
return level+2;
else
*(linebuf++) = allbuf[level];
}
return -1;
}
/**********************************************************************/
/* A request has caused a call to accept() on the server port to
* return. Process the request appropriately.
* Parameters: the socket connected to the client */
/**********************************************************************/
void accept_request(void *arg)
{
int *pclient = (int*)arg;
int client = *pclient;
char buf[1024];
size_t numchars;
char method[16];
char url[32];
char path[64];
size_t i, j;
struct stat st;
int cgi = 0; /* becomes true if server decides this is a CGI
* program */
char *query_string = NULL;
numchars = recv(client, buf, sizeof(buf), 0);
i = 0; j = 0;
while (!ISspace(buf[i]) && (i < sizeof(method) - 1))
{
method[i] = buf[i];
i++;
}
j=i;
method[i] = '\0';
if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
{
unimplemented(client);
return;
}
if (strcasecmp(method, "POST") == 0)
cgi = 1;
i = 0;
while (ISspace(buf[j]) && (j < numchars))
j++;
while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < numchars))
{
url[i] = buf[j];
i++; j++;
}
url[i] = '\0';
if (strcasecmp(method, "GET") == 0)
{
query_string = url;
while ((*query_string != '?') && (*query_string != '\0'))
query_string++;
if (*query_string == '?')
{
cgi = 1;
*query_string = '\0';
query_string++;
}
}
sprintf(path, "htdocs%s", url);
if (path[strlen(path) - 1] == '/')
strcat(path, "index.html");
if (stat(path, &st) == -1) {
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
not_found(client);
}
else
{
if ((st.st_mode & S_IFMT) == S_IFDIR)
strcat(path, "/index.html");
if ((st.st_mode & S_IXUSR) ||
(st.st_mode & S_IXGRP) ||
(st.st_mode & S_IXOTH) )
cgi = 1;
cgi = 0;
if (!cgi)
serve_file(client, path);
else
execute_cgi(client, path, method, query_string);
}
close(client);
free(pclient);
}
/**********************************************************************/
/* Inform the client that a request it has made has a problem.
* Parameters: client socket */
/**********************************************************************/
void bad_request(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "Content-type: text/html\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "<P>Your browser sent a bad request, ");
send(client, buf, sizeof(buf), 0);
sprintf(buf, "such as a POST without a Content-Length.\r\n");
send(client, buf, sizeof(buf), 0);
}
/**********************************************************************/
/* Put the entire contents of a file out on a socket. This function
* is named after the UNIX "cat" command, because it might have been
* easier just to do something like pipe, fork, and exec("cat").
* Parameters: the client socket descriptor
* FILE pointer for the file to cat */
/**********************************************************************/
#define HTML_PAGE "<HTML> \
<TITLE>Index</TITLE> \
<BODY> \
<P>Welcome to J. David's webserver.\
<H1>CGI demo \
<FORM ACTION=\"color.cgi\" METHOD=\"POST\">\
Enter a color: <INPUT TYPE=\"text\" NAME=\"color\">\
<INPUT TYPE=\"submit\">\
</FORM>\
</BODY>\
</HTML>"
void cat(int client, FILE *resource)
{
#if ENABLE_NTYCO
char buf[1024] = HTML_PAGE;
send(client, buf, strlen(buf), 0);
#else
char buf[1024] = {0};
fgets(buf, sizeof(buf), resource);
while (!feof(resource))
{
send(client, buf, strlen(buf), 0);
fgets(buf, sizeof(buf), resource);
}
#endif
}
/**********************************************************************/
/* Inform the client that a CGI script could not be executed.
* Parameter: the client socket descriptor. */
/**********************************************************************/
void cannot_execute(int client)
{
char buf[1024];
sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<P>Error prohibited CGI execution.\r\n");
send(client, buf, strlen(buf), 0);
}
/**********************************************************************/
/* Print out an error message with perror() (for system errors; based
* on value of errno, which indicates system call errors) and exit the
* program indicating an error. */
/**********************************************************************/
void error_die(const char *sc)
{
perror(sc);
exit(1);
}
/**********************************************************************/
/* Execute a CGI script. Will need to set environment variables as
* appropriate.
* Parameters: client socket descriptor
* path to the CGI script */
/**********************************************************************/
void execute_cgi(int client, const char *path,
const char *method, const char *query_string)
{
char buf[1024];
int cgi_output[2];
int cgi_input[2];
pid_t pid;
int status;
int i;
char c;
int numchars = 1;
int content_length = -1;
buf[0] = 'A'; buf[1] = '\0';
if (strcasecmp(method, "GET") == 0)
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
else if (strcasecmp(method, "POST") == 0) /*POST*/
{
numchars = get_line(client, buf, sizeof(buf));
while ((numchars > 0) && strcmp("\n", buf))
{
buf[15] = '\0';
if (strcasecmp(buf, "Content-Length:") == 0)
content_length = atoi(&(buf[16]));
numchars = get_line(client, buf, sizeof(buf));
}
if (content_length == -1) {
bad_request(client);
return;
}
}
else/*HEAD or other*/
{
}
if (pipe(cgi_output) < 0) {
cannot_execute(client);
return;
}
if (pipe(cgi_input) < 0) {
cannot_execute(client);
return;
}
if ( (pid = fork()) < 0 ) {
cannot_execute(client);
return;
}
sprintf(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
if (pid == 0) /* child: CGI script */
{
char meth_env[255];
char query_env[255];
char length_env[255];
dup2(cgi_output[1], STDOUT);
dup2(cgi_input[0], STDIN);
close(cgi_output[0]);
close(cgi_input[1]);
sprintf(meth_env, "REQUEST_METHOD=%s", method);
putenv(meth_env);
if (strcasecmp(method, "GET") == 0) {
sprintf(query_env, "QUERY_STRING=%s", query_string);
putenv(query_env);
}
else { /* POST */
sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
putenv(length_env);
}
execl(path, "", NULL);
exit(0);
} else { /* parent */
close(cgi_output[1]);
close(cgi_input[0]);
if (strcasecmp(method, "POST") == 0)
for (i = 0; i < content_length; i++) {
recv(client, &c, 1, 0);
int len = write(cgi_input[1], &c, 1);
}
while (read(cgi_output[0], &c, 1) > 0)
send(client, &c, 1, 0);
close(cgi_output[0]);
close(cgi_input[1]);
waitpid(pid, &status, 0);
}
}
/**********************************************************************/
/* Get a line from a socket, whether the line ends in a newline,
* carriage return, or a CRLF combination. Terminates the string read
* with a null character. If no newline indicator is found before the
* end of the buffer, the string is terminated with a null. If any of
* the above three line terminators is read, the last character of the
* string will be a linefeed and the string will be terminated with a
* null character.
* Parameters: the socket descriptor
* the buffer to save the data in
* the size of the buffer
* Returns: the number of bytes stored (excluding null) */
/**********************************************************************/
int get_line(int sock, char *buf, int size)
{
int i = 0;
char c = '\0';
int n;
while ((i < size - 1) && (c != '\n'))
{
n = recv(sock, &c, 1, 0);
if (n > 0)
{
if (c == '\r')
{
n = recv(sock, &c, 1, MSG_PEEK);
if ((n > 0) && (c == '\n'))
recv(sock, &c, 1, 0);
else
c = '\n';
}
buf[i] = c;
i++;
}
else
c = '\n';
}
buf[i] = '\0';
return(i);
}
/**********************************************************************/
/* Return the informational HTTP headers about a file. */
/* Parameters: the socket to print the headers on
* the name of the file */
/**********************************************************************/
void headers(int client, const char *filename)
{
char buf[1024] = {0};
(void)filename; /* could use filename to determine file type */
#if ENABLE_NTYCO
sprintf(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, SERVER_STRING);
strcat(buf, "Content-Type: text/html\r\n");
strcat(buf, "\r\n");
send(client, buf, strlen(buf), 0);
#else
strcpy(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
strcpy(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
strcpy(buf, "\r\n");
send(client, buf, strlen(buf), 0);
#endif
}
/**********************************************************************/
/* Give a client a 404 not found status message. */
/**********************************************************************/
void not_found(int client)
{
char buf[1024];
#if ENABLE_NTYCO
sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
strcat(buf, SERVER_STRING);
strcat(buf, "Content-Type: text/html\r\n");
strcat(buf, "\r\n");
strcat(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
strcat(buf, "<BODY><P>The server could not fulfill\r\n");
strcat(buf, "your request because the resource specified\r\n");
strcat(buf, "is unavailable or nonexistent.\r\n");
strcat(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
#else
sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "your request because the resource specified\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "is unavailable or nonexistent.\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
#endif
}
/**********************************************************************/
/* Send a regular file to the client. Use headers, and report
* errors to client if they occur.
* Parameters: a pointer to a file structure produced from the socket
* file descriptor
* the name of the file to serve */
/**********************************************************************/
void serve_file(int client, const char *filename)
{
FILE *resource = NULL;
int numchars = 1;
char buf[1024];
#if (ENABLE_NTYCO == 0)
buf[0] = 'A'; buf[1] = '\0';
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
resource = fopen(filename, "r");
if (resource == NULL)
not_found(client);
else
{
headers(client, filename);
cat(client, resource);
}
fclose(resource);
#else
headers(client, filename);
cat(client, resource);
#endif
}
/**********************************************************************/
/* This function starts the process of listening for web connections
* on a specified port. If the port is 0, then dynamically allocate a
* port and modify the original port variable to reflect the actual
* port.
* Parameters: pointer to variable containing the port to connect on
* Returns: the socket */
/**********************************************************************/
int startup(u_short *port)
{
int httpd = 0;
int on = 1;
struct sockaddr_in name;
httpd = socket(PF_INET, SOCK_STREAM, 0);
if (httpd == -1)
error_die("socket");
memset(&name, 0, sizeof(name));
name.sin_family = AF_INET;
name.sin_port = htons(*port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if ((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
{
error_die("setsockopt failed");
}
if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
error_die("bind");
if (*port == 0) /* if dynamically allocating a port */
{
socklen_t namelen = sizeof(name);
if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
error_die("getsockname");
*port = ntohs(name.sin_port);
}
if (listen(httpd, 5) < 0)
error_die("listen");
return(httpd);
}
/**********************************************************************/
/* Inform the client that the requested web method has not been
* implemented.
* Parameter: the client socket */
/**********************************************************************/
void unimplemented(int client)
{
char buf[1024];
#if ENABLE_NTYCO
sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
strcat(buf, SERVER_STRING);
strcat(buf, "Content-Type: text/html\r\n");
strcat(buf, "\r\n");
strcat(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
strcat(buf, "</TITLE></HEAD>\r\n");
strcat(buf, "<BODY><P>HTTP request method not supported.\r\n");
strcat(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
#else
sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, SERVER_STRING);
send(client, buf, strlen(buf), 0);
sprintf(buf, "Content-Type: text/html\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</TITLE></HEAD>\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
send(client, buf, strlen(buf), 0);
sprintf(buf, "</BODY></HTML>\r\n");
send(client, buf, strlen(buf), 0);
#endif
}
void server(void *arg) {
unsigned short port = *(unsigned short *)arg;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name);
free(arg);
int fd = nty_socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return ;
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in));
listen(fd, 20);
while (1) {
int *client_sock = (int *)malloc(sizeof(int));
*client_sock = accept(fd,
(struct sockaddr *)&client_name,
&client_name_len);
if (*client_sock == -1)
error_die("accept");
/* accept_request(&client_sock); */
#if 0
printf(" %d.%d.%d.%d:%d clientfd:%d --> New Client Connected \n",
*(unsigned char*)(&client_name.sin_addr.s_addr), *((unsigned char*)(&client_name.sin_addr.s_addr)+1),
*((unsigned char*)(&client_name.sin_addr.s_addr)+2), *((unsigned char*)(&client_name.sin_addr.s_addr)+3),
client_name.sin_port, *client_sock);
#endif
nty_coroutine *read_co;
nty_coroutine_create(&read_co, accept_request, client_sock);
}
}
int mulcore_entry(int begin_port) {
nty_coroutine *co = NULL;
int i = 0;
unsigned short base_port = begin_port;
unsigned short *port = calloc(1, sizeof(unsigned short));
*port = base_port + i;
nty_coroutine_create(&co, server, port); ////////no run
nty_schedule_run(); //run
}
int process_bind(void) {
int num = sysconf(_SC_NPROCESSORS_CONF);
pid_t self_id = syscall(__NR_gettid);
//printf("selfid --> %d\n", self_id);
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(self_id % num, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
mulcore_entry(9096);
}
struct timeval* get_shm_timevalue(void) {
return global_shmaddr ? &global_shmaddr->tv_begin : NULL;
}
void set_shm_timevalue(struct timeval *tv) {
if (global_shmaddr == NULL || tv == NULL) {
return ;
}
memcpy(&global_shmaddr->tv_begin, tv, sizeof(struct timeval));
}
int add_shmvalue(void) {
int value = 0;
int ret = -1;
do {
value = global_shmaddr->total;
ret = cmpxchg(&global_shmaddr->total, (unsigned long)value, (unsigned long)(value+1), 4);
} while (ret != value);
return global_shmaddr->total;
}
int sub_shmvalue(void) {
int value = 0;
int ret = -1;
do {
value = global_shmaddr->total;
ret = cmpxchg(&global_shmaddr->total, (unsigned long)value, (unsigned long)(value-1), 4);
} while (ret != value);
return global_shmaddr->total;
}
int lock_accept_mutex(void) {
int ret = cmpxchg(&global_shmaddr->accept_lock, (unsigned long)0, (unsigned long)1, 4);
return ret; //success 0, failed 1.
}
int unlock_accept_mutex(void) {
int ret = cmpxchg(&global_shmaddr->accept_lock, (unsigned long)1, (unsigned long)0, 4);
return ret; //unlock 1, lock 0
}
int init_shmvalue(void) {
global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600);
if (global_shmid < 0) {
perror("shmget failed\n");
return -1;
}
global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0);
if (global_shmaddr == (shm_area*)-1) {
perror("shmat addr error");
return -1;
}
global_shmaddr->total = 0;
gettimeofday(&global_shmaddr->tv_begin, NULL);
}
int main(int argc, char *argv[]) {
int ret = init_shmvalue();
if (ret == -1) {
printf("init share memory failed\n");
return -1;
}
int num = sysconf(_SC_NPROCESSORS_CONF);
int i = 0;
pid_t pid=0;
for(i = 0;i < num;i ++) {
pid=fork();
if(pid <= (pid_t) 0)
{
usleep(1);
break;
}
}
if (pid > 0) {
printf("ntyco_httpd server running ...\n");
getchar();
} else if (pid == 0) {
process_bind();
}
}

View File

@@ -1,49 +0,0 @@
#include "nty_coroutine.h"
#include <stdio.h>
#include <string.h>
#include <mysql.h>
void func (void *arg) {
MYSQL* m_mysql = mysql_init(NULL);
if (!m_mysql) {
printf("mysql_init failed\n");
return ;
}
if (!mysql_real_connect(m_mysql,
"192.168.233.133", "king", "123456",
"KING_DB", 3306,
NULL, CLIENT_FOUND_ROWS)) {
printf("mysql_real_connect failed: %s\n", mysql_error(m_mysql));
return ;
} else{
printf("mysql_real_connect success\n");
}
}
int main() {
#if 1
init_hook();
nty_coroutine *co = NULL;
nty_coroutine_create(&co, func, NULL);
nty_schedule_run(); //run
#else
func(NULL);
#endif
}

View File

@@ -1,315 +0,0 @@
#include "nty_coroutine.h"
#include <mysql.h>
#define KING_DB_SERVER_IP "192.168.233.133"
#define KING_DB_SERVER_PORT 3306
#define KING_DB_USERNAME "king"
#define KING_DB_PASSWORD "123456"
#define KING_DB_DEFAULTDB "KING_DB"
#define SQL_INSERT_TBL_USER "INSERT TBL_USER(U_NAME, U_GENDER) VALUES('King', 'man');"
#define SQL_SELECT_TBL_USER "SELECT * FROM TBL_USER;"
#define SQL_DELETE_TBL_USER "CALL PROC_DELETE_USER('King')"
#define SQL_INSERT_IMG_USER "INSERT TBL_USER(U_NAME, U_GENDER, U_IMG) VALUES('King', 'man', ?);"
#define SQL_SELECT_IMG_USER "SELECT U_IMG FROM TBL_USER WHERE U_NAME='King';"
#define FILE_IMAGE_LENGTH (64*1024)
// C U R D -->
//
int king_mysql_select(MYSQL *handle) { //
// mysql_real_query --> sql
if (mysql_real_query(handle, SQL_SELECT_TBL_USER, strlen(SQL_SELECT_TBL_USER))) {
printf("mysql_real_query : %s\n", mysql_error(handle));
return -1;
}
// store -->
MYSQL_RES *res = mysql_store_result(handle);
if (res == NULL) {
printf("mysql_store_result : %s\n", mysql_error(handle));
return -2;
}
// rows / fields
int rows = mysql_num_rows(res);
printf("rows: %d\n", rows);
int fields = mysql_num_fields(res);
printf("fields: %d\n", fields);
// fetch
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
int i = 0;
for (i = 0;i < fields;i ++) {
printf("%s\t", row[i]);
}
printf("\n");
}
mysql_free_result(res);
return 0;
}
// filename : path + file name
// buffer : store image data
int read_image(char *filename, char *buffer) {
if (filename == NULL || buffer == NULL) return -1;
FILE *fp = fopen(filename, "rb"); //
if (fp == NULL) {
printf("fopen failed\n");
return -2;
}
// file size
fseek(fp, 0, SEEK_END);
int length = ftell(fp); // file size
fseek(fp, 0, SEEK_SET);
int size = fread(buffer, 1, length, fp);
if (size != length) {
printf("fread failed: %d\n", size);
return -3;
}
fclose(fp);
return size;
}
// filename :
// buffer :
// length :
int write_image(char *filename, char *buffer, int length) {
if (filename == NULL || buffer == NULL || length <= 0) return -1;
FILE *fp = fopen(filename, "wb+"); //
if (fp == NULL) {
printf("fopen failed\n");
return -2;
}
int size = fwrite(buffer, 1, length, fp);
if (size != length) {
printf("fwrite failed: %d\n", size);
return -3;
}
fclose(fp);
return size;
}
int mysql_write(MYSQL *handle, char *buffer, int length) {
if (handle == NULL || buffer == NULL || length <= 0) return -1;
MYSQL_STMT *stmt = mysql_stmt_init(handle);
int ret = mysql_stmt_prepare(stmt, SQL_INSERT_IMG_USER, strlen(SQL_INSERT_IMG_USER));
if (ret) {
printf("mysql_stmt_prepare : %s\n", mysql_error(handle));
return -2;
}
MYSQL_BIND param = {0};
param.buffer_type = MYSQL_TYPE_LONG_BLOB;
param.buffer = NULL;
param.is_null = 0;
param.length = NULL;
ret = mysql_stmt_bind_param(stmt, &param);
if (ret) {
printf("mysql_stmt_bind_param : %s\n", mysql_error(handle));
return -3;
}
ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
if (ret) {
printf("mysql_stmt_send_long_data : %s\n", mysql_error(handle));
return -4;
}
ret = mysql_stmt_execute(stmt);
if (ret) {
printf("mysql_stmt_execute : %s\n", mysql_error(handle));
return -5;
}
ret = mysql_stmt_close(stmt);
if (ret) {
printf("mysql_stmt_close : %s\n", mysql_error(handle));
return -6;
}
return ret;
}
int mysql_read(MYSQL *handle, char *buffer, int length) {
if (handle == NULL || buffer == NULL || length <= 0) return -1;
MYSQL_STMT *stmt = mysql_stmt_init(handle);
int ret = mysql_stmt_prepare(stmt, SQL_SELECT_IMG_USER, strlen(SQL_SELECT_IMG_USER));
if (ret) {
printf("mysql_stmt_prepare : %s\n", mysql_error(handle));
return -2;
}
MYSQL_BIND result = {0};
result.buffer_type = MYSQL_TYPE_LONG_BLOB;
unsigned long total_length = 0;
result.length = &total_length;
ret = mysql_stmt_bind_result(stmt, &result);
if (ret) {
printf("mysql_stmt_bind_result : %s\n", mysql_error(handle));
return -3;
}
ret = mysql_stmt_execute(stmt);
if (ret) {
printf("mysql_stmt_execute : %s\n", mysql_error(handle));
return -4;
}
ret = mysql_stmt_store_result(stmt);
if (ret) {
printf("mysql_stmt_store_result : %s\n", mysql_error(handle));
return -5;
}
while (1) {
ret = mysql_stmt_fetch(stmt);
if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) break; //
int start = 0;
while (start < (int)total_length) {
result.buffer = buffer + start;
result.buffer_length = 1;
mysql_stmt_fetch_column(stmt, &result, 0, start);
start += result.buffer_length;
}
}
mysql_stmt_close(stmt);
return total_length;
}
void coroutine_func(void *arg) {
MYSQL mysql;
printf("coroutine_func\n");
if (NULL == mysql_init(&mysql)) {
printf("mysql_init : %s\n", mysql_error(&mysql));
return ;
}
if (!mysql_real_connect(&mysql, KING_DB_SERVER_IP, KING_DB_USERNAME, KING_DB_PASSWORD,
KING_DB_DEFAULTDB, KING_DB_SERVER_PORT, NULL, 0)) {
printf("mysql_real_connect : %s\n", mysql_error(&mysql));
goto Exit;
}
// mysql --> insert
printf("case 1 : mysql --> insert \n");
#if 1
if (mysql_real_query(&mysql, SQL_INSERT_TBL_USER, strlen(SQL_INSERT_TBL_USER))) {
printf("mysql_real_query : %s\n", mysql_error(&mysql));
goto Exit;
}
#endif
king_mysql_select(&mysql);
// mysql --> delete
printf("case 2 : mysql --> delete \n");
#if 1
if (mysql_real_query(&mysql, SQL_DELETE_TBL_USER, strlen(SQL_DELETE_TBL_USER))) {
printf("mysql_real_query : %s\n", mysql_error(&mysql));
goto Exit;
}
#endif
king_mysql_select(&mysql);
printf("case 3 : mysql --> read image and write mysql\n");
char buffer[FILE_IMAGE_LENGTH] = {0};
int length = read_image("0voice.jpg", buffer);
if (length < 0) goto Exit;
mysql_write(&mysql, buffer, length); ///
printf("case 4 : mysql --> read mysql and write image\n");
memset(buffer, 0, FILE_IMAGE_LENGTH);
length = mysql_read(&mysql, buffer, FILE_IMAGE_LENGTH);
write_image("a.jpg", buffer, length);
Exit:
mysql_close(&mysql);
return ;
}
int main() {
#if 1
//init_hook();
nty_coroutine *co = NULL;
nty_coroutine_create(&co, coroutine_func, NULL);
nty_schedule_run(); //run
#else
coroutine_func(NULL);
#endif
}

View File

@@ -1,108 +0,0 @@
#include "nty_coroutine.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
void coroutine_func(void *arg) {
unsigned int j, isunix = 0;
redisContext *c;
redisReply *reply;
const char *hostname = "192.168.233.133";
int port = 6379;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
if (isunix) {
c = redisConnectUnixWithTimeout(hostname, timeout);
} else {
c = redisConnectWithTimeout(hostname, port, timeout);
}
if (c == NULL || c->err) {
if (c) {
printf("Connection error: %s\n", c->errstr);
redisFree(c);
} else {
printf("Connection error: can't allocate redis context\n");
}
exit(1);
}
/* PING server */
reply = redisCommand(c,"PING");
printf("PING: %s\n", reply->str);
freeReplyObject(reply);
/* Set a key */
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
printf("SET: %s\n", reply->str);
freeReplyObject(reply);
/* Set a key using binary safe API */
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
printf("SET (binary API): %s\n", reply->str);
freeReplyObject(reply);
/* Try a GET and two INCR */
reply = redisCommand(c,"GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* again ... */
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* Create a list of numbers, from 0 to 9 */
reply = redisCommand(c,"DEL mylist");
freeReplyObject(reply);
for (j = 0; j < 10; j++) {
char buf[64];
snprintf(buf,64,"%u",j);
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
freeReplyObject(reply);
}
/* Let's check what we have inside the list */
reply = redisCommand(c,"LRANGE mylist 0 -1");
if (reply->type == REDIS_REPLY_ARRAY) {
for (j = 0; j < reply->elements; j++) {
printf("%u) %s\n", j, reply->element[j]->str);
}
}
freeReplyObject(reply);
/* Disconnects and frees the context */
redisFree(c);
return ;
}
int main(int argc, char **argv) {
//init_hook();
nty_coroutine *co = NULL;
nty_coroutine_create(&co, coroutine_func, NULL);
nty_schedule_run(); //run
}

View File

@@ -1,150 +0,0 @@
/*
* 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"
#include <arpa/inet.h>
#define MAX_CLIENT_NUM 1000000
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
void server_reader(void *arg) {
int fd = *(int *)arg;
free(arg);
int ret = 0;
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN;
while (1) {
char buf[1024] = {0};
ret = nty_recv(fd, buf, 1024, 0);
if (ret > 0) {
if(fd > MAX_CLIENT_NUM)
printf("read from server: %.*s\n", ret, buf);
ret = nty_send(fd, buf, strlen(buf), 0);
if (ret == -1) {
nty_close(fd);
break;
}
} else if (ret == 0) {
nty_close(fd);
break;
}
}
}
void server(void *arg) {
unsigned short port = *(unsigned short *)arg;
free(arg);
int fd = nty_socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return ;
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in));
listen(fd, 20);
printf("listen port : %d\n", port);
struct timeval tv_begin;
gettimeofday(&tv_begin, NULL);
while (1) {
socklen_t len = sizeof(struct sockaddr_in);
int cli_fd = nty_accept(fd, (struct sockaddr*)&remote, &len);
if (cli_fd % 1000 == 999) {
struct timeval tv_cur;
memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
gettimeofday(&tv_begin, NULL);
int time_used = TIME_SUB_MS(tv_begin, tv_cur);
printf("client fd : %d, time_used: %d\n", cli_fd, time_used);
}
printf("new client comming\n");
nty_coroutine *read_co;
int *arg = malloc(sizeof(int));
*arg = cli_fd;
nty_coroutine_create(&read_co, server_reader, arg);
}
}
int main(int argc, char *argv[]) {
nty_coroutine *co = NULL;
int i = 0;
unsigned short base_port = 9096;
for (i = 0;i < 100;i ++) {
unsigned short *port = calloc(1, sizeof(unsigned short));
*port = base_port + i;
nty_coroutine_create(&co, server, port); ////////no run
}
nty_schedule_run(); //run
return 0;
}

View File

@@ -1,351 +0,0 @@
/*
* 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 <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <sys/syscall.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define __USE_GNU
#include <sched.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include "nty_coroutine.h"
static int global_shmid = -1;
static int global_semid = -1;
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
typedef struct _shm_area {
int total;
int lock;
struct timeval tv_begin;
} shm_area;
static shm_area *global_shmaddr = NULL;
#define MAX_CLIENT_NUM 1000000
struct timeval* get_shm_timevalue(void);
void set_shm_timevalue(struct timeval *tv);
int add_shmvalue(void);
int sub_shmvalue(void);
int init_shmvalue(void);
unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) {
unsigned long prev;
volatile unsigned int *_ptr = (volatile unsigned int *)(addr);
switch (size) {
case 1: {
__asm__ volatile (
"lock; cmpxchgb %b1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 2: {
__asm__ volatile (
"lock; cmpxchgw %w1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 4: {
__asm__ volatile (
"lock; cmpxchg %1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
}
return prev;
}
#define SERVER_STRING "Server: ntyco\r\n"
int headers(char *buffer)
{
strcat(buffer, "HTTP/1.0 200 OK\r\n");
strcat(buffer, SERVER_STRING);
strcat(buffer, "Content-Type: text/html\r\n");
strcat(buffer, "\r\n");
return strlen(buffer);
}
int body(char *buffer) {
strcat(buffer, "<html><h1> coroutine --> ntyco<h1></html>");
return strlen(buffer);
}
void server_reader(void *arg) {
int fd = *(int *)arg;
int ret = 0;
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN;
while (1) {
char buf[1024] = {0};
ret = nty_recv(fd, buf, 1024, 0);
if (ret > 0) {
if(fd > MAX_CLIENT_NUM)
printf("read from server: %.*s\n", ret, buf);
memset(buf, 0, 1024);
int hlen = headers(buf);
int blen = body(buf+hlen);
ret = nty_send(fd, buf, strlen(buf), 0);
if (ret == -1) {
nty_close(fd);
sub_shmvalue();
break;
}
} else if (ret == 0) {
nty_close(fd);
sub_shmvalue();
break;
}
}
}
void server(void *arg) {
unsigned short port = *(unsigned short *)arg;
free(arg);
int fd = nty_socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return ;
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in));
listen(fd, 20);
printf("listen port : %d\n", port);
while (1) {
socklen_t len = sizeof(struct sockaddr_in);
int cli_fd = nty_accept(fd, (struct sockaddr*)&remote, &len);
printf("new client comming\n");
nty_coroutine *read_co;
nty_coroutine_create(&read_co, server_reader, &cli_fd);
int value = add_shmvalue();
if (value % 1000 == 999) {
struct timeval *tv_begin = get_shm_timevalue();
struct timeval tv_cur;
memcpy(&tv_cur, tv_begin, sizeof(struct timeval));
gettimeofday(tv_begin, NULL);
int time_used = TIME_SUB_MS((*tv_begin), tv_cur);
printf("client sum: %d, time_used: %d\n", value, time_used);
}
}
}
int mulcore_entry(int begin_port) {
nty_coroutine *co = NULL;
int i = 0;
unsigned short base_port = begin_port;
//for (i = 0;i < 10;i ++) {
unsigned short *port = calloc(1, sizeof(unsigned short));
*port = base_port + i;
nty_coroutine_create(&co, server, port); ////////no run
//}
nty_schedule_run(); //run
}
int process_bind(void) {
int num = sysconf(_SC_NPROCESSORS_CONF);
pid_t self_id = syscall(__NR_gettid);
//printf("selfid --> %d\n", self_id);
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(self_id % num, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
mulcore_entry(9096);
}
struct timeval* get_shm_timevalue(void) {
return global_shmaddr ? &global_shmaddr->tv_begin : NULL;
}
void set_shm_timevalue(struct timeval *tv) {
if (global_shmaddr == NULL || tv == NULL) {
return ;
}
memcpy(&global_shmaddr->tv_begin, tv, sizeof(struct timeval));
}
int add_shmvalue(void) {
int value = 0;
int ret = -1;
do {
value = global_shmaddr->total;
ret = cmpxchg(&global_shmaddr->total, (unsigned long)value, (unsigned long)(value+1), 4);
} while (ret != value);
return global_shmaddr->total;
}
int sub_shmvalue(void) {
int value = 0;
int ret = -1;
do {
value = global_shmaddr->total;
ret = cmpxchg(&global_shmaddr->total, (unsigned long)value, (unsigned long)(value-1), 4);
} while (ret != value);
return global_shmaddr->total;
}
int init_shmvalue(void) {
global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600);
if (global_shmid < 0) {
perror("shmget failed\n");
return -1;
}
global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0);
if (global_shmaddr == (shm_area*)-1) {
perror("shmat addr error");
return -1;
}
global_shmaddr->total = 0;
gettimeofday(&global_shmaddr->tv_begin, NULL);
}
int main(int argc, char *argv[]) {
int ret = init_shmvalue();
if (ret == -1) {
printf("init share memory failed\n");
return -1;
}
fork();
fork();
//fork();
//fork();
//fork();
process_bind();

View File

@@ -1,377 +0,0 @@
#include "nty_coroutine.h"
#include <arpa/inet.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#define MAX_CLIENT_NUM 1000000
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
#define NTY_WEBSOCKET_SERVER_PORT 9096
#define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define MAX_BUFFER_LENGTH 1024
struct _nty_ophdr {
unsigned char opcode:4,
rsv3:1,
rsv2:1,
rsv1:1,
fin:1;
unsigned char payload_length:7,
mask:1;
} __attribute__ ((packed));
struct _nty_websocket_head_126 {
unsigned short payload_length;
char mask_key[4];
unsigned char data[8];
} __attribute__ ((packed));
struct _nty_websocket_head_127 {
unsigned long long payload_length;
char mask_key[4];
unsigned char data[8];
} __attribute__ ((packed));
#define UNION_HEADER(type1, type2) \
struct { \
struct type1 hdr; \
struct type2 len; \
}
typedef struct _nty_websocket_head_127 nty_websocket_head_127;
typedef struct _nty_websocket_head_126 nty_websocket_head_126;
typedef struct _nty_ophdr nty_ophdr;
static int ntySetNonblock(int fd) {
int flags;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return flags;
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) return -1;
return 0;
}
static int ntySetBlock(int fd)
{
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) return flags;
flags &=~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0) return -1;
return 0;
}
int base64_encode(char *in_str, int in_len, char *out_str) {
BIO *b64, *bio;
BUF_MEM *bptr = NULL;
size_t size = 0;
if (in_str == NULL || out_str == NULL)
return -1;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_write(bio, in_str, in_len);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bptr);
memcpy(out_str, bptr->data, bptr->length);
out_str[bptr->length-1] = '\0';
size = bptr->length;
BIO_free_all(bio);
return size;
}
int readline(char* allbuf,int level,char* linebuf){
int len = strlen(allbuf);
for (;level < len; ++level) {
if(allbuf[level]=='\r' && allbuf[level+1]=='\n')
return level+2;
else
*(linebuf++) = allbuf[level];
}
return -1;
}
void umask(char *data,int len,char *mask){
int i;
for (i = 0;i < len;i ++)
*(data+i) ^= *(mask+(i%4));
}
char* decode_packet(unsigned char *stream, char *mask, int length, int *ret) {
nty_ophdr *hdr = (nty_ophdr*)stream;
unsigned char *data = stream + sizeof(nty_ophdr);
int size = 0;
int start = 0;
//char mask[4] = {0};
int i = 0;
if ((hdr->mask & 0x7F) == 126) {
nty_websocket_head_126 *hdr126 = (nty_websocket_head_126*)data;
size = hdr126->payload_length;
for (i = 0;i < 4;i ++) {
mask[i] = hdr126->mask_key[i];
}
start = 8;
} else if ((hdr->mask & 0x7F) == 127) {
nty_websocket_head_127 *hdr127 = (nty_websocket_head_127*)data;
size = hdr127->payload_length;
for (i = 0;i < 4;i ++) {
mask[i] = hdr127->mask_key[i];
}
start = 14;
} else {
size = hdr->payload_length;
memcpy(mask, data, 4);
start = 6;
}
*ret = size;
umask(stream+start, size, mask);
return stream + start;
}
int encode_packet(char *buffer,char *mask, char *stream, int length) {
nty_ophdr head = {0};
head.fin = 1;
head.opcode = 1;
int size = 0;
if (length < 126) {
head.payload_length = length;
memcpy(buffer, &head, sizeof(nty_ophdr));
size = 2;
} else if (length < 0xffff) {
nty_websocket_head_126 hdr = {0};
hdr.payload_length = length;
memcpy(hdr.mask_key, mask, 4);
memcpy(buffer, &head, sizeof(nty_ophdr));
memcpy(buffer+sizeof(nty_ophdr), &hdr, sizeof(nty_websocket_head_126));
size = sizeof(nty_websocket_head_126);
} else {
nty_websocket_head_127 hdr = {0};
hdr.payload_length = length;
memcpy(hdr.mask_key, mask, 4);
memcpy(buffer, &head, sizeof(nty_ophdr));
memcpy(buffer+sizeof(nty_ophdr), &hdr, sizeof(nty_websocket_head_127));
size = sizeof(nty_websocket_head_127);
}
memcpy(buffer+2, stream, length);
return length + 2;
}
void server_reader(void *arg) {
int fd = *(int *)arg;
int length = 0;
int ret = 0;
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN;
while (1) {
char stream[MAX_BUFFER_LENGTH] = {0};
length = nty_recv(fd, stream, MAX_BUFFER_LENGTH, 0);
if (length > 0) {
if(fd > MAX_CLIENT_NUM)
printf("read from server: %.*s\n", length, stream);
char mask[4] = {0};
char *data = decode_packet(stream, mask, length, &ret);
printf(" data : %s , length : %d\n", data, ret);
#if 1
char buffer[MAX_BUFFER_LENGTH+14] = {0};
ret = encode_packet(buffer, mask, data, ret);
ret = nty_send(fd, buffer, ret, 0);
#endif
} else if (length == 0) {
nty_close(fd);
break;
}
}
}
int handshake(int cli_fd) {
int level = 0;
char buffer[MAX_BUFFER_LENGTH];
char linebuf[128]; //Sec-WebSocket-Accept
char sec_accept[32] = {0}; //sha1 data
unsigned char sha1_data[SHA_DIGEST_LENGTH+1] = {0}; //reponse head buffer
//char head[MAX_BUFFER_LENGTH] = {0};
#if 1
if (read(cli_fd, buffer, sizeof(buffer))<=0)
perror("read");
#else
int ret = 0;
int length = recv_buffer(cli_fd, buffer, MAX_BUFFER_LENGTH, &ret);
if (ret < 0) perror("read");
#endif
printf("request\n");
printf("%s\n",buffer);
do {
memset(linebuf, 0, sizeof(linebuf));
level = readline(buffer,level,linebuf);
if (strstr(linebuf,"Sec-WebSocket-Key") != NULL) {
strcat(linebuf, GUID);
SHA1((unsigned char*)&linebuf+19,strlen(linebuf+19),(unsigned char*)&sha1_data);
memset(buffer, 0, MAX_BUFFER_LENGTH);
base64_encode(sha1_data,strlen(sha1_data),sec_accept);
sprintf(buffer, "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade: websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: %s\r\n" \
"\r\n", sec_accept);
printf("response\n");
printf("%s",buffer);
#if 1
if (write(cli_fd, buffer, strlen(buffer)) < 0)
perror("write");
#else
length = send_buffer(cli_fd, head, strlen(head));
assert(length == strlen(head));
#endif
printf("accept : %s\n", sec_accept);
break;
}
}while((buffer[level]!='\r' || buffer[level+1]!='\n') && level!=-1);
return 0;
}
int init_server(void) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("socket failed\n");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(NTY_WEBSOCKET_SERVER_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
printf("bind failed\n");
return -2;
}
if (listen(sockfd, 5) < 0) {
printf("listen failed\n");
return -3;
}
return sockfd;
}
void server(void *arg) {
int sockfd = init_server();
struct timeval tv_begin;
gettimeofday(&tv_begin, NULL);
while (1) {
socklen_t len = sizeof(struct sockaddr_in);
struct sockaddr_in remote;
int cli_fd = nty_accept(sockfd, (struct sockaddr*)&remote, &len);
if (cli_fd % 1000 == 999) {
struct timeval tv_cur;
memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
gettimeofday(&tv_begin, NULL);
int time_used = TIME_SUB_MS(tv_begin, tv_cur);
printf("client fd : %d, time_used: %d\n", cli_fd, time_used);
}
printf("new client comming\n");
ntySetBlock(cli_fd);
handshake(cli_fd);
ntySetNonblock(cli_fd);
nty_coroutine *read_co = NULL;
nty_coroutine_create(&read_co, server_reader, &cli_fd);
}
}
int main() {
nty_coroutine *co = NULL;
nty_coroutine_create(&co, server, NULL);
nty_schedule_run();
}

View File

@@ -1,536 +0,0 @@
/*
* 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 <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <sys/syscall.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/poll.h>
#define __USE_GNU
#include <sched.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include "nty_coroutine.h"
#define MAX_CLIENT_NUM 1000000
#define TOTALFDS 16
typedef struct _shm_area {
int totalfds[TOTALFDS];
char cpu_lb[TOTALFDS];
//mtx : default 0
// 1 : lock -- del epoll
// 2 : lock -- del complete
// 3 : unlock -- add
// 0 : unlock -- add complete
int accept_mtx;
} shm_area;
static shm_area *global_shmaddr = NULL;
static int global_shmid = -1;
int cpu_size = 0;
int accept_disable = 1000;
int enable_accept = 1;
pid_t self_id = 0;
unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) {
unsigned long prev;
volatile unsigned int *_ptr = (volatile unsigned int *)(addr);
switch (size) {
case 1: {
__asm__ volatile (
"lock; cmpxchgb %b1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 2: {
__asm__ volatile (
"lock; cmpxchgw %w1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
case 4: {
__asm__ volatile (
"lock; cmpxchg %1, %2"
: "=a" (prev)
: "r" (_new), "m" (*_ptr), "0" (_old)
: "memory");
break;
}
}
return prev;
}
int atomic_add(volatile int *value, int add)
{
__asm__ volatile (
"lock;"
" addl %0, %1; "
: "+r" (add) : "m" (*value) : "cc", "memory");
return add;
}
int atomic_sub(volatile int *value, int sub)
{
__asm__ volatile (
"lock;"
" subl %0, %1; "
: "+r" (sub) : "m" (*value) : "cc", "memory");
return sub;
}
#define ISspace(x) isspace((int)(x))
#define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n"
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define ENABLE_NTYCO 0
#if ENABLE_NTYCO
#define socket nty_socket
#define accept nty_accept
#define recv(a, b, c, d) nty_recv(a, b, c, d)
#define send(a, b, c, d) nty_send(a, b, c, d)
#define MAX_BUFFER_LENGTH 1024
#endif
#define INC_COUNTFD do { \
atomic_add(&global_shmaddr->totalfds[self_id % cpu_size], 1); \
} while (0)
#define DEC_COUNTFD do { \
atomic_sub(&global_shmaddr->totalfds[self_id % cpu_size], 1); \
} while (0)
int get_countfd(void) {
return global_shmaddr->totalfds[self_id % cpu_size];
}
int max_countfd(void) {
int count = -1;
int i = 0;
for (i = 0;i < cpu_size;i ++) {
if (count < global_shmaddr->totalfds[i]) {
count = global_shmaddr->totalfds[i];
}
}
return count;
}
int min_countfd(void) {
int count = 0xffffffff;
int i = 0;
for (i = 0;i < cpu_size;i ++) {
if (count > global_shmaddr->totalfds[i]) {
count = global_shmaddr->totalfds[i];
}
}
return count;
}
int compare_out_countfd(void) {
int current = get_countfd();
int min = min_countfd();
if ((current * 7 / 8) > min) {
return 1;
} else {
return 0;
}
}
int compare_in_countfd(void) {
int current = get_countfd();
int max = max_countfd();
if ((current * 8 / 7) < max) {
return 1;
} else {
return 0;
}
}
void print_countfds(void) {
int i = 0;
for (i = 0;i < cpu_size;i ++) {
printf("%5d : %5d ", i, global_shmaddr->totalfds[i]);
}
printf("\n");
}
void lock_accept(void) {
global_shmaddr->cpu_lb[self_id % cpu_size] = 1;
int count = 0xffffffff;
int i = 0;
for (i = 0;i < cpu_size;i ++) {
if (count > global_shmaddr->totalfds[i]) {
count = global_shmaddr->totalfds[i];
}
}
for (i = 0;i < cpu_size;i ++) {
if (count == global_shmaddr->totalfds[i]) {
global_shmaddr->cpu_lb[i] = 3;
}
}
}
char read_accept(void) {
return global_shmaddr->cpu_lb[self_id % cpu_size];
}
void write_accept(char state) { //0, 1, 2, 3
global_shmaddr->cpu_lb[self_id % cpu_size] = state;
}
int lock(void) {
return cmpxchg(&global_shmaddr->accept_mtx, 0, 1, 4); //zero:success, non-zero:failed
}
void unlock(void) {
global_shmaddr->accept_mtx = 0;
}
void accept_request(void *arg);
void bad_request(int);
void cat(int);
void cannot_execute(int);
void error_die(const char *);
void execute_cgi(int, const char *, const char *, const char *);
int get_line(int, char *, int);
void headers(int);
void not_found(int);
void serve_file(int);
int startup(u_short *);
void unimplemented(int);
void accept_request(void* arg)
{
int client = *(int*)arg;
char buf[1024];
size_t numchars;
char method[16];
char url[32];
char path[64];
size_t i, j;
struct stat st;
int cgi = 0; /* becomes true if server decides this is a CGI
* program */
char *query_string = NULL;
while (1) {
numchars = nty_recv(client, buf, sizeof(buf), 0);
if (numchars > 0) {
serve_file(client);
} else if (numchars == 0) {
nty_close(client);
DEC_COUNTFD;
break;
} else if (numchars == -1) {
if (errno == EAGAIN) {
continue;
}
nty_close(client);
DEC_COUNTFD;
break;
}
}
}
#define HTML_PAGE "<!DOCTYPE html> \
<html> \
<head> \
<title>Welcome to nginx!</title> \
<style> \
body { \
width: 35em;\
margin: 0 auto;\
font-family: Tahoma, Verdana, Arial, sans-serif;\
}\
</style>\
</head>\
<body>\
<h1>Welcome to nginx!</h1>\
<p>If you see this page, the nginx web server is successfully installed and\
working. Further configuration is required.</p>\
\
<p>For online documentation and support please refer to\
<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\
Commercial support is available at\
<a href=\"http://nginx.com/\">nginx.com</a>.</p>\
\
<p><em>Thank you for using nginx.</em></p>\
</body>\
</html>"
void error_die(const char *sc)
{
printf("%s\n", sc);
exit(1);
}
void headers(int client)
{
char buf[1024] = {0};
char content[128] = {0};
sprintf(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, SERVER_STRING);
strcat(buf, "Content-Type: text/html\r\n");
#if 0
strcat(buf, "Transfer-Encoding: chunked\r\n");
#else
sprintf(content, "Content-Length: %ld\r\n", strlen(HTML_PAGE));
strcat(buf, content);
#endif
strcat(buf, "\r\n");
strcat(buf, HTML_PAGE);
int ret = nty_send(client, buf, strlen(buf), 0);
if (ret == -1) {
printf("send : errno : %d\n", errno);
} else {
//printf("headers send ret : %d\n", ret);
}
}
void serve_file(int client)
{
headers(client);
}
#define MAX_EPOLLSIZE 10240
void server(void *arg) {
int fd = *(int *)arg;
while (1) {
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
if (lock()) {
nty_coroutine_sleep(0);
continue;
}
int clientfd = nty_accept(fd, (struct sockaddr*)&client_addr, &client_len);
unlock();
if (clientfd < 0) {
return ;
}
INC_COUNTFD;
nty_coroutine *read_co;
int *client_sock = (int *)malloc(sizeof(int));
*client_sock = clientfd;
nty_coroutine_create(&read_co, accept_request, client_sock);
print_countfds();
}
}
int process_bind(int fd) {
int num = sysconf(_SC_NPROCESSORS_CONF);
self_id = syscall(__NR_gettid);
//printf("selfid --> %d\n", self_id);
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(self_id % num, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
nty_coroutine *co = NULL;
nty_coroutine_create(&co, server, &fd);
nty_schedule_run();
}
int init_shmvalue(int num) {
global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600);
if (global_shmid < 0) {
perror("shmget failed\n");
return -1;
}
global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0);
if (global_shmaddr == (shm_area*)-1) {
perror("shmat addr error");
return -1;
}
memset(global_shmaddr->totalfds, 0, TOTALFDS * sizeof(int));
memset(global_shmaddr->cpu_lb, 0, TOTALFDS * sizeof(char));
global_shmaddr->accept_mtx = 0;
}
int main(int argc, char *argv[]) {
short port = 9001;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name);
int fd = nty_socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) return -1;
struct sockaddr_in local, remote;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in));
listen(fd, 5);
int num = sysconf(_SC_NPROCESSORS_CONF);
cpu_size = num;
init_shmvalue(num);
int i = 0;
pid_t pid = 0;
for(i = 0;i < num;i ++) {
pid = fork();
if(pid <= (pid_t) 0)
{
usleep(1);
break;
}
}
if (pid > 0) {
printf("ntyco_httpd server running ...\n");
getchar();
} else if (pid == 0) {
process_bind(fd);
}
}

View File

@@ -1,52 +0,0 @@
<button onclick="svc_connectPlatform()"> connect</button>
<button onclick="svc_send('hello, websocket')"> send</button>
<script>
function svc_connectPlatform() {
//alert("");
var wsServer = 'ws://192.168.189.128:9096/';
try {
svc_websocket = new WebSocket(wsServer);
} catch (evt) {
console.log("new WebSocket error:" + evt.data);
svc_websocket = null;
if (typeof(connCb) != "undefined" && connCb != null)
connCb("-1", "connect error!");
return;
}
//alert("");
svc_websocket.onopen = svc_onOpen;
svc_websocket.onclose = svc_onClose;
svc_websocket.onmessage = svc_onMessage;
svc_websocket.onerror = svc_onError;
}
function svc_onOpen(evt) {
console.log("Connected to WebSocket server.");
}
function svc_onClose(evt) {
console.log("Disconnected");
}
function svc_onMessage(evt) {
alert('Retrieved data from server: ' + evt.data);
}
function svc_onError(evt) {
console.log('Error occured: ' + evt.data);
}
function svc_send(msg) {
if (svc_websocket.readyState == WebSocket.OPEN) {
svc_websocket.send(msg);
} else {
console.log("send failed. websocket not open. please check.");
}
}
</script>

View File

@@ -2,29 +2,17 @@
## 需求
1. ntyco需要作为kvstore的submodule,通过git clone一次下载。 **完成**
2. README需要包含编译步骤测试方案与可行性性能数据。
2. README需要包含编译步骤测试方案与可行性性能数据。 **完成**
3. 全量持久化保存数据集。 **BUG FIX完成**
4. 持久化的性能数据。
5. 特殊字符可以解决redis的resp协议。 **完成**
```
简单字符串
+OK\r\n
错误
-ERR message\r\n
整数
:1000\r\n
批量字符串
$6\r\nfoobar\r\n
数组
*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
```
6. 实现配置文件把日志级别端口ip主从模式持久化方案。 **完成**
7. 持久化落盘用io_uring加载配置文件用mmap。
7. 持久化落盘用io_uring加载配置文件用mmap。 **完成**
8. 主从同步的性能,开启与关闭性能做到。
9. 主从同步600w条,出现的coredump。
10. 主从同步用ebpf实现。
11. 内存池测试qps与虚拟内存物理内存。
12. 实现一个内存泄露检测组件。
12. 实现一个内存泄露检测组件。 **完成**
## 环境安装与编译
@@ -33,10 +21,13 @@ $6\r\nfoobar\r\n
sudo apt install libxml2 libxml2-dev
# hiredis client
sudo apt install -y libhiredis-dev
# bpftrace
sudo apt install -y bpftrace
git clone git@gitlab.0voice.com:lianyiheng/9.1-kvstore.git
cd 9.1-kvstore/
make
```
## 测试

26
dump/kvs_dump.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef __KVS_DUMP_H__
#define __KVS_DUMP_H__
#include "kvstore.h"
extern char global_oplog_file[256];
extern char global_array_file[256];
extern char global_rbtree_file[256];
extern char global_hash_file[256];
int kvs_create_snapshot(const char* array_file, const char* rbtree_file, const char* hash_file);
int kvs_create_snapshot_async(const char *ip, int port);
void __create_snapshot_ok(const char* array_file, const char* rbtree_file, const char* hash_file);
extern int global_oplog_fd;
int init_cmd_log(const char *file, int *logfd);
int destroy_cmd_log(int logfd);
int kvs_oplog_append(const uint8_t *cmd, size_t len, int logfd);
int kvs_replay_log(int logfd);
int ksv_clear_log(int logfd);
#endif

View File

@@ -1,4 +1,4 @@
#include "kvstore.h"
#include "kvs_dump.h"
#include "kvs_rw_tools.h"
#include "memory/alloc_dispatch.h"
#include "kvs_protocol_resp.h"
@@ -7,7 +7,7 @@
#include <fcntl.h>
#include <unistd.h>
int global_cmd_log_fd = -1;
int global_oplog_fd = -1;
static off_t g_log_off = -1;
int init_cmd_log(const char *file, int *logfd){
@@ -24,7 +24,7 @@ int init_cmd_log(const char *file, int *logfd){
int destroy_cmd_log(int logfd){
fsync(logfd);
close(logfd);
global_cmd_log_fd = -1;
global_oplog_fd = -1;
return 0;
}

78
dump/kvs_snapshot.c Normal file
View File

@@ -0,0 +1,78 @@
#include "kvstore.h"
#include <unistd.h>
char global_oplog_file[256] = "kvs_oplog.default.db";
char global_array_file[256] = "kvs_array.default.db";
char global_rbtree_file[256] = "kvs_rbtree.default.db";
char global_hash_file[256] = "kvs_hash.default.db";
int kvs_create_snapshot(const char* array_file, const char* rbtree_file, const char* hash_file){
int ret = 0;
int rc = 0;
#if ENABLE_ARRAY
rc = kvs_array_save(&global_array, array_file);
if(rc < 0){
printf("kvs_engine_array save error\n");
ret = -1;
}
#endif
#if ENABLE_RBTREE
rc = kvs_rbtree_save(&global_rbtree, rbtree_file);
if(rc < 0){
printf("kvs_engine_rbtree save error\n");
ret = -1;
}
#endif
#if ENABLE_HASH
rc = kvs_hash_save(&global_hash, hash_file);
if(rc < 0){
printf("kvs_engine_hash save error\n");
ret = -1;
}
#endif
return ret;
}
void __create_snapshot_ok(const char* array_file, const char* rbtree_file, const char* hash_file){
}
int kvs_create_snapshot_async(const char *ip, int port){
int pipefd[2]; // 用于子进程通知主进程
if (pipe(pipefd) == -1) { perror("pipe"); return -1; }
pid_t pid = fork();
if (pid == -1) { perror("fork"); return -1; }
if (pid == 0) { // 子进程
close(pipefd[0]); // 关闭读端
// 指定临时文件路径,避免覆盖 global_xxx_file
char tmp_array[128]; // 可写缓冲区
char tmp_rbtree[128];
char tmp_hash[128];
snprintf(tmp_array, sizeof(tmp_array), "snapshot_array_%s.tmp", ip);
snprintf(tmp_rbtree, sizeof(tmp_rbtree), "snapshot_rbtree_%s.tmp", ip);
snprintf(tmp_hash, sizeof(tmp_hash), "snapshot_hash_%s.tmp", ip);
int ret = kvs_create_snapshot(tmp_array, tmp_rbtree, tmp_hash);
if (ret == 0) {
// 成功rename 到最终路径,或直接通知
write(pipefd[1], "OK", 2); // 通知主进程
} else {
write(pipefd[1], "ERR", 3);
}
close(pipefd[1]);
_exit(0); // 子进程退出
// hook point
__create_snapshot_ok(tmp_array, tmp_rbtree, tmp_hash);
} else { // 主进程
close(pipefd[1]); // 关闭写端
// 立即返回,继续处理其他请求(不阻塞)
// 可以记录 pid在别处 waitpid(pid, NULL, WNOHANG) 检查完成
// 或用信号signal(SIGCHLD, handler); 在 handler 中 read(pipefd[0]) 检查 "OK"
return 0; // SYNC 响应成功,主进程继续
}
}

View File

@@ -1,14 +0,0 @@
#ifndef __KVS_INC_LOG_H__
#define __KVS_INC_LOG_H__
#include <stdint.h>
#include <stdio.h>
int init_cmd_log(const char *file, int *logfd);
int destroy_cmd_log(int logfd);
int kvs_oplog_append(const uint8_t *cmd, size_t len, int logfd);
int kvs_replay_log(int logfd);
int ksv_clear_log(int logfd);
#endif

View File

@@ -1,5 +1,6 @@
#include "kvs_protocol_resp.h"
#include "kvs_rw_tools.h"
#include "dump/kvs_dump.h"
#if ENABLE_ARRAY
extern kvs_array_t global_array;
@@ -535,12 +536,14 @@ int resp_dispatch(const resp_cmd_t *cmd, resp_value_t *out_value) {
/* ---------------- misc ---------------- */
case KVS_CMD_SAVE: {
if (cmd->argc != 1) { *out_value = resp_error("ERR wrong number of arguments for 'save'"); return 0; }
int r = kvs_save_to_file();
int r = kvs_create_snapshot(global_array_file, global_rbtree_file, global_hash_file);
if(r == 0) ksv_clear_log(global_oplog_fd);
if (r < 0) { *out_value = resp_error("ERR save failed"); return 0; }
*out_value = resp_simple("OK");
return 0;
}
case KVS_CMD_PSYNC:
kvs_create_snapshot_async(cmd->argv[1].ptr, atoi(cmd->argv[2].ptr));
*out_value = resp_simple("OK");
return 0;
default:

View File

@@ -1,6 +1,5 @@
#include "kvs_rw_tools.h"
#include "memory/alloc_dispatch.h"
#include "kvs_oplog.h"
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
@@ -17,7 +16,7 @@ extern kvs_rbtree_t global_rbtree;
extern kvs_hash_t global_hash;
#endif
extern int global_cmd_log_fd;
extern int global_oplog_fd;
#include <errno.h>
int write_full(int fd, const void *buf, size_t len)

View File

@@ -1,84 +1,110 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "server.h"
#include <arpa/inet.h>
static int kvs_write_u8(uint8_t **pp, uint8_t v) {
uint8_t *p = *pp;
*p = v;
*pp = p + 1;
/* 创建并监听用于接收快照的 TCP 监听 socket成功返回 listen fd失败返回 -1 */
static int create_listen_socket(const char *ip, int port){
}
/* 主动连接 master 指定地址用于控制面通信SSYNC / SREADY返回连接 fd 或 -1 */
static int connect_master(const char *master_ip, int master_port){
}
/* 通过控制连接向 master 发送 SSYNC 请求,声明本 slave 的快照接收地址 */
static int send_ssync(int ctrl_fd, const char *listen_ip, int listen_port){
}
/* 接收并校验 master 对 SSYNC 的确认响应(如 +OK成功返回 0 */
static int recv_ssync_ok(int ctrl_fd){
}
/* 在快照监听 socket 上阻塞等待 master 的快照发送连接,返回已建立连接的 fd */
static int accept_snapshot_conn(int listen_fd){
}
/* 从快照连接中接收完整快照数据并构建内存状态,确保快照已完全应用 */
static int recv_and_apply_snapshot(int snapshot_fd){
}
/* 通过控制连接向 master 发送 SREADY 通知表示快照已应用slave 即将进入服务态 */
int send_sready(int ctrl_fd){
}
int slave_bootstrap(
const char *listen_ip,
int listen_port,
const char *master_ip,
int master_port
) {
int listen_fd = -1;
int ctrl_fd = -1;
int snap_fd = -1;
/* 1. 监听 snapshot port */
listen_fd = create_listen_socket(listen_ip, listen_port);
if (listen_fd < 0) {
goto fail;
}
/* 2. 连接 master, 发送 SSYNC */
ctrl_fd = connect_master(master_ip, master_port);
if (ctrl_fd < 0) {
goto fail;
}
if (send_ssync(ctrl_fd, listen_ip, listen_port) < 0) {
goto fail;
}
if (recv_ssync_ok(ctrl_fd) < 0) {
goto fail;
}
close(ctrl_fd);
ctrl_fd = -1;
/* 3. accept snapshot 连接 */
snap_fd = accept_snapshot_conn(listen_fd);
if (snap_fd < 0) {
goto fail;
}
/* 4. 接收 snapshot */
if (recv_and_apply_snapshot(snap_fd) < 0) {
goto fail;
}
close(snap_fd);
snap_fd = -1;
close(listen_fd);
listen_fd = -1;
/* 5. 通知 master 快照传输完毕 */
ctrl_fd = connect_master(master_ip, master_port);
if (ctrl_fd >= 0) {
send_sready(ctrl_fd);
close(ctrl_fd);
ctrl_fd = -1;
}
/* 6. bootstrap complete */
return 0;
}
static int kvs_write_u32(uint8_t **pp, uint32_t v) {
uint8_t *p = *pp;
uint32_t be = htonl(v);
memcpy(p, &be, 4);
*pp = p + 4;
return 0;
}
static uint64_t kvs_get_log_tail_offset(void) {
int fd = open("kvs_cmd_log.db", O_RDONLY);
if (fd < 0) {
// 文件不存在:从 0 开始同步
if (errno == ENOENT) return 0;
// 其他错误:保守起见从 0 开始
return 0;
}
off_t end = lseek(fd, 0, SEEK_END);
close(fd);
if (end < 0) return 0;
return (uint64_t)end; // 指向 EOF下一次写入的位置
}
int try_connect_master(char *ip, int port){
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
int rt = 1;
while(1){
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd < 0){
continue;
}
if(0 == connect(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))){
// [OP KVS_CMD_PSYNC=15][ARGC 1][ARGLEN 4][ARG offset]
char buf[100];
char *p = buf;
kvs_write_u8((uint8_t**)&p, 15);
kvs_write_u8((uint8_t**)&p, 1);
uint64_t len = sizeof(uint64_t);
kvs_write_u32((uint8_t**)&p, len);
uint64_t offset = kvs_get_log_tail_offset();
memcpy(p, (void*)&offset, len);
p += sizeof(offset);
send(fd, buf, p-buf, 0);
recv(fd, buf, 100, 0);
return fd;
}
close(fd);
}
fail:
if (snap_fd >= 0) close(snap_fd);
if (ctrl_fd >= 0) close(ctrl_fd);
if (listen_fd >= 0) close(listen_fd);
return -1;
}

210
kvstore.c
View File

@@ -4,7 +4,7 @@
#include "kvstore.h"
#include "kvs_rw_tools.h"
#include "kvs_protocol_resp.h"
#include "kvs_oplog.h"
#include "dump/kvs_dump.h"
#include "memory/alloc_dispatch.h"
#include "common/config.h"
#include "diskuring/diskuring.h"
@@ -19,17 +19,7 @@
#include <arpa/inet.h>
#include <libxml/parser.h>
#if ENABLE_ARRAY
extern kvs_array_t global_array;
#endif
#if ENABLE_RBTREE
extern kvs_rbtree_t global_rbtree;
#endif
#if ENABLE_HASH
extern kvs_hash_t global_hash;
#endif
extern int slave_bootstrap(const char *listen_ip, int listen_port, const char *master_ip, int master_port);
#if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
extern mp_pool_t global_mempool;
@@ -37,13 +27,10 @@ extern mp_pool_t global_mempool;
AppConfig global_cfg;
extern int global_cmd_log_fd;
extern int global_oplog_fd;
extern iouring_ctx_t global_uring_ctx;
char global_oplog_file[256] = "kvs_oplog.default.db";
char global_array_file[256] = "kvs_array.default.db";
char global_rbtree_file[256] = "kvs_rbtree.default.db";
char global_hash_file[256] = "kvs_hash.default.db";
int kvs_protocol(struct conn* conn){
if (!conn) return -1;
@@ -118,24 +105,12 @@ int kvs_protocol(struct conn* conn){
}
if (is_update) {
kvs_oplog_append(p, len, global_cmd_log_fd);
kvs_oplog_append(p, len, global_oplog_fd);
}
}
}
}
/* PSYNC触发同步线程按你原来逻辑从 argv[1] 取参数) */
if (cmd.argc > 0 && cmd.argv[0].ptr &&
ascii_casecmp(cmd.argv[0].ptr, cmd.argv[0].len, "PSYNC") == 0) {
if (cmd.argc >= 2 && cmd.argv[1].ptr) {
build_thread_to_sync((const char *)cmd.argv[1].ptr, conn);
} else {
/* 如果你希望 PSYNC 无参也能触发,可以传 NULL 或空串 */
build_thread_to_sync(NULL, conn);
}
}
/* 构建响应 */
int cap = KVS_MAX_RESPONSE - out_len;
if (cap <= 0) {
@@ -153,177 +128,11 @@ int kvs_protocol(struct conn* conn){
consumed += len;
}
// slave 暂时不需要回报或者回一个new_offset
if(conn->is_from_master){
conn->wlength = 0;
return consumed;
}
*response_length = out_len;
return consumed;
}
int kvs_save_to_file(){
int ret = 0;
int rc = 0;
#if ENABLE_ARRAY
rc = kvs_array_save(&global_array, global_array_file);
if(rc < 0){
printf("kvs_engine_array save error\n");
ret = -1;
}
#endif
#if ENABLE_RBTREE
rc = kvs_rbtree_save(&global_rbtree, global_rbtree_file);
if(rc < 0){
printf("kvs_engine_rbtree save error\n");
ret = -1;
}
#endif
#if ENABLE_HASH
rc = kvs_hash_save(&global_hash, global_hash_file);
if(rc < 0){
printf("kvs_engine_hash save error\n");
ret = -1;
}
#endif
ksv_clear_log(global_cmd_log_fd);
return ret;
}
extern void sync_wakeup(int fd);
static int g_slavefd = -1;
static uint64_t g_offset = 0;
static void *sync_thread_main(void *arg) {
struct conn *conn = (struct conn*) arg;
int logfd = open(global_oplog_file, O_RDONLY);
if (logfd < 0) {
printf("open replaylog failed: %s\n", strerror(errno));
return NULL;
}
pthread_mutex_lock(&conn->g_sync_lock);
uint64_t off = g_offset;
pthread_mutex_unlock(&conn->g_sync_lock);
while (1) {
// 单槽位:等 reactor 发完再填
pthread_mutex_lock(&conn->g_sync_lock);
int busy = (conn->wlength > 0);
pthread_mutex_unlock(&conn->g_sync_lock);
if (busy) { usleep(10 * 1000); continue; }
size_t filled = 0;
int records = 0;
// 试图攒一批
while (filled < (size_t)KVS_MAX_RESPONSE && records < 128) {
// 读 len 头
uint32_t nlen = 0;
ssize_t r = pread(logfd, &nlen, sizeof(nlen), (off_t)off);
if (r == 0) {
// EOF文件当前没更多数据
break;
}
if (r < 0) {
if (errno == EINTR) continue;
printf("pread len error: %s\n", strerror(errno));
close(logfd);
return NULL;
}
if (r < (ssize_t)sizeof(nlen)) {
// 半截 lenwriter 还没写完头
break;
}
uint32_t len = ntohl(nlen);
if(len <= 0) {
printf("sync error\n");
}
// 这一条放不进本批次,就先发已有的
if (filled + len > (size_t)KVS_MAX_RESPONSE) {
break;
}
// 读 payload(cmd)
ssize_t pr = pread(logfd, conn->wbuffer + filled, len,
(off_t)(off + sizeof(nlen)));
if (pr == 0) {
// payload 还没写到
break;
}
if (pr < 0) {
if (errno == EINTR) continue;
printf("pread payload error: %s\n", strerror(errno));
close(logfd);
return NULL;
}
if (pr < (ssize_t)len) {
// 半截 payloadwriter 还没写完这一条
break;
}
// 成功拿到一条完整记录:推进
off += sizeof(nlen) + (uint64_t)len;
filled += (size_t)len;
records++;
}
if (filled > 0) {
// 提交给 reactor 发送
pthread_mutex_lock(&conn->g_sync_lock);
conn->wlength = (int)filled;
g_offset = off;
pthread_mutex_unlock(&conn->g_sync_lock);
// 唤醒 reactor 发
sync_wakeup(conn->fd); // 或 g_slavefd
continue;
}
// 没攒到任何完整记录:说明真到末尾/半条记录,等一会儿
usleep(10*1000);
}
close(logfd);
return NULL;
}
void build_thread_to_sync(const uint8_t *offset, struct conn* conn){
uint64_t off64 = 0;
memcpy(&off64, offset, 8);
pthread_mutex_lock(&conn->g_sync_lock);
g_slavefd = conn->fd;
g_offset = (uint64_t)off64;
printf("offset:%ld\n", off64);
conn->wlength = 0;
pthread_mutex_unlock(&conn->g_sync_lock);
pthread_t tid;
int rc = pthread_create(&tid, NULL, sync_thread_main, conn);
if (rc != 0) {
printf("pthread_create failed: %s\n", strerror(rc));
return;
}
pthread_detach(tid);
}
int init_kvengine(void) {
@@ -349,8 +158,8 @@ int init_kvengine(void) {
#endif
if(global_cfg.persistence == PERSIST_INCREMENTAL){
init_cmd_log(global_oplog_file, &global_cmd_log_fd);
kvs_replay_log(global_cmd_log_fd);
init_cmd_log(global_oplog_file, &global_oplog_fd);
kvs_replay_log(global_oplog_fd);
}
printf("kvengine init complete\n");
@@ -368,7 +177,7 @@ void dest_kvengine(void) {
kvs_hash_destroy(&global_hash);
#endif
destroy_cmd_log(global_cmd_log_fd);
destroy_cmd_log(global_oplog_fd);
}
void init_memory_pool(AppConfig *cfg){
@@ -477,6 +286,7 @@ int main(int argc, char *argv[]) {
if(global_cfg.mode == MODE_SLAVE){
master_ip = global_cfg.master_ip;
master_port = global_cfg.master_port;
slave_bootstrap(global_cfg.ip, port, master_ip, master_port);
}else if(global_cfg.mode == MODE_MASTER){
}
@@ -487,7 +297,7 @@ int main(int argc, char *argv[]) {
init_kvengine();
#if (NETWORK_SELECT == NETWORK_REACTOR)
reactor_start(port, kvs_protocol, master_ip, master_port); //
reactor_start(port, kvs_protocol); //
#elif (NETWORK_SELECT == NETWORK_PROACTOR)
proactor_start(port, kvs_protocol);
#elif (NETWORK_SELECT == NETWORK_NTYCO)

View File

@@ -42,12 +42,11 @@
// typedef int (*msg_handler)(char *request, int request_length, char *response, int *response_length);
typedef int (*msg_handler)(struct conn* conn);
extern int reactor_start(unsigned short port, msg_handler handler, const char *m_ip, int m_port);
extern int reactor_start(unsigned short port, msg_handler handler);
extern int proactor_start(unsigned short port, msg_handler handler);
extern int ntyco_start(unsigned short port, msg_handler handler);
extern int try_connect_master(char *ip, int port);
void build_thread_to_sync(const uint8_t *offset, struct conn* conn);
#if ENABLE_ARRAY
@@ -268,8 +267,19 @@ int kvs_hash_exist(kvs_hash_t *hash, char *key);
#endif
#endif
#if ENABLE_ARRAY
extern kvs_array_t global_array;
#endif
int kvs_save_to_file();
#if ENABLE_RBTREE
extern kvs_rbtree_t global_rbtree;
#endif
#if ENABLE_HASH
extern kvs_hash_t global_hash;
#endif
void __compeleted_cmd(const uint8_t *cmd, size_t len);
#endif

View File

@@ -31,8 +31,6 @@
// typedef int (*msg_handler)(char *request, int request_length, char *response, int *response_length);
typedef int (*msg_handler)(struct conn* conn);
extern int try_connect_master(char *ip, int port);
static msg_handler kvs_handler;
// 0 need more, -1 error, =1 suc
@@ -354,7 +352,7 @@ int r_init_server(unsigned short port) {
}
int reactor_start(unsigned short port, msg_handler handler, char *m_ip, int m_port) {
int reactor_start(unsigned short port, msg_handler handler) {
//unsigned short port = 2000;
kvs_handler = handler;
@@ -366,13 +364,6 @@ int reactor_start(unsigned short port, msg_handler handler, char *m_ip, int m_po
return -1;
}
// slave
if(m_ip != NULL){
int masterfd = try_connect_master(m_ip, m_port);
event_register(masterfd, EPOLLIN);
conn_list[masterfd].is_from_master = 1;
}
int i = 0;
for (i = 0;i < MAX_PORTS;i ++) {