├── .gitignore ├── Makefile ├── README.md ├── core ├── CMakeLists.txt ├── Makefile ├── nty_coroutine.c ├── nty_coroutine.h ├── nty_epoll.c ├── nty_queue.h ├── nty_schedule.c ├── nty_socket.c └── nty_tree.h ├── deps └── openssl-1.1.0g.tar.gz ├── htdocs ├── check.cgi ├── color.cgi └── index.html ├── sample ├── CMakeLists.txt ├── Makefile ├── hook_tcpserver.c ├── nty_bench.c ├── nty_client.c ├── nty_http_epoll.c ├── nty_http_server.c ├── nty_http_server_mulcore.c ├── nty_mysql_client.c ├── nty_mysql_oper.c ├── nty_rediscli.c ├── nty_server.c ├── nty_server_mulcore.c ├── nty_websocket_server.c └── ntyco_httpd.c └── websocket └── websocket_client.html /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | bin/ 3 | objs/ 4 | lib/ 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = gcc 3 | ECHO = echo 4 | 5 | SUB_DIR = core/ 6 | SAMPLE_DIR = sample/ 7 | ROOT_DIR = $(shell pwd) 8 | OBJS_DIR = $(ROOT_DIR)/objs 9 | BIN_DIR = $(ROOT_DIR)/bin 10 | 11 | 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 12 | 13 | LIB = libntyco.a 14 | 15 | FLAG = -lpthread -O3 -ldl -I $(ROOT_DIR)/core 16 | 17 | THIRDFLAG = -lcrypto -lssl -lmysqlclient -lhiredis -I /usr/include/mysql/ -I /usr/local/include/hiredis/ 18 | 19 | CUR_SOURCE = ${wildcard *.c} 20 | CUR_OBJS = ${patsubst %.c, %.o, %(CUR_SOURCE)} 21 | 22 | export CC BIN_DIR OBJS_DIR ROOT_IDR FLAG BIN ECHO EFLAG 23 | 24 | 25 | 26 | all : check_objs check_bin $(SUB_DIR) $(LIB) 27 | .PHONY : all 28 | 29 | bin: $(SAMPLE_DIR) $(BIN) 30 | 31 | # lib: $(SUB_DIR) $(LIB) 32 | 33 | $(SUB_DIR) : ECHO 34 | make -C $@ 35 | 36 | #DEBUG : ECHO 37 | # make -C bin 38 | 39 | ECHO : 40 | @echo $(SUB_DIR) 41 | 42 | check_objs: 43 | if [ ! -d "objs" ]; then \ 44 | mkdir -p objs; \ 45 | fi 46 | 47 | check_bin: 48 | if [ ! -d "bin" ]; then \ 49 | mkdir -p bin; \ 50 | fi 51 | 52 | 53 | 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 54 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 55 | 56 | 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 57 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 58 | 59 | 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 60 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 61 | 62 | 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 63 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 64 | 65 | 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 66 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 67 | 68 | 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 69 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG) 70 | 71 | 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 72 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG) 73 | 74 | 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 75 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG) 76 | 77 | 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 78 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) $(THIRDFLAG) 79 | 80 | 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 81 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 82 | 83 | 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 84 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 85 | 86 | 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 87 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 88 | 89 | libntyco.a : $(OBJS_DIR)/nty_socket.o $(OBJS_DIR)/nty_coroutine.o $(OBJS_DIR)/nty_epoll.o $(OBJS_DIR)/nty_schedule.o 90 | ar rcs $@ $^ 91 | 92 | clean : 93 | rm -rf $(BIN_DIR)/* $(OBJS_DIR)/* libntyco.a 94 | 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## NtyCo 2 | 3 | #### coroutine 4 | [实现原理](https://github.com/wangbojing/NtyCo/wiki/NtyCo%E7%9A%84%E5%AE%9E%E7%8E%B0) 5 | [配套视频讲解](https://it.0voice.com/p/t_pc/goods_pc_detail/goods_detail/course_2QFAeORw45TjJA1y9tq8CmdVJTQ) 6 | 7 | ## details 8 | #### coroutine FSM 9 | ![](http://bojing.wang/wp-content/uploads/2018/08/status_machine.png) 10 | 11 | #### storage structure (ready, wait, sleep, status) 12 | ![](http://bojing.wang/wp-content/uploads/2018/08/6.1.png) 13 | 14 | #### nty_server process 15 | ![](https://cos.0voice.com/nty_server_uml.png) 16 | 17 | #### compile 18 | 19 | ``` 20 | 编译ntyco的core文件与编译libntyco.a的静态库 21 | $ make 22 | 23 | // 编译sample 24 | $ make bin 25 | ``` 26 | 27 | #### err info 28 | ``` 29 | nty_mysql_oper.c:8:19: fatal error: mysql.h: No such file or directory 30 | 31 | 解决方案: 32 | # sudo apt-get install libmysqlclient-dev 33 | 34 | nty_rediscli.c:11:21: fatal error: hiredis.h: No such file or directory 35 | 36 | 解决方案: 37 | 需要编译安装hiredis: https://github.com/redis/hiredis 38 | 39 | ``` 40 | 41 | 42 | #### server 43 | ``` 44 | $ ./bin/nty_server 45 | ``` 46 | #### client 47 | ``` 48 | ./bin/nty_client 49 | ``` 50 | 51 | #### mul_process, mul_core 52 | ``` 53 | $ ./bin/nty_server_mulcore 54 | ``` 55 | #### websocket 56 | ``` 57 | $ ./bin/nty_websocket_server 58 | ``` 59 | 60 | #### bench 61 | ``` 62 | $ ./bin/nty_bench 63 | ``` 64 | ![](http://bojing.wang/wp-content/uploads/2018/08/nty_bench_ntyco.png) 65 | ![](http://bojing.wang/wp-content/uploads/2018/08/nty_bench_nginx.png) 66 | 67 | 68 | #### http server 69 | ``` 70 | $ ./bin/nty_http_server_mulcore 71 | ``` 72 | 73 | ![](http://bojing.wang/wp-content/uploads/2018/08/ntyco_ab.png)![](http://bojing.wang/wp-content/uploads/2018/08/nginx_ab.png) 74 | 75 | ##### [对应视频讲解](https://ke.qq.com/course/2705727?tuin=1bf84273) 76 | -------------------------------------------------------------------------------- /core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(. SRC) 2 | 3 | add_library(nty_core ${SRC}) 4 | -------------------------------------------------------------------------------- /core/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | CUR_SOURCE = ${wildcard *.c} 4 | 5 | CUR_OBJS = ${patsubst %.c, %.o, $(CUR_SOURCE)} 6 | 7 | all : $(SUB_DIR) $(CUR_OBJS) 8 | 9 | $(SUB_DIR) : ECHO 10 | make -C $@ 11 | 12 | $(CUR_OBJS) : %.o : %.c 13 | $(CC) -c $^ -o $(OBJS_DIR)/$@ $(FLAG) 14 | 15 | ECHO : 16 | @echo $(SUB_DIR) 17 | -------------------------------------------------------------------------------- /core/nty_coroutine.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | #include "nty_coroutine.h" 46 | 47 | pthread_key_t global_sched_key; 48 | static pthread_once_t sched_key_once = PTHREAD_ONCE_INIT; 49 | 50 | // https://github.com/halayli/lthread/blob/master/src/lthread.c#L58 51 | 52 | #ifdef _USE_UCONTEXT 53 | 54 | static void 55 | _save_stack(nty_coroutine *co) { 56 | char* top = co->sched->stack + co->sched->stack_size; 57 | char dummy = 0; 58 | assert(top - &dummy <= NTY_CO_MAX_STACKSIZE); 59 | if (co->stack_size < top - &dummy) { 60 | co->stack = realloc(co->stack, top - &dummy); 61 | assert(co->stack != NULL); 62 | } 63 | co->stack_size = top - &dummy; 64 | memcpy(co->stack, &dummy, co->stack_size); 65 | } 66 | 67 | static void 68 | _load_stack(nty_coroutine *co) { 69 | memcpy(co->sched->stack + co->sched->stack_size - co->stack_size, co->stack, co->stack_size); 70 | } 71 | 72 | static void _exec(void *lt) { 73 | nty_coroutine *co = (nty_coroutine*)lt; 74 | co->func(co->arg); 75 | co->status |= (BIT(NTY_COROUTINE_STATUS_EXITED) | BIT(NTY_COROUTINE_STATUS_FDEOF) | BIT(NTY_COROUTINE_STATUS_DETACH)); 76 | nty_coroutine_yield(co); 77 | } 78 | 79 | #else 80 | 81 | int _switch(nty_cpu_ctx *new_ctx, nty_cpu_ctx *cur_ctx); 82 | 83 | #ifdef __i386__ 84 | __asm__ ( 85 | " .text \n" 86 | " .p2align 2,,3 \n" 87 | ".globl _switch \n" 88 | "_switch: \n" 89 | "__switch: \n" 90 | "movl 8(%esp), %edx # fs->%edx \n" 91 | "movl %esp, 0(%edx) # save esp \n" 92 | "movl %ebp, 4(%edx) # save ebp \n" 93 | "movl (%esp), %eax # save eip \n" 94 | "movl %eax, 8(%edx) \n" 95 | "movl %ebx, 12(%edx) # save ebx,esi,edi \n" 96 | "movl %esi, 16(%edx) \n" 97 | "movl %edi, 20(%edx) \n" 98 | "movl 4(%esp), %edx # ts->%edx \n" 99 | "movl 20(%edx), %edi # restore ebx,esi,edi \n" 100 | "movl 16(%edx), %esi \n" 101 | "movl 12(%edx), %ebx \n" 102 | "movl 0(%edx), %esp # restore esp \n" 103 | "movl 4(%edx), %ebp # restore ebp \n" 104 | "movl 8(%edx), %eax # restore eip \n" 105 | "movl %eax, (%esp) \n" 106 | "ret \n" 107 | ); 108 | #elif defined(__x86_64__) 109 | 110 | __asm__ ( 111 | " .text \n" 112 | " .p2align 4,,15 \n" 113 | ".globl _switch \n" 114 | ".globl __switch \n" 115 | "_switch: \n" 116 | "__switch: \n" 117 | " movq %rsp, 0(%rsi) # save stack_pointer \n" 118 | " movq %rbp, 8(%rsi) # save frame_pointer \n" 119 | " movq (%rsp), %rax # save insn_pointer \n" 120 | " movq %rax, 16(%rsi) \n" 121 | " movq %rbx, 24(%rsi) # save rbx,r12-r15 \n" 122 | " movq %r12, 32(%rsi) \n" 123 | " movq %r13, 40(%rsi) \n" 124 | " movq %r14, 48(%rsi) \n" 125 | " movq %r15, 56(%rsi) \n" 126 | " movq 56(%rdi), %r15 \n" 127 | " movq 48(%rdi), %r14 \n" 128 | " movq 40(%rdi), %r13 # restore rbx,r12-r15 \n" 129 | " movq 32(%rdi), %r12 \n" 130 | " movq 24(%rdi), %rbx \n" 131 | " movq 8(%rdi), %rbp # restore frame_pointer \n" 132 | " movq 0(%rdi), %rsp # restore stack_pointer \n" 133 | " movq 16(%rdi), %rax # restore insn_pointer \n" 134 | " movq %rax, (%rsp) \n" 135 | " ret \n" 136 | ); 137 | #endif 138 | 139 | 140 | static void _exec(void *lt) { 141 | #if defined(__lvm__) && defined(__x86_64__) 142 | __asm__("movq 16(%%rbp), %[lt]" : [lt] "=r" (lt)); 143 | #endif 144 | 145 | nty_coroutine *co = (nty_coroutine*)lt; 146 | co->func(co->arg); 147 | co->status |= (BIT(NTY_COROUTINE_STATUS_EXITED) | BIT(NTY_COROUTINE_STATUS_FDEOF) | BIT(NTY_COROUTINE_STATUS_DETACH)); 148 | #if 1 149 | nty_coroutine_yield(co); 150 | #else 151 | co->ops = 0; 152 | _switch(&co->sched->ctx, &co->ctx); 153 | #endif 154 | } 155 | 156 | static inline void nty_coroutine_madvise(nty_coroutine *co) { 157 | 158 | size_t current_stack = (co->stack + co->stack_size) - co->ctx.esp; 159 | assert(current_stack <= co->stack_size); 160 | 161 | if (current_stack < co->last_stack_size && 162 | co->last_stack_size > co->sched->page_size) { 163 | size_t tmp = current_stack + (-current_stack & (co->sched->page_size - 1)); 164 | assert(madvise(co->stack, co->stack_size-tmp, MADV_DONTNEED) == 0); 165 | } 166 | co->last_stack_size = current_stack; 167 | } 168 | 169 | #endif 170 | 171 | extern int nty_schedule_create(int stack_size); 172 | 173 | 174 | 175 | void nty_coroutine_free(nty_coroutine *co) { 176 | if (co == NULL) return ; 177 | co->sched->spawned_coroutines --; 178 | #if 1 179 | if (co->stack) { 180 | free(co->stack); 181 | co->stack = NULL; 182 | } 183 | #endif 184 | if (co) { 185 | free(co); 186 | } 187 | 188 | } 189 | 190 | static void nty_coroutine_init(nty_coroutine *co) { 191 | 192 | #ifdef _USE_UCONTEXT 193 | getcontext(&co->ctx); 194 | co->ctx.uc_stack.ss_sp = co->sched->stack; 195 | co->ctx.uc_stack.ss_size = co->sched->stack_size; 196 | co->ctx.uc_link = &co->sched->ctx; 197 | // printf("TAG21\n"); 198 | makecontext(&co->ctx, (void (*)(void)) _exec, 1, (void*)co); 199 | // printf("TAG22\n"); 200 | #else 201 | void **stack = (void **)(co->stack + co->stack_size); 202 | 203 | stack[-3] = NULL; 204 | stack[-2] = (void *)co; 205 | 206 | co->ctx.esp = (void*)stack - (4 * sizeof(void*)); 207 | co->ctx.ebp = (void*)stack - (3 * sizeof(void*)); 208 | co->ctx.eip = (void*)_exec; 209 | #endif 210 | co->status = BIT(NTY_COROUTINE_STATUS_READY); 211 | 212 | } 213 | 214 | void nty_coroutine_yield(nty_coroutine *co) { 215 | co->ops = 0; 216 | #ifdef _USE_UCONTEXT 217 | if ((co->status & BIT(NTY_COROUTINE_STATUS_EXITED)) == 0) { 218 | _save_stack(co); 219 | } 220 | swapcontext(&co->ctx, &co->sched->ctx); 221 | #else 222 | _switch(&co->sched->ctx, &co->ctx); 223 | #endif 224 | } 225 | 226 | int nty_coroutine_resume(nty_coroutine *co) { 227 | 228 | if (co->status & BIT(NTY_COROUTINE_STATUS_NEW)) { 229 | nty_coroutine_init(co); 230 | } 231 | #ifdef _USE_UCONTEXT 232 | else { 233 | _load_stack(co); 234 | } 235 | #endif 236 | nty_schedule *sched = nty_coroutine_get_sched(); 237 | sched->curr_thread = co; 238 | #ifdef _USE_UCONTEXT 239 | swapcontext(&sched->ctx, &co->ctx); 240 | #else 241 | _switch(&co->ctx, &co->sched->ctx); 242 | nty_coroutine_madvise(co); 243 | #endif 244 | sched->curr_thread = NULL; 245 | 246 | #if 1 247 | if (co->status & BIT(NTY_COROUTINE_STATUS_EXITED)) { 248 | if (co->status & BIT(NTY_COROUTINE_STATUS_DETACH)) { 249 | nty_coroutine_free(co); 250 | } 251 | return -1; 252 | } 253 | #endif 254 | return 0; 255 | } 256 | 257 | 258 | void nty_coroutine_renice(nty_coroutine *co) { 259 | co->ops ++; 260 | #if 1 261 | if (co->ops < 5) return ; 262 | #endif 263 | TAILQ_INSERT_TAIL(&nty_coroutine_get_sched()->ready, co, ready_next); 264 | nty_coroutine_yield(co); 265 | } 266 | 267 | 268 | void nty_coroutine_sleep(uint64_t msecs) { 269 | nty_coroutine *co = nty_coroutine_get_sched()->curr_thread; 270 | 271 | if (msecs == 0) { 272 | TAILQ_INSERT_TAIL(&co->sched->ready, co, ready_next); 273 | nty_coroutine_yield(co); 274 | } else { 275 | nty_schedule_sched_sleepdown(co, msecs); 276 | } 277 | } 278 | 279 | void nty_coroutine_detach(void) { 280 | nty_coroutine *co = nty_coroutine_get_sched()->curr_thread; 281 | co->status |= BIT(NTY_COROUTINE_STATUS_DETACH); 282 | } 283 | 284 | static void nty_coroutine_sched_key_destructor(void *data) { 285 | free(data); 286 | } 287 | 288 | static void __attribute__((constructor(1000))) nty_coroutine_sched_key_creator(void) { 289 | assert(pthread_key_create(&global_sched_key, nty_coroutine_sched_key_destructor) == 0); 290 | assert(pthread_setspecific(global_sched_key, NULL) == 0); 291 | 292 | return ; 293 | } 294 | 295 | 296 | // coroutine --> 297 | // create 298 | // 299 | int nty_coroutine_create(nty_coroutine **new_co, proc_coroutine func, void *arg) { 300 | 301 | assert(pthread_once(&sched_key_once, nty_coroutine_sched_key_creator) == 0); 302 | nty_schedule *sched = nty_coroutine_get_sched(); 303 | 304 | if (sched == NULL) { 305 | nty_schedule_create(0); 306 | 307 | sched = nty_coroutine_get_sched(); 308 | if (sched == NULL) { 309 | printf("Failed to create scheduler\n"); 310 | return -1; 311 | } 312 | } 313 | 314 | nty_coroutine *co = calloc(1, sizeof(nty_coroutine)); 315 | if (co == NULL) { 316 | printf("Failed to allocate memory for new coroutine\n"); 317 | return -2; 318 | } 319 | 320 | #ifdef _USE_UCONTEXT 321 | co->stack = NULL; 322 | co->stack_size = 0; 323 | #else 324 | int ret = posix_memalign(&co->stack, getpagesize(), sched->stack_size); 325 | if (ret) { 326 | printf("Failed to allocate stack for new coroutine\n"); 327 | free(co); 328 | return -3; 329 | } 330 | co->stack_size = sched->stack_size; 331 | #endif 332 | co->sched = sched; 333 | co->status = BIT(NTY_COROUTINE_STATUS_NEW); // 334 | co->id = sched->spawned_coroutines ++; 335 | co->func = func; 336 | #if CANCEL_FD_WAIT_UINT64 337 | co->fd = -1; 338 | co->events = 0; 339 | #else 340 | co->fd_wait = -1; 341 | #endif 342 | co->arg = arg; 343 | co->birth = nty_coroutine_usec_now(); 344 | *new_co = co; 345 | 346 | TAILQ_INSERT_TAIL(&co->sched->ready, co, ready_next); 347 | 348 | return 0; 349 | } 350 | 351 | 352 | 353 | 354 | -------------------------------------------------------------------------------- /core/nty_coroutine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | #ifndef __NTY_COROUTINE_H__ 47 | #define __NTY_COROUTINE_H__ 48 | 49 | 50 | #define _GNU_SOURCE 51 | #include 52 | 53 | #define _USE_UCONTEXT 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | 69 | #ifdef _USE_UCONTEXT 70 | #include 71 | #endif 72 | 73 | #include 74 | #include 75 | 76 | #include 77 | 78 | #include "nty_queue.h" 79 | #include "nty_tree.h" 80 | 81 | #define NTY_CO_MAX_EVENTS (1024*1024) 82 | #define NTY_CO_MAX_STACKSIZE (128*1024) // {http: 16*1024, tcp: 4*1024} 83 | 84 | #define BIT(x) (1 << (x)) 85 | #define CLEARBIT(x) ~(1 << (x)) 86 | 87 | #define CANCEL_FD_WAIT_UINT64 1 88 | 89 | typedef void (*proc_coroutine)(void *); 90 | 91 | 92 | typedef enum { 93 | NTY_COROUTINE_STATUS_WAIT_READ, 94 | NTY_COROUTINE_STATUS_WAIT_WRITE, 95 | NTY_COROUTINE_STATUS_NEW, 96 | NTY_COROUTINE_STATUS_READY, 97 | NTY_COROUTINE_STATUS_EXITED, 98 | NTY_COROUTINE_STATUS_BUSY, 99 | NTY_COROUTINE_STATUS_SLEEPING, 100 | NTY_COROUTINE_STATUS_EXPIRED, 101 | NTY_COROUTINE_STATUS_FDEOF, 102 | NTY_COROUTINE_STATUS_DETACH, 103 | NTY_COROUTINE_STATUS_CANCELLED, 104 | NTY_COROUTINE_STATUS_PENDING_RUNCOMPUTE, 105 | NTY_COROUTINE_STATUS_RUNCOMPUTE, 106 | NTY_COROUTINE_STATUS_WAIT_IO_READ, 107 | NTY_COROUTINE_STATUS_WAIT_IO_WRITE, 108 | NTY_COROUTINE_STATUS_WAIT_MULTI 109 | } nty_coroutine_status; 110 | 111 | typedef enum { 112 | NTY_COROUTINE_COMPUTE_BUSY, 113 | NTY_COROUTINE_COMPUTE_FREE 114 | } nty_coroutine_compute_status; 115 | 116 | typedef enum { 117 | NTY_COROUTINE_EV_READ, 118 | NTY_COROUTINE_EV_WRITE 119 | } nty_coroutine_event; 120 | 121 | 122 | LIST_HEAD(_nty_coroutine_link, _nty_coroutine); 123 | TAILQ_HEAD(_nty_coroutine_queue, _nty_coroutine); 124 | 125 | RB_HEAD(_nty_coroutine_rbtree_sleep, _nty_coroutine); 126 | RB_HEAD(_nty_coroutine_rbtree_wait, _nty_coroutine); 127 | 128 | 129 | 130 | typedef struct _nty_coroutine_link nty_coroutine_link; 131 | typedef struct _nty_coroutine_queue nty_coroutine_queue; 132 | 133 | typedef struct _nty_coroutine_rbtree_sleep nty_coroutine_rbtree_sleep; 134 | typedef struct _nty_coroutine_rbtree_wait nty_coroutine_rbtree_wait; 135 | 136 | 137 | #ifndef _USE_UCONTEXT 138 | typedef struct _nty_cpu_ctx { 139 | void *esp; // 140 | void *ebp; 141 | void *eip; 142 | void *edi; 143 | void *esi; 144 | void *ebx; 145 | void *r1; 146 | void *r2; 147 | void *r3; 148 | void *r4; 149 | void *r5; 150 | } nty_cpu_ctx; 151 | #endif 152 | 153 | /// 154 | typedef struct _nty_schedule { 155 | uint64_t birth; 156 | #ifdef _USE_UCONTEXT 157 | ucontext_t ctx; 158 | #else 159 | nty_cpu_ctx ctx; 160 | #endif 161 | void *stack; 162 | size_t stack_size; 163 | int spawned_coroutines; 164 | uint64_t default_timeout; 165 | struct _nty_coroutine *curr_thread; 166 | int page_size; 167 | 168 | int poller_fd; 169 | int eventfd; 170 | struct epoll_event eventlist[NTY_CO_MAX_EVENTS]; 171 | int nevents; 172 | 173 | int num_new_events; 174 | pthread_mutex_t defer_mutex; 175 | 176 | nty_coroutine_queue ready; 177 | nty_coroutine_queue defer; 178 | 179 | nty_coroutine_link busy; 180 | 181 | nty_coroutine_rbtree_sleep sleeping; 182 | nty_coroutine_rbtree_wait waiting; 183 | 184 | //private 185 | 186 | } nty_schedule; 187 | 188 | typedef struct _nty_coroutine { 189 | 190 | //private 191 | 192 | #ifdef _USE_UCONTEXT 193 | ucontext_t ctx; 194 | #else 195 | nty_cpu_ctx ctx; 196 | #endif 197 | proc_coroutine func; 198 | void *arg; 199 | void *data; 200 | size_t stack_size; 201 | size_t last_stack_size; 202 | 203 | nty_coroutine_status status; 204 | nty_schedule *sched; 205 | 206 | uint64_t birth; 207 | uint64_t id; 208 | #if CANCEL_FD_WAIT_UINT64 209 | int fd; 210 | unsigned short events; //POLL_EVENT 211 | #else 212 | int64_t fd_wait; 213 | #endif 214 | char funcname[64]; 215 | struct _nty_coroutine *co_join; 216 | 217 | void **co_exit_ptr; 218 | void *stack; 219 | void *ebp; 220 | uint32_t ops; 221 | uint64_t sleep_usecs; 222 | 223 | RB_ENTRY(_nty_coroutine) sleep_node; 224 | RB_ENTRY(_nty_coroutine) wait_node; 225 | 226 | LIST_ENTRY(_nty_coroutine) busy_next; 227 | 228 | TAILQ_ENTRY(_nty_coroutine) ready_next; 229 | TAILQ_ENTRY(_nty_coroutine) defer_next; 230 | TAILQ_ENTRY(_nty_coroutine) cond_next; 231 | 232 | TAILQ_ENTRY(_nty_coroutine) io_next; 233 | TAILQ_ENTRY(_nty_coroutine) compute_next; 234 | 235 | struct { 236 | void *buf; 237 | size_t nbytes; 238 | int fd; 239 | int ret; 240 | int err; 241 | } io; 242 | 243 | struct _nty_coroutine_compute_sched *compute_sched; 244 | int ready_fds; 245 | struct pollfd *pfds; 246 | nfds_t nfds; 247 | } nty_coroutine; 248 | 249 | 250 | typedef struct _nty_coroutine_compute_sched { 251 | #ifdef _USE_UCONTEXT 252 | ucontext_t ctx; 253 | #else 254 | nty_cpu_ctx ctx; 255 | #endif 256 | nty_coroutine_queue coroutines; 257 | 258 | nty_coroutine *curr_coroutine; 259 | 260 | pthread_mutex_t run_mutex; 261 | pthread_cond_t run_cond; 262 | 263 | pthread_mutex_t co_mutex; 264 | LIST_ENTRY(_nty_coroutine_compute_sched) compute_next; 265 | 266 | nty_coroutine_compute_status compute_status; 267 | } nty_coroutine_compute_sched; 268 | 269 | extern pthread_key_t global_sched_key; 270 | static inline nty_schedule *nty_coroutine_get_sched(void) { 271 | return pthread_getspecific(global_sched_key); 272 | } 273 | 274 | static inline uint64_t nty_coroutine_diff_usecs(uint64_t t1, uint64_t t2) { 275 | return t2-t1; 276 | } 277 | 278 | static inline uint64_t nty_coroutine_usec_now(void) { 279 | struct timeval t1 = {0, 0}; 280 | gettimeofday(&t1, NULL); 281 | 282 | return t1.tv_sec * 1000000 + t1.tv_usec; 283 | } 284 | 285 | 286 | 287 | int nty_epoller_create(void); 288 | 289 | 290 | void nty_schedule_cancel_event(nty_coroutine *co); 291 | void nty_schedule_sched_event(nty_coroutine *co, int fd, nty_coroutine_event e, uint64_t timeout); 292 | 293 | void nty_schedule_desched_sleepdown(nty_coroutine *co); 294 | void nty_schedule_sched_sleepdown(nty_coroutine *co, uint64_t msecs); 295 | 296 | nty_coroutine* nty_schedule_desched_wait(int fd); 297 | void nty_schedule_sched_wait(nty_coroutine *co, int fd, unsigned short events, uint64_t timeout); 298 | 299 | void nty_schedule_run(void); 300 | 301 | int nty_epoller_ev_register_trigger(void); 302 | int nty_epoller_wait(struct timespec t); 303 | int nty_coroutine_resume(nty_coroutine *co); 304 | void nty_coroutine_free(nty_coroutine *co); 305 | int nty_coroutine_create(nty_coroutine **new_co, proc_coroutine func, void *arg); 306 | void nty_coroutine_yield(nty_coroutine *co); 307 | 308 | void nty_coroutine_sleep(uint64_t msecs); 309 | 310 | 311 | int nty_socket(int domain, int type, int protocol); 312 | int nty_accept(int fd, struct sockaddr *addr, socklen_t *len); 313 | ssize_t nty_recv(int fd, void *buf, size_t len, int flags); 314 | ssize_t nty_send(int fd, const void *buf, size_t len, int flags); 315 | int nty_close(int fd); 316 | int nty_poll(struct pollfd *fds, nfds_t nfds, int timeout); 317 | int nty_connect(int fd, struct sockaddr *name, socklen_t namelen); 318 | 319 | ssize_t nty_sendto(int fd, const void *buf, size_t len, int flags, 320 | const struct sockaddr *dest_addr, socklen_t addrlen); 321 | ssize_t nty_recvfrom(int fd, void *buf, size_t len, int flags, 322 | struct sockaddr *src_addr, socklen_t *addrlen); 323 | 324 | 325 | #define COROUTINE_HOOK 326 | 327 | #ifdef COROUTINE_HOOK 328 | 329 | 330 | typedef int (*socket_t)(int domain, int type, int protocol); 331 | extern socket_t socket_f; 332 | 333 | typedef int(*connect_t)(int, const struct sockaddr *, socklen_t); 334 | extern connect_t connect_f; 335 | 336 | typedef ssize_t(*read_t)(int, void *, size_t); 337 | extern read_t read_f; 338 | 339 | 340 | typedef ssize_t(*recv_t)(int sockfd, void *buf, size_t len, int flags); 341 | extern recv_t recv_f; 342 | 343 | typedef ssize_t(*recvfrom_t)(int sockfd, void *buf, size_t len, int flags, 344 | struct sockaddr *src_addr, socklen_t *addrlen); 345 | extern recvfrom_t recvfrom_f; 346 | 347 | typedef ssize_t(*write_t)(int, const void *, size_t); 348 | extern write_t write_f; 349 | 350 | typedef ssize_t(*send_t)(int sockfd, const void *buf, size_t len, int flags); 351 | extern send_t send_f; 352 | 353 | typedef ssize_t(*sendto_t)(int sockfd, const void *buf, size_t len, int flags, 354 | const struct sockaddr *dest_addr, socklen_t addrlen); 355 | extern sendto_t sendto_f; 356 | 357 | typedef int(*accept_t)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 358 | extern accept_t accept_f; 359 | 360 | // new-syscall 361 | typedef int(*close_t)(int); 362 | extern close_t close_f; 363 | 364 | 365 | int init_hook(void); 366 | 367 | 368 | /* 369 | 370 | typedef int(*fcntl_t)(int __fd, int __cmd, ...); 371 | extern fcntl_t fcntl_f; 372 | 373 | typedef int (*getsockopt_t)(int sockfd, int level, int optname, 374 | void *optval, socklen_t *optlen); 375 | extern getsockopt_t getsockopt_f; 376 | 377 | typedef int (*setsockopt_t)(int sockfd, int level, int optname, 378 | const void *optval, socklen_t optlen); 379 | extern setsockopt_t setsockopt_f; 380 | 381 | */ 382 | 383 | #endif 384 | 385 | 386 | 387 | #endif 388 | 389 | 390 | -------------------------------------------------------------------------------- /core/nty_epoll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | #include 46 | 47 | #include "nty_coroutine.h" 48 | 49 | 50 | int nty_epoller_create(void) { 51 | return epoll_create(1024); 52 | } 53 | 54 | int nty_epoller_wait(struct timespec t) { 55 | nty_schedule *sched = nty_coroutine_get_sched(); 56 | return epoll_wait(sched->poller_fd, sched->eventlist, NTY_CO_MAX_EVENTS, t.tv_sec*1000.0 + t.tv_nsec/1000000.0); 57 | } 58 | 59 | int nty_epoller_ev_register_trigger(void) { 60 | nty_schedule *sched = nty_coroutine_get_sched(); 61 | 62 | if (!sched->eventfd) { 63 | sched->eventfd = eventfd(0, EFD_NONBLOCK); 64 | assert(sched->eventfd != -1); 65 | } 66 | 67 | struct epoll_event ev; 68 | ev.events = EPOLLIN; 69 | ev.data.fd = sched->eventfd; 70 | int ret = epoll_ctl(sched->poller_fd, EPOLL_CTL_ADD, sched->eventfd, &ev); 71 | 72 | assert(ret != -1); 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /core/nty_queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | #ifndef __NTY_QUEUE_H__ 46 | #define __NTY_QUEUE_H__ 47 | 48 | #include 49 | 50 | #ifdef QUEUE_MACRO_DEBUG 51 | /* Store the last 2 places the queue element or head was altered */ 52 | struct qm_trace { 53 | char * lastfile; 54 | int lastline; 55 | char * prevfile; 56 | int prevline; 57 | }; 58 | 59 | #define TRACEBUF struct qm_trace trace; 60 | #define TRASHIT(x) do {(x) = (void *)-1;} while (0) 61 | 62 | #define QMD_TRACE_HEAD(head) do { \ 63 | (head)->trace.prevline = (head)->trace.lastline; \ 64 | (head)->trace.prevfile = (head)->trace.lastfile; \ 65 | (head)->trace.lastline = __LINE__; \ 66 | (head)->trace.lastfile = __FILE__; \ 67 | } while (0) 68 | 69 | #define QMD_TRACE_ELEM(elem) do { \ 70 | (elem)->trace.prevline = (elem)->trace.lastline; \ 71 | (elem)->trace.prevfile = (elem)->trace.lastfile; \ 72 | (elem)->trace.lastline = __LINE__; \ 73 | (elem)->trace.lastfile = __FILE__; \ 74 | } while (0) 75 | 76 | #else 77 | #define QMD_TRACE_ELEM(elem) 78 | #define QMD_TRACE_HEAD(head) 79 | #define TRACEBUF 80 | #define TRASHIT(x) 81 | #endif /* QUEUE_MACRO_DEBUG */ 82 | 83 | 84 | 85 | /* 86 | * Singly-linked List declarations. 87 | */ 88 | #define SLIST_HEAD(name, type) \ 89 | struct name { \ 90 | struct type *slh_first; /* first element */ \ 91 | } 92 | 93 | #define SLIST_HEAD_INITIALIZER(head) \ 94 | { NULL } 95 | 96 | #define SLIST_ENTRY(type) \ 97 | struct { \ 98 | struct type *sle_next; /* next element */ \ 99 | } 100 | 101 | /* 102 | * Singly-linked List functions. 103 | */ 104 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 105 | 106 | #define SLIST_FIRST(head) ((head)->slh_first) 107 | 108 | #define SLIST_FOREACH(var, head, field) \ 109 | for ((var) = SLIST_FIRST((head)); \ 110 | (var); \ 111 | (var) = SLIST_NEXT((var), field)) 112 | 113 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 114 | for ((var) = SLIST_FIRST((head)); \ 115 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 116 | (var) = (tvar)) 117 | 118 | #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 119 | for ((varp) = &SLIST_FIRST((head)); \ 120 | ((var) = *(varp)) != NULL; \ 121 | (varp) = &SLIST_NEXT((var), field)) 122 | 123 | #define SLIST_INIT(head) do { \ 124 | SLIST_FIRST((head)) = NULL; \ 125 | } while (0) 126 | 127 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 128 | SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 129 | SLIST_NEXT((slistelm), field) = (elm); \ 130 | } while (0) 131 | 132 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 133 | SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 134 | SLIST_FIRST((head)) = (elm); \ 135 | } while (0) 136 | 137 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 138 | 139 | #define SLIST_REMOVE(head, elm, type, field) do { \ 140 | if (SLIST_FIRST((head)) == (elm)) { \ 141 | SLIST_REMOVE_HEAD((head), field); \ 142 | } \ 143 | else { \ 144 | struct type *curelm = SLIST_FIRST((head)); \ 145 | while (SLIST_NEXT(curelm, field) != (elm)) \ 146 | curelm = SLIST_NEXT(curelm, field); \ 147 | SLIST_REMOVE_AFTER(curelm, field); \ 148 | } \ 149 | TRASHIT((elm)->field.sle_next); \ 150 | } while (0) 151 | 152 | #define SLIST_REMOVE_AFTER(elm, field) do { \ 153 | SLIST_NEXT(elm, field) = \ 154 | SLIST_NEXT(SLIST_NEXT(elm, field), field); \ 155 | } while (0) 156 | 157 | #define SLIST_REMOVE_HEAD(head, field) do { \ 158 | SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 159 | } while (0) 160 | 161 | 162 | 163 | /* 164 | * Singly-linked Tail queue declarations. 165 | */ 166 | #define STAILQ_HEAD(name, type) \ 167 | struct name { \ 168 | struct type *stqh_first;/* first element */ \ 169 | struct type **stqh_last;/* addr of last next element */ \ 170 | } 171 | 172 | #define STAILQ_HEAD_INITIALIZER(head) \ 173 | { NULL, &(head).stqh_first } 174 | 175 | #define STAILQ_ENTRY(type) \ 176 | struct { \ 177 | struct type *stqe_next; /* next element */ \ 178 | } 179 | 180 | /* 181 | * Singly-linked Tail queue functions. 182 | */ 183 | #define STAILQ_CONCAT(head1, head2) do { \ 184 | if (!STAILQ_EMPTY((head2))) { \ 185 | *(head1)->stqh_last = (head2)->stqh_first; \ 186 | (head1)->stqh_last = (head2)->stqh_last; \ 187 | STAILQ_INIT((head2)); \ 188 | } \ 189 | } while (0) 190 | 191 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 192 | 193 | #define STAILQ_FIRST(head) ((head)->stqh_first) 194 | 195 | #define STAILQ_FOREACH(var, head, field) \ 196 | for((var) = STAILQ_FIRST((head)); \ 197 | (var); \ 198 | (var) = STAILQ_NEXT((var), field)) 199 | 200 | 201 | #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ 202 | for ((var) = STAILQ_FIRST((head)); \ 203 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 204 | (var) = (tvar)) 205 | 206 | #define STAILQ_INIT(head) do { \ 207 | STAILQ_FIRST((head)) = NULL; \ 208 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 209 | } while (0) 210 | 211 | #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 212 | if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ 213 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 214 | STAILQ_NEXT((tqelm), field) = (elm); \ 215 | } while (0) 216 | 217 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 218 | if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 219 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 220 | STAILQ_FIRST((head)) = (elm); \ 221 | } while (0) 222 | 223 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 224 | STAILQ_NEXT((elm), field) = NULL; \ 225 | *(head)->stqh_last = (elm); \ 226 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 227 | } while (0) 228 | 229 | #define STAILQ_LAST(head, type, field) \ 230 | (STAILQ_EMPTY((head)) ? \ 231 | NULL : \ 232 | ((struct type *)(void *) \ 233 | ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) 234 | 235 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 236 | 237 | #define STAILQ_REMOVE(head, elm, type, field) do { \ 238 | if (STAILQ_FIRST((head)) == (elm)) { \ 239 | STAILQ_REMOVE_HEAD((head), field); \ 240 | } \ 241 | else { \ 242 | struct type *curelm = STAILQ_FIRST((head)); \ 243 | while (STAILQ_NEXT(curelm, field) != (elm)) \ 244 | curelm = STAILQ_NEXT(curelm, field); \ 245 | STAILQ_REMOVE_AFTER(head, curelm, field); \ 246 | } \ 247 | TRASHIT((elm)->field.stqe_next); \ 248 | } while (0) 249 | 250 | #define STAILQ_REMOVE_HEAD(head, field) do { \ 251 | if ((STAILQ_FIRST((head)) = \ 252 | STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 253 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 254 | } while (0) 255 | 256 | #define STAILQ_REMOVE_AFTER(head, elm, field) do { \ 257 | if ((STAILQ_NEXT(elm, field) = \ 258 | STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ 259 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 260 | } while (0) 261 | 262 | #define STAILQ_SWAP(head1, head2, type) do { \ 263 | struct type *swap_first = STAILQ_FIRST(head1); \ 264 | struct type **swap_last = (head1)->stqh_last; \ 265 | STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ 266 | (head1)->stqh_last = (head2)->stqh_last; \ 267 | STAILQ_FIRST(head2) = swap_first; \ 268 | (head2)->stqh_last = swap_last; \ 269 | if (STAILQ_EMPTY(head1)) \ 270 | (head1)->stqh_last = &STAILQ_FIRST(head1); \ 271 | if (STAILQ_EMPTY(head2)) \ 272 | (head2)->stqh_last = &STAILQ_FIRST(head2); \ 273 | } while (0) 274 | 275 | 276 | 277 | /* 278 | * List declarations. 279 | */ 280 | #define LIST_HEAD(name, type) \ 281 | struct name { \ 282 | struct type *lh_first; /* first element */ \ 283 | } 284 | 285 | #define LIST_HEAD_INITIALIZER(head) \ 286 | { NULL } 287 | 288 | #define LIST_ENTRY(type) \ 289 | struct { \ 290 | struct type *le_next; /* next element */ \ 291 | struct type **le_prev; /* address of previous next element */ \ 292 | } 293 | 294 | 295 | /* 296 | * List functions. 297 | */ 298 | 299 | #if (defined(_KERNEL) && defined(INVARIANTS)) 300 | #define QMD_LIST_CHECK_HEAD(head, field) do { \ 301 | if (LIST_FIRST((head)) != NULL && \ 302 | LIST_FIRST((head))->field.le_prev != \ 303 | &LIST_FIRST((head))) \ 304 | panic("Bad list head %p first->prev != head", (head)); \ 305 | } while (0) 306 | 307 | #define QMD_LIST_CHECK_NEXT(elm, field) do { \ 308 | if (LIST_NEXT((elm), field) != NULL && \ 309 | LIST_NEXT((elm), field)->field.le_prev != \ 310 | &((elm)->field.le_next)) \ 311 | panic("Bad link elm %p next->prev != elm", (elm)); \ 312 | } while (0) 313 | 314 | #define QMD_LIST_CHECK_PREV(elm, field) do { \ 315 | if (*(elm)->field.le_prev != (elm)) \ 316 | panic("Bad link elm %p prev->next != elm", (elm)); \ 317 | } while (0) 318 | #else 319 | #define QMD_LIST_CHECK_HEAD(head, field) 320 | #define QMD_LIST_CHECK_NEXT(elm, field) 321 | #define QMD_LIST_CHECK_PREV(elm, field) 322 | #endif /* (_KERNEL && INVARIANTS) */ 323 | 324 | 325 | 326 | #define LIST_EMPTY(head) ((head)->lh_first == NULL) 327 | 328 | #define LIST_FIRST(head) ((head)->lh_first) 329 | 330 | #define LIST_FOREACH(var, head, field) \ 331 | for ((var) = LIST_FIRST((head)); \ 332 | (var); \ 333 | (var) = LIST_NEXT((var), field)) 334 | 335 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 336 | for ((var) = LIST_FIRST((head)); \ 337 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 338 | (var) = (tvar)) 339 | 340 | #define LIST_INIT(head) do { \ 341 | LIST_FIRST((head)) = NULL; \ 342 | } while (0) 343 | 344 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 345 | QMD_LIST_CHECK_NEXT(listelm, field); \ 346 | if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ 347 | LIST_NEXT((listelm), field)->field.le_prev = \ 348 | &LIST_NEXT((elm), field); \ 349 | LIST_NEXT((listelm), field) = (elm); \ 350 | (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 351 | } while (0) 352 | 353 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 354 | QMD_LIST_CHECK_PREV(listelm, field); \ 355 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 356 | LIST_NEXT((elm), field) = (listelm); \ 357 | *(listelm)->field.le_prev = (elm); \ 358 | (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 359 | } while (0) 360 | 361 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 362 | QMD_LIST_CHECK_HEAD((head), field); \ 363 | if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 364 | LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ 365 | LIST_FIRST((head)) = (elm); \ 366 | (elm)->field.le_prev = &LIST_FIRST((head)); \ 367 | } while (0) 368 | 369 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 370 | 371 | #define LIST_REMOVE(elm, field) do { \ 372 | QMD_LIST_CHECK_NEXT(elm, field); \ 373 | QMD_LIST_CHECK_PREV(elm, field); \ 374 | if (LIST_NEXT((elm), field) != NULL) \ 375 | LIST_NEXT((elm), field)->field.le_prev = \ 376 | (elm)->field.le_prev; \ 377 | *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 378 | TRASHIT((elm)->field.le_next); \ 379 | TRASHIT((elm)->field.le_prev); \ 380 | } while (0) 381 | 382 | #define LIST_SWAP(head1, head2, type, field) do { \ 383 | struct type *swap_tmp = LIST_FIRST((head1)); \ 384 | LIST_FIRST((head1)) = LIST_FIRST((head2)); \ 385 | LIST_FIRST((head2)) = swap_tmp; \ 386 | if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ 387 | swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ 388 | if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ 389 | swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ 390 | } while (0) 391 | 392 | 393 | 394 | 395 | /* 396 | * Tail queue declarations. 397 | */ 398 | #define TAILQ_HEAD(name, type) \ 399 | struct name { \ 400 | struct type *tqh_first; /* first element */ \ 401 | struct type **tqh_last; /* addr of last next element */ \ 402 | TRACEBUF \ 403 | } 404 | 405 | #define TAILQ_HEAD_INITIALIZER(head) \ 406 | { NULL, &(head).tqh_first } 407 | 408 | #define TAILQ_ENTRY(type) \ 409 | struct { \ 410 | struct type *tqe_next; /* next element */ \ 411 | struct type **tqe_prev; /* address of previous next element */ \ 412 | TRACEBUF \ 413 | } 414 | 415 | 416 | 417 | /* 418 | * Tail queue functions. 419 | */ 420 | #if (defined(_KERNEL) && defined(INVARIANTS)) 421 | #define QMD_TAILQ_CHECK_HEAD(head, field) do { \ 422 | if (!TAILQ_EMPTY(head) && \ 423 | TAILQ_FIRST((head))->field.tqe_prev != \ 424 | &TAILQ_FIRST((head))) \ 425 | panic("Bad tailq head %p first->prev != head", (head)); \ 426 | } while (0) 427 | 428 | #define QMD_TAILQ_CHECK_TAIL(head, field) do { \ 429 | if (*(head)->tqh_last != NULL) \ 430 | panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ 431 | } while (0) 432 | 433 | #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ 434 | if (TAILQ_NEXT((elm), field) != NULL && \ 435 | TAILQ_NEXT((elm), field)->field.tqe_prev != \ 436 | &((elm)->field.tqe_next)) \ 437 | panic("Bad link elm %p next->prev != elm", (elm)); \ 438 | } while (0) 439 | 440 | #define QMD_TAILQ_CHECK_PREV(elm, field) do { \ 441 | if (*(elm)->field.tqe_prev != (elm)) \ 442 | panic("Bad link elm %p prev->next != elm", (elm)); \ 443 | } while (0) 444 | #else 445 | #define QMD_TAILQ_CHECK_HEAD(head, field) 446 | #define QMD_TAILQ_CHECK_TAIL(head, headname) 447 | #define QMD_TAILQ_CHECK_NEXT(elm, field) 448 | #define QMD_TAILQ_CHECK_PREV(elm, field) 449 | #endif /* (_KERNEL && INVARIANTS) */ 450 | 451 | #define TAILQ_CONCAT(head1, head2, field) do { \ 452 | if (!TAILQ_EMPTY(head2)) { \ 453 | *(head1)->tqh_last = (head2)->tqh_first; \ 454 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 455 | (head1)->tqh_last = (head2)->tqh_last; \ 456 | TAILQ_INIT((head2)); \ 457 | QMD_TRACE_HEAD(head1); \ 458 | QMD_TRACE_HEAD(head2); \ 459 | } \ 460 | } while (0) 461 | 462 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 463 | 464 | #define TAILQ_FIRST(head) ((head)->tqh_first) 465 | 466 | #define TAILQ_FOREACH(var, head, field) \ 467 | for ((var) = TAILQ_FIRST((head)); \ 468 | (var); \ 469 | (var) = TAILQ_NEXT((var), field)) 470 | 471 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 472 | for ((var) = TAILQ_FIRST((head)); \ 473 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 474 | (var) = (tvar)) 475 | 476 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 477 | for ((var) = TAILQ_LAST((head), headname); \ 478 | (var); \ 479 | (var) = TAILQ_PREV((var), headname, field)) 480 | 481 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 482 | for ((var) = TAILQ_LAST((head), headname); \ 483 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 484 | (var) = (tvar)) 485 | 486 | #define TAILQ_INIT(head) do { \ 487 | TAILQ_FIRST((head)) = NULL; \ 488 | (head)->tqh_last = &TAILQ_FIRST((head)); \ 489 | QMD_TRACE_HEAD(head); \ 490 | } while (0) 491 | 492 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 493 | QMD_TAILQ_CHECK_NEXT(listelm, field); \ 494 | if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ 495 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 496 | &TAILQ_NEXT((elm), field); \ 497 | else { \ 498 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 499 | QMD_TRACE_HEAD(head); \ 500 | } \ 501 | TAILQ_NEXT((listelm), field) = (elm); \ 502 | (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 503 | QMD_TRACE_ELEM(&(elm)->field); \ 504 | QMD_TRACE_ELEM(&listelm->field); \ 505 | } while (0) 506 | 507 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 508 | QMD_TAILQ_CHECK_PREV(listelm, field); \ 509 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 510 | TAILQ_NEXT((elm), field) = (listelm); \ 511 | *(listelm)->field.tqe_prev = (elm); \ 512 | (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 513 | QMD_TRACE_ELEM(&(elm)->field); \ 514 | QMD_TRACE_ELEM(&listelm->field); \ 515 | } while (0) 516 | 517 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 518 | QMD_TAILQ_CHECK_HEAD(head, field); \ 519 | if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 520 | TAILQ_FIRST((head))->field.tqe_prev = \ 521 | &TAILQ_NEXT((elm), field); \ 522 | else \ 523 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 524 | TAILQ_FIRST((head)) = (elm); \ 525 | (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 526 | QMD_TRACE_HEAD(head); \ 527 | QMD_TRACE_ELEM(&(elm)->field); \ 528 | } while (0) 529 | 530 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 531 | QMD_TAILQ_CHECK_TAIL(head, field); \ 532 | TAILQ_NEXT((elm), field) = NULL; \ 533 | (elm)->field.tqe_prev = (head)->tqh_last; \ 534 | *(head)->tqh_last = (elm); \ 535 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 536 | QMD_TRACE_HEAD(head); \ 537 | QMD_TRACE_ELEM(&(elm)->field); \ 538 | } while (0) 539 | 540 | #define TAILQ_LAST(head, headname) \ 541 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 542 | 543 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 544 | 545 | #define TAILQ_PREV(elm, headname, field) \ 546 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 547 | 548 | #define TAILQ_REMOVE(head, elm, field) do { \ 549 | QMD_TAILQ_CHECK_NEXT(elm, field); \ 550 | QMD_TAILQ_CHECK_PREV(elm, field); \ 551 | if ((TAILQ_NEXT((elm), field)) != NULL) \ 552 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 553 | (elm)->field.tqe_prev; \ 554 | else { \ 555 | (head)->tqh_last = (elm)->field.tqe_prev; \ 556 | QMD_TRACE_HEAD(head); \ 557 | } \ 558 | *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 559 | TRASHIT((elm)->field.tqe_next); \ 560 | TRASHIT((elm)->field.tqe_prev); \ 561 | QMD_TRACE_ELEM(&(elm)->field); \ 562 | } while (0) 563 | 564 | #define TAILQ_SWAP(head1, head2, type, field) do { \ 565 | struct type *swap_first = (head1)->tqh_first; \ 566 | struct type **swap_last = (head1)->tqh_last; \ 567 | (head1)->tqh_first = (head2)->tqh_first; \ 568 | (head1)->tqh_last = (head2)->tqh_last; \ 569 | (head2)->tqh_first = swap_first; \ 570 | (head2)->tqh_last = swap_last; \ 571 | if ((swap_first = (head1)->tqh_first) != NULL) \ 572 | swap_first->field.tqe_prev = &(head1)->tqh_first; \ 573 | else \ 574 | (head1)->tqh_last = &(head1)->tqh_first; \ 575 | if ((swap_first = (head2)->tqh_first) != NULL) \ 576 | swap_first->field.tqe_prev = &(head2)->tqh_first; \ 577 | else \ 578 | (head2)->tqh_last = &(head2)->tqh_first; \ 579 | } while (0) 580 | 581 | 582 | 583 | 584 | #endif 585 | 586 | 587 | 588 | 589 | 590 | -------------------------------------------------------------------------------- /core/nty_schedule.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | #include "nty_coroutine.h" 47 | 48 | 49 | 50 | #define FD_KEY(f,e) (((int64_t)(f) << (sizeof(int32_t) * 8)) | e) 51 | #define FD_EVENT(f) ((int32_t)(f)) 52 | #define FD_ONLY(f) ((f) >> ((sizeof(int32_t) * 8))) 53 | 54 | 55 | static inline int nty_coroutine_sleep_cmp(nty_coroutine *co1, nty_coroutine *co2) { 56 | if (co1->sleep_usecs < co2->sleep_usecs) { 57 | return -1; 58 | } 59 | if (co1->sleep_usecs == co2->sleep_usecs) { 60 | return 0; 61 | } 62 | return 1; 63 | } 64 | 65 | static inline int nty_coroutine_wait_cmp(nty_coroutine *co1, nty_coroutine *co2) { 66 | #if CANCEL_FD_WAIT_UINT64 67 | if (co1->fd < co2->fd) return -1; 68 | else if (co1->fd == co2->fd) return 0; 69 | else return 1; 70 | #else 71 | if (co1->fd_wait < co2->fd_wait) { 72 | return -1; 73 | } 74 | if (co1->fd_wait == co2->fd_wait) { 75 | return 0; 76 | } 77 | #endif 78 | return 1; 79 | } 80 | 81 | 82 | RB_GENERATE(_nty_coroutine_rbtree_sleep, _nty_coroutine, sleep_node, nty_coroutine_sleep_cmp); 83 | RB_GENERATE(_nty_coroutine_rbtree_wait, _nty_coroutine, wait_node, nty_coroutine_wait_cmp); 84 | 85 | 86 | 87 | void nty_schedule_sched_sleepdown(nty_coroutine *co, uint64_t msecs) { 88 | uint64_t usecs = msecs * 1000u; 89 | 90 | nty_coroutine *co_tmp = RB_FIND(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co); 91 | if (co_tmp != NULL) { 92 | RB_REMOVE(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co_tmp); 93 | } 94 | 95 | co->sleep_usecs = nty_coroutine_diff_usecs(co->sched->birth, nty_coroutine_usec_now()) + usecs; 96 | 97 | while (msecs) { 98 | co_tmp = RB_INSERT(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co); 99 | if (co_tmp) { 100 | printf("1111 sleep_usecs %"PRIu64"\n", co->sleep_usecs); 101 | co->sleep_usecs ++; 102 | continue; 103 | } 104 | co->status |= BIT(NTY_COROUTINE_STATUS_SLEEPING); 105 | break; 106 | } 107 | 108 | //yield 109 | } 110 | 111 | void nty_schedule_desched_sleepdown(nty_coroutine *co) { 112 | if (co->status & BIT(NTY_COROUTINE_STATUS_SLEEPING)) { 113 | RB_REMOVE(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co); 114 | 115 | co->status &= CLEARBIT(NTY_COROUTINE_STATUS_SLEEPING); 116 | co->status |= BIT(NTY_COROUTINE_STATUS_READY); 117 | co->status &= CLEARBIT(NTY_COROUTINE_STATUS_EXPIRED); 118 | } 119 | } 120 | 121 | nty_coroutine *nty_schedule_search_wait(int fd) { 122 | nty_coroutine find_it = {0}; 123 | find_it.fd = fd; 124 | 125 | nty_schedule *sched = nty_coroutine_get_sched(); 126 | 127 | nty_coroutine *co = RB_FIND(_nty_coroutine_rbtree_wait, &sched->waiting, &find_it); 128 | co->status = 0; 129 | 130 | return co; 131 | } 132 | 133 | nty_coroutine* nty_schedule_desched_wait(int fd) { 134 | 135 | nty_coroutine find_it = {0}; 136 | find_it.fd = fd; 137 | 138 | nty_schedule *sched = nty_coroutine_get_sched(); 139 | 140 | nty_coroutine *co = RB_FIND(_nty_coroutine_rbtree_wait, &sched->waiting, &find_it); 141 | if (co != NULL) { 142 | RB_REMOVE(_nty_coroutine_rbtree_wait, &co->sched->waiting, co); 143 | } 144 | co->status = 0; 145 | nty_schedule_desched_sleepdown(co); 146 | 147 | return co; 148 | } 149 | 150 | void nty_schedule_sched_wait(nty_coroutine *co, int fd, unsigned short events, uint64_t timeout) { 151 | 152 | if (co->status & BIT(NTY_COROUTINE_STATUS_WAIT_READ) || 153 | co->status & BIT(NTY_COROUTINE_STATUS_WAIT_WRITE)) { 154 | printf("Unexpected event. lt id %"PRIu64" fd %"PRId32" already in %"PRId32" state\n", 155 | co->id, co->fd, co->status); 156 | assert(0); 157 | } 158 | 159 | if (events & POLLIN) { 160 | co->status |= NTY_COROUTINE_STATUS_WAIT_READ; 161 | } else if (events & POLLOUT) { 162 | co->status |= NTY_COROUTINE_STATUS_WAIT_WRITE; 163 | } else { 164 | printf("events : %d\n", events); 165 | assert(0); 166 | } 167 | 168 | co->fd = fd; 169 | co->events = events; 170 | nty_coroutine *co_tmp = RB_INSERT(_nty_coroutine_rbtree_wait, &co->sched->waiting, co); 171 | 172 | assert(co_tmp == NULL); 173 | 174 | //printf("timeout --> %"PRIu64"\n", timeout); 175 | if (timeout == 1) return ; //Error 176 | 177 | nty_schedule_sched_sleepdown(co, timeout); 178 | 179 | } 180 | 181 | void nty_schedule_cancel_wait(nty_coroutine *co) { 182 | RB_REMOVE(_nty_coroutine_rbtree_wait, &co->sched->waiting, co); 183 | } 184 | 185 | void nty_schedule_free(nty_schedule *sched) { 186 | if (sched->poller_fd > 0) { 187 | close(sched->poller_fd); 188 | } 189 | if (sched->eventfd > 0) { 190 | close(sched->eventfd); 191 | } 192 | if (sched->stack != NULL) { 193 | free(sched->stack); 194 | } 195 | 196 | free(sched); 197 | 198 | assert(pthread_setspecific(global_sched_key, NULL) == 0); 199 | } 200 | 201 | int nty_schedule_create(int stack_size) { 202 | 203 | int sched_stack_size = stack_size ? stack_size : NTY_CO_MAX_STACKSIZE; 204 | 205 | nty_schedule *sched = (nty_schedule*)calloc(1, sizeof(nty_schedule)); 206 | if (sched == NULL) { 207 | printf("Failed to initialize scheduler\n"); 208 | return -1; 209 | } 210 | 211 | assert(pthread_setspecific(global_sched_key, sched) == 0); 212 | 213 | sched->poller_fd = nty_epoller_create(); 214 | if (sched->poller_fd == -1) { 215 | printf("Failed to initialize epoller\n"); 216 | nty_schedule_free(sched); 217 | return -2; 218 | } 219 | 220 | nty_epoller_ev_register_trigger(); 221 | 222 | sched->stack_size = sched_stack_size; 223 | sched->page_size = getpagesize(); 224 | 225 | #ifdef _USE_UCONTEXT 226 | int ret = posix_memalign(&sched->stack, sched->page_size, sched->stack_size); 227 | assert(ret == 0); 228 | #else 229 | sched->stack = NULL; 230 | bzero(&sched->ctx, sizeof(nty_cpu_ctx)); 231 | #endif 232 | 233 | sched->spawned_coroutines = 0; 234 | sched->default_timeout = 3000000u; 235 | 236 | RB_INIT(&sched->sleeping); 237 | RB_INIT(&sched->waiting); 238 | 239 | sched->birth = nty_coroutine_usec_now(); 240 | 241 | TAILQ_INIT(&sched->ready); 242 | TAILQ_INIT(&sched->defer); 243 | LIST_INIT(&sched->busy); 244 | 245 | } 246 | 247 | 248 | static nty_coroutine *nty_schedule_expired(nty_schedule *sched) { 249 | 250 | uint64_t t_diff_usecs = nty_coroutine_diff_usecs(sched->birth, nty_coroutine_usec_now()); 251 | nty_coroutine *co = RB_MIN(_nty_coroutine_rbtree_sleep, &sched->sleeping); 252 | if (co == NULL) return NULL; 253 | 254 | if (co->sleep_usecs <= t_diff_usecs) { 255 | RB_REMOVE(_nty_coroutine_rbtree_sleep, &co->sched->sleeping, co); 256 | return co; 257 | } 258 | return NULL; 259 | } 260 | 261 | static inline int nty_schedule_isdone(nty_schedule *sched) { 262 | return (RB_EMPTY(&sched->waiting) && 263 | LIST_EMPTY(&sched->busy) && 264 | RB_EMPTY(&sched->sleeping) && 265 | TAILQ_EMPTY(&sched->ready)); 266 | } 267 | 268 | static uint64_t nty_schedule_min_timeout(nty_schedule *sched) { 269 | uint64_t t_diff_usecs = nty_coroutine_diff_usecs(sched->birth, nty_coroutine_usec_now()); 270 | uint64_t min = sched->default_timeout; 271 | 272 | nty_coroutine *co = RB_MIN(_nty_coroutine_rbtree_sleep, &sched->sleeping); 273 | if (!co) return min; 274 | 275 | min = co->sleep_usecs; 276 | if (min > t_diff_usecs) { 277 | return min - t_diff_usecs; 278 | } 279 | 280 | return 0; 281 | } 282 | 283 | static int nty_schedule_epoll(nty_schedule *sched) { 284 | 285 | sched->num_new_events = 0; 286 | 287 | struct timespec t = {0, 0}; 288 | uint64_t usecs = nty_schedule_min_timeout(sched); 289 | if (usecs && TAILQ_EMPTY(&sched->ready)) { 290 | t.tv_sec = usecs / 1000000u; 291 | if (t.tv_sec != 0) { 292 | t.tv_nsec = (usecs % 1000u) * 1000u; 293 | } else { 294 | t.tv_nsec = usecs * 1000u; 295 | } 296 | } else { 297 | return 0; 298 | } 299 | 300 | int nready = 0; 301 | while (1) { 302 | nready = nty_epoller_wait(t); 303 | if (nready == -1) { 304 | if (errno == EINTR) continue; 305 | else assert(0); 306 | } 307 | break; 308 | } 309 | 310 | sched->nevents = 0; 311 | sched->num_new_events = nready; 312 | 313 | return 0; 314 | } 315 | 316 | void nty_schedule_run(void) { 317 | 318 | nty_schedule *sched = nty_coroutine_get_sched(); 319 | if (sched == NULL) return ; 320 | 321 | while (!nty_schedule_isdone(sched)) { 322 | 323 | // 1. expired --> sleep rbtree 324 | nty_coroutine *expired = NULL; 325 | while ((expired = nty_schedule_expired(sched)) != NULL) { 326 | nty_coroutine_resume(expired); 327 | } 328 | // 2. ready queue 329 | nty_coroutine *last_co_ready = TAILQ_LAST(&sched->ready, _nty_coroutine_queue); 330 | while (!TAILQ_EMPTY(&sched->ready)) { 331 | nty_coroutine *co = TAILQ_FIRST(&sched->ready); 332 | TAILQ_REMOVE(&co->sched->ready, co, ready_next); 333 | 334 | if (co->status & BIT(NTY_COROUTINE_STATUS_FDEOF)) { 335 | nty_coroutine_free(co); 336 | break; 337 | } 338 | 339 | nty_coroutine_resume(co); 340 | if (co == last_co_ready) break; 341 | } 342 | 343 | // 3. wait rbtree 344 | nty_schedule_epoll(sched); 345 | while (sched->num_new_events) { 346 | int idx = --sched->num_new_events; 347 | struct epoll_event *ev = sched->eventlist+idx; 348 | 349 | int fd = ev->data.fd; 350 | int is_eof = ev->events & EPOLLHUP; 351 | if (is_eof) errno = ECONNRESET; 352 | 353 | nty_coroutine *co = nty_schedule_search_wait(fd); 354 | if (co != NULL) { 355 | if (is_eof) { 356 | co->status |= BIT(NTY_COROUTINE_STATUS_FDEOF); 357 | } 358 | nty_coroutine_resume(co); 359 | } 360 | 361 | is_eof = 0; 362 | } 363 | } 364 | 365 | nty_schedule_free(sched); 366 | 367 | return ; 368 | } 369 | 370 | -------------------------------------------------------------------------------- /core/nty_socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | #include "nty_coroutine.h" 46 | 47 | 48 | 49 | static uint32_t nty_pollevent_2epoll( short events ) 50 | { 51 | uint32_t e = 0; 52 | if( events & POLLIN ) e |= EPOLLIN; 53 | if( events & POLLOUT ) e |= EPOLLOUT; 54 | if( events & POLLHUP ) e |= EPOLLHUP; 55 | if( events & POLLERR ) e |= EPOLLERR; 56 | if( events & POLLRDNORM ) e |= EPOLLRDNORM; 57 | if( events & POLLWRNORM ) e |= EPOLLWRNORM; 58 | return e; 59 | } 60 | static short nty_epollevent_2poll( uint32_t events ) 61 | { 62 | short e = 0; 63 | if( events & EPOLLIN ) e |= POLLIN; 64 | if( events & EPOLLOUT ) e |= POLLOUT; 65 | if( events & EPOLLHUP ) e |= POLLHUP; 66 | if( events & EPOLLERR ) e |= POLLERR; 67 | if( events & EPOLLRDNORM ) e |= POLLRDNORM; 68 | if( events & EPOLLWRNORM ) e |= POLLWRNORM; 69 | return e; 70 | } 71 | /* 72 | * nty_poll_inner --> 1. sockfd--> epoll, 2 yield, 3. epoll x sockfd 73 | * fds : 74 | */ 75 | 76 | static int nty_poll_inner(struct pollfd *fds, nfds_t nfds, int timeout) { 77 | 78 | if (timeout == 0) 79 | { 80 | return poll(fds, nfds, timeout); 81 | } 82 | if (timeout < 0) 83 | { 84 | timeout = INT_MAX; 85 | } 86 | 87 | nty_schedule *sched = nty_coroutine_get_sched(); 88 | if (sched == NULL) { 89 | printf("scheduler not exit!\n"); 90 | return -1; 91 | } 92 | 93 | nty_coroutine *co = sched->curr_thread; 94 | 95 | int i = 0; 96 | for (i = 0;i < nfds;i ++) { 97 | 98 | struct epoll_event ev; 99 | ev.events = nty_pollevent_2epoll(fds[i].events); 100 | ev.data.fd = fds[i].fd; 101 | epoll_ctl(sched->poller_fd, EPOLL_CTL_ADD, fds[i].fd, &ev); 102 | 103 | co->events = fds[i].events; 104 | nty_schedule_sched_wait(co, fds[i].fd, fds[i].events, timeout); 105 | } 106 | nty_coroutine_yield(co); 107 | 108 | for (i = 0;i < nfds;i ++) { 109 | 110 | struct epoll_event ev; 111 | ev.events = nty_pollevent_2epoll(fds[i].events); 112 | ev.data.fd = fds[i].fd; 113 | epoll_ctl(sched->poller_fd, EPOLL_CTL_DEL, fds[i].fd, &ev); 114 | 115 | nty_schedule_desched_wait(fds[i].fd); 116 | } 117 | 118 | return nfds; 119 | } 120 | 121 | 122 | int nty_socket(int domain, int type, int protocol) { 123 | 124 | int fd = socket(domain, type, protocol); 125 | if (fd == -1) { 126 | printf("Failed to create a new socket\n"); 127 | return -1; 128 | } 129 | int ret = fcntl(fd, F_SETFL, O_NONBLOCK); 130 | if (ret == -1) { 131 | close(ret); 132 | return -1; 133 | } 134 | int reuse = 1; 135 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 136 | 137 | return fd; 138 | } 139 | 140 | //nty_accept 141 | //return failed == -1, success > 0 142 | 143 | int nty_accept(int fd, struct sockaddr *addr, socklen_t *len) { 144 | int sockfd = -1; 145 | int timeout = 1; 146 | nty_coroutine *co = nty_coroutine_get_sched()->curr_thread; 147 | 148 | while (1) { 149 | struct pollfd fds; 150 | fds.fd = fd; 151 | fds.events = POLLIN | POLLERR | POLLHUP; 152 | nty_poll_inner(&fds, 1, timeout); 153 | 154 | sockfd = accept(fd, addr, len); 155 | if (sockfd < 0) { 156 | if (errno == EAGAIN) { 157 | continue; 158 | } else if (errno == ECONNABORTED) { 159 | printf("accept : ECONNABORTED\n"); 160 | 161 | } else if (errno == EMFILE || errno == ENFILE) { 162 | printf("accept : EMFILE || ENFILE\n"); 163 | } 164 | return -1; 165 | } else { 166 | break; 167 | } 168 | } 169 | 170 | int ret = fcntl(sockfd, F_SETFL, O_NONBLOCK); 171 | if (ret == -1) { 172 | close(sockfd); 173 | return -1; 174 | } 175 | int reuse = 1; 176 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 177 | 178 | return sockfd; 179 | } 180 | 181 | 182 | int nty_connect(int fd, struct sockaddr *name, socklen_t namelen) { 183 | 184 | int ret = 0; 185 | 186 | while (1) { 187 | 188 | struct pollfd fds; 189 | fds.fd = fd; 190 | fds.events = POLLOUT | POLLERR | POLLHUP; 191 | nty_poll_inner(&fds, 1, 1); 192 | 193 | ret = connect(fd, name, namelen); 194 | if (ret == 0) break; 195 | 196 | if (ret == -1 && (errno == EAGAIN || 197 | errno == EWOULDBLOCK || 198 | errno == EINPROGRESS)) { 199 | continue; 200 | } else { 201 | break; 202 | } 203 | } 204 | 205 | return ret; 206 | } 207 | 208 | //recv 209 | // add epoll first 210 | // 211 | ssize_t nty_recv(int fd, void *buf, size_t len, int flags) { 212 | 213 | struct pollfd fds; 214 | fds.fd = fd; 215 | fds.events = POLLIN | POLLERR | POLLHUP; 216 | 217 | nty_poll_inner(&fds, 1, 1); 218 | 219 | int ret = recv(fd, buf, len, flags); 220 | if (ret < 0) { 221 | //if (errno == EAGAIN) return ret; 222 | if (errno == ECONNRESET) return -1; 223 | //printf("recv error : %d, ret : %d\n", errno, ret); 224 | 225 | } 226 | return ret; 227 | } 228 | 229 | 230 | ssize_t nty_send(int fd, const void *buf, size_t len, int flags) { 231 | 232 | int sent = 0; 233 | 234 | int ret = send(fd, ((char*)buf)+sent, len-sent, flags); 235 | if (ret == 0) return ret; 236 | if (ret > 0) sent += ret; 237 | 238 | while (sent < len) { 239 | struct pollfd fds; 240 | fds.fd = fd; 241 | fds.events = POLLOUT | POLLERR | POLLHUP; 242 | 243 | nty_poll_inner(&fds, 1, 1); 244 | ret = send(fd, ((char*)buf)+sent, len-sent, flags); 245 | //printf("send --> len : %d\n", ret); 246 | if (ret <= 0) { 247 | break; 248 | } 249 | sent += ret; 250 | } 251 | 252 | if (ret <= 0 && sent == 0) return ret; 253 | 254 | return sent; 255 | } 256 | 257 | 258 | ssize_t nty_sendto(int fd, const void *buf, size_t len, int flags, 259 | const struct sockaddr *dest_addr, socklen_t addrlen) { 260 | 261 | 262 | int sent = 0; 263 | 264 | while (sent < len) { 265 | struct pollfd fds; 266 | fds.fd = fd; 267 | fds.events = POLLOUT | POLLERR | POLLHUP; 268 | 269 | nty_poll_inner(&fds, 1, 1); 270 | int ret = sendto(fd, ((char*)buf)+sent, len-sent, flags, dest_addr, addrlen); 271 | if (ret <= 0) { 272 | if (errno == EAGAIN) continue; 273 | else if (errno == ECONNRESET) { 274 | return ret; 275 | } 276 | printf("send errno : %d, ret : %d\n", errno, ret); 277 | assert(0); 278 | } 279 | sent += ret; 280 | } 281 | return sent; 282 | 283 | } 284 | 285 | ssize_t nty_recvfrom(int fd, void *buf, size_t len, int flags, 286 | struct sockaddr *src_addr, socklen_t *addrlen) { 287 | 288 | struct pollfd fds; 289 | fds.fd = fd; 290 | fds.events = POLLIN | POLLERR | POLLHUP; 291 | 292 | nty_poll_inner(&fds, 1, 1); 293 | 294 | int ret = recvfrom(fd, buf, len, flags, src_addr, addrlen); 295 | if (ret < 0) { 296 | if (errno == EAGAIN) return ret; 297 | if (errno == ECONNRESET) return 0; 298 | 299 | printf("recv error : %d, ret : %d\n", errno, ret); 300 | assert(0); 301 | } 302 | return ret; 303 | 304 | } 305 | 306 | 307 | 308 | 309 | int nty_close(int fd) { 310 | #if 0 311 | nty_schedule *sched = nty_coroutine_get_sched(); 312 | 313 | nty_coroutine *co = sched->curr_thread; 314 | if (co) { 315 | TAILQ_INSERT_TAIL(&nty_coroutine_get_sched()->ready, co, ready_next); 316 | co->status |= BIT(NTY_COROUTINE_STATUS_FDEOF); 317 | } 318 | #endif 319 | return close(fd); 320 | } 321 | 322 | 323 | #ifdef COROUTINE_HOOK 324 | 325 | socket_t socket_f = NULL; 326 | 327 | read_t read_f = NULL; 328 | recv_t recv_f = NULL; 329 | recvfrom_t recvfrom_f = NULL; 330 | 331 | write_t write_f = NULL; 332 | send_t send_f = NULL; 333 | sendto_t sendto_f = NULL; 334 | 335 | accept_t accept_f = NULL; 336 | close_t close_f = NULL; 337 | connect_t connect_f = NULL; 338 | 339 | 340 | int init_hook(void) { 341 | 342 | socket_f = (socket_t)dlsym(RTLD_NEXT, "socket"); 343 | 344 | read_f = (read_t)dlsym(RTLD_NEXT, "read"); 345 | recv_f = (recv_t)dlsym(RTLD_NEXT, "recv"); 346 | recvfrom_f = (recvfrom_t)dlsym(RTLD_NEXT, "recvfrom"); 347 | 348 | write_f = (write_t)dlsym(RTLD_NEXT, "write"); 349 | send_f = (send_t)dlsym(RTLD_NEXT, "send"); 350 | sendto_f = (sendto_t)dlsym(RTLD_NEXT, "sendto"); 351 | 352 | accept_f = (accept_t)dlsym(RTLD_NEXT, "accept"); 353 | close_f = (close_t)dlsym(RTLD_NEXT, "close"); 354 | connect_f = (connect_t)dlsym(RTLD_NEXT, "connect"); 355 | 356 | } 357 | 358 | 359 | 360 | int socket(int domain, int type, int protocol) { 361 | 362 | if (!socket_f) init_hook(); 363 | 364 | nty_schedule *sched = nty_coroutine_get_sched(); 365 | if (sched == NULL) { 366 | return socket_f(domain, type, protocol); 367 | } 368 | 369 | int fd = socket_f(domain, type, protocol); 370 | if (fd == -1) { 371 | printf("Failed to create a new socket\n"); 372 | return -1; 373 | } 374 | int ret = fcntl(fd, F_SETFL, O_NONBLOCK); 375 | if (ret == -1) { 376 | close(ret); 377 | return -1; 378 | } 379 | int reuse = 1; 380 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 381 | 382 | return fd; 383 | } 384 | 385 | ssize_t read(int fd, void *buf, size_t count) { 386 | 387 | if (!read_f) init_hook(); 388 | 389 | nty_schedule *sched = nty_coroutine_get_sched(); 390 | if (sched == NULL) { 391 | return read_f(fd, buf, count); 392 | } 393 | 394 | struct pollfd fds; 395 | fds.fd = fd; 396 | fds.events = POLLIN | POLLERR | POLLHUP; 397 | 398 | nty_poll_inner(&fds, 1, 1); 399 | 400 | int ret = read_f(fd, buf, count); 401 | if (ret < 0) { 402 | //if (errno == EAGAIN) return ret; 403 | if (errno == ECONNRESET) return -1; 404 | //printf("recv error : %d, ret : %d\n", errno, ret); 405 | 406 | } 407 | return ret; 408 | } 409 | 410 | ssize_t recv(int fd, void *buf, size_t len, int flags) { 411 | 412 | if (!recv_f) init_hook(); 413 | 414 | nty_schedule *sched = nty_coroutine_get_sched(); 415 | if (sched == NULL) { 416 | return recv_f(fd, buf, len, flags); 417 | } 418 | 419 | struct pollfd fds; 420 | fds.fd = fd; 421 | fds.events = POLLIN | POLLERR | POLLHUP; 422 | 423 | nty_poll_inner(&fds, 1, 1); 424 | 425 | int ret = recv_f(fd, buf, len, flags); 426 | if (ret < 0) { 427 | //if (errno == EAGAIN) return ret; 428 | if (errno == ECONNRESET) return -1; 429 | //printf("recv error : %d, ret : %d\n", errno, ret); 430 | 431 | } 432 | return ret; 433 | } 434 | 435 | 436 | ssize_t recvfrom(int fd, void *buf, size_t len, int flags, 437 | struct sockaddr *src_addr, socklen_t *addrlen) { 438 | 439 | if (!recvfrom_f) init_hook(); 440 | 441 | nty_schedule *sched = nty_coroutine_get_sched(); 442 | if (sched == NULL) { 443 | return recvfrom_f(fd, buf, len, flags, src_addr, addrlen); 444 | } 445 | 446 | struct pollfd fds; 447 | fds.fd = fd; 448 | fds.events = POLLIN | POLLERR | POLLHUP; 449 | 450 | nty_poll_inner(&fds, 1, 1); 451 | 452 | int ret = recvfrom_f(fd, buf, len, flags, src_addr, addrlen); 453 | if (ret < 0) { 454 | if (errno == EAGAIN) return ret; 455 | if (errno == ECONNRESET) return 0; 456 | 457 | printf("recv error : %d, ret : %d\n", errno, ret); 458 | assert(0); 459 | } 460 | return ret; 461 | 462 | } 463 | 464 | 465 | ssize_t write(int fd, const void *buf, size_t count) { 466 | 467 | if (!write_f) init_hook(); 468 | 469 | nty_schedule *sched = nty_coroutine_get_sched(); 470 | if (sched == NULL) { 471 | return write_f(fd, buf, count); 472 | } 473 | 474 | int sent = 0; 475 | 476 | int ret = write_f(fd, ((char*)buf)+sent, count-sent); 477 | if (ret == 0) return ret; 478 | if (ret > 0) sent += ret; 479 | 480 | while (sent < count) { 481 | struct pollfd fds; 482 | fds.fd = fd; 483 | fds.events = POLLOUT | POLLERR | POLLHUP; 484 | 485 | nty_poll_inner(&fds, 1, 1); 486 | ret = write_f(fd, ((char*)buf)+sent, count-sent); 487 | //printf("send --> len : %d\n", ret); 488 | if (ret <= 0) { 489 | break; 490 | } 491 | sent += ret; 492 | } 493 | 494 | if (ret <= 0 && sent == 0) return ret; 495 | 496 | return sent; 497 | } 498 | 499 | 500 | ssize_t send(int fd, const void *buf, size_t len, int flags) { 501 | 502 | if (!send_f) init_hook(); 503 | 504 | nty_schedule *sched = nty_coroutine_get_sched(); 505 | if (sched == NULL) { 506 | return send_f(fd, buf, len, flags); 507 | } 508 | 509 | int sent = 0; 510 | 511 | int ret = send_f(fd, ((char*)buf)+sent, len-sent, flags); 512 | if (ret == 0) return ret; 513 | if (ret > 0) sent += ret; 514 | 515 | while (sent < len) { 516 | struct pollfd fds; 517 | fds.fd = fd; 518 | fds.events = POLLOUT | POLLERR | POLLHUP; 519 | 520 | nty_poll_inner(&fds, 1, 1); 521 | ret = send_f(fd, ((char*)buf)+sent, len-sent, flags); 522 | //printf("send --> len : %d\n", ret); 523 | if (ret <= 0) { 524 | break; 525 | } 526 | sent += ret; 527 | } 528 | 529 | if (ret <= 0 && sent == 0) return ret; 530 | 531 | return sent; 532 | } 533 | 534 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, 535 | const struct sockaddr *dest_addr, socklen_t addrlen) { 536 | 537 | if (!sendto_f) init_hook(); 538 | 539 | nty_schedule *sched = nty_coroutine_get_sched(); 540 | if (sched == NULL) { 541 | return sendto_f(sockfd, buf, len, flags, dest_addr, addrlen); 542 | } 543 | 544 | struct pollfd fds; 545 | fds.fd = sockfd; 546 | fds.events = POLLOUT | POLLERR | POLLHUP; 547 | 548 | nty_poll_inner(&fds, 1, 1); 549 | 550 | int ret = sendto_f(sockfd, buf, len, flags, dest_addr, addrlen); 551 | if (ret < 0) { 552 | if (errno == EAGAIN) return ret; 553 | if (errno == ECONNRESET) return 0; 554 | 555 | printf("recv error : %d, ret : %d\n", errno, ret); 556 | assert(0); 557 | } 558 | return ret; 559 | 560 | } 561 | 562 | 563 | 564 | int accept(int fd, struct sockaddr *addr, socklen_t *len) { 565 | 566 | if (!accept_f) init_hook(); 567 | 568 | nty_schedule *sched = nty_coroutine_get_sched(); 569 | if (sched == NULL) { 570 | return accept_f(fd, addr, len); 571 | } 572 | 573 | int sockfd = -1; 574 | int timeout = 1; 575 | nty_coroutine *co = nty_coroutine_get_sched()->curr_thread; 576 | 577 | while (1) { 578 | struct pollfd fds; 579 | fds.fd = fd; 580 | fds.events = POLLIN | POLLERR | POLLHUP; 581 | nty_poll_inner(&fds, 1, timeout); 582 | 583 | sockfd = accept_f(fd, addr, len); 584 | if (sockfd < 0) { 585 | if (errno == EAGAIN) { 586 | continue; 587 | } else if (errno == ECONNABORTED) { 588 | printf("accept : ECONNABORTED\n"); 589 | 590 | } else if (errno == EMFILE || errno == ENFILE) { 591 | printf("accept : EMFILE || ENFILE\n"); 592 | } 593 | return -1; 594 | } else { 595 | break; 596 | } 597 | } 598 | 599 | int ret = fcntl(sockfd, F_SETFL, O_NONBLOCK); 600 | if (ret == -1) { 601 | close(sockfd); 602 | return -1; 603 | } 604 | int reuse = 1; 605 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 606 | 607 | return sockfd; 608 | } 609 | 610 | int close(int fd) { 611 | 612 | if (!close_f) init_hook(); 613 | 614 | return close_f(fd); 615 | } 616 | 617 | 618 | 619 | int connect(int fd, const struct sockaddr *addr, socklen_t addrlen) { 620 | 621 | if (!connect_f) init_hook(); 622 | 623 | nty_schedule *sched = nty_coroutine_get_sched(); 624 | if (sched == NULL) { 625 | return connect_f(fd, addr, addrlen); 626 | } 627 | 628 | int ret = 0; 629 | 630 | while (1) { 631 | 632 | struct pollfd fds; 633 | fds.fd = fd; 634 | fds.events = POLLOUT | POLLERR | POLLHUP; 635 | nty_poll_inner(&fds, 1, 1); 636 | 637 | ret = connect_f(fd, addr, addrlen); 638 | if (ret == 0) break; 639 | 640 | if (ret == -1 && (errno == EAGAIN || 641 | errno == EWOULDBLOCK || 642 | errno == EINPROGRESS)) { 643 | continue; 644 | } else { 645 | break; 646 | } 647 | } 648 | 649 | return ret; 650 | } 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | #endif 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | -------------------------------------------------------------------------------- /deps/openssl-1.1.0g.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangbojing/NtyCo/72ab5fd04f0c228f464f160aaa521bb791b34aa5/deps/openssl-1.1.0g.tar.gz -------------------------------------------------------------------------------- /htdocs/check.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -Tw 2 | 3 | use strict; 4 | use CGI; 5 | 6 | my($cgi) = new CGI; 7 | 8 | print $cgi->header('text/html'); 9 | print $cgi->start_html(-title => "Example CGI script", 10 | -BGCOLOR => 'red'); 11 | print $cgi->h1("CGI Example"); 12 | print $cgi->p, "This is an example of CGI\n"; 13 | print $cgi->p, "Parameters given to this script:\n"; 14 | print "
    \n"; 15 | foreach my $param ($cgi->param) 16 | { 17 | print "
  • ", "$param ", $cgi->param($param), "\n"; 18 | } 19 | print "
"; 20 | print $cgi->end_html, "\n"; 21 | -------------------------------------------------------------------------------- /htdocs/color.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -Tw 2 | 3 | use strict; 4 | use CGI; 5 | 6 | my($cgi) = new CGI; 7 | 8 | print $cgi->header; 9 | my($color) = "blue"; 10 | $color = $cgi->param('color') if defined $cgi->param('color'); 11 | 12 | print $cgi->start_html(-title => uc($color), 13 | -BGCOLOR => $color); 14 | print $cgi->h1("This is $color"); 15 | print $cgi->end_html; 16 | -------------------------------------------------------------------------------- /htdocs/index.html: -------------------------------------------------------------------------------- 1 | 2 | Index 3 | 4 |

Welcome to J. David's webserver. 5 |

CGI demo 6 |
7 | Enter a color: 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | aux_source_directory(. SRC) 3 | 4 | # 编译不过的,先放这里 5 | set(NOT_COMPILE ) 6 | 7 | foreach(FILE_PATH ${SRC}) 8 | string(REGEX REPLACE ".+/(.+)\\..*" "\\1" FILE_NAME ${FILE_PATH}) 9 | list(FIND NOT_COMPILE ${FILE_NAME} RESULT) 10 | if(${RESULT} EQUAL -1) 11 | message(${FILE_NAME}) 12 | add_executable(${FILE_NAME} ${FILE_PATH}) 13 | target_link_libraries(${FILE_NAME} nty_core ${LIBS}) 14 | endif() 15 | endforeach() 16 | -------------------------------------------------------------------------------- /sample/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | CUR_SOURCE = ${wildcard *.c} 4 | 5 | CUR_OBJS = ${patsubst %.c, %.o, $(CUR_SOURCE)} 6 | 7 | all : $(SUB_DIR) $(CUR_OBJS) 8 | 9 | $(SUB_DIR) : ECHO 10 | make -C $@ 11 | 12 | $(CUR_OBJS) : %.o : %.c 13 | $(CC) -c $^ -o $(OBJS_DIR)/$@ $(FLAG) 14 | 15 | ECHO : 16 | @echo $(SUB_DIR) 17 | -------------------------------------------------------------------------------- /sample/hook_tcpserver.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #include "nty_coroutine.h" 6 | 7 | #include 8 | 9 | 10 | 11 | void server_reader(void *arg) { 12 | int fd = *(int *)arg; 13 | int ret = 0; 14 | 15 | 16 | while (1) { 17 | 18 | char buf[1024] = {0}; 19 | ret = recv(fd, buf, 1024, 0); 20 | if (ret > 0) { 21 | printf("read from server: %.*s\n", ret, buf); 22 | 23 | ret = send(fd, buf, strlen(buf), 0); 24 | if (ret == -1) { 25 | close(fd); 26 | break; 27 | } 28 | } else if (ret == 0) { 29 | close(fd); 30 | break; 31 | } 32 | 33 | } 34 | } 35 | 36 | 37 | 38 | void server(void *arg) { 39 | 40 | unsigned short port = *(unsigned short *)arg; 41 | 42 | int fd = socket(AF_INET, SOCK_STREAM, 0); 43 | if (fd < 0) return ; 44 | 45 | struct sockaddr_in local, remote; 46 | local.sin_family = AF_INET; 47 | local.sin_port = htons(port); 48 | local.sin_addr.s_addr = INADDR_ANY; 49 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 50 | 51 | listen(fd, 20); 52 | printf("listen port : %d\n", port); 53 | 54 | 55 | while (1) { 56 | socklen_t len = sizeof(struct sockaddr_in); 57 | int cli_fd = accept(fd, (struct sockaddr*)&remote, &len); 58 | 59 | 60 | nty_coroutine *read_co; 61 | nty_coroutine_create(&read_co, server_reader, &cli_fd); 62 | 63 | } 64 | 65 | } 66 | 67 | 68 | 69 | 70 | int main(int argc, char *argv[]) { 71 | 72 | int port = atoi(argv[1]); 73 | 74 | 75 | nty_coroutine *co = NULL; 76 | nty_coroutine_create(&co, server, &port); 77 | 78 | nty_schedule_run(); 79 | 80 | } 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /sample/nty_bench.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | /* 46 | * (C) Radim Kolar 1997-2004 47 | * This is free software, see GNU Public License version 2 for 48 | * details. 49 | * 50 | * Simple forking WWW Server benchmark: 51 | * 52 | * Usage: 53 | * webbench --help 54 | * 55 | * Return codes: 56 | * 0 - sucess 57 | * 1 - benchmark failed (server is not on-line) 58 | * 2 - bad param 59 | * 3 - internal error, fork failed 60 | * 61 | */ 62 | 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | 77 | #include "nty_coroutine.h" 78 | 79 | #define ENABLE_NTYCO 1 80 | #define MAX_BUFFER_LENGTH 1024 81 | 82 | 83 | #define write(a, b, c) nty_send(a, b, c, 0) 84 | #define send(a, b, c, d) nty_send(a, b, c, d) 85 | #define read(a, b, c) nty_recv(a, b, c, 0) 86 | #define recv(a, b, c, d) nty_recv(a, b, c, d) 87 | #define connect(a, b, c) nty_connect(a, b, c) 88 | #define socket(a, b, c) nty_socket(a, b, c) 89 | #define close(a) nty_close(a) 90 | #define accept(a, b, c) nty_accept(a, b, c) 91 | 92 | 93 | 94 | int Socket(const char *host, int clientPort) 95 | { 96 | int sock; 97 | unsigned long inaddr; 98 | struct sockaddr_in ad; 99 | struct hostent *hp; 100 | 101 | memset(&ad, 0, sizeof(ad)); 102 | ad.sin_family = AF_INET; 103 | 104 | inaddr = inet_addr(host); 105 | if (inaddr != INADDR_NONE) 106 | memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr)); 107 | else 108 | { 109 | hp = gethostbyname(host); 110 | if (hp == NULL) 111 | return -1; 112 | memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); 113 | } 114 | ad.sin_port = htons(clientPort); 115 | 116 | sock = socket(AF_INET, SOCK_STREAM, 0); 117 | if (sock < 0) 118 | return sock; 119 | if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0) 120 | return -1; 121 | return sock; 122 | } 123 | 124 | 125 | #include 126 | #include 127 | #include 128 | #include 129 | #include 130 | #include 131 | #include 132 | 133 | /* values */ 134 | volatile int timerexpired=0; 135 | int speed=0; 136 | int failed=0; 137 | int bytes=0; 138 | /* globals */ 139 | int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */ 140 | /* Allow: GET, HEAD, OPTIONS, TRACE */ 141 | #define METHOD_GET 0 142 | #define METHOD_HEAD 1 143 | #define METHOD_OPTIONS 2 144 | #define METHOD_TRACE 3 145 | #define PROGRAM_VERSION "1.5" 146 | int method=METHOD_GET; 147 | int clients=1; 148 | 149 | 150 | #if ENABLE_NTYCO 151 | // clients --> fork num 152 | // nreqs --> http request 153 | // socket --> io num 154 | // socket per fork --> sockets / client 155 | // request per socket --> request / sockets 156 | 157 | int nreqs = 0; 158 | int sockets = 0; 159 | #endif 160 | int force=0; 161 | int force_reload=0; 162 | int proxyport=80; 163 | char *proxyhost=NULL; 164 | int benchtime=30; 165 | /* internal */ 166 | int mypipe[2]; 167 | char host[MAXHOSTNAMELEN]; 168 | #define REQUEST_SIZE 2048 169 | char request[REQUEST_SIZE] = {0}; 170 | 171 | static const struct option long_options[]= 172 | { 173 | {"force",no_argument,&force,1}, 174 | {"reload",no_argument,&force_reload,1}, 175 | {"time",required_argument,NULL,'t'}, 176 | {"help",no_argument,NULL,'?'}, 177 | {"http09",no_argument,NULL,'9'}, 178 | {"http10",no_argument,NULL,'1'}, 179 | {"http11",no_argument,NULL,'2'}, 180 | {"get",no_argument,&method,METHOD_GET}, 181 | {"head",no_argument,&method,METHOD_HEAD}, 182 | {"options",no_argument,&method,METHOD_OPTIONS}, 183 | {"trace",no_argument,&method,METHOD_TRACE}, 184 | {"version",no_argument,NULL,'V'}, 185 | {"proxy",required_argument,NULL,'p'}, 186 | {"clients",required_argument,NULL,'c'}, 187 | {NULL,0,NULL,0} 188 | }; 189 | 190 | /* prototypes */ 191 | static void benchcore(const char* host,const int port, const char *request); 192 | static int bench(void); 193 | static void build_request(const char *url); 194 | 195 | static void alarm_handler(int signal) 196 | { 197 | timerexpired=1; 198 | } 199 | 200 | static void usage(void) 201 | { 202 | fprintf(stderr, 203 | "webbench [option]... URL\n" 204 | " -f|--force Don't wait for reply from server.\n" 205 | " -r|--reload Send reload request - Pragma: no-cache.\n" 206 | " -t|--time Run benchmark for seconds. Default 30.\n" 207 | " -n|--request Sum of requestion\n" 208 | " -s|--socket Sum of socket\n" 209 | " -p|--proxy Use proxy server for request.\n" 210 | " -c|--clients Run HTTP clients at once. Default one.\n" 211 | " -9|--http09 Use HTTP/0.9 style requests.\n" 212 | " -1|--http10 Use HTTP/1.0 protocol.\n" 213 | " -2|--http11 Use HTTP/1.1 protocol.\n" 214 | " --get Use GET request method.\n" 215 | " --head Use HEAD request method.\n" 216 | " --options Use OPTIONS request method.\n" 217 | " --trace Use TRACE request method.\n" 218 | " -?|-h|--help This information.\n" 219 | " -V|--version Display program version.\n" 220 | ); 221 | }; 222 | int main(int argc, char *argv[]) 223 | { 224 | int opt=0; 225 | int options_index=0; 226 | char *tmp=NULL; 227 | 228 | if(argc==1) 229 | { 230 | usage(); 231 | return 2; 232 | } 233 | 234 | while((opt=getopt_long(argc,argv,"912Vfrt:p:n:s:c:?h",long_options,&options_index))!=EOF ) 235 | { 236 | switch(opt) 237 | { 238 | case 0 : break; 239 | case 'f': force=1;break; 240 | case 'r': force_reload=1;break; 241 | case '9': http10=0;break; 242 | case '1': http10=1;break; 243 | case '2': http10=2;break; 244 | case 'V': printf(PROGRAM_VERSION"\n");exit(0); 245 | case 't': benchtime=atoi(optarg);break; 246 | case 'p': 247 | /* proxy server parsing server:port */ 248 | tmp=strrchr(optarg,':'); 249 | proxyhost=optarg; 250 | if(tmp==NULL) 251 | { 252 | break; 253 | } 254 | if(tmp==optarg) 255 | { 256 | fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg); 257 | return 2; 258 | } 259 | if(tmp==optarg+strlen(optarg)-1) 260 | { 261 | fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg); 262 | return 2; 263 | } 264 | *tmp='\0'; 265 | proxyport=atoi(tmp+1);break; 266 | case ':': 267 | case 'h': 268 | case '?': usage();return 2;break; 269 | case 'c': clients=atoi(optarg);break; 270 | #if ENABLE_NTYCO 271 | case 'n': nreqs=atoi(optarg);break; 272 | case 's': sockets=atoi(optarg);break; 273 | #endif 274 | } 275 | } 276 | 277 | if(optind==argc) { 278 | fprintf(stderr,"webbench: Missing URL!\n"); 279 | usage(); 280 | return 2; 281 | } 282 | 283 | if(clients==0) clients=1; 284 | if(benchtime==0) benchtime=60; 285 | 286 | #if ENABLE_NTYCO 287 | if (clients > 10) clients = 10; 288 | if (nreqs < 1000) nreqs = 1000; 289 | //if (sockets < clients) sockets = clients; 290 | if (sockets % clients != 0) sockets = sockets / clients * clients; 291 | #endif 292 | 293 | /* Copyright */ 294 | fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n" 295 | "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n" 296 | ); 297 | build_request(argv[optind]); 298 | /* print bench info */ 299 | printf("\nBenchmarking: "); 300 | switch(method) 301 | { 302 | case METHOD_GET: 303 | default: 304 | printf("GET");break; 305 | case METHOD_OPTIONS: 306 | printf("OPTIONS");break; 307 | case METHOD_HEAD: 308 | printf("HEAD");break; 309 | case METHOD_TRACE: 310 | printf("TRACE");break; 311 | } 312 | printf(" %s",argv[optind]); 313 | switch(http10) 314 | { 315 | case 0: printf(" (using HTTP/0.9)");break; 316 | case 2: printf(" (using HTTP/1.1)");break; 317 | } 318 | printf("\n"); 319 | if(clients==1) printf("1 client"); 320 | else 321 | printf("%d clients",clients); 322 | 323 | printf(", running %d sec", benchtime); 324 | if(force) printf(", early socket close"); 325 | if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport); 326 | if(force_reload) printf(", forcing reload"); 327 | printf(".\n"); 328 | return bench(); 329 | } 330 | 331 | void build_request(const char *url) 332 | { 333 | char tmp[10]; 334 | int i; 335 | 336 | bzero(host,MAXHOSTNAMELEN); 337 | bzero(request,REQUEST_SIZE); 338 | 339 | if(force_reload && proxyhost!=NULL && http10<1) http10=1; 340 | if(method==METHOD_HEAD && http10<1) http10=1; 341 | if(method==METHOD_OPTIONS && http10<2) http10=2; 342 | if(method==METHOD_TRACE && http10<2) http10=2; 343 | 344 | switch(method) 345 | { 346 | default: 347 | case METHOD_GET: strcpy(request,"GET");break; 348 | case METHOD_HEAD: strcpy(request,"HEAD");break; 349 | case METHOD_OPTIONS: strcpy(request,"OPTIONS");break; 350 | case METHOD_TRACE: strcpy(request,"TRACE");break; 351 | } 352 | 353 | strcat(request," "); 354 | 355 | if(NULL==strstr(url,"://")) 356 | { 357 | fprintf(stderr, "\n%s: is not a valid URL.\n",url); 358 | exit(2); 359 | } 360 | if(strlen(url)>1500) 361 | { 362 | fprintf(stderr,"URL is too long.\n"); 363 | exit(2); 364 | } 365 | if(proxyhost==NULL) 366 | if (0!=strncasecmp("http://",url,7)) 367 | { fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n"); 368 | exit(2); 369 | } 370 | /* protocol/host delimiter */ 371 | i=strstr(url,"://")-url+3; 372 | /* printf("%d\n",i); */ 373 | 374 | if(strchr(url+i,'/')==NULL) { 375 | fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n"); 376 | exit(2); 377 | } 378 | if(proxyhost==NULL) 379 | { 380 | /* get port from hostname */ 381 | if(index(url+i,':')!=NULL && 382 | index(url+i,':')0) 407 | strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n"); 408 | if(proxyhost==NULL && http10>0) 409 | { 410 | strcat(request,"Host: "); 411 | strcat(request,host); 412 | strcat(request,"\r\n"); 413 | } 414 | if(force_reload && proxyhost!=NULL) 415 | { 416 | strcat(request,"Pragma: no-cache\r\n"); 417 | } 418 | if(http10>1) 419 | strcat(request,"Connection: close\r\n"); 420 | /* add empty line at end */ 421 | if(http10>0) strcat(request,"\r\n"); 422 | // printf("Req=%s\n",request); 423 | } 424 | 425 | /* vraci system rc error kod */ 426 | static int bench(void) 427 | { 428 | int i,j,k; 429 | pid_t pid=0; 430 | FILE *f; 431 | #if ENABLE_NTYCO == 0 432 | /* check avaibility of target server */ 433 | i=Socket(proxyhost==NULL?host:proxyhost,proxyport); 434 | if(i<0) { 435 | fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n"); 436 | return 1; 437 | } 438 | close(i); 439 | #endif 440 | /* create pipe */ 441 | if(pipe(mypipe)) 442 | { 443 | perror("pipe failed."); 444 | return 3; 445 | } 446 | 447 | /* not needed, since we have alarm() in childrens */ 448 | /* wait 4 next system clock tick */ 449 | /* 450 | cas=time(NULL); 451 | while(time(NULL)==cas) 452 | sched_yield(); 453 | */ 454 | printf("bench enter\n"); 455 | 456 | /* fork childs */ 457 | for(i=0;i %d\n", sockfd, count); 580 | if (count < 0) { 581 | *ret = -1; 582 | break; 583 | } else if (count == 0) { 584 | *ret = 0; 585 | close(sockfd); 586 | break; 587 | } else { 588 | //printf("sockfd : %d, recv_buffer --> %d\n", sockfd, count); 589 | idx += count; 590 | } 591 | } 592 | if (idx > 0) *ret = 1; 593 | 594 | return idx; 595 | } 596 | 597 | 598 | void httprequest_commit(void *arg) { 599 | char buf[1500] = {0}; 600 | struct serv_host *shost = (struct serv_host *)arg; 601 | 602 | int slen = strlen(shost->req); 603 | 604 | int idx = 0; 605 | for (idx = 0;idx < (nreqs / sockets);idx ++) { 606 | 607 | int s = Socket(shost->host, shost->port); 608 | if (s < 0) { 609 | failed ++; 610 | continue ; 611 | } 612 | 613 | if (slen != send(s, shost->req, slen, 0)) { 614 | failed ++; 615 | close(s); 616 | continue; 617 | } 618 | 619 | memset(buf, 0, 1500); 620 | #if ENABLE_NTYCO 621 | int ret = 0; 622 | int rlen = recv_buffer(s, buf, 1500, &ret); 623 | #else 624 | int rlen = recv(s, buf, 1500, 0); 625 | #endif 626 | if (ret < 0) { 627 | failed ++; 628 | } else { 629 | 630 | if (testok(buf)) { 631 | speed ++; 632 | 633 | } else { 634 | failed ++; 635 | 636 | } 637 | bytes += rlen; 638 | } 639 | } 640 | 641 | return ; 642 | } 643 | 644 | 645 | void benchcore(const char *host,const int port,const char *req) 646 | { 647 | int rlen; 648 | char buf[1500]; 649 | int s,i; 650 | struct sigaction sa; 651 | 652 | /* setup alarm signal handler */ 653 | sa.sa_handler=alarm_handler; 654 | sa.sa_flags=0; 655 | if(sigaction(SIGALRM,&sa,NULL)) 656 | exit(3); 657 | alarm(benchtime); 658 | 659 | #if ENABLE_NTYCO 660 | 661 | //int i = 0; 662 | nty_coroutine *co = NULL; 663 | struct serv_host shost = {host, port, req}; 664 | 665 | for (i = 0;i < sockets / clients;i ++) { 666 | 667 | nty_coroutine_create(&co, httprequest_commit, &shost); 668 | } 669 | nty_schedule_run(); 670 | 671 | #else 672 | 673 | rlen=strlen(req); 674 | nexttry:while(1) 675 | { 676 | if(timerexpired) 677 | { 678 | if(failed>0) 679 | { 680 | /* fprintf(stderr,"Correcting failed by signal\n"); */ 681 | failed--; 682 | } 683 | return; 684 | } 685 | s=Socket(host,port); 686 | if(s<0) { failed++;continue;} 687 | if(rlen!=write(s, req, rlen)) {failed++;close(s);continue;} 688 | 689 | #if ENABLE_NTYCO 690 | if(http10==0) 691 | close(s); 692 | #else 693 | if(http10==0) 694 | if(shutdown(s,1)) { failed++;close(s);continue;} 695 | 696 | #endif 697 | if(force==0) 698 | { 699 | /* read all available data from socket */ 700 | while(1) 701 | { 702 | if(timerexpired) break; 703 | i=read(s,buf,1500); 704 | /* fprintf(stderr,"%d\n",i); */ 705 | if(i<0) 706 | { 707 | failed++; 708 | close(s); 709 | goto nexttry; 710 | } 711 | else 712 | if(i==0) break; 713 | else 714 | bytes+=i; 715 | } 716 | } 717 | if(close(s)) {failed++;continue;} 718 | speed++; 719 | } 720 | #endif 721 | } 722 | 723 | 724 | 725 | 726 | 727 | 728 | -------------------------------------------------------------------------------- /sample/nty_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | 47 | #include "nty_coroutine.h" 48 | 49 | #include 50 | 51 | 52 | 53 | #define NTY_SERVER_IPADDR "127.0.0.1" 54 | #define NTY_SERVER_PORT 9096 55 | 56 | int init_client(void) { 57 | 58 | int clientfd = nty_socket(AF_INET, SOCK_STREAM, 0); 59 | if (clientfd <= 0) { 60 | printf("socket failed\n"); 61 | return -1; 62 | } 63 | 64 | struct sockaddr_in serveraddr = {0}; 65 | serveraddr.sin_family = AF_INET; 66 | serveraddr.sin_port = htons(NTY_SERVER_PORT); 67 | serveraddr.sin_addr.s_addr = inet_addr(NTY_SERVER_IPADDR); 68 | 69 | int result = nty_connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); 70 | if (result != 0) { 71 | printf("connect failed\n"); 72 | return -2; 73 | } 74 | 75 | return clientfd; 76 | 77 | } 78 | 79 | void client(void *arg) { 80 | 81 | int clientfd = init_client(); 82 | char *buffer = "ntyco_client\r\n"; 83 | 84 | while (1) { 85 | 86 | int length = nty_send(clientfd, buffer, strlen(buffer), 0); 87 | printf("echo length : %d\n", length); 88 | 89 | sleep(1); 90 | } 91 | 92 | } 93 | 94 | 95 | 96 | int main(int argc, char *argv[]) { 97 | nty_coroutine *co = NULL; 98 | 99 | nty_coroutine_create(&co, client, NULL); 100 | 101 | nty_schedule_run(); //run 102 | 103 | return 0; 104 | } 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /sample/nty_http_epoll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | 47 | 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | 58 | #include 59 | #include 60 | #include 61 | 62 | #include 63 | 64 | #include 65 | #include 66 | #include 67 | 68 | #define __USE_GNU 69 | 70 | #include 71 | #include 72 | #include 73 | 74 | #include 75 | 76 | #define MAX_CLIENT_NUM 1000000 77 | #define TOTALFDS 16 78 | 79 | typedef struct _shm_area { 80 | int totalfds[TOTALFDS]; 81 | char cpu_lb[TOTALFDS]; 82 | //mtx : default 0 83 | // 1 : lock -- del epoll 84 | // 2 : lock -- del complete 85 | // 3 : unlock -- add 86 | // 0 : unlock -- add complete 87 | int accept_mtx; 88 | } shm_area; 89 | 90 | static shm_area *global_shmaddr = NULL; 91 | static int global_shmid = -1; 92 | 93 | int cpu_size = 0; 94 | int accept_disable = 1000; 95 | int enable_accept = 1; 96 | pid_t self_id = 0; 97 | 98 | 99 | 100 | unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) { 101 | unsigned long prev; 102 | volatile unsigned int *_ptr = (volatile unsigned int *)(addr); 103 | 104 | switch (size) { 105 | case 1: { 106 | __asm__ volatile ( 107 | "lock; cmpxchgb %b1, %2" 108 | : "=a" (prev) 109 | : "r" (_new), "m" (*_ptr), "0" (_old) 110 | : "memory"); 111 | break; 112 | } 113 | case 2: { 114 | __asm__ volatile ( 115 | "lock; cmpxchgw %w1, %2" 116 | : "=a" (prev) 117 | : "r" (_new), "m" (*_ptr), "0" (_old) 118 | : "memory"); 119 | break; 120 | } 121 | case 4: { 122 | __asm__ volatile ( 123 | "lock; cmpxchg %1, %2" 124 | : "=a" (prev) 125 | : "r" (_new), "m" (*_ptr), "0" (_old) 126 | : "memory"); 127 | break; 128 | } 129 | } 130 | 131 | return prev; 132 | } 133 | 134 | int atomic_add(volatile int *value, int add) 135 | { 136 | __asm__ volatile ( 137 | 138 | "lock;" 139 | " addl %0, %1; " 140 | 141 | : "+r" (add) : "m" (*value) : "cc", "memory"); 142 | 143 | return add; 144 | } 145 | 146 | int atomic_sub(volatile int *value, int sub) 147 | { 148 | __asm__ volatile ( 149 | 150 | "lock;" 151 | " subl %0, %1; " 152 | 153 | : "+r" (sub) : "m" (*value) : "cc", "memory"); 154 | 155 | return sub; 156 | } 157 | 158 | 159 | 160 | 161 | 162 | #define ISspace(x) isspace((int)(x)) 163 | 164 | #define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n" 165 | #define STDIN 0 166 | #define STDOUT 1 167 | #define STDERR 2 168 | 169 | #define ENABLE_NTYCO 0 170 | 171 | #if ENABLE_NTYCO 172 | 173 | #define socket nty_socket 174 | #define accept nty_accept 175 | #define recv(a, b, c, d) nty_recv(a, b, c, d) 176 | #define send(a, b, c, d) nty_send(a, b, c, d) 177 | 178 | #define MAX_BUFFER_LENGTH 1024 179 | 180 | 181 | 182 | #endif 183 | 184 | #define INC_COUNTFD do { \ 185 | atomic_add(&global_shmaddr->totalfds[self_id % cpu_size], 1); \ 186 | } while (0) 187 | 188 | 189 | #define DEC_COUNTFD do { \ 190 | atomic_sub(&global_shmaddr->totalfds[self_id % cpu_size], 1); \ 191 | } while (0) 192 | 193 | int get_countfd(void) { 194 | return global_shmaddr->totalfds[self_id % cpu_size]; 195 | } 196 | 197 | int max_countfd(void) { 198 | 199 | int count = -1; 200 | int i = 0; 201 | 202 | for (i = 0;i < cpu_size;i ++) { 203 | if (count < global_shmaddr->totalfds[i]) { 204 | count = global_shmaddr->totalfds[i]; 205 | } 206 | } 207 | return count; 208 | } 209 | 210 | int min_countfd(void) { 211 | 212 | int count = 0xffffffff; 213 | int i = 0; 214 | 215 | for (i = 0;i < cpu_size;i ++) { 216 | if (count > global_shmaddr->totalfds[i]) { 217 | count = global_shmaddr->totalfds[i]; 218 | } 219 | } 220 | return count; 221 | } 222 | 223 | int compare_out_countfd(void) { 224 | 225 | int current = get_countfd(); 226 | int min = min_countfd(); 227 | 228 | if ((current * 7 / 8) > min) { 229 | return 1; 230 | } else { 231 | return 0; 232 | } 233 | } 234 | 235 | int compare_in_countfd(void) { 236 | 237 | int current = get_countfd(); 238 | int max = max_countfd(); 239 | 240 | if ((current * 8 / 7) < max) { 241 | return 1; 242 | } else { 243 | return 0; 244 | } 245 | } 246 | 247 | void print_countfds(void) { 248 | 249 | int i = 0; 250 | for (i = 0;i < cpu_size;i ++) { 251 | printf("%5d : %5d ", i, global_shmaddr->totalfds[i]); 252 | } 253 | printf("\n"); 254 | } 255 | 256 | void lock_accept(void) { 257 | 258 | global_shmaddr->cpu_lb[self_id % cpu_size] = 1; 259 | 260 | int count = 0xffffffff; 261 | int i = 0; 262 | 263 | for (i = 0;i < cpu_size;i ++) { 264 | if (count > global_shmaddr->totalfds[i]) { 265 | count = global_shmaddr->totalfds[i]; 266 | } 267 | } 268 | 269 | for (i = 0;i < cpu_size;i ++) { 270 | if (count == global_shmaddr->totalfds[i]) { 271 | global_shmaddr->cpu_lb[i] = 3; 272 | } 273 | } 274 | 275 | } 276 | 277 | char read_accept(void) { 278 | return global_shmaddr->cpu_lb[self_id % cpu_size]; 279 | } 280 | 281 | void write_accept(char state) { //0, 1, 2, 3 282 | global_shmaddr->cpu_lb[self_id % cpu_size] = state; 283 | } 284 | 285 | int lock(void) { 286 | 287 | return cmpxchg(&global_shmaddr->accept_mtx, 0, 1, 4); //zero:success, non-zero:failed 288 | 289 | } 290 | 291 | void unlock(void) { 292 | 293 | global_shmaddr->accept_mtx = 0; 294 | 295 | } 296 | 297 | 298 | void accept_request(int fd, int epfd); 299 | void bad_request(int); 300 | void cat(int); 301 | void cannot_execute(int); 302 | void error_die(const char *); 303 | void execute_cgi(int, const char *, const char *, const char *); 304 | int get_line(int, char *, int); 305 | void headers(int); 306 | void not_found(int); 307 | void serve_file(int); 308 | int startup(u_short *); 309 | void unimplemented(int); 310 | 311 | 312 | ssize_t nsend(int fd, const void *buf, size_t len, int flags) { 313 | 314 | int sent = 0; 315 | 316 | int ret = send(fd, ((char*)buf)+sent, len-sent, flags); 317 | if (ret == 0) return ret; 318 | if (ret > 0) sent += ret; 319 | 320 | while (sent < len) { 321 | #if 0 322 | struct pollfd fds; 323 | fds.fd = fd; 324 | fds.events = POLLIN | POLLERR | POLLHUP; 325 | poll(&fds, 1, -1); 326 | #endif 327 | ret = send(fd, ((char*)buf)+sent, len-sent, flags); 328 | //printf("send --> len : %d\n", ret); 329 | if (ret <= 0) { 330 | if (errno == EAGAIN) continue; 331 | 332 | break; 333 | } 334 | sent += ret; 335 | } 336 | 337 | if (ret <= 0 && sent == 0) return ret; 338 | 339 | return sent; 340 | } 341 | 342 | static int ntySetNonblock(int fd) { 343 | int flags; 344 | 345 | flags = fcntl(fd, F_GETFL, 0); 346 | if (flags < 0) return flags; 347 | flags |= O_NONBLOCK; 348 | if (fcntl(fd, F_SETFL, flags) < 0) return -1; 349 | return 0; 350 | } 351 | 352 | static int ntySetReUseAddr(int fd) { 353 | int reuse = 1; 354 | return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 355 | } 356 | 357 | 358 | /**********************************************************************/ 359 | /* A request has caused a call to accept() on the server port to 360 | * return. Process the request appropriately. 361 | * Parameters: the socket connected to the client */ 362 | /**********************************************************************/ 363 | void accept_request(int fd, int epfd) 364 | { 365 | int client = fd; 366 | 367 | char buf[1024]; 368 | size_t numchars; 369 | char method[16]; 370 | char url[32]; 371 | char path[64]; 372 | size_t i, j; 373 | struct stat st; 374 | int cgi = 0; /* becomes true if server decides this is a CGI 375 | * program */ 376 | char *query_string = NULL; 377 | 378 | numchars = recv(client, buf, sizeof(buf), 0); 379 | if (numchars == -1) { 380 | //printf("recv errno : %d\n", errno); 381 | if (errno == ECONNRESET) { 382 | close(client); 383 | 384 | struct epoll_event ev; 385 | ev.events = EPOLLIN | EPOLLET; 386 | ev.data.fd = client; 387 | epoll_ctl(epfd, EPOLL_CTL_DEL, client, &ev); 388 | 389 | DEC_COUNTFD; 390 | } 391 | } else if (numchars == 0) { 392 | close(client); 393 | 394 | struct epoll_event ev; 395 | ev.events = EPOLLIN | EPOLLET; 396 | ev.data.fd = client; 397 | epoll_ctl(epfd, EPOLL_CTL_DEL, client, &ev); 398 | 399 | DEC_COUNTFD; 400 | } else { 401 | //printf("recv numchars : %ld\n", numchars); 402 | } 403 | //serve_file(client, path); 404 | 405 | } 406 | 407 | #if 0 408 | #define HTML_PAGE " \ 409 | Index \ 410 | \ 411 |

Welcome to J. David's webserver.\ 412 |

CGI demo \ 413 |
\ 414 | Enter a color: \ 415 | \ 416 |
\ 417 | \ 418 | " 419 | 420 | #else 421 | #define HTML_PAGE " \ 422 | \ 423 | \ 424 | Welcome to nginx! \ 425 | \ 432 | \ 433 | \ 434 |

Welcome to nginx!

\ 435 |

If you see this page, the nginx web server is successfully installed and\ 436 | working. Further configuration is required.

\ 437 | \ 438 |

For online documentation and support please refer to\ 439 | nginx.org.
\ 440 | Commercial support is available at\ 441 | nginx.com.

\ 442 | \ 443 |

Thank you for using nginx.

\ 444 | \ 445 | " 446 | #endif 447 | 448 | void cat(int client) 449 | { 450 | 451 | //char buf[1024] = HTML_PAGE; 452 | 453 | int ret = send(client, HTML_PAGE, strlen(HTML_PAGE), 0); 454 | if (ret == -1) { 455 | printf("send : errno : %d\n", errno); 456 | } else { 457 | printf("cat send ret : %d\n", ret); 458 | } 459 | 460 | } 461 | 462 | void error_die(const char *sc) 463 | { 464 | printf("%s\n", sc); 465 | exit(1); 466 | } 467 | 468 | void headers(int client) 469 | { 470 | char buf[1024] = {0}; 471 | char content[128] = {0}; 472 | 473 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 474 | strcat(buf, SERVER_STRING); 475 | strcat(buf, "Content-Type: text/html\r\n"); 476 | #if 0 477 | strcat(buf, "Transfer-Encoding: chunked\r\n"); 478 | #else 479 | sprintf(content, "Content-Length: %ld\r\n", strlen(HTML_PAGE)); 480 | strcat(buf, content); 481 | #endif 482 | strcat(buf, "\r\n"); 483 | 484 | strcat(buf, HTML_PAGE); 485 | 486 | int ret = send(client, buf, strlen(buf), 0); 487 | if (ret == -1) { 488 | printf("send : errno : %d\n", errno); 489 | } else { 490 | //printf("headers send ret : %d\n", ret); 491 | } 492 | 493 | 494 | } 495 | 496 | /**********************************************************************/ 497 | /* Send a regular file to the client. Use headers, and report 498 | * errors to client if they occur. 499 | * Parameters: a pointer to a file structure produced from the socket 500 | * file descriptor 501 | * the name of the file to serve */ 502 | /**********************************************************************/ 503 | void serve_file(int client) 504 | { 505 | headers(client); 506 | //cat(client); 507 | 508 | } 509 | 510 | #define MAX_EPOLLSIZE 10240 511 | 512 | void server(void *arg) { 513 | 514 | int fd = *(int *)arg; 515 | 516 | int epfd = epoll_create(1); 517 | struct epoll_event events[MAX_EPOLLSIZE]; 518 | 519 | struct epoll_event ev; 520 | ev.events = EPOLLIN; 521 | ev.data.fd = fd; 522 | epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); 523 | int acc = 1; // 524 | 525 | while (1) { 526 | #if 0 527 | char lock = read_accept(); 528 | if (lock == 1) { //lock 529 | ev.events = EPOLLIN; 530 | ev.data.fd = fd; 531 | epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev); 532 | 533 | write_accept(2); //add complete 534 | 535 | } else if (acc == 0 && lock == 3) { 536 | ev.events = EPOLLIN; 537 | ev.data.fd = fd; 538 | epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); 539 | 540 | write_accept(0); 541 | } 542 | #endif 543 | int nready = epoll_wait(epfd, events, MAX_EPOLLSIZE, 1); 544 | if (nready == -1) { 545 | if (errno == EINTR) { 546 | printf("errno : EINTR\n"); 547 | continue; 548 | } 549 | continue; 550 | } 551 | 552 | int i = 0; 553 | for (i = 0;i < nready;i ++) { 554 | int sockfd = events[i].data.fd; 555 | if (sockfd == fd) { 556 | 557 | struct sockaddr_in client_addr; 558 | memset(&client_addr, 0, sizeof(struct sockaddr_in)); 559 | socklen_t client_len = sizeof(client_addr); 560 | #if 0 561 | if (get_countfd() % accept_disable == 999) { 562 | lock_accept(); 563 | acc = 0; 564 | } 565 | char lock = read_accept(); 566 | if (lock != 0 && lock != 3) continue; 567 | #endif 568 | if (lock()) { 569 | continue; 570 | } 571 | int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); 572 | unlock(); 573 | 574 | if (clientfd < 0) { 575 | if (errno == EAGAIN) { 576 | //printf("accept : EAGAIN\n"); 577 | continue; 578 | } else if (errno == ECONNABORTED) { 579 | printf("accept : ECONNABORTED\n"); 580 | 581 | } else if (errno == EMFILE || errno == ENFILE) { 582 | printf("accept : EMFILE || ENFILE\n"); 583 | } 584 | return ; 585 | } 586 | 587 | INC_COUNTFD; 588 | 589 | ntySetNonblock(clientfd); 590 | ntySetReUseAddr(clientfd); 591 | 592 | struct epoll_event ev; 593 | ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT; 594 | ev.data.fd = clientfd; 595 | epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev); 596 | 597 | } 598 | else if (events[i].events & EPOLLIN) { 599 | 600 | accept_request(sockfd, epfd); 601 | #if 1 602 | //struct epoll_event ev; 603 | ev.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; 604 | ev.data.fd = sockfd; 605 | epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); 606 | 607 | //close(sockfd); 608 | #endif 609 | } 610 | else if (events[i].events & EPOLLOUT) { 611 | 612 | serve_file(sockfd); 613 | 614 | //close(sockfd); 615 | 616 | //struct epoll_event ev; 617 | ev.events = EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR; 618 | ev.data.fd = sockfd; 619 | epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); 620 | 621 | DEC_COUNTFD; 622 | 623 | } 624 | else if (events[i].events & (EPOLLHUP|EPOLLRDHUP|EPOLLERR)) { 625 | 626 | close(sockfd); 627 | 628 | printf(" EPOLLHUP | EPOLLRDHUP\n"); 629 | //struct epoll_event ev; 630 | ev.events = EPOLLIN | EPOLLET | EPOLLONESHOT; 631 | ev.data.fd = sockfd; 632 | epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, &ev); 633 | 634 | DEC_COUNTFD; 635 | } 636 | } 637 | 638 | // print_countfds(); 639 | } 640 | 641 | } 642 | 643 | int mulcore_entry(int begin_port) { 644 | 645 | int i = 0; 646 | unsigned short base_port = begin_port; 647 | 648 | unsigned short *port = calloc(1, sizeof(unsigned short)); 649 | *port = base_port; 650 | server(port); 651 | 652 | } 653 | 654 | int process_bind(int fd) { 655 | 656 | int num = sysconf(_SC_NPROCESSORS_CONF); 657 | 658 | self_id = syscall(__NR_gettid); 659 | //printf("selfid --> %d\n", self_id); 660 | 661 | cpu_set_t mask; 662 | 663 | CPU_ZERO(&mask); 664 | CPU_SET(self_id % num, &mask); 665 | 666 | sched_setaffinity(0, sizeof(mask), &mask); 667 | server(&fd); 668 | //mulcore_entry(9000); 669 | 670 | } 671 | 672 | int init_shmvalue(int num) { 673 | 674 | global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600); 675 | if (global_shmid < 0) { 676 | perror("shmget failed\n"); 677 | return -1; 678 | } 679 | global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0); 680 | if (global_shmaddr == (shm_area*)-1) { 681 | perror("shmat addr error"); 682 | return -1; 683 | } 684 | memset(global_shmaddr->totalfds, 0, TOTALFDS * sizeof(int)); 685 | memset(global_shmaddr->cpu_lb, 0, TOTALFDS * sizeof(char)); 686 | global_shmaddr->accept_mtx = 0; 687 | } 688 | 689 | 690 | 691 | 692 | int main(int argc, char *argv[]) { 693 | 694 | short port = 9000; 695 | struct sockaddr_in client_name; 696 | socklen_t client_name_len = sizeof(client_name); 697 | 698 | int fd = socket(AF_INET, SOCK_STREAM, 0); 699 | if (fd < 0) return -1; 700 | 701 | ntySetNonblock(fd); 702 | ntySetReUseAddr(fd); 703 | 704 | 705 | struct sockaddr_in local, remote; 706 | local.sin_family = AF_INET; 707 | local.sin_port = htons(port); 708 | local.sin_addr.s_addr = INADDR_ANY; 709 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 710 | 711 | listen(fd, 20); 712 | 713 | int num = sysconf(_SC_NPROCESSORS_CONF); 714 | cpu_size = num; 715 | init_shmvalue(num); 716 | 717 | int i = 0; 718 | pid_t pid=0; 719 | for(i = 0;i < num;i ++) { 720 | pid=fork(); 721 | if(pid <= (pid_t) 0) 722 | { 723 | usleep(1); 724 | break; 725 | } 726 | } 727 | #if 1 728 | if (pid > 0) { 729 | printf("ntyco_httpd server running ...\n"); 730 | getchar(); 731 | } else if (pid == 0) { 732 | process_bind(fd); 733 | } 734 | #else 735 | 736 | 737 | INC_COUNTFD; 738 | 739 | INC_COUNTFD; 740 | print_countfds(); 741 | 742 | 743 | #endif 744 | } 745 | 746 | -------------------------------------------------------------------------------- /sample/nty_http_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | /* J. David's webserver */ 46 | /* This is a simple webserver. 47 | * Created November 1999 by J. David Blackstone. 48 | * CSE 4344 (Network concepts), Prof. Zeigler 49 | * University of Texas at Arlington 50 | */ 51 | /* This program compiles for Sparc Solaris 2.6. 52 | * To compile for Linux: 53 | * 1) Comment out the #include line. 54 | * 2) Comment out the line that defines the variable newthread. 55 | * 3) Comment out the two lines that run pthread_create(). 56 | * 4) Uncomment the line that runs accept_request(). 57 | * 5) Remove -lsocket from the Makefile. 58 | */ 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | 74 | #define ISspace(x) isspace((int)(x)) 75 | 76 | #define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n" 77 | #define STDIN 0 78 | #define STDOUT 1 79 | #define STDERR 2 80 | 81 | #define ENABLE_NTYCO 1 82 | 83 | #if ENABLE_NTYCO 84 | #include "nty_coroutine.h" 85 | 86 | #define socket nty_socket 87 | #define accept nty_accept 88 | #define recv(a, b, c, d) nty_recv(a, b, c, d) 89 | #define send(a, b, c, d) nty_send(a, b, c, d) 90 | 91 | #define MAX_BUFFER_LENGTH 1024 92 | 93 | #endif 94 | 95 | void accept_request(void *); 96 | void bad_request(int); 97 | void cat(int, FILE *); 98 | void cannot_execute(int); 99 | void error_die(const char *); 100 | void execute_cgi(int, const char *, const char *, const char *); 101 | int get_line(int, char *, int); 102 | void headers(int, const char *); 103 | void not_found(int); 104 | void serve_file(int, const char *); 105 | int startup(u_short *); 106 | void unimplemented(int); 107 | 108 | int readline(char* allbuf,int level,char* linebuf){ 109 | int len = strlen(allbuf); 110 | 111 | for (;level < len; ++level) { 112 | if(allbuf[level]=='\r' && allbuf[level+1]=='\n') 113 | return level+2; 114 | else 115 | *(linebuf++) = allbuf[level]; 116 | } 117 | 118 | return -1; 119 | } 120 | 121 | 122 | /**********************************************************************/ 123 | /* A request has caused a call to accept() on the server port to 124 | * return. Process the request appropriately. 125 | * Parameters: the socket connected to the client */ 126 | /**********************************************************************/ 127 | void accept_request(void *arg) 128 | { 129 | int *pclient = (int*)arg; 130 | int client = *pclient; 131 | 132 | char buf[1024]; 133 | size_t numchars; 134 | char method[255]; 135 | char url[255]; 136 | char path[512]; 137 | size_t i, j; 138 | struct stat st; 139 | int cgi = 0; /* becomes true if server decides this is a CGI 140 | * program */ 141 | char *query_string = NULL; 142 | 143 | numchars = nty_recv(client, buf, sizeof(buf), 0); 144 | 145 | i = 0; j = 0; 146 | while (!ISspace(buf[i]) && (i < sizeof(method) - 1)) 147 | { 148 | method[i] = buf[i]; 149 | i++; 150 | } 151 | j=i; 152 | method[i] = '\0'; 153 | 154 | if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) 155 | { 156 | unimplemented(client); 157 | return; 158 | } 159 | 160 | if (strcasecmp(method, "POST") == 0) 161 | cgi = 1; 162 | 163 | i = 0; 164 | while (ISspace(buf[j]) && (j < numchars)) 165 | j++; 166 | while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < numchars)) 167 | { 168 | url[i] = buf[j]; 169 | i++; j++; 170 | } 171 | url[i] = '\0'; 172 | 173 | if (strcasecmp(method, "GET") == 0) 174 | { 175 | query_string = url; 176 | while ((*query_string != '?') && (*query_string != '\0')) 177 | query_string++; 178 | if (*query_string == '?') 179 | { 180 | cgi = 1; 181 | *query_string = '\0'; 182 | query_string++; 183 | } 184 | } 185 | 186 | sprintf(path, "htdocs%s", url); 187 | if (path[strlen(path) - 1] == '/') 188 | strcat(path, "index.html"); 189 | if (stat(path, &st) == -1) { 190 | while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ 191 | numchars = get_line(client, buf, sizeof(buf)); 192 | not_found(client); 193 | } 194 | else 195 | { 196 | if ((st.st_mode & S_IFMT) == S_IFDIR) 197 | strcat(path, "/index.html"); 198 | if ((st.st_mode & S_IXUSR) || 199 | (st.st_mode & S_IXGRP) || 200 | (st.st_mode & S_IXOTH) ) 201 | cgi = 1; 202 | 203 | cgi = 0; 204 | 205 | if (!cgi) 206 | serve_file(client, path); 207 | else 208 | execute_cgi(client, path, method, query_string); 209 | } 210 | 211 | nty_close(client); 212 | free(pclient); 213 | } 214 | 215 | 216 | /**********************************************************************/ 217 | /* Inform the client that a request it has made has a problem. 218 | * Parameters: client socket */ 219 | /**********************************************************************/ 220 | void bad_request(int client) 221 | { 222 | char buf[1024]; 223 | 224 | sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n"); 225 | send(client, buf, sizeof(buf), 0); 226 | sprintf(buf, "Content-type: text/html\r\n"); 227 | send(client, buf, sizeof(buf), 0); 228 | sprintf(buf, "\r\n"); 229 | send(client, buf, sizeof(buf), 0); 230 | sprintf(buf, "

Your browser sent a bad request, "); 231 | send(client, buf, sizeof(buf), 0); 232 | sprintf(buf, "such as a POST without a Content-Length.\r\n"); 233 | send(client, buf, sizeof(buf), 0); 234 | } 235 | 236 | /**********************************************************************/ 237 | /* Put the entire contents of a file out on a socket. This function 238 | * is named after the UNIX "cat" command, because it might have been 239 | * easier just to do something like pipe, fork, and exec("cat"). 240 | * Parameters: the client socket descriptor 241 | * FILE pointer for the file to cat */ 242 | /**********************************************************************/ 243 | void cat(int client, FILE *resource) 244 | { 245 | char buf[1024]; 246 | 247 | char *ch = fgets(buf, sizeof(buf), resource); 248 | while (!feof(resource)) 249 | { 250 | send(client, buf, strlen(buf), 0); 251 | ch = fgets(buf, sizeof(buf), resource); 252 | } 253 | } 254 | 255 | /**********************************************************************/ 256 | /* Inform the client that a CGI script could not be executed. 257 | * Parameter: the client socket descriptor. */ 258 | /**********************************************************************/ 259 | void cannot_execute(int client) 260 | { 261 | char buf[1024]; 262 | 263 | sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n"); 264 | send(client, buf, strlen(buf), 0); 265 | sprintf(buf, "Content-type: text/html\r\n"); 266 | send(client, buf, strlen(buf), 0); 267 | sprintf(buf, "\r\n"); 268 | send(client, buf, strlen(buf), 0); 269 | sprintf(buf, "

Error prohibited CGI execution.\r\n"); 270 | send(client, buf, strlen(buf), 0); 271 | } 272 | 273 | /**********************************************************************/ 274 | /* Print out an error message with perror() (for system errors; based 275 | * on value of errno, which indicates system call errors) and exit the 276 | * program indicating an error. */ 277 | /**********************************************************************/ 278 | void error_die(const char *sc) 279 | { 280 | perror(sc); 281 | exit(1); 282 | } 283 | 284 | /**********************************************************************/ 285 | /* Execute a CGI script. Will need to set environment variables as 286 | * appropriate. 287 | * Parameters: client socket descriptor 288 | * path to the CGI script */ 289 | /**********************************************************************/ 290 | void execute_cgi(int client, const char *path, 291 | const char *method, const char *query_string) 292 | { 293 | char buf[1024]; 294 | int cgi_output[2]; 295 | int cgi_input[2]; 296 | pid_t pid; 297 | int status; 298 | int i; 299 | char c; 300 | int numchars = 1; 301 | int content_length = -1; 302 | 303 | buf[0] = 'A'; buf[1] = '\0'; 304 | if (strcasecmp(method, "GET") == 0) 305 | while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ 306 | numchars = get_line(client, buf, sizeof(buf)); 307 | else if (strcasecmp(method, "POST") == 0) /*POST*/ 308 | { 309 | numchars = get_line(client, buf, sizeof(buf)); 310 | while ((numchars > 0) && strcmp("\n", buf)) 311 | { 312 | buf[15] = '\0'; 313 | if (strcasecmp(buf, "Content-Length:") == 0) 314 | content_length = atoi(&(buf[16])); 315 | numchars = get_line(client, buf, sizeof(buf)); 316 | } 317 | if (content_length == -1) { 318 | bad_request(client); 319 | return; 320 | } 321 | } 322 | else/*HEAD or other*/ 323 | { 324 | } 325 | 326 | 327 | if (pipe(cgi_output) < 0) { 328 | cannot_execute(client); 329 | return; 330 | } 331 | if (pipe(cgi_input) < 0) { 332 | cannot_execute(client); 333 | return; 334 | } 335 | 336 | if ( (pid = fork()) < 0 ) { 337 | cannot_execute(client); 338 | return; 339 | } 340 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 341 | send(client, buf, strlen(buf), 0); 342 | if (pid == 0) /* child: CGI script */ 343 | { 344 | char meth_env[255]; 345 | char query_env[255]; 346 | char length_env[255]; 347 | 348 | dup2(cgi_output[1], STDOUT); 349 | dup2(cgi_input[0], STDIN); 350 | close(cgi_output[0]); 351 | close(cgi_input[1]); 352 | sprintf(meth_env, "REQUEST_METHOD=%s", method); 353 | putenv(meth_env); 354 | if (strcasecmp(method, "GET") == 0) { 355 | sprintf(query_env, "QUERY_STRING=%s", query_string); 356 | putenv(query_env); 357 | } 358 | else { /* POST */ 359 | sprintf(length_env, "CONTENT_LENGTH=%d", content_length); 360 | putenv(length_env); 361 | } 362 | execl(path, "", NULL); 363 | exit(0); 364 | } else { /* parent */ 365 | close(cgi_output[1]); 366 | close(cgi_input[0]); 367 | if (strcasecmp(method, "POST") == 0) 368 | for (i = 0; i < content_length; i++) { 369 | recv(client, &c, 1, 0); 370 | int len = write(cgi_input[1], &c, 1); 371 | } 372 | while (read(cgi_output[0], &c, 1) > 0) 373 | send(client, &c, 1, 0); 374 | 375 | close(cgi_output[0]); 376 | close(cgi_input[1]); 377 | waitpid(pid, &status, 0); 378 | } 379 | } 380 | 381 | /**********************************************************************/ 382 | /* Get a line from a socket, whether the line ends in a newline, 383 | * carriage return, or a CRLF combination. Terminates the string read 384 | * with a null character. If no newline indicator is found before the 385 | * end of the buffer, the string is terminated with a null. If any of 386 | * the above three line terminators is read, the last character of the 387 | * string will be a linefeed and the string will be terminated with a 388 | * null character. 389 | * Parameters: the socket descriptor 390 | * the buffer to save the data in 391 | * the size of the buffer 392 | * Returns: the number of bytes stored (excluding null) */ 393 | /**********************************************************************/ 394 | int get_line(int sock, char *buf, int size) 395 | { 396 | int i = 0; 397 | char c = '\0'; 398 | int n; 399 | 400 | while ((i < size - 1) && (c != '\n')) 401 | { 402 | 403 | n = recv(sock, &c, 1, 0); 404 | 405 | if (n > 0) 406 | { 407 | if (c == '\r') 408 | { 409 | n = recv(sock, &c, 1, MSG_PEEK); 410 | 411 | if ((n > 0) && (c == '\n')) 412 | recv(sock, &c, 1, 0); 413 | else 414 | c = '\n'; 415 | } 416 | buf[i] = c; 417 | i++; 418 | } 419 | else 420 | c = '\n'; 421 | } 422 | buf[i] = '\0'; 423 | 424 | return(i); 425 | } 426 | 427 | /**********************************************************************/ 428 | /* Return the informational HTTP headers about a file. */ 429 | /* Parameters: the socket to print the headers on 430 | * the name of the file */ 431 | /**********************************************************************/ 432 | void headers(int client, const char *filename) 433 | { 434 | char buf[1024]; 435 | (void)filename; /* could use filename to determine file type */ 436 | 437 | strcpy(buf, "HTTP/1.0 200 OK\r\n"); 438 | send(client, buf, strlen(buf), 0); 439 | strcpy(buf, SERVER_STRING); 440 | send(client, buf, strlen(buf), 0); 441 | sprintf(buf, "Content-Type: text/html\r\n"); 442 | send(client, buf, strlen(buf), 0); 443 | strcpy(buf, "\r\n"); 444 | send(client, buf, strlen(buf), 0); 445 | } 446 | 447 | /**********************************************************************/ 448 | /* Give a client a 404 not found status message. */ 449 | /**********************************************************************/ 450 | void not_found(int client) 451 | { 452 | char buf[1024]; 453 | 454 | sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n"); 455 | send(client, buf, strlen(buf), 0); 456 | sprintf(buf, SERVER_STRING); 457 | send(client, buf, strlen(buf), 0); 458 | sprintf(buf, "Content-Type: text/html\r\n"); 459 | send(client, buf, strlen(buf), 0); 460 | sprintf(buf, "\r\n"); 461 | send(client, buf, strlen(buf), 0); 462 | sprintf(buf, "Not Found\r\n"); 463 | send(client, buf, strlen(buf), 0); 464 | sprintf(buf, "

The server could not fulfill\r\n"); 465 | send(client, buf, strlen(buf), 0); 466 | sprintf(buf, "your request because the resource specified\r\n"); 467 | send(client, buf, strlen(buf), 0); 468 | sprintf(buf, "is unavailable or nonexistent.\r\n"); 469 | send(client, buf, strlen(buf), 0); 470 | sprintf(buf, "\r\n"); 471 | send(client, buf, strlen(buf), 0); 472 | } 473 | 474 | /**********************************************************************/ 475 | /* Send a regular file to the client. Use headers, and report 476 | * errors to client if they occur. 477 | * Parameters: a pointer to a file structure produced from the socket 478 | * file descriptor 479 | * the name of the file to serve */ 480 | /**********************************************************************/ 481 | void serve_file(int client, const char *filename) 482 | { 483 | FILE *resource = NULL; 484 | int numchars = 1; 485 | char buf[1024]; 486 | 487 | #if (ENABLE_NTYCO == 0) 488 | buf[0] = 'A'; buf[1] = '\0'; 489 | while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ 490 | numchars = get_line(client, buf, sizeof(buf)); 491 | #endif 492 | 493 | resource = fopen(filename, "r"); 494 | if (resource == NULL) 495 | not_found(client); 496 | else 497 | { 498 | headers(client, filename); 499 | cat(client, resource); 500 | } 501 | fclose(resource); 502 | } 503 | 504 | /**********************************************************************/ 505 | /* This function starts the process of listening for web connections 506 | * on a specified port. If the port is 0, then dynamically allocate a 507 | * port and modify the original port variable to reflect the actual 508 | * port. 509 | * Parameters: pointer to variable containing the port to connect on 510 | * Returns: the socket */ 511 | /**********************************************************************/ 512 | int startup(u_short *port) 513 | { 514 | int httpd = 0; 515 | int on = 1; 516 | struct sockaddr_in name; 517 | 518 | httpd = socket(PF_INET, SOCK_STREAM, 0); 519 | if (httpd == -1) 520 | error_die("socket"); 521 | memset(&name, 0, sizeof(name)); 522 | name.sin_family = AF_INET; 523 | name.sin_port = htons(*port); 524 | name.sin_addr.s_addr = htonl(INADDR_ANY); 525 | if ((setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) 526 | { 527 | error_die("setsockopt failed"); 528 | } 529 | if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) 530 | error_die("bind"); 531 | if (*port == 0) /* if dynamically allocating a port */ 532 | { 533 | socklen_t namelen = sizeof(name); 534 | if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) 535 | error_die("getsockname"); 536 | *port = ntohs(name.sin_port); 537 | } 538 | if (listen(httpd, 5) < 0) 539 | error_die("listen"); 540 | 541 | 542 | return(httpd); 543 | } 544 | 545 | /**********************************************************************/ 546 | /* Inform the client that the requested web method has not been 547 | * implemented. 548 | * Parameter: the client socket */ 549 | /**********************************************************************/ 550 | void unimplemented(int client) 551 | { 552 | char buf[1024]; 553 | 554 | sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n"); 555 | send(client, buf, strlen(buf), 0); 556 | sprintf(buf, SERVER_STRING); 557 | send(client, buf, strlen(buf), 0); 558 | sprintf(buf, "Content-Type: text/html\r\n"); 559 | send(client, buf, strlen(buf), 0); 560 | sprintf(buf, "\r\n"); 561 | send(client, buf, strlen(buf), 0); 562 | sprintf(buf, "Method Not Implemented\r\n"); 563 | send(client, buf, strlen(buf), 0); 564 | sprintf(buf, "\r\n"); 565 | send(client, buf, strlen(buf), 0); 566 | sprintf(buf, "

HTTP request method not supported.\r\n"); 567 | send(client, buf, strlen(buf), 0); 568 | sprintf(buf, "\r\n"); 569 | send(client, buf, strlen(buf), 0); 570 | } 571 | 572 | /**********************************************************************/ 573 | 574 | 575 | void server(void *arg) 576 | { 577 | int server_sock = -1; 578 | u_short port = 4000; 579 | struct sockaddr_in client_name; 580 | socklen_t client_name_len = sizeof(client_name); 581 | 582 | server_sock = startup(&port); 583 | printf("httpd running on port %d\n", port); 584 | 585 | while (1) 586 | { 587 | int *client_sock = (int *)malloc(sizeof(int)); 588 | *client_sock = accept(server_sock, 589 | (struct sockaddr *)&client_name, 590 | &client_name_len); 591 | if (*client_sock == -1) 592 | error_die("accept"); 593 | /* accept_request(&client_sock); */ 594 | #if 1 //ENABLE_NTYCO 595 | 596 | printf(" %d.%d.%d.%d:%d clientfd:%d --> New Client Connected \n", 597 | *(unsigned char*)(&client_name.sin_addr.s_addr), *((unsigned char*)(&client_name.sin_addr.s_addr)+1), 598 | *((unsigned char*)(&client_name.sin_addr.s_addr)+2), *((unsigned char*)(&client_name.sin_addr.s_addr)+3), 599 | client_name.sin_port, *client_sock); 600 | 601 | nty_coroutine *read_co; 602 | nty_coroutine_create(&read_co, accept_request, client_sock); 603 | 604 | #else 605 | pthread_t newthread; 606 | if (pthread_create(&newthread , NULL, (void *)accept_request, (void *)(intptr_t)client_sock) != 0) 607 | perror("pthread_create"); 608 | #endif 609 | } 610 | 611 | nty_close(server_sock); 612 | 613 | return ; 614 | } 615 | 616 | 617 | int main(int argc, char *argv[]) { 618 | 619 | nty_coroutine *co = NULL; 620 | nty_coroutine_create(&co, server, 0); ////////no run 621 | 622 | 623 | nty_schedule_run(); //run 624 | 625 | return 0; 626 | } 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | -------------------------------------------------------------------------------- /sample/nty_mysql_client.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #include "nty_coroutine.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | void func (void *arg) { 14 | 15 | 16 | MYSQL* m_mysql = mysql_init(NULL); 17 | if (!m_mysql) { 18 | printf("mysql_init failed\n"); 19 | return ; 20 | } 21 | 22 | if (!mysql_real_connect(m_mysql, 23 | "192.168.233.133", "king", "123456", 24 | "KING_DB", 3306, 25 | NULL, CLIENT_FOUND_ROWS)) { 26 | printf("mysql_real_connect failed: %s\n", mysql_error(m_mysql)); 27 | return ; 28 | } else{ 29 | printf("mysql_real_connect success\n"); 30 | } 31 | 32 | 33 | } 34 | 35 | int main() { 36 | #if 1 37 | init_hook(); 38 | 39 | nty_coroutine *co = NULL; 40 | nty_coroutine_create(&co, func, NULL); 41 | nty_schedule_run(); //run 42 | #else 43 | 44 | func(NULL); 45 | 46 | #endif 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /sample/nty_mysql_oper.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #include "nty_coroutine.h" 6 | 7 | 8 | #include 9 | 10 | 11 | #define KING_DB_SERVER_IP "192.168.233.133" 12 | #define KING_DB_SERVER_PORT 3306 13 | 14 | #define KING_DB_USERNAME "king" 15 | #define KING_DB_PASSWORD "123456" 16 | 17 | #define KING_DB_DEFAULTDB "KING_DB" 18 | 19 | 20 | #define SQL_INSERT_TBL_USER "INSERT TBL_USER(U_NAME, U_GENDER) VALUES('King', 'man');" 21 | #define SQL_SELECT_TBL_USER "SELECT * FROM TBL_USER;" 22 | 23 | #define SQL_DELETE_TBL_USER "CALL PROC_DELETE_USER('King')" 24 | #define SQL_INSERT_IMG_USER "INSERT TBL_USER(U_NAME, U_GENDER, U_IMG) VALUES('King', 'man', ?);" 25 | 26 | #define SQL_SELECT_IMG_USER "SELECT U_IMG FROM TBL_USER WHERE U_NAME='King';" 27 | 28 | 29 | #define FILE_IMAGE_LENGTH (64*1024) 30 | // C U R D --> 31 | // 32 | 33 | int king_mysql_select(MYSQL *handle) { // 34 | 35 | // mysql_real_query --> sql 36 | if (mysql_real_query(handle, SQL_SELECT_TBL_USER, strlen(SQL_SELECT_TBL_USER))) { 37 | printf("mysql_real_query : %s\n", mysql_error(handle)); 38 | return -1; 39 | } 40 | 41 | 42 | // store --> 43 | MYSQL_RES *res = mysql_store_result(handle); 44 | if (res == NULL) { 45 | printf("mysql_store_result : %s\n", mysql_error(handle)); 46 | return -2; 47 | } 48 | 49 | // rows / fields 50 | int rows = mysql_num_rows(res); 51 | printf("rows: %d\n", rows); 52 | 53 | int fields = mysql_num_fields(res); 54 | printf("fields: %d\n", fields); 55 | 56 | // fetch 57 | MYSQL_ROW row; 58 | while ((row = mysql_fetch_row(res))) { 59 | 60 | int i = 0; 61 | for (i = 0;i < fields;i ++) { 62 | printf("%s\t", row[i]); 63 | } 64 | printf("\n"); 65 | 66 | } 67 | 68 | mysql_free_result(res); 69 | 70 | return 0; 71 | } 72 | 73 | 74 | // filename : path + file name 75 | // buffer : store image data 76 | 77 | int read_image(char *filename, char *buffer) { 78 | 79 | if (filename == NULL || buffer == NULL) return -1; 80 | 81 | FILE *fp = fopen(filename, "rb"); // 82 | if (fp == NULL) { 83 | printf("fopen failed\n"); 84 | return -2; 85 | } 86 | 87 | // file size 88 | fseek(fp, 0, SEEK_END); 89 | int length = ftell(fp); // file size 90 | fseek(fp, 0, SEEK_SET); 91 | 92 | int size = fread(buffer, 1, length, fp); 93 | if (size != length) { 94 | printf("fread failed: %d\n", size); 95 | return -3; 96 | } 97 | 98 | fclose(fp); 99 | 100 | return size; 101 | 102 | } 103 | 104 | // filename : 105 | // buffer : 106 | // length : 107 | 108 | int write_image(char *filename, char *buffer, int length) { 109 | 110 | if (filename == NULL || buffer == NULL || length <= 0) return -1; 111 | 112 | FILE *fp = fopen(filename, "wb+"); // 113 | if (fp == NULL) { 114 | printf("fopen failed\n"); 115 | return -2; 116 | } 117 | 118 | int size = fwrite(buffer, 1, length, fp); 119 | if (size != length) { 120 | printf("fwrite failed: %d\n", size); 121 | return -3; 122 | } 123 | 124 | fclose(fp); 125 | 126 | return size; 127 | } 128 | 129 | int mysql_write(MYSQL *handle, char *buffer, int length) { 130 | 131 | if (handle == NULL || buffer == NULL || length <= 0) return -1; 132 | 133 | MYSQL_STMT *stmt = mysql_stmt_init(handle); 134 | int ret = mysql_stmt_prepare(stmt, SQL_INSERT_IMG_USER, strlen(SQL_INSERT_IMG_USER)); 135 | if (ret) { 136 | printf("mysql_stmt_prepare : %s\n", mysql_error(handle)); 137 | return -2; 138 | } 139 | 140 | MYSQL_BIND param = {0}; 141 | param.buffer_type = MYSQL_TYPE_LONG_BLOB; 142 | param.buffer = NULL; 143 | param.is_null = 0; 144 | param.length = NULL; 145 | 146 | ret = mysql_stmt_bind_param(stmt, ¶m); 147 | if (ret) { 148 | printf("mysql_stmt_bind_param : %s\n", mysql_error(handle)); 149 | return -3; 150 | } 151 | 152 | ret = mysql_stmt_send_long_data(stmt, 0, buffer, length); 153 | if (ret) { 154 | printf("mysql_stmt_send_long_data : %s\n", mysql_error(handle)); 155 | return -4; 156 | } 157 | 158 | ret = mysql_stmt_execute(stmt); 159 | if (ret) { 160 | printf("mysql_stmt_execute : %s\n", mysql_error(handle)); 161 | return -5; 162 | } 163 | 164 | ret = mysql_stmt_close(stmt); 165 | if (ret) { 166 | printf("mysql_stmt_close : %s\n", mysql_error(handle)); 167 | return -6; 168 | } 169 | 170 | 171 | return ret; 172 | } 173 | 174 | int mysql_read(MYSQL *handle, char *buffer, int length) { 175 | 176 | if (handle == NULL || buffer == NULL || length <= 0) return -1; 177 | 178 | MYSQL_STMT *stmt = mysql_stmt_init(handle); 179 | int ret = mysql_stmt_prepare(stmt, SQL_SELECT_IMG_USER, strlen(SQL_SELECT_IMG_USER)); 180 | if (ret) { 181 | printf("mysql_stmt_prepare : %s\n", mysql_error(handle)); 182 | return -2; 183 | } 184 | 185 | 186 | MYSQL_BIND result = {0}; 187 | 188 | result.buffer_type = MYSQL_TYPE_LONG_BLOB; 189 | unsigned long total_length = 0; 190 | result.length = &total_length; 191 | 192 | ret = mysql_stmt_bind_result(stmt, &result); 193 | if (ret) { 194 | printf("mysql_stmt_bind_result : %s\n", mysql_error(handle)); 195 | return -3; 196 | } 197 | 198 | ret = mysql_stmt_execute(stmt); 199 | if (ret) { 200 | printf("mysql_stmt_execute : %s\n", mysql_error(handle)); 201 | return -4; 202 | } 203 | 204 | ret = mysql_stmt_store_result(stmt); 205 | if (ret) { 206 | printf("mysql_stmt_store_result : %s\n", mysql_error(handle)); 207 | return -5; 208 | } 209 | 210 | 211 | while (1) { 212 | 213 | ret = mysql_stmt_fetch(stmt); 214 | if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) break; // 215 | 216 | int start = 0; 217 | while (start < (int)total_length) { 218 | result.buffer = buffer + start; 219 | result.buffer_length = 1; 220 | mysql_stmt_fetch_column(stmt, &result, 0, start); 221 | start += result.buffer_length; 222 | } 223 | } 224 | 225 | mysql_stmt_close(stmt); 226 | 227 | return total_length; 228 | 229 | } 230 | 231 | void coroutine_func(void *arg) { 232 | 233 | MYSQL mysql; 234 | 235 | printf("coroutine_func\n"); 236 | if (NULL == mysql_init(&mysql)) { 237 | printf("mysql_init : %s\n", mysql_error(&mysql)); 238 | return ; 239 | } 240 | 241 | if (!mysql_real_connect(&mysql, KING_DB_SERVER_IP, KING_DB_USERNAME, KING_DB_PASSWORD, 242 | KING_DB_DEFAULTDB, KING_DB_SERVER_PORT, NULL, 0)) { 243 | 244 | printf("mysql_real_connect : %s\n", mysql_error(&mysql)); 245 | goto Exit; 246 | } 247 | 248 | // mysql --> insert 249 | printf("case 1 : mysql --> insert \n"); 250 | #if 1 251 | if (mysql_real_query(&mysql, SQL_INSERT_TBL_USER, strlen(SQL_INSERT_TBL_USER))) { 252 | printf("mysql_real_query : %s\n", mysql_error(&mysql)); 253 | goto Exit; 254 | } 255 | #endif 256 | 257 | king_mysql_select(&mysql); 258 | 259 | // mysql --> delete 260 | 261 | printf("case 2 : mysql --> delete \n"); 262 | #if 1 263 | if (mysql_real_query(&mysql, SQL_DELETE_TBL_USER, strlen(SQL_DELETE_TBL_USER))) { 264 | printf("mysql_real_query : %s\n", mysql_error(&mysql)); 265 | goto Exit; 266 | } 267 | #endif 268 | 269 | king_mysql_select(&mysql); 270 | 271 | 272 | 273 | printf("case 3 : mysql --> read image and write mysql\n"); 274 | 275 | char buffer[FILE_IMAGE_LENGTH] = {0}; 276 | int length = read_image("0voice.jpg", buffer); 277 | if (length < 0) goto Exit; 278 | 279 | mysql_write(&mysql, buffer, length); /// 280 | 281 | 282 | printf("case 4 : mysql --> read mysql and write image\n"); 283 | 284 | memset(buffer, 0, FILE_IMAGE_LENGTH); 285 | length = mysql_read(&mysql, buffer, FILE_IMAGE_LENGTH); 286 | 287 | write_image("a.jpg", buffer, length); 288 | 289 | Exit: 290 | mysql_close(&mysql); 291 | 292 | return ; 293 | 294 | } 295 | 296 | 297 | int main() { 298 | #if 1 299 | //init_hook(); 300 | 301 | nty_coroutine *co = NULL; 302 | nty_coroutine_create(&co, coroutine_func, NULL); 303 | nty_schedule_run(); //run 304 | #else 305 | 306 | coroutine_func(NULL); 307 | 308 | #endif 309 | } 310 | 311 | 312 | 313 | 314 | 315 | 316 | -------------------------------------------------------------------------------- /sample/nty_rediscli.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #include "nty_coroutine.h" 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | void coroutine_func(void *arg) { 15 | unsigned int j, isunix = 0; 16 | redisContext *c; 17 | redisReply *reply; 18 | const char *hostname = "192.168.233.133"; 19 | int port = 6379; 20 | 21 | struct timeval timeout = { 1, 500000 }; // 1.5 seconds 22 | if (isunix) { 23 | c = redisConnectUnixWithTimeout(hostname, timeout); 24 | } else { 25 | c = redisConnectWithTimeout(hostname, port, timeout); 26 | } 27 | if (c == NULL || c->err) { 28 | if (c) { 29 | printf("Connection error: %s\n", c->errstr); 30 | redisFree(c); 31 | } else { 32 | printf("Connection error: can't allocate redis context\n"); 33 | } 34 | exit(1); 35 | } 36 | 37 | /* PING server */ 38 | reply = redisCommand(c,"PING"); 39 | printf("PING: %s\n", reply->str); 40 | freeReplyObject(reply); 41 | 42 | /* Set a key */ 43 | reply = redisCommand(c,"SET %s %s", "foo", "hello world"); 44 | printf("SET: %s\n", reply->str); 45 | freeReplyObject(reply); 46 | 47 | /* Set a key using binary safe API */ 48 | reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); 49 | printf("SET (binary API): %s\n", reply->str); 50 | freeReplyObject(reply); 51 | 52 | /* Try a GET and two INCR */ 53 | reply = redisCommand(c,"GET foo"); 54 | printf("GET foo: %s\n", reply->str); 55 | freeReplyObject(reply); 56 | 57 | reply = redisCommand(c,"INCR counter"); 58 | printf("INCR counter: %lld\n", reply->integer); 59 | freeReplyObject(reply); 60 | /* again ... */ 61 | reply = redisCommand(c,"INCR counter"); 62 | printf("INCR counter: %lld\n", reply->integer); 63 | freeReplyObject(reply); 64 | 65 | /* Create a list of numbers, from 0 to 9 */ 66 | reply = redisCommand(c,"DEL mylist"); 67 | freeReplyObject(reply); 68 | for (j = 0; j < 10; j++) { 69 | char buf[64]; 70 | 71 | snprintf(buf,64,"%u",j); 72 | reply = redisCommand(c,"LPUSH mylist element-%s", buf); 73 | freeReplyObject(reply); 74 | } 75 | 76 | /* Let's check what we have inside the list */ 77 | reply = redisCommand(c,"LRANGE mylist 0 -1"); 78 | if (reply->type == REDIS_REPLY_ARRAY) { 79 | for (j = 0; j < reply->elements; j++) { 80 | printf("%u) %s\n", j, reply->element[j]->str); 81 | } 82 | } 83 | freeReplyObject(reply); 84 | 85 | /* Disconnects and frees the context */ 86 | redisFree(c); 87 | 88 | return ; 89 | } 90 | 91 | 92 | int main(int argc, char **argv) { 93 | 94 | //init_hook(); 95 | 96 | nty_coroutine *co = NULL; 97 | nty_coroutine_create(&co, coroutine_func, NULL); 98 | nty_schedule_run(); //run 99 | 100 | 101 | 102 | } 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /sample/nty_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | #include "nty_coroutine.h" 47 | 48 | #include 49 | 50 | #define MAX_CLIENT_NUM 1000000 51 | #define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000) 52 | 53 | 54 | void server_reader(void *arg) { 55 | int fd = *(int *)arg; 56 | free(arg); 57 | int ret = 0; 58 | 59 | 60 | struct pollfd fds; 61 | fds.fd = fd; 62 | fds.events = POLLIN; 63 | 64 | while (1) { 65 | 66 | char buf[1024] = {0}; 67 | ret = nty_recv(fd, buf, 1024, 0); 68 | if (ret > 0) { 69 | if(fd > MAX_CLIENT_NUM) 70 | printf("read from server: %.*s\n", ret, buf); 71 | 72 | ret = nty_send(fd, buf, strlen(buf), 0); 73 | if (ret == -1) { 74 | nty_close(fd); 75 | break; 76 | } 77 | } else if (ret == 0) { 78 | nty_close(fd); 79 | break; 80 | } 81 | 82 | } 83 | } 84 | 85 | 86 | void server(void *arg) { 87 | 88 | unsigned short port = *(unsigned short *)arg; 89 | free(arg); 90 | 91 | int fd = nty_socket(AF_INET, SOCK_STREAM, 0); 92 | if (fd < 0) return ; 93 | 94 | struct sockaddr_in local, remote; 95 | local.sin_family = AF_INET; 96 | local.sin_port = htons(port); 97 | local.sin_addr.s_addr = INADDR_ANY; 98 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 99 | 100 | listen(fd, 20); 101 | printf("listen port : %d\n", port); 102 | 103 | 104 | struct timeval tv_begin; 105 | gettimeofday(&tv_begin, NULL); 106 | 107 | while (1) { 108 | socklen_t len = sizeof(struct sockaddr_in); 109 | int cli_fd = nty_accept(fd, (struct sockaddr*)&remote, &len); 110 | if (cli_fd % 1000 == 999) { 111 | 112 | struct timeval tv_cur; 113 | memcpy(&tv_cur, &tv_begin, sizeof(struct timeval)); 114 | 115 | gettimeofday(&tv_begin, NULL); 116 | int time_used = TIME_SUB_MS(tv_begin, tv_cur); 117 | 118 | printf("client fd : %d, time_used: %d\n", cli_fd, time_used); 119 | } 120 | printf("new client comming\n"); 121 | 122 | nty_coroutine *read_co; 123 | int *arg = malloc(sizeof(int)); 124 | *arg = cli_fd; 125 | nty_coroutine_create(&read_co, server_reader, arg); 126 | 127 | } 128 | 129 | } 130 | 131 | 132 | 133 | int main(int argc, char *argv[]) { 134 | nty_coroutine *co = NULL; 135 | 136 | int i = 0; 137 | unsigned short base_port = 9096; 138 | for (i = 0;i < 100;i ++) { 139 | unsigned short *port = calloc(1, sizeof(unsigned short)); 140 | *port = base_port + i; 141 | nty_coroutine_create(&co, server, port); ////////no run 142 | } 143 | 144 | nty_schedule_run(); //run 145 | 146 | return 0; 147 | } 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /sample/nty_server_mulcore.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | 47 | 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | 58 | #include 59 | #include 60 | #include 61 | 62 | 63 | #define __USE_GNU 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | #include 70 | 71 | #include "nty_coroutine.h" 72 | 73 | static int global_shmid = -1; 74 | static int global_semid = -1; 75 | 76 | #define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000) 77 | 78 | 79 | typedef struct _shm_area { 80 | int total; 81 | int lock; 82 | struct timeval tv_begin; 83 | } shm_area; 84 | 85 | static shm_area *global_shmaddr = NULL; 86 | 87 | 88 | #define MAX_CLIENT_NUM 1000000 89 | 90 | 91 | struct timeval* get_shm_timevalue(void); 92 | void set_shm_timevalue(struct timeval *tv); 93 | 94 | 95 | int add_shmvalue(void); 96 | int sub_shmvalue(void); 97 | 98 | int init_shmvalue(void); 99 | 100 | 101 | unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) { 102 | unsigned long prev; 103 | volatile unsigned int *_ptr = (volatile unsigned int *)(addr); 104 | 105 | switch (size) { 106 | case 1: { 107 | __asm__ volatile ( 108 | "lock; cmpxchgb %b1, %2" 109 | : "=a" (prev) 110 | : "r" (_new), "m" (*_ptr), "0" (_old) 111 | : "memory"); 112 | break; 113 | } 114 | case 2: { 115 | __asm__ volatile ( 116 | "lock; cmpxchgw %w1, %2" 117 | : "=a" (prev) 118 | : "r" (_new), "m" (*_ptr), "0" (_old) 119 | : "memory"); 120 | break; 121 | } 122 | case 4: { 123 | __asm__ volatile ( 124 | "lock; cmpxchg %1, %2" 125 | : "=a" (prev) 126 | : "r" (_new), "m" (*_ptr), "0" (_old) 127 | : "memory"); 128 | break; 129 | } 130 | } 131 | 132 | return prev; 133 | } 134 | 135 | #define SERVER_STRING "Server: ntyco\r\n" 136 | 137 | 138 | int headers(char *buffer) 139 | { 140 | strcat(buffer, "HTTP/1.0 200 OK\r\n"); 141 | strcat(buffer, SERVER_STRING); 142 | strcat(buffer, "Content-Type: text/html\r\n"); 143 | strcat(buffer, "\r\n"); 144 | 145 | return strlen(buffer); 146 | } 147 | 148 | int body(char *buffer) { 149 | strcat(buffer, "

coroutine --> ntyco

"); 150 | 151 | return strlen(buffer); 152 | } 153 | 154 | void server_reader(void *arg) { 155 | int fd = *(int *)arg; 156 | int ret = 0; 157 | 158 | 159 | struct pollfd fds; 160 | fds.fd = fd; 161 | fds.events = POLLIN; 162 | 163 | while (1) { 164 | 165 | char buf[1024] = {0}; 166 | ret = nty_recv(fd, buf, 1024, 0); 167 | if (ret > 0) { 168 | if(fd > MAX_CLIENT_NUM) 169 | printf("read from server: %.*s\n", ret, buf); 170 | 171 | memset(buf, 0, 1024); 172 | int hlen = headers(buf); 173 | int blen = body(buf+hlen); 174 | 175 | ret = nty_send(fd, buf, strlen(buf), 0); 176 | if (ret == -1) { 177 | nty_close(fd); 178 | sub_shmvalue(); 179 | 180 | break; 181 | } 182 | } else if (ret == 0) { 183 | nty_close(fd); 184 | 185 | sub_shmvalue(); 186 | 187 | break; 188 | } 189 | } 190 | } 191 | 192 | 193 | void server(void *arg) { 194 | 195 | unsigned short port = *(unsigned short *)arg; 196 | free(arg); 197 | 198 | int fd = nty_socket(AF_INET, SOCK_STREAM, 0); 199 | if (fd < 0) return ; 200 | 201 | struct sockaddr_in local, remote; 202 | local.sin_family = AF_INET; 203 | local.sin_port = htons(port); 204 | local.sin_addr.s_addr = INADDR_ANY; 205 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 206 | 207 | listen(fd, 20); 208 | printf("listen port : %d\n", port); 209 | 210 | while (1) { 211 | socklen_t len = sizeof(struct sockaddr_in); 212 | int cli_fd = nty_accept(fd, (struct sockaddr*)&remote, &len); 213 | 214 | printf("new client comming\n"); 215 | 216 | nty_coroutine *read_co; 217 | nty_coroutine_create(&read_co, server_reader, &cli_fd); 218 | 219 | int value = add_shmvalue(); 220 | if (value % 1000 == 999) { 221 | struct timeval *tv_begin = get_shm_timevalue(); 222 | 223 | struct timeval tv_cur; 224 | memcpy(&tv_cur, tv_begin, sizeof(struct timeval)); 225 | gettimeofday(tv_begin, NULL); 226 | 227 | int time_used = TIME_SUB_MS((*tv_begin), tv_cur); 228 | 229 | printf("client sum: %d, time_used: %d\n", value, time_used); 230 | } 231 | 232 | } 233 | 234 | } 235 | 236 | int mulcore_entry(int begin_port) { 237 | 238 | nty_coroutine *co = NULL; 239 | 240 | int i = 0; 241 | unsigned short base_port = begin_port; 242 | //for (i = 0;i < 10;i ++) { 243 | unsigned short *port = calloc(1, sizeof(unsigned short)); 244 | *port = base_port + i; 245 | nty_coroutine_create(&co, server, port); ////////no run 246 | //} 247 | 248 | nty_schedule_run(); //run 249 | 250 | } 251 | 252 | int process_bind(void) { 253 | 254 | int num = sysconf(_SC_NPROCESSORS_CONF); 255 | 256 | pid_t self_id = syscall(__NR_gettid); 257 | //printf("selfid --> %d\n", self_id); 258 | 259 | cpu_set_t mask; 260 | 261 | CPU_ZERO(&mask); 262 | CPU_SET(self_id % num, &mask); 263 | 264 | sched_setaffinity(0, sizeof(mask), &mask); 265 | 266 | mulcore_entry(9096); 267 | 268 | } 269 | 270 | 271 | struct timeval* get_shm_timevalue(void) { 272 | 273 | return global_shmaddr ? &global_shmaddr->tv_begin : NULL; 274 | 275 | } 276 | 277 | void set_shm_timevalue(struct timeval *tv) { 278 | if (global_shmaddr == NULL || tv == NULL) { 279 | return ; 280 | } 281 | 282 | memcpy(&global_shmaddr->tv_begin, tv, sizeof(struct timeval)); 283 | 284 | } 285 | 286 | int add_shmvalue(void) { 287 | int value = 0; 288 | int ret = -1; 289 | 290 | do { 291 | 292 | value = global_shmaddr->total; 293 | ret = cmpxchg(&global_shmaddr->total, (unsigned long)value, (unsigned long)(value+1), 4); 294 | 295 | } while (ret != value); 296 | 297 | return global_shmaddr->total; 298 | } 299 | 300 | int sub_shmvalue(void) { 301 | int value = 0; 302 | int ret = -1; 303 | 304 | do { 305 | 306 | value = global_shmaddr->total; 307 | ret = cmpxchg(&global_shmaddr->total, (unsigned long)value, (unsigned long)(value-1), 4); 308 | 309 | } while (ret != value); 310 | 311 | return global_shmaddr->total; 312 | } 313 | 314 | 315 | int init_shmvalue(void) { 316 | 317 | global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600); 318 | if (global_shmid < 0) { 319 | perror("shmget failed\n"); 320 | return -1; 321 | } 322 | global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0); 323 | if (global_shmaddr == (shm_area*)-1) { 324 | perror("shmat addr error"); 325 | return -1; 326 | } 327 | global_shmaddr->total = 0; 328 | gettimeofday(&global_shmaddr->tv_begin, NULL); 329 | 330 | } 331 | 332 | 333 | 334 | int main(int argc, char *argv[]) { 335 | 336 | int ret = init_shmvalue(); 337 | if (ret == -1) { 338 | printf("init share memory failed\n"); 339 | return -1; 340 | } 341 | 342 | fork(); 343 | fork(); 344 | //fork(); 345 | //fork(); 346 | //fork(); 347 | 348 | process_bind(); 349 | 350 | } 351 | 352 | -------------------------------------------------------------------------------- /sample/nty_websocket_server.c: -------------------------------------------------------------------------------- 1 | 2 | #include "nty_coroutine.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define MAX_CLIENT_NUM 1000000 13 | #define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000) 14 | 15 | #define NTY_WEBSOCKET_SERVER_PORT 9096 16 | #define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 17 | #define MAX_BUFFER_LENGTH 1024 18 | 19 | struct _nty_ophdr { 20 | 21 | unsigned char opcode:4, 22 | rsv3:1, 23 | rsv2:1, 24 | rsv1:1, 25 | fin:1; 26 | unsigned char payload_length:7, 27 | mask:1; 28 | 29 | } __attribute__ ((packed)); 30 | 31 | struct _nty_websocket_head_126 { 32 | unsigned short payload_length; 33 | char mask_key[4]; 34 | unsigned char data[8]; 35 | } __attribute__ ((packed)); 36 | 37 | struct _nty_websocket_head_127 { 38 | 39 | unsigned long long payload_length; 40 | char mask_key[4]; 41 | 42 | unsigned char data[8]; 43 | 44 | } __attribute__ ((packed)); 45 | 46 | #define UNION_HEADER(type1, type2) \ 47 | struct { \ 48 | struct type1 hdr; \ 49 | struct type2 len; \ 50 | } 51 | 52 | 53 | typedef struct _nty_websocket_head_127 nty_websocket_head_127; 54 | typedef struct _nty_websocket_head_126 nty_websocket_head_126; 55 | typedef struct _nty_ophdr nty_ophdr; 56 | 57 | 58 | static int ntySetNonblock(int fd) { 59 | int flags; 60 | 61 | flags = fcntl(fd, F_GETFL, 0); 62 | if (flags < 0) return flags; 63 | flags |= O_NONBLOCK; 64 | if (fcntl(fd, F_SETFL, flags) < 0) return -1; 65 | return 0; 66 | } 67 | 68 | static int ntySetBlock(int fd) 69 | { 70 | int flags = fcntl(fd, F_GETFL, 0); 71 | if (flags < 0) return flags; 72 | flags &=~O_NONBLOCK; 73 | if (fcntl(fd, F_SETFL, flags) < 0) return -1; 74 | 75 | return 0; 76 | } 77 | 78 | 79 | int base64_encode(char *in_str, int in_len, char *out_str) { 80 | BIO *b64, *bio; 81 | BUF_MEM *bptr = NULL; 82 | size_t size = 0; 83 | 84 | if (in_str == NULL || out_str == NULL) 85 | return -1; 86 | 87 | b64 = BIO_new(BIO_f_base64()); 88 | bio = BIO_new(BIO_s_mem()); 89 | bio = BIO_push(b64, bio); 90 | 91 | BIO_write(bio, in_str, in_len); 92 | BIO_flush(bio); 93 | 94 | BIO_get_mem_ptr(bio, &bptr); 95 | memcpy(out_str, bptr->data, bptr->length); 96 | out_str[bptr->length-1] = '\0'; 97 | size = bptr->length; 98 | 99 | BIO_free_all(bio); 100 | return size; 101 | } 102 | 103 | 104 | int readline(char* allbuf,int level,char* linebuf){ 105 | int len = strlen(allbuf); 106 | 107 | for (;level < len; ++level) { 108 | if(allbuf[level]=='\r' && allbuf[level+1]=='\n') 109 | return level+2; 110 | else 111 | *(linebuf++) = allbuf[level]; 112 | } 113 | 114 | return -1; 115 | } 116 | 117 | void umask(char *data,int len,char *mask){ 118 | int i; 119 | for (i = 0;i < len;i ++) 120 | *(data+i) ^= *(mask+(i%4)); 121 | } 122 | 123 | 124 | char* decode_packet(unsigned char *stream, char *mask, int length, int *ret) { 125 | 126 | nty_ophdr *hdr = (nty_ophdr*)stream; 127 | unsigned char *data = stream + sizeof(nty_ophdr); 128 | int size = 0; 129 | int start = 0; 130 | //char mask[4] = {0}; 131 | int i = 0; 132 | 133 | if ((hdr->mask & 0x7F) == 126) { 134 | 135 | nty_websocket_head_126 *hdr126 = (nty_websocket_head_126*)data; 136 | size = hdr126->payload_length; 137 | 138 | for (i = 0;i < 4;i ++) { 139 | mask[i] = hdr126->mask_key[i]; 140 | } 141 | 142 | start = 8; 143 | 144 | } else if ((hdr->mask & 0x7F) == 127) { 145 | 146 | nty_websocket_head_127 *hdr127 = (nty_websocket_head_127*)data; 147 | size = hdr127->payload_length; 148 | 149 | for (i = 0;i < 4;i ++) { 150 | mask[i] = hdr127->mask_key[i]; 151 | } 152 | 153 | start = 14; 154 | 155 | } else { 156 | size = hdr->payload_length; 157 | 158 | memcpy(mask, data, 4); 159 | start = 6; 160 | } 161 | 162 | *ret = size; 163 | umask(stream+start, size, mask); 164 | 165 | return stream + start; 166 | 167 | } 168 | 169 | int encode_packet(char *buffer,char *mask, char *stream, int length) { 170 | 171 | nty_ophdr head = {0}; 172 | head.fin = 1; 173 | head.opcode = 1; 174 | int size = 0; 175 | 176 | if (length < 126) { 177 | head.payload_length = length; 178 | memcpy(buffer, &head, sizeof(nty_ophdr)); 179 | size = 2; 180 | } else if (length < 0xffff) { 181 | nty_websocket_head_126 hdr = {0}; 182 | hdr.payload_length = length; 183 | memcpy(hdr.mask_key, mask, 4); 184 | 185 | memcpy(buffer, &head, sizeof(nty_ophdr)); 186 | memcpy(buffer+sizeof(nty_ophdr), &hdr, sizeof(nty_websocket_head_126)); 187 | size = sizeof(nty_websocket_head_126); 188 | 189 | } else { 190 | 191 | nty_websocket_head_127 hdr = {0}; 192 | hdr.payload_length = length; 193 | memcpy(hdr.mask_key, mask, 4); 194 | 195 | memcpy(buffer, &head, sizeof(nty_ophdr)); 196 | memcpy(buffer+sizeof(nty_ophdr), &hdr, sizeof(nty_websocket_head_127)); 197 | 198 | size = sizeof(nty_websocket_head_127); 199 | 200 | } 201 | 202 | memcpy(buffer+2, stream, length); 203 | 204 | return length + 2; 205 | } 206 | 207 | 208 | 209 | void server_reader(void *arg) { 210 | int fd = *(int *)arg; 211 | int length = 0; 212 | int ret = 0; 213 | 214 | struct pollfd fds; 215 | fds.fd = fd; 216 | fds.events = POLLIN; 217 | 218 | while (1) { 219 | 220 | char stream[MAX_BUFFER_LENGTH] = {0}; 221 | length = nty_recv(fd, stream, MAX_BUFFER_LENGTH, 0); 222 | if (length > 0) { 223 | if(fd > MAX_CLIENT_NUM) 224 | printf("read from server: %.*s\n", length, stream); 225 | 226 | char mask[4] = {0}; 227 | char *data = decode_packet(stream, mask, length, &ret); 228 | 229 | printf(" data : %s , length : %d\n", data, ret); 230 | 231 | #if 1 232 | char buffer[MAX_BUFFER_LENGTH+14] = {0}; 233 | ret = encode_packet(buffer, mask, data, ret); 234 | ret = nty_send(fd, buffer, ret, 0); 235 | #endif 236 | } else if (length == 0) { 237 | nty_close(fd); 238 | break; 239 | } 240 | 241 | } 242 | } 243 | 244 | 245 | int handshake(int cli_fd) { 246 | int level = 0; 247 | char buffer[MAX_BUFFER_LENGTH]; 248 | char linebuf[128]; //Sec-WebSocket-Accept 249 | char sec_accept[32] = {0}; //sha1 data 250 | unsigned char sha1_data[SHA_DIGEST_LENGTH+1] = {0}; //reponse head buffer 251 | //char head[MAX_BUFFER_LENGTH] = {0}; 252 | 253 | #if 1 254 | if (read(cli_fd, buffer, sizeof(buffer))<=0) 255 | perror("read"); 256 | #else 257 | 258 | int ret = 0; 259 | int length = recv_buffer(cli_fd, buffer, MAX_BUFFER_LENGTH, &ret); 260 | if (ret < 0) perror("read"); 261 | 262 | #endif 263 | printf("request\n"); 264 | printf("%s\n",buffer); 265 | 266 | do { 267 | memset(linebuf, 0, sizeof(linebuf)); 268 | level = readline(buffer,level,linebuf); 269 | 270 | if (strstr(linebuf,"Sec-WebSocket-Key") != NULL) { 271 | 272 | strcat(linebuf, GUID); 273 | 274 | SHA1((unsigned char*)&linebuf+19,strlen(linebuf+19),(unsigned char*)&sha1_data); 275 | 276 | memset(buffer, 0, MAX_BUFFER_LENGTH); 277 | base64_encode(sha1_data,strlen(sha1_data),sec_accept); 278 | sprintf(buffer, "HTTP/1.1 101 Switching Protocols\r\n" \ 279 | "Upgrade: websocket\r\n" \ 280 | "Connection: Upgrade\r\n" \ 281 | "Sec-WebSocket-Accept: %s\r\n" \ 282 | "\r\n", sec_accept); 283 | 284 | 285 | printf("response\n"); 286 | printf("%s",buffer); 287 | #if 1 288 | if (write(cli_fd, buffer, strlen(buffer)) < 0) 289 | perror("write"); 290 | #else 291 | 292 | length = send_buffer(cli_fd, head, strlen(head)); 293 | assert(length == strlen(head)); 294 | 295 | #endif 296 | printf("accept : %s\n", sec_accept); 297 | break; 298 | } 299 | 300 | }while((buffer[level]!='\r' || buffer[level+1]!='\n') && level!=-1); 301 | 302 | return 0; 303 | 304 | } 305 | 306 | 307 | int init_server(void) { 308 | 309 | int sockfd = socket(AF_INET, SOCK_STREAM, 0); 310 | if (sockfd < 0) { 311 | printf("socket failed\n"); 312 | return -1; 313 | } 314 | 315 | struct sockaddr_in addr; 316 | addr.sin_family = AF_INET; 317 | addr.sin_port = htons(NTY_WEBSOCKET_SERVER_PORT); 318 | addr.sin_addr.s_addr = INADDR_ANY; 319 | 320 | if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) { 321 | printf("bind failed\n"); 322 | return -2; 323 | } 324 | 325 | if (listen(sockfd, 5) < 0) { 326 | printf("listen failed\n"); 327 | return -3; 328 | } 329 | 330 | return sockfd; 331 | 332 | } 333 | 334 | void server(void *arg) { 335 | 336 | int sockfd = init_server(); 337 | 338 | struct timeval tv_begin; 339 | gettimeofday(&tv_begin, NULL); 340 | 341 | while (1) { 342 | socklen_t len = sizeof(struct sockaddr_in); 343 | struct sockaddr_in remote; 344 | 345 | int cli_fd = nty_accept(sockfd, (struct sockaddr*)&remote, &len); 346 | if (cli_fd % 1000 == 999) { 347 | 348 | struct timeval tv_cur; 349 | memcpy(&tv_cur, &tv_begin, sizeof(struct timeval)); 350 | 351 | gettimeofday(&tv_begin, NULL); 352 | int time_used = TIME_SUB_MS(tv_begin, tv_cur); 353 | 354 | printf("client fd : %d, time_used: %d\n", cli_fd, time_used); 355 | } 356 | printf("new client comming\n"); 357 | ntySetBlock(cli_fd); 358 | handshake(cli_fd); 359 | ntySetNonblock(cli_fd); 360 | 361 | nty_coroutine *read_co = NULL; 362 | nty_coroutine_create(&read_co, server_reader, &cli_fd); 363 | 364 | } 365 | 366 | } 367 | 368 | int main() { 369 | 370 | nty_coroutine *co = NULL; 371 | nty_coroutine_create(&co, server, NULL); 372 | 373 | nty_schedule_run(); 374 | } 375 | 376 | 377 | 378 | -------------------------------------------------------------------------------- /sample/ntyco_httpd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author : WangBoJing , email : 1989wangbojing@gmail.com 3 | * 4 | * Copyright Statement: 5 | * -------------------- 6 | * This software is protected by Copyright and the information contained 7 | * herein is confidential. The software may not be copied and the information 8 | * contained herein may not be used or disclosed except with the written 9 | * permission of Author. (C) 2017 10 | * 11 | * 12 | 13 | **** ***** ***** 14 | *** * ** *** 15 | *** * * * ** 16 | * ** * * ** ** 17 | * ** * * ** * 18 | * ** * ** ** * 19 | * ** * *** ** 20 | * ** * *********** ***** ***** ** **** 21 | * ** * ** ** ** ** ** ** 22 | * ** * ** ** * ** * ** 23 | * ** * ** * * ** ** ** 24 | * ** * ** ** * ** * ** 25 | * ** * ** * * ** ** ** 26 | * ** * ** ** * ** ** ** 27 | * ** * ** ** * ** ** ** 28 | * ** * ** * * ** ** ** 29 | * ** * ** ** * ** * ** ** 30 | * *** ** * * ** * ** ** 31 | * *** ** * ** * * ** ** 32 | * ** ** * ** ** * ** ** 33 | * ** ** * * ** * ** ** 34 | ***** * **** * ***** **** 35 | * 36 | * 37 | ***** 38 | **** 39 | 40 | 41 | 42 | * 43 | */ 44 | 45 | 46 | 47 | 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | 58 | #include 59 | #include 60 | #include 61 | 62 | #include 63 | 64 | #include 65 | #include 66 | #include 67 | 68 | #define __USE_GNU 69 | 70 | #include 71 | #include 72 | #include 73 | 74 | #include 75 | 76 | #include "nty_coroutine.h" 77 | 78 | 79 | #define MAX_CLIENT_NUM 1000000 80 | #define TOTALFDS 16 81 | 82 | 83 | typedef struct _shm_area { 84 | int totalfds[TOTALFDS]; 85 | char cpu_lb[TOTALFDS]; 86 | //mtx : default 0 87 | // 1 : lock -- del epoll 88 | // 2 : lock -- del complete 89 | // 3 : unlock -- add 90 | // 0 : unlock -- add complete 91 | int accept_mtx; 92 | } shm_area; 93 | 94 | static shm_area *global_shmaddr = NULL; 95 | static int global_shmid = -1; 96 | 97 | int cpu_size = 0; 98 | int accept_disable = 1000; 99 | int enable_accept = 1; 100 | pid_t self_id = 0; 101 | 102 | 103 | 104 | unsigned long cmpxchg(void *addr, unsigned long _old, unsigned long _new, int size) { 105 | unsigned long prev; 106 | volatile unsigned int *_ptr = (volatile unsigned int *)(addr); 107 | 108 | switch (size) { 109 | case 1: { 110 | __asm__ volatile ( 111 | "lock; cmpxchgb %b1, %2" 112 | : "=a" (prev) 113 | : "r" (_new), "m" (*_ptr), "0" (_old) 114 | : "memory"); 115 | break; 116 | } 117 | case 2: { 118 | __asm__ volatile ( 119 | "lock; cmpxchgw %w1, %2" 120 | : "=a" (prev) 121 | : "r" (_new), "m" (*_ptr), "0" (_old) 122 | : "memory"); 123 | break; 124 | } 125 | case 4: { 126 | __asm__ volatile ( 127 | "lock; cmpxchg %1, %2" 128 | : "=a" (prev) 129 | : "r" (_new), "m" (*_ptr), "0" (_old) 130 | : "memory"); 131 | break; 132 | } 133 | } 134 | 135 | return prev; 136 | } 137 | 138 | 139 | int atomic_add(volatile int *value, int add) 140 | { 141 | __asm__ volatile ( 142 | 143 | "lock;" 144 | " addl %0, %1; " 145 | 146 | : "+r" (add) : "m" (*value) : "cc", "memory"); 147 | 148 | return add; 149 | } 150 | 151 | int atomic_sub(volatile int *value, int sub) 152 | { 153 | __asm__ volatile ( 154 | 155 | "lock;" 156 | " subl %0, %1; " 157 | 158 | : "+r" (sub) : "m" (*value) : "cc", "memory"); 159 | 160 | return sub; 161 | } 162 | 163 | 164 | #define ISspace(x) isspace((int)(x)) 165 | 166 | #define SERVER_STRING "Server: ntyco_httpd/0.1.0\r\n" 167 | #define STDIN 0 168 | #define STDOUT 1 169 | #define STDERR 2 170 | 171 | #define ENABLE_NTYCO 0 172 | 173 | #if ENABLE_NTYCO 174 | 175 | #define socket nty_socket 176 | #define accept nty_accept 177 | #define recv(a, b, c, d) nty_recv(a, b, c, d) 178 | #define send(a, b, c, d) nty_send(a, b, c, d) 179 | 180 | #define MAX_BUFFER_LENGTH 1024 181 | 182 | 183 | 184 | #endif 185 | 186 | #define INC_COUNTFD do { \ 187 | atomic_add(&global_shmaddr->totalfds[self_id % cpu_size], 1); \ 188 | } while (0) 189 | 190 | 191 | #define DEC_COUNTFD do { \ 192 | atomic_sub(&global_shmaddr->totalfds[self_id % cpu_size], 1); \ 193 | } while (0) 194 | 195 | int get_countfd(void) { 196 | return global_shmaddr->totalfds[self_id % cpu_size]; 197 | } 198 | 199 | int max_countfd(void) { 200 | 201 | int count = -1; 202 | int i = 0; 203 | 204 | for (i = 0;i < cpu_size;i ++) { 205 | if (count < global_shmaddr->totalfds[i]) { 206 | count = global_shmaddr->totalfds[i]; 207 | } 208 | } 209 | return count; 210 | } 211 | 212 | int min_countfd(void) { 213 | 214 | int count = 0xffffffff; 215 | int i = 0; 216 | 217 | for (i = 0;i < cpu_size;i ++) { 218 | if (count > global_shmaddr->totalfds[i]) { 219 | count = global_shmaddr->totalfds[i]; 220 | } 221 | } 222 | return count; 223 | } 224 | 225 | int compare_out_countfd(void) { 226 | 227 | int current = get_countfd(); 228 | int min = min_countfd(); 229 | 230 | if ((current * 7 / 8) > min) { 231 | return 1; 232 | } else { 233 | return 0; 234 | } 235 | } 236 | 237 | int compare_in_countfd(void) { 238 | 239 | int current = get_countfd(); 240 | int max = max_countfd(); 241 | 242 | if ((current * 8 / 7) < max) { 243 | return 1; 244 | } else { 245 | return 0; 246 | } 247 | } 248 | 249 | void print_countfds(void) { 250 | 251 | int i = 0; 252 | for (i = 0;i < cpu_size;i ++) { 253 | printf("%5d : %5d ", i, global_shmaddr->totalfds[i]); 254 | } 255 | printf("\n"); 256 | } 257 | 258 | void lock_accept(void) { 259 | 260 | global_shmaddr->cpu_lb[self_id % cpu_size] = 1; 261 | 262 | int count = 0xffffffff; 263 | int i = 0; 264 | 265 | for (i = 0;i < cpu_size;i ++) { 266 | if (count > global_shmaddr->totalfds[i]) { 267 | count = global_shmaddr->totalfds[i]; 268 | } 269 | } 270 | 271 | for (i = 0;i < cpu_size;i ++) { 272 | if (count == global_shmaddr->totalfds[i]) { 273 | global_shmaddr->cpu_lb[i] = 3; 274 | } 275 | } 276 | 277 | } 278 | 279 | char read_accept(void) { 280 | return global_shmaddr->cpu_lb[self_id % cpu_size]; 281 | } 282 | 283 | void write_accept(char state) { //0, 1, 2, 3 284 | global_shmaddr->cpu_lb[self_id % cpu_size] = state; 285 | } 286 | 287 | int lock(void) { 288 | 289 | return cmpxchg(&global_shmaddr->accept_mtx, 0, 1, 4); //zero:success, non-zero:failed 290 | 291 | } 292 | 293 | void unlock(void) { 294 | 295 | global_shmaddr->accept_mtx = 0; 296 | 297 | } 298 | 299 | 300 | void accept_request(void *arg); 301 | void bad_request(int); 302 | void cat(int); 303 | void cannot_execute(int); 304 | void error_die(const char *); 305 | void execute_cgi(int, const char *, const char *, const char *); 306 | int get_line(int, char *, int); 307 | void headers(int); 308 | void not_found(int); 309 | void serve_file(int); 310 | int startup(u_short *); 311 | void unimplemented(int); 312 | 313 | 314 | void accept_request(void* arg) 315 | { 316 | int client = *(int*)arg; 317 | 318 | char buf[1024]; 319 | size_t numchars; 320 | char method[16]; 321 | char url[32]; 322 | char path[64]; 323 | size_t i, j; 324 | struct stat st; 325 | int cgi = 0; /* becomes true if server decides this is a CGI 326 | * program */ 327 | char *query_string = NULL; 328 | 329 | while (1) { 330 | 331 | numchars = nty_recv(client, buf, sizeof(buf), 0); 332 | if (numchars > 0) { 333 | serve_file(client); 334 | } else if (numchars == 0) { 335 | nty_close(client); 336 | DEC_COUNTFD; 337 | break; 338 | } else if (numchars == -1) { 339 | if (errno == EAGAIN) { 340 | continue; 341 | } 342 | nty_close(client); 343 | DEC_COUNTFD; 344 | break; 345 | } 346 | } 347 | 348 | } 349 | 350 | 351 | #define HTML_PAGE " \ 352 | \ 353 | \ 354 | Welcome to nginx! \ 355 | \ 362 | \ 363 | \ 364 |

Welcome to nginx!

\ 365 |

If you see this page, the nginx web server is successfully installed and\ 366 | working. Further configuration is required.

\ 367 | \ 368 |

For online documentation and support please refer to\ 369 | nginx.org.
\ 370 | Commercial support is available at\ 371 | nginx.com.

\ 372 | \ 373 |

Thank you for using nginx.

\ 374 | \ 375 | " 376 | 377 | 378 | void error_die(const char *sc) 379 | { 380 | printf("%s\n", sc); 381 | exit(1); 382 | } 383 | 384 | void headers(int client) 385 | { 386 | char buf[1024] = {0}; 387 | char content[128] = {0}; 388 | 389 | sprintf(buf, "HTTP/1.0 200 OK\r\n"); 390 | strcat(buf, SERVER_STRING); 391 | strcat(buf, "Content-Type: text/html\r\n"); 392 | #if 0 393 | strcat(buf, "Transfer-Encoding: chunked\r\n"); 394 | #else 395 | sprintf(content, "Content-Length: %ld\r\n", strlen(HTML_PAGE)); 396 | strcat(buf, content); 397 | #endif 398 | strcat(buf, "\r\n"); 399 | 400 | strcat(buf, HTML_PAGE); 401 | 402 | int ret = nty_send(client, buf, strlen(buf), 0); 403 | if (ret == -1) { 404 | printf("send : errno : %d\n", errno); 405 | } else { 406 | //printf("headers send ret : %d\n", ret); 407 | } 408 | 409 | 410 | } 411 | 412 | void serve_file(int client) 413 | { 414 | headers(client); 415 | } 416 | 417 | #define MAX_EPOLLSIZE 10240 418 | 419 | void server(void *arg) { 420 | 421 | int fd = *(int *)arg; 422 | 423 | while (1) { 424 | 425 | struct sockaddr_in client_addr; 426 | memset(&client_addr, 0, sizeof(struct sockaddr_in)); 427 | socklen_t client_len = sizeof(client_addr); 428 | 429 | if (lock()) { 430 | nty_coroutine_sleep(0); 431 | continue; 432 | } 433 | 434 | int clientfd = nty_accept(fd, (struct sockaddr*)&client_addr, &client_len); 435 | unlock(); 436 | 437 | if (clientfd < 0) { 438 | return ; 439 | } 440 | 441 | INC_COUNTFD; 442 | 443 | nty_coroutine *read_co; 444 | int *client_sock = (int *)malloc(sizeof(int)); 445 | *client_sock = clientfd; 446 | nty_coroutine_create(&read_co, accept_request, client_sock); 447 | 448 | print_countfds(); 449 | } 450 | 451 | } 452 | 453 | int process_bind(int fd) { 454 | 455 | int num = sysconf(_SC_NPROCESSORS_CONF); 456 | 457 | self_id = syscall(__NR_gettid); 458 | //printf("selfid --> %d\n", self_id); 459 | 460 | cpu_set_t mask; 461 | 462 | CPU_ZERO(&mask); 463 | CPU_SET(self_id % num, &mask); 464 | 465 | sched_setaffinity(0, sizeof(mask), &mask); 466 | 467 | nty_coroutine *co = NULL; 468 | nty_coroutine_create(&co, server, &fd); 469 | 470 | nty_schedule_run(); 471 | } 472 | 473 | int init_shmvalue(int num) { 474 | 475 | global_shmid = shmget(IPC_PRIVATE, sizeof(shm_area), IPC_CREAT|0600); 476 | if (global_shmid < 0) { 477 | perror("shmget failed\n"); 478 | return -1; 479 | } 480 | global_shmaddr = (shm_area*)shmat(global_shmid, NULL, 0); 481 | if (global_shmaddr == (shm_area*)-1) { 482 | perror("shmat addr error"); 483 | return -1; 484 | } 485 | memset(global_shmaddr->totalfds, 0, TOTALFDS * sizeof(int)); 486 | memset(global_shmaddr->cpu_lb, 0, TOTALFDS * sizeof(char)); 487 | global_shmaddr->accept_mtx = 0; 488 | } 489 | 490 | 491 | int main(int argc, char *argv[]) { 492 | 493 | short port = 9001; 494 | struct sockaddr_in client_name; 495 | socklen_t client_name_len = sizeof(client_name); 496 | 497 | int fd = nty_socket(AF_INET, SOCK_STREAM, 0); 498 | if (fd < 0) return -1; 499 | 500 | struct sockaddr_in local, remote; 501 | local.sin_family = AF_INET; 502 | local.sin_port = htons(port); 503 | local.sin_addr.s_addr = INADDR_ANY; 504 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 505 | 506 | listen(fd, 5); 507 | 508 | int num = sysconf(_SC_NPROCESSORS_CONF); 509 | cpu_size = num; 510 | init_shmvalue(num); 511 | 512 | int i = 0; 513 | pid_t pid = 0; 514 | for(i = 0;i < num;i ++) { 515 | pid = fork(); 516 | if(pid <= (pid_t) 0) 517 | { 518 | usleep(1); 519 | break; 520 | } 521 | } 522 | 523 | if (pid > 0) { 524 | printf("ntyco_httpd server running ...\n"); 525 | getchar(); 526 | } else if (pid == 0) { 527 | process_bind(fd); 528 | } 529 | 530 | } 531 | 532 | 533 | 534 | 535 | 536 | 537 | -------------------------------------------------------------------------------- /websocket/websocket_client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | --------------------------------------------------------------------------------