├── .gitignore ├── README.md ├── readme └── coctx_swap_S.md └── src ├── LICENSE.txt ├── Makefile ├── co.mk ├── co_closure.h ├── co_epoll.cpp ├── co_epoll.h ├── co_hook_sys_call.cpp ├── co_routine.cpp ├── co_routine.h ├── co_routine_inner.h ├── co_routine_specific.h ├── coctx.cpp ├── coctx.h ├── coctx_swap.S ├── example_closure.cpp ├── example_cond.cpp ├── example_copystack.cpp ├── example_echocli.cpp ├── example_echosvr.cpp ├── example_poll.cpp ├── example_setenv.cpp ├── example_specific.cpp └── example_thread.cpp /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyrdl/libco-code-study/0fce7846e7e79a674fb5fdb16ddf34d78bff7853/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) 2 | # libco 源码学习 3 | 4 | [libco](https://github.com/Tencent/libco)是腾讯开源的一个协程库 5 | 6 | # 源码阅读与思考 7 | 8 | * [coctx_swap.S](https://github.com/yyrdl/libco-code-study/blob/master/readme/coctx_swap_S.md) 9 | -------------------------------------------------------------------------------- /readme/coctx_swap_S.md: -------------------------------------------------------------------------------- 1 | # coctx_swap.S 2 | 3 | 在这个汇编文件定义了函数coctx_swap 函数(co_routine context swap)。该函数的作用是 4 | 保存当前co_routine的执行环境到结构体coctx_t ,然后将CPU上下文设置为目标co_routine的上下文. 5 | 6 | # 相关知识 7 | 8 | ## 两个寄存器 9 | 10 | * esp 栈顶指针寄存器,指向调用栈的栈顶(始终指向,意味着栈分配到哪里了,从当前栈往高地址是已被分配了的) 11 | * ebp 基址指针寄存器,指向当前活动栈帧的基址 12 | 13 | >一个function 调用会在栈上生成一个record ,称之为栈帧 14 | 15 | ## function 调用与栈活动(正常的情况下) 16 | 17 | * 1.将传给被调用函数的参数从右至左压栈 18 | * 2.将返回地址压栈,返回地址即函数调用结束后要执行的下一条指令的地址 19 | * 3.将当前EBP 寄存器里的值压栈 20 | * 4.将EBP寄存器的值设为ESP寄存器保存的值 21 | * 5.在栈里为当前函数局部变量分配所需的空间,表现为修改ESP寄存器的值(一般是减4的整数倍,栈分配是从高地址向低地址分配) 22 | 23 | ## 其他 24 | 25 | * [X86 REGISTERS](https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture) 26 | 27 | * [FUNCTIONS and STACK FRAME](https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames) 28 | 29 | * [计算机组成原理](http://product.dangdang.com/23793048.html) 30 | 31 | 32 | # 源码注解 33 | 34 | 只注解了32位部分,64位部分内容一致 35 | 36 | ```s 37 | .globl coctx_swap 38 | #if !defined( __APPLE__ ) 39 | .type coctx_swap, @function 40 | #endif 41 | coctx_swap: 42 | 43 | #if defined(__i386__) 44 | leal 4(%esp), %eax //sp R[eax]=R[esp]+4 R[eax]的值应该为coctx_swap的第一个参数在栈中的地址 45 | movl 4(%esp), %esp // R[esp]=Mem[R[esp]+4] 将esp指向 &(curr->ctx) 当前routine 上下文的内存地址,ctx在堆区,现在esp应指向reg[0] 46 | leal 32(%esp), %esp //parm a : ®s[7] + sizeof(void*) push 操作是以esp的值为基准,push一个值,则esp的值减一个单位(因为是按栈区的操作逻辑,从高位往低位分配地址),但ctx是在堆区,所以应将esp指向reg[7],然后从eax到-4(%eax)push 47 | //保存寄存器值到栈中,实际对应coctx_t->regs 数组在栈中的位置(参见coctx.h 中coctx_t的定义) 48 | pushl %eax //esp ->parm a 49 | 50 | pushl %ebp 51 | pushl %esi 52 | pushl %edi 53 | pushl %edx 54 | pushl %ecx 55 | pushl %ebx 56 | pushl -4(%eax) //将函数返回地址压栈,即coctx_swap 之后的指令地址,保存返回地址,保存到coctx_t->regs[0] 57 | 58 | //恢复运行目标routine时的环境(各个寄存器的值和栈状态) 59 | movl 4(%eax), %esp //parm b -> ®s[0] //切换esp到目标 routine ctx在栈中的起始地址,这个地址正好对应regs[0],pop一次 esp会加一个单位的值 60 | 61 | popl %eax //ret func addr regs[0] 暂存返回地址到 EAX 62 | //恢复当时的寄存器状态 63 | popl %ebx // regs[1] 64 | popl %ecx // regs[2] 65 | popl %edx // regs[3] 66 | popl %edi // regs[4] 67 | popl %esi // regs[5] 68 | popl %ebp // regs[6] 69 | popl %esp // regs[7] 70 | //将返回地址压栈 71 | pushl %eax //set ret func addr 72 | //将 eax清零 73 | xorl %eax, %eax 74 | //返回,这里返回之后就切换到目标routine了,C++代码中调用coctx_swap的地方之后的代码将得不到立即执行 75 | ret 76 | 77 | #elif defined(__x86_64__) 78 | leaq 8(%rsp),%rax 79 | leaq 112(%rdi),%rsp 80 | pushq %rax 81 | pushq %rbx 82 | pushq %rcx 83 | pushq %rdx 84 | 85 | pushq -8(%rax) //ret func addr 86 | 87 | pushq %rsi 88 | pushq %rdi 89 | pushq %rbp 90 | pushq %r8 91 | pushq %r9 92 | pushq %r12 93 | pushq %r13 94 | pushq %r14 95 | pushq %r15 96 | 97 | movq %rsi, %rsp 98 | popq %r15 99 | popq %r14 100 | popq %r13 101 | popq %r12 102 | popq %r9 103 | popq %r8 104 | popq %rbp 105 | popq %rdi 106 | popq %rsi 107 | popq %rax //ret func addr 108 | popq %rdx 109 | popq %rcx 110 | popq %rbx 111 | popq %rsp 112 | pushq %rax 113 | 114 | xorl %eax, %eax 115 | ret 116 | #endif 117 | 118 | ``` 119 | 120 | # 问题 121 | 122 | * 1.随意改变ESP的值不会导致栈分配冲突么?是怎么解决的?to be continue... 123 | 124 | 答: 运行时栈区不再由系统分配,而是由函数co_create_env 分配,co_create_env会分配最小 128kb最大8MB的内存空间作为一个co_routine的运行时栈空间。 125 | 每次co_routine调度时,系统(汇编部分coctx_swap方法)会保存当前co_routine的栈区到内存,并切换栈区基地址和栈顶地址指针到目标co_routine的基地址和栈顶地址(用过设置对应寄存器的值)。这样就不可能导致栈空间分配冲突。 126 | -------------------------------------------------------------------------------- /src/LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyrdl/libco-code-study/0fce7846e7e79a674fb5fdb16ddf34d78bff7853/src/LICENSE.txt -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Tencent is pleased to support the open source community by making Libco available. 3 | # 4 | # Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | 20 | COMM_MAKE = 1 21 | COMM_ECHO = 1 22 | version=0.5 23 | v=debug 24 | include co.mk 25 | 26 | ########## options ########## 27 | CFLAGS += -g -fno-strict-aliasing -O2 -Wall -export-dynamic \ 28 | -Wall -pipe -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64 29 | 30 | LINKS += -g -L./lib -lcolib -lpthread -ldl 31 | 32 | COLIB_OBJS=co_epoll.o co_routine.o co_hook_sys_call.o coctx_swap.o coctx.o 33 | #co_swapcontext.o 34 | 35 | PROGS = colib example_poll example_echosvr example_echocli example_thread example_cond example_specific example_copystack example_closure 36 | 37 | all:$(PROGS) 38 | 39 | colib:libcolib.a libcolib.so 40 | 41 | libcolib.a: $(COLIB_OBJS) 42 | $(ARSTATICLIB) 43 | libcolib.so: $(COLIB_OBJS) 44 | $(BUILDSHARELIB) 45 | 46 | example_echosvr:example_echosvr.o 47 | $(BUILDEXE) 48 | example_echocli:example_echocli.o 49 | $(BUILDEXE) 50 | example_thread:example_thread.o 51 | $(BUILDEXE) 52 | example_poll:example_poll.o 53 | $(BUILDEXE) 54 | example_exit:example_exit.o 55 | $(BUILDEXE) 56 | example_cond:example_cond.o 57 | $(BUILDEXE) 58 | example_specific:example_specific.o 59 | $(BUILDEXE) 60 | example_copystack:example_copystack.o 61 | $(BUILDEXE) 62 | example_setenv:example_setenv.o 63 | $(BUILDEXE) 64 | example_closure:example_closure.o 65 | $(BUILDEXE) 66 | 67 | dist: clean libco-$(version).src.tar.gz 68 | 69 | libco-$(version).src.tar.gz: 70 | @find . -type f | grep -v CVS | grep -v .svn | sed s:^./:libco-$(version)/: > MANIFEST 71 | @(cd ..; ln -s libco_pub libco-$(version)) 72 | (cd ..; tar cvf - `cat libco_pub/MANIFEST` | gzip > libco_pub/libco-$(version).src.tar.gz) 73 | @(cd ..; rm libco-$(version)) 74 | 75 | clean: 76 | $(CLEAN) *.o $(PROGS) 77 | rm -fr MANIFEST lib solib libco-$(version).src.tar.gz libco-$(version) 78 | 79 | -------------------------------------------------------------------------------- /src/co.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Tencent is pleased to support the open source community by making Libco available. 3 | # 4 | # Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | 20 | 21 | ##### Makefile Rules ########## 22 | MAIL_ROOT=. 23 | SRCROOT=. 24 | 25 | ##define the compliers 26 | CPP = g++ 27 | CC = gcc 28 | AR = ar -rc 29 | RANLIB = ranlib 30 | 31 | CPPSHARE = $(CPP) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o 32 | CSHARE = $(CC) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o 33 | 34 | ifeq ($v,release) 35 | CFLAGS= -O2 $(INCLS) -fPIC -DLINUX -pipe -Wno-deprecated -c 36 | else 37 | CFLAGS= -g $(INCLS) -fPIC -DLINUX -pipe -c -fno-inline 38 | endif 39 | 40 | ifneq ($v,release) 41 | BFLAGS= -g 42 | endif 43 | 44 | STATICLIBPATH=$(SRCROOT)/lib 45 | DYNAMICLIBPATH=$(SRCROOT)/solib 46 | 47 | INCLS += -I$(SRCROOT) 48 | 49 | ## default links 50 | ifeq ($(LINKS_DYNAMIC), 1) 51 | LINKS += -L$(DYNAMICLIBPATH) -L$(STATICLIBPATH) 52 | else 53 | LINKS += -L$(STATICLIBPATH) 54 | endif 55 | 56 | CPPSRCS = $(wildcard *.cpp) 57 | CSRCS = $(wildcard *.c) 58 | CPPOBJS = $(patsubst %.cpp,%.o,$(CPPSRCS)) 59 | COBJS = $(patsubst %.c,%.o,$(CSRCS)) 60 | 61 | SRCS = $(CPPSRCS) $(CSRCS) 62 | OBJS = $(CPPOBJS) $(COBJS) 63 | 64 | CPPCOMPI=$(CPP) $(CFLAGS) -Wno-deprecated 65 | CCCOMPI=$(CC) $(CFLAGS) 66 | 67 | BUILDEXE = $(CPP) $(BFLAGS) -o $@ $^ $(LINKS) 68 | CLEAN = rm -f *.o 69 | 70 | CPPCOMPILE = $(CPPCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@ 71 | CCCOMPILE = $(CCCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@ 72 | 73 | ARSTATICLIB = $(AR) $@.tmp $^ $(AR_FLAGS); \ 74 | if [ $$? -ne 0 ]; then exit 1; fi; \ 75 | test -d $(STATICLIBPATH) || mkdir -p $(STATICLIBPATH); \ 76 | mv -f $@.tmp $(STATICLIBPATH)/$@; 77 | 78 | BUILDSHARELIB = $(CPPSHARE) $@.tmp $^ $(BS_FLAGS); \ 79 | if [ $$? -ne 0 ]; then exit 1; fi; \ 80 | test -d $(DYNAMICLIBPATH) || mkdir -p $(DYNAMICLIBPATH); \ 81 | mv -f $@.tmp $(DYNAMICLIBPATH)/$@; 82 | 83 | .cpp.o: 84 | $(CPPCOMPILE) 85 | .c.o: 86 | $(CCCOMPILE) 87 | -------------------------------------------------------------------------------- /src/co_closure.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyrdl/libco-code-study/0fce7846e7e79a674fb5fdb16ddf34d78bff7853/src/co_closure.h -------------------------------------------------------------------------------- /src/co_epoll.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_epoll.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifndef __APPLE__ 27 | 28 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) 29 | { 30 | return epoll_wait( epfd,events->events,maxevents,timeout ); 31 | } 32 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) 33 | { 34 | return epoll_ctl( epfd,op,fd,ev ); 35 | } 36 | int co_epoll_create( int size ) 37 | { 38 | return epoll_create( size ); 39 | } 40 | 41 | struct co_epoll_res *co_epoll_res_alloc( int n ) 42 | { 43 | struct co_epoll_res * ptr = (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); 44 | 45 | ptr->size = n; 46 | ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); 47 | 48 | return ptr; 49 | 50 | } 51 | void co_epoll_res_free( struct co_epoll_res * ptr ) 52 | { 53 | if( !ptr ) return; 54 | if( ptr->events ) free( ptr->events ); 55 | free( ptr ); 56 | } 57 | 58 | #else 59 | class clsFdMap // million of fd , 1024 * 1024 60 | { 61 | private: 62 | static const int row_size = 1024; 63 | static const int col_size = 1024; 64 | 65 | void **m_pp[ 1024 ]; 66 | public: 67 | clsFdMap() 68 | { 69 | memset( m_pp,0,sizeof(m_pp) ); 70 | } 71 | ~clsFdMap() 72 | { 73 | for(int i=0;i= sizeof(m_pp)/sizeof(m_pp[0]) ) 91 | { 92 | assert( __LINE__ == 0 ); 93 | return -__LINE__; 94 | } 95 | if( !m_pp[ idx ] ) 96 | { 97 | m_pp[ idx ] = (void**)calloc( 1,sizeof(void*) * col_size ); 98 | } 99 | m_pp[ idx ][ fd % col_size ] = (void*)ptr; 100 | return 0; 101 | } 102 | inline void *get( int fd ) 103 | { 104 | int idx = fd / row_size; 105 | if( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) ) 106 | { 107 | return NULL; 108 | } 109 | void **lp = m_pp[ idx ]; 110 | if( !lp ) return NULL; 111 | 112 | return lp[ fd % col_size ]; 113 | } 114 | }; 115 | 116 | __thread clsFdMap *s_fd_map = NULL; 117 | 118 | static inline clsFdMap *get_fd_map() 119 | { 120 | if( !s_fd_map ) 121 | { 122 | s_fd_map = new clsFdMap(); 123 | } 124 | return s_fd_map; 125 | } 126 | 127 | struct kevent_pair_t 128 | { 129 | int fire_idx; 130 | int events; 131 | uint64_t u64; 132 | }; 133 | int co_epoll_create( int size ) 134 | { 135 | return kqueue(); 136 | } 137 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) 138 | { 139 | struct timespec t = { 0 }; 140 | if( timeout > 0 ) 141 | { 142 | t.tv_sec = timeout; 143 | } 144 | int ret = kevent( epfd, 145 | NULL, 0, //register null 146 | events->eventlist, maxevents,//just retrival 147 | ( -1 == timeout ) ? NULL : &t ); 148 | int j = 0; 149 | for(int i=0;ieventlist[i]; 152 | struct kevent_pair_t *ptr = (struct kevent_pair_t*)kev.udata; 153 | struct epoll_event *ev = events->events + i; 154 | if( 0 == ptr->fire_idx ) 155 | { 156 | ptr->fire_idx = i + 1; 157 | memset( ev,0,sizeof(*ev) ); 158 | ++j; 159 | } 160 | else 161 | { 162 | ev = events->events + ptr->fire_idx - 1; 163 | } 164 | if( EVFILT_READ == kev.filter ) 165 | { 166 | ev->events |= EPOLLIN; 167 | } 168 | else if( EVFILT_WRITE == kev.filter ) 169 | { 170 | ev->events |= EPOLLOUT; 171 | } 172 | ev->data.u64 = ptr->u64; 173 | } 174 | for(int i=0;ieventlist[i].udata) )->fire_idx = 0; 177 | } 178 | return j; 179 | } 180 | int co_epoll_del( int epfd,int fd ) 181 | { 182 | 183 | struct timespec t = { 0 }; 184 | struct kevent_pair_t *ptr = ( struct kevent_pair_t* )get_fd_map()->get( fd ); 185 | if( !ptr ) return 0; 186 | if( EPOLLIN & ptr->events ) 187 | { 188 | struct kevent kev = { 0 }; 189 | kev.ident = fd; 190 | kev.filter = EVFILT_READ; 191 | kev.flags = EV_DELETE; 192 | kevent( epfd,&kev,1, NULL,0,&t ); 193 | } 194 | if( EPOLLOUT & ptr->events ) 195 | { 196 | struct kevent kev = { 0 }; 197 | kev.ident = fd; 198 | kev.filter = EVFILT_WRITE; 199 | kev.flags = EV_DELETE; 200 | kevent( epfd,&kev,1, NULL,0,&t ); 201 | } 202 | get_fd_map()->clear( fd ); 203 | free( ptr ); 204 | return 0; 205 | } 206 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) 207 | { 208 | if( EPOLL_CTL_DEL == op ) 209 | { 210 | return co_epoll_del( epfd,fd ); 211 | } 212 | 213 | const int flags = ( EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP ); 214 | if( ev->events & ~flags ) 215 | { 216 | return -1; 217 | } 218 | 219 | if( EPOLL_CTL_ADD == op && get_fd_map()->get( fd ) ) 220 | { 221 | errno = EEXIST; 222 | return -1; 223 | } 224 | else if( EPOLL_CTL_MOD == op && !get_fd_map()->get( fd ) ) 225 | { 226 | errno = ENOENT; 227 | return -1; 228 | } 229 | 230 | struct kevent_pair_t *ptr = (struct kevent_pair_t*)get_fd_map()->get( fd ); 231 | if( !ptr ) 232 | { 233 | ptr = (kevent_pair_t*)calloc(1,sizeof(kevent_pair_t)); 234 | get_fd_map()->set( fd,ptr ); 235 | } 236 | 237 | int ret = 0; 238 | struct timespec t = { 0 }; 239 | 240 | printf("ptr->events 0x%X\n",ptr->events); 241 | 242 | if( EPOLL_CTL_MOD == op ) 243 | { 244 | //1.delete if exists 245 | if( ptr->events & EPOLLIN ) 246 | { 247 | struct kevent kev = { 0 }; 248 | EV_SET( &kev,fd,EVFILT_READ,EV_DELETE,0,0,NULL ); 249 | kevent( epfd, &kev,1, NULL,0, &t ); 250 | } 251 | //1.delete if exists 252 | if( ptr->events & EPOLLOUT ) 253 | { 254 | struct kevent kev = { 0 }; 255 | EV_SET( &kev,fd,EVFILT_WRITE,EV_DELETE,0,0,NULL ); 256 | ret = kevent( epfd, &kev,1, NULL,0, &t ); 257 | printf("delete write ret %d\n",ret ); 258 | } 259 | } 260 | 261 | do 262 | { 263 | if( ev->events & EPOLLIN ) 264 | { 265 | 266 | //2.add 267 | struct kevent kev = { 0 }; 268 | EV_SET( &kev,fd,EVFILT_READ,EV_ADD,0,0,ptr ); 269 | ret = kevent( epfd, &kev,1, NULL,0, &t ); 270 | if( ret ) break; 271 | } 272 | if( ev->events & EPOLLOUT ) 273 | { 274 | //2.add 275 | struct kevent kev = { 0 }; 276 | EV_SET( &kev,fd,EVFILT_WRITE,EV_ADD,0,0,ptr ); 277 | ret = kevent( epfd, &kev,1, NULL,0, &t ); 278 | if( ret ) break; 279 | } 280 | } while( 0 ); 281 | 282 | if( ret ) 283 | { 284 | get_fd_map()->clear( fd ); 285 | free( ptr ); 286 | return ret; 287 | } 288 | 289 | ptr->events = ev->events; 290 | ptr->u64 = ev->data.u64; 291 | 292 | 293 | return ret; 294 | } 295 | 296 | struct co_epoll_res *co_epoll_res_alloc( int n ) 297 | { 298 | struct co_epoll_res * ptr = 299 | (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); 300 | 301 | ptr->size = n; 302 | ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); 303 | ptr->eventlist = (struct kevent*)calloc( 1,n * sizeof( struct kevent) ); 304 | 305 | return ptr; 306 | } 307 | 308 | void co_epoll_res_free( struct co_epoll_res * ptr ) 309 | { 310 | if( !ptr ) return; 311 | if( ptr->events ) free( ptr->events ); 312 | if( ptr->eventlist ) free( ptr->eventlist ); 313 | free( ptr ); 314 | } 315 | 316 | #endif 317 | 318 | 319 | -------------------------------------------------------------------------------- /src/co_epoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_EPOLL_H__ 20 | #define __CO_EPOLL_H__ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #ifndef __APPLE__ 30 | 31 | #include 32 | 33 | struct co_epoll_res 34 | { 35 | int size; 36 | struct epoll_event *events; 37 | struct kevent *eventlist; 38 | }; 39 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); 40 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); 41 | int co_epoll_create( int size ); 42 | struct co_epoll_res *co_epoll_res_alloc( int n ); 43 | void co_epoll_res_free( struct co_epoll_res * ); 44 | 45 | #else 46 | 47 | #include 48 | enum EPOLL_EVENTS 49 | { 50 | EPOLLIN = 0X001, 51 | EPOLLPRI = 0X002, 52 | EPOLLOUT = 0X004, 53 | 54 | EPOLLERR = 0X008, 55 | EPOLLHUP = 0X010, 56 | }; 57 | #define EPOLL_CTL_ADD 1 58 | #define EPOLL_CTL_DEL 2 59 | #define EPOLL_CTL_MOD 3 60 | typedef union epoll_data 61 | { 62 | void *ptr; 63 | int fd; 64 | uint32_t u32; 65 | uint64_t u64; 66 | 67 | } epoll_data_t; 68 | 69 | struct epoll_event 70 | { 71 | uint32_t events; 72 | epoll_data_t data; 73 | }; 74 | 75 | struct co_epoll_res 76 | { 77 | int size; 78 | struct epoll_event *events; 79 | struct kevent *eventlist; 80 | }; 81 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); 82 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); 83 | int co_epoll_create( int size ); 84 | struct co_epoll_res *co_epoll_res_alloc( int n ); 85 | void co_epoll_res_free( struct co_epoll_res * ); 86 | 87 | #endif 88 | #endif 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/co_hook_sys_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | 43 | #include 44 | #include "co_routine.h" 45 | #include "co_routine_inner.h" 46 | #include "co_routine_specific.h" 47 | 48 | typedef long long ll64_t; 49 | 50 | struct rpchook_t 51 | { 52 | int user_flag; 53 | struct sockaddr_in dest; //maybe sockaddr_un; 54 | int domain; //AF_LOCAL , AF_INET 55 | 56 | struct timeval read_timeout; 57 | struct timeval write_timeout; 58 | }; 59 | static inline pid_t GetPid() 60 | { 61 | char **p = (char**)pthread_self(); 62 | return p ? *(pid_t*)(p + 18) : getpid(); 63 | } 64 | static rpchook_t *g_rpchook_socket_fd[ 102400 ] = { 0 };//最大句柄数 102400 65 | //定义系统标准库函数类型 66 | typedef int (*socket_pfn_t)(int domain, int type, int protocol); 67 | typedef int (*connect_pfn_t)(int socket, const struct sockaddr *address, socklen_t address_len); 68 | typedef int (*close_pfn_t)(int fd); 69 | 70 | typedef ssize_t (*read_pfn_t)(int fildes, void *buf, size_t nbyte); 71 | typedef ssize_t (*write_pfn_t)(int fildes, const void *buf, size_t nbyte); 72 | 73 | typedef ssize_t (*sendto_pfn_t)(int socket, const void *message, size_t length, 74 | int flags, const struct sockaddr *dest_addr, 75 | socklen_t dest_len); 76 | 77 | typedef ssize_t (*recvfrom_pfn_t)(int socket, void *buffer, size_t length, 78 | int flags, struct sockaddr *address, 79 | socklen_t *address_len); 80 | 81 | typedef size_t (*send_pfn_t)(int socket, const void *buffer, size_t length, int flags); 82 | typedef ssize_t (*recv_pfn_t)(int socket, void *buffer, size_t length, int flags); 83 | 84 | typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); 85 | typedef int (*setsockopt_pfn_t)(int socket, int level, int option_name, 86 | const void *option_value, socklen_t option_len); 87 | 88 | typedef int (*fcntl_pfn_t)(int fildes, int cmd, ...); 89 | typedef struct tm *(*localtime_r_pfn_t)( const time_t *timep, struct tm *result ); 90 | 91 | typedef void *(*pthread_getspecific_pfn_t)(pthread_key_t key); 92 | typedef int (*pthread_setspecific_pfn_t)(pthread_key_t key, const void *value); 93 | 94 | typedef int (*setenv_pfn_t)(const char *name, const char *value, int overwrite); 95 | typedef int (*unsetenv_pfn_t)(const char *name); 96 | typedef char *(*getenv_pfn_t)(const char *name); 97 | typedef hostent* (*gethostbyname_pfn_t)(const char *name); 98 | typedef res_state (*__res_state_pfn_t)(); 99 | typedef int (*__poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); 100 | 101 | //从动态链接库获取标准函数 102 | static socket_pfn_t g_sys_socket_func = (socket_pfn_t)dlsym(RTLD_NEXT,"socket"); 103 | static connect_pfn_t g_sys_connect_func = (connect_pfn_t)dlsym(RTLD_NEXT,"connect"); 104 | static close_pfn_t g_sys_close_func = (close_pfn_t)dlsym(RTLD_NEXT,"close"); 105 | 106 | static read_pfn_t g_sys_read_func = (read_pfn_t)dlsym(RTLD_NEXT,"read"); 107 | static write_pfn_t g_sys_write_func = (write_pfn_t)dlsym(RTLD_NEXT,"write"); 108 | 109 | static sendto_pfn_t g_sys_sendto_func = (sendto_pfn_t)dlsym(RTLD_NEXT,"sendto"); 110 | static recvfrom_pfn_t g_sys_recvfrom_func = (recvfrom_pfn_t)dlsym(RTLD_NEXT,"recvfrom"); 111 | 112 | static send_pfn_t g_sys_send_func = (send_pfn_t)dlsym(RTLD_NEXT,"send"); 113 | static recv_pfn_t g_sys_recv_func = (recv_pfn_t)dlsym(RTLD_NEXT,"recv"); 114 | 115 | static poll_pfn_t g_sys_poll_func = (poll_pfn_t)dlsym(RTLD_NEXT,"poll"); 116 | 117 | static setsockopt_pfn_t g_sys_setsockopt_func 118 | = (setsockopt_pfn_t)dlsym(RTLD_NEXT,"setsockopt"); 119 | static fcntl_pfn_t g_sys_fcntl_func = (fcntl_pfn_t)dlsym(RTLD_NEXT,"fcntl"); 120 | 121 | static setenv_pfn_t g_sys_setenv_func = (setenv_pfn_t)dlsym(RTLD_NEXT,"setenv"); 122 | static unsetenv_pfn_t g_sys_unsetenv_func = (unsetenv_pfn_t)dlsym(RTLD_NEXT,"unsetenv"); 123 | static getenv_pfn_t g_sys_getenv_func = (getenv_pfn_t)dlsym(RTLD_NEXT,"getenv"); 124 | static __res_state_pfn_t g_sys___res_state_func = (__res_state_pfn_t)dlsym(RTLD_NEXT,"__res_state"); 125 | 126 | static gethostbyname_pfn_t g_sys_gethostbyname_func = (gethostbyname_pfn_t)dlsym(RTLD_NEXT, "gethostbyname"); 127 | 128 | static __poll_pfn_t g_sys___poll_func = (__poll_pfn_t)dlsym(RTLD_NEXT, "__poll"); 129 | 130 | 131 | /* 132 | static pthread_getspecific_pfn_t g_sys_pthread_getspecific_func 133 | = (pthread_getspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_getspecific"); 134 | 135 | static pthread_setspecific_pfn_t g_sys_pthread_setspecific_func 136 | = (pthread_setspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_setspecific"); 137 | 138 | static pthread_rwlock_rdlock_pfn_t g_sys_pthread_rwlock_rdlock_func 139 | = (pthread_rwlock_rdlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_rdlock"); 140 | 141 | static pthread_rwlock_wrlock_pfn_t g_sys_pthread_rwlock_wrlock_func 142 | = (pthread_rwlock_wrlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_wrlock"); 143 | 144 | static pthread_rwlock_unlock_pfn_t g_sys_pthread_rwlock_unlock_func 145 | = (pthread_rwlock_unlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_unlock"); 146 | */ 147 | 148 | 149 | 150 | static inline unsigned long long get_tick_count() 151 | { 152 | uint32_t lo, hi; 153 | __asm__ __volatile__ ( 154 | "rdtscp" : "=a"(lo), "=d"(hi) 155 | ); 156 | return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); 157 | } 158 | 159 | struct rpchook_connagent_head_t 160 | { 161 | unsigned char bVersion; 162 | struct in_addr iIP; 163 | unsigned short hPort; 164 | unsigned int iBodyLen; 165 | unsigned int iOssAttrID; 166 | unsigned char bIsRespNotExist; 167 | unsigned char sReserved[6]; 168 | }__attribute__((packed)); 169 | 170 | //宏定义,如果指定name的函数没有获取到,就从动态链接库中加载 171 | #define HOOK_SYS_FUNC(name) if( !g_sys_##name##_func ) { g_sys_##name##_func = (name##_pfn_t)dlsym(RTLD_NEXT,#name); } 172 | 173 | static inline ll64_t diff_ms(struct timeval &begin,struct timeval &end) 174 | { 175 | ll64_t u = (end.tv_sec - begin.tv_sec) ; 176 | u *= 1000 * 10; 177 | u += ( end.tv_usec - begin.tv_usec ) / ( 100 ); 178 | return u; 179 | } 180 | 181 | /*******************************start 句柄管理*****************************************/ 182 | 183 | static inline rpchook_t * get_by_fd( int fd ) 184 | { 185 | if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) 186 | { 187 | return g_rpchook_socket_fd[ fd ]; 188 | } 189 | return NULL; 190 | } 191 | static inline rpchook_t * alloc_by_fd( int fd ) 192 | { 193 | if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) 194 | { 195 | rpchook_t *lp = (rpchook_t*)calloc( 1,sizeof(rpchook_t) ); 196 | lp->read_timeout.tv_sec = 1; 197 | lp->write_timeout.tv_sec = 1; 198 | g_rpchook_socket_fd[ fd ] = lp; 199 | return lp; 200 | } 201 | return NULL; 202 | } 203 | static inline void free_by_fd( int fd ) 204 | { 205 | if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) 206 | { 207 | rpchook_t *lp = g_rpchook_socket_fd[ fd ]; 208 | if( lp ) 209 | { 210 | g_rpchook_socket_fd[ fd ] = NULL; 211 | free(lp); 212 | } 213 | } 214 | return; 215 | 216 | } 217 | /************************************end 句柄管理*************************************************/ 218 | 219 | //hook socket 220 | int socket(int domain, int type, int protocol) 221 | { 222 | HOOK_SYS_FUNC( socket ); 223 | 224 | if( !co_is_enable_sys_hook() ) 225 | { 226 | return g_sys_socket_func( domain,type,protocol ); 227 | } 228 | int fd = g_sys_socket_func(domain,type,protocol); 229 | if( fd < 0 ) 230 | { 231 | return fd; 232 | } 233 | 234 | rpchook_t *lp = alloc_by_fd( fd ); 235 | lp->domain = domain; 236 | 237 | fcntl( fd, F_SETFL, g_sys_fcntl_func(fd, F_GETFL,0 ) );//得到之后又设回去?答:注意fcnt1已经被hook了 238 | 239 | return fd;//返回句柄号 240 | } 241 | 242 | int co_accept( int fd, struct sockaddr *addr, socklen_t *len ) 243 | { 244 | int cli = accept( fd,addr,len ); 245 | if( cli < 0 ) 246 | { 247 | return cli; 248 | } 249 | alloc_by_fd( cli ); 250 | return cli; 251 | } 252 | int connect(int fd, const struct sockaddr *address, socklen_t address_len) 253 | { 254 | HOOK_SYS_FUNC( connect ); 255 | 256 | if( !co_is_enable_sys_hook() ) 257 | { 258 | return g_sys_connect_func(fd,address,address_len); 259 | } 260 | 261 | //1.sys call 262 | int ret = g_sys_connect_func( fd,address,address_len ); 263 | 264 | rpchook_t *lp = get_by_fd( fd ); 265 | if( !lp ) return ret;//如果该句柄不存在,直接返回原始系统函数connect的返回值 266 | 267 | if( sizeof(lp->dest) >= address_len ) 268 | { 269 | memcpy( &(lp->dest),address,(int)address_len ); 270 | } 271 | if( O_NONBLOCK & lp->user_flag )//如果用户设置了非阻塞模式 272 | { 273 | return ret; 274 | } 275 | 276 | if (!(ret < 0 && errno == EINPROGRESS))//如果不是正在连接,则返回 277 | { 278 | return ret; 279 | } 280 | 281 | //2.wait 282 | int pollret = 0; 283 | struct pollfd pf = { 0 }; 284 | 285 | for(int i=0;i<3;i++) //25s * 3 = 75s 286 | { 287 | memset( &pf,0,sizeof(pf) ); 288 | pf.fd = fd; 289 | pf.events = ( POLLOUT | POLLERR | POLLHUP );//对可写,出错,挂起事件感兴趣 290 | 291 | pollret = poll( &pf,1,25000 ); 292 | 293 | if( 1 == pollret ) 294 | { 295 | break; 296 | } 297 | } 298 | if( pf.revents & POLLOUT ) //connect succ 299 | { 300 | errno = 0; 301 | return 0; 302 | } 303 | 304 | //3.set errno 失败了 305 | int err = 0; 306 | socklen_t errlen = sizeof(err); 307 | getsockopt( fd,SOL_SOCKET,SO_ERROR,&err,&errlen); 308 | if( err )//如果有系统失败原因 309 | { 310 | errno = err; 311 | } 312 | else//否则就是超时失败75秒超时 313 | { 314 | errno = ETIMEDOUT; 315 | } 316 | return ret; 317 | } 318 | 319 | 320 | int close(int fd) 321 | { 322 | HOOK_SYS_FUNC( close ); 323 | 324 | if( !co_is_enable_sys_hook() ) 325 | { 326 | return g_sys_close_func( fd ); 327 | } 328 | 329 | free_by_fd( fd );//释放对应的rpchook_t 330 | int ret = g_sys_close_func(fd); 331 | 332 | return ret; 333 | } 334 | ssize_t read( int fd, void *buf, size_t nbyte ) 335 | { 336 | HOOK_SYS_FUNC( read ); 337 | 338 | if( !co_is_enable_sys_hook() ) 339 | { 340 | return g_sys_read_func( fd,buf,nbyte ); 341 | } 342 | rpchook_t *lp = get_by_fd( fd ); 343 | 344 | if( !lp || ( O_NONBLOCK & lp->user_flag ) ) 345 | { 346 | ssize_t ret = g_sys_read_func( fd,buf,nbyte ); 347 | return ret; 348 | } 349 | int timeout = ( lp->read_timeout.tv_sec * 1000 ) 350 | + ( lp->read_timeout.tv_usec / 1000 );//超时换算成毫秒 351 | 352 | struct pollfd pf = { 0 }; 353 | pf.fd = fd; 354 | pf.events = ( POLLIN | POLLERR | POLLHUP ); 355 | 356 | int pollret = poll( &pf,1,timeout ); 357 | 358 | ssize_t readret = g_sys_read_func( fd,(char*)buf ,nbyte ); 359 | 360 | if( readret < 0 )//读失败打个日志干嘛,应该丢给使用者选择性处理啊 361 | { 362 | co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d", 363 | fd,readret,errno,pollret,timeout); 364 | } 365 | 366 | return readret; 367 | 368 | } 369 | ssize_t write( int fd, const void *buf, size_t nbyte ) 370 | { 371 | HOOK_SYS_FUNC( write ); 372 | 373 | if( !co_is_enable_sys_hook() ) 374 | { 375 | return g_sys_write_func( fd,buf,nbyte ); 376 | } 377 | rpchook_t *lp = get_by_fd( fd ); 378 | 379 | if( !lp || ( O_NONBLOCK & lp->user_flag ) ) 380 | { 381 | ssize_t ret = g_sys_write_func( fd,buf,nbyte ); 382 | return ret; 383 | } 384 | size_t wrotelen = 0; 385 | int timeout = ( lp->write_timeout.tv_sec * 1000 ) 386 | + ( lp->write_timeout.tv_usec / 1000 ); 387 | 388 | ssize_t writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen ); 389 | 390 | if (writeret == 0) 391 | { 392 | return writeret; 393 | } 394 | 395 | if( writeret > 0 ) 396 | { 397 | wrotelen += writeret; 398 | } 399 | while( wrotelen < nbyte ) 400 | { 401 | 402 | struct pollfd pf = { 0 }; 403 | pf.fd = fd; 404 | pf.events = ( POLLOUT | POLLERR | POLLHUP ); 405 | poll( &pf,1,timeout ); 406 | 407 | writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen ); 408 | 409 | if( writeret <= 0 ) 410 | { 411 | break; 412 | } 413 | wrotelen += writeret ; 414 | } 415 | if (writeret <= 0 && wrotelen == 0) 416 | { 417 | return writeret; 418 | } 419 | return wrotelen; 420 | } 421 | 422 | ssize_t sendto(int socket, const void *message, size_t length, 423 | int flags, const struct sockaddr *dest_addr, 424 | socklen_t dest_len) 425 | { 426 | /* 427 | 1.no enable sys call ? sys 428 | 2.( !lp || lp is non block ) ? sys 429 | 3.try 430 | 4.wait 431 | 5.try 432 | */ 433 | HOOK_SYS_FUNC( sendto ); 434 | if( !co_is_enable_sys_hook() ) 435 | { 436 | return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); 437 | } 438 | 439 | rpchook_t *lp = get_by_fd( socket ); 440 | if( !lp || ( O_NONBLOCK & lp->user_flag ) ) 441 | { 442 | return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); 443 | } 444 | 445 | ssize_t ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); 446 | if( ret < 0 && EAGAIN == errno ) 447 | { 448 | int timeout = ( lp->write_timeout.tv_sec * 1000 ) 449 | + ( lp->write_timeout.tv_usec / 1000 ); 450 | 451 | 452 | struct pollfd pf = { 0 }; 453 | pf.fd = socket; 454 | pf.events = ( POLLOUT | POLLERR | POLLHUP ); 455 | poll( &pf,1,timeout ); 456 | 457 | ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); 458 | 459 | } 460 | return ret; 461 | } 462 | 463 | ssize_t recvfrom(int socket, void *buffer, size_t length, 464 | int flags, struct sockaddr *address, 465 | socklen_t *address_len) 466 | { 467 | HOOK_SYS_FUNC( recvfrom ); 468 | if( !co_is_enable_sys_hook() ) 469 | { 470 | return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); 471 | } 472 | 473 | rpchook_t *lp = get_by_fd( socket ); 474 | if( !lp || ( O_NONBLOCK & lp->user_flag ) ) 475 | { 476 | return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); 477 | } 478 | 479 | int timeout = ( lp->read_timeout.tv_sec * 1000 ) 480 | + ( lp->read_timeout.tv_usec / 1000 ); 481 | 482 | 483 | struct pollfd pf = { 0 }; 484 | pf.fd = socket; 485 | pf.events = ( POLLIN | POLLERR | POLLHUP ); 486 | poll( &pf,1,timeout ); 487 | 488 | ssize_t ret = g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); 489 | return ret; 490 | } 491 | 492 | ssize_t send(int socket, const void *buffer, size_t length, int flags) 493 | { 494 | HOOK_SYS_FUNC( send ); 495 | 496 | if( !co_is_enable_sys_hook() ) 497 | { 498 | return g_sys_send_func( socket,buffer,length,flags ); 499 | } 500 | rpchook_t *lp = get_by_fd( socket ); 501 | 502 | if( !lp || ( O_NONBLOCK & lp->user_flag ) ) 503 | { 504 | return g_sys_send_func( socket,buffer,length,flags ); 505 | } 506 | size_t wrotelen = 0; 507 | int timeout = ( lp->write_timeout.tv_sec * 1000 ) 508 | + ( lp->write_timeout.tv_usec / 1000 ); 509 | 510 | ssize_t writeret = g_sys_send_func( socket,buffer,length,flags ); 511 | if (writeret == 0) 512 | { 513 | return writeret; 514 | } 515 | 516 | if( writeret > 0 ) 517 | { 518 | wrotelen += writeret; 519 | } 520 | while( wrotelen < length ) 521 | { 522 | 523 | struct pollfd pf = { 0 }; 524 | pf.fd = socket; 525 | pf.events = ( POLLOUT | POLLERR | POLLHUP ); 526 | poll( &pf,1,timeout ); 527 | 528 | writeret = g_sys_send_func( socket,(const char*)buffer + wrotelen,length - wrotelen,flags ); 529 | 530 | if( writeret <= 0 ) 531 | { 532 | break; 533 | } 534 | wrotelen += writeret ; 535 | } 536 | if (writeret <= 0 && wrotelen == 0) 537 | { 538 | return writeret; 539 | } 540 | return wrotelen; 541 | } 542 | 543 | ssize_t recv( int socket, void *buffer, size_t length, int flags ) 544 | { 545 | HOOK_SYS_FUNC( recv ); 546 | 547 | if( !co_is_enable_sys_hook() ) 548 | { 549 | return g_sys_recv_func( socket,buffer,length,flags ); 550 | } 551 | rpchook_t *lp = get_by_fd( socket ); 552 | 553 | if( !lp || ( O_NONBLOCK & lp->user_flag ) ) 554 | { 555 | return g_sys_recv_func( socket,buffer,length,flags ); 556 | } 557 | int timeout = ( lp->read_timeout.tv_sec * 1000 ) 558 | + ( lp->read_timeout.tv_usec / 1000 ); 559 | 560 | struct pollfd pf = { 0 }; 561 | pf.fd = socket; 562 | pf.events = ( POLLIN | POLLERR | POLLHUP ); 563 | 564 | int pollret = poll( &pf,1,timeout ); 565 | 566 | ssize_t readret = g_sys_recv_func( socket,buffer,length,flags ); 567 | 568 | if( readret < 0 ) 569 | { 570 | co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d", 571 | socket,readret,errno,pollret,timeout); 572 | } 573 | 574 | return readret; 575 | 576 | } 577 | 578 | extern int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc); 579 | 580 | int poll(struct pollfd fds[], nfds_t nfds, int timeout) 581 | { 582 | 583 | HOOK_SYS_FUNC( poll ); 584 | 585 | if( !co_is_enable_sys_hook() ) 586 | { 587 | return g_sys_poll_func( fds,nfds,timeout ); 588 | } 589 | 590 | return co_poll_inner( co_get_epoll_ct(),fds,nfds,timeout, g_sys_poll_func); 591 | 592 | } 593 | int setsockopt(int fd, int level, int option_name, 594 | const void *option_value, socklen_t option_len) 595 | { 596 | HOOK_SYS_FUNC( setsockopt ); 597 | 598 | if( !co_is_enable_sys_hook() ) 599 | { 600 | return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len ); 601 | } 602 | rpchook_t *lp = get_by_fd( fd ); 603 | 604 | if( lp && SOL_SOCKET == level ) 605 | { 606 | struct timeval *val = (struct timeval*)option_value; 607 | if( SO_RCVTIMEO == option_name ) 608 | { 609 | memcpy( &lp->read_timeout,val,sizeof(*val) ); 610 | } 611 | else if( SO_SNDTIMEO == option_name ) 612 | { 613 | memcpy( &lp->write_timeout,val,sizeof(*val) ); 614 | } 615 | } 616 | return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len ); 617 | } 618 | 619 | 620 | int fcntl(int fildes, int cmd, ...) 621 | { 622 | HOOK_SYS_FUNC( fcntl ); 623 | 624 | if( fildes < 0 ) 625 | { 626 | return __LINE__; 627 | } 628 | 629 | va_list arg_list; 630 | va_start( arg_list,cmd ); 631 | 632 | int ret = -1; 633 | rpchook_t *lp = get_by_fd( fildes ); 634 | switch( cmd ) 635 | { 636 | case F_DUPFD: 637 | { 638 | int param = va_arg(arg_list,int); 639 | ret = g_sys_fcntl_func( fildes,cmd,param ); 640 | break; 641 | } 642 | case F_GETFD: 643 | { 644 | ret = g_sys_fcntl_func( fildes,cmd ); 645 | break; 646 | } 647 | case F_SETFD: 648 | { 649 | int param = va_arg(arg_list,int); 650 | ret = g_sys_fcntl_func( fildes,cmd,param ); 651 | break; 652 | } 653 | case F_GETFL: 654 | { 655 | ret = g_sys_fcntl_func( fildes,cmd ); 656 | break; 657 | } 658 | case F_SETFL: 659 | { 660 | int param = va_arg(arg_list,int); 661 | int flag = param; 662 | if( co_is_enable_sys_hook() && lp ) 663 | { 664 | flag |= O_NONBLOCK; 665 | } 666 | ret = g_sys_fcntl_func( fildes,cmd,flag ); 667 | if( 0 == ret && lp ) 668 | { 669 | lp->user_flag = param; 670 | } 671 | break; 672 | } 673 | case F_GETOWN: 674 | { 675 | ret = g_sys_fcntl_func( fildes,cmd ); 676 | break; 677 | } 678 | case F_SETOWN: 679 | { 680 | int param = va_arg(arg_list,int); 681 | ret = g_sys_fcntl_func( fildes,cmd,param ); 682 | break; 683 | } 684 | case F_GETLK: 685 | { 686 | struct flock *param = va_arg(arg_list,struct flock *); 687 | ret = g_sys_fcntl_func( fildes,cmd,param ); 688 | break; 689 | } 690 | case F_SETLK: 691 | { 692 | struct flock *param = va_arg(arg_list,struct flock *); 693 | ret = g_sys_fcntl_func( fildes,cmd,param ); 694 | break; 695 | } 696 | case F_SETLKW: 697 | { 698 | struct flock *param = va_arg(arg_list,struct flock *); 699 | ret = g_sys_fcntl_func( fildes,cmd,param ); 700 | break; 701 | } 702 | } 703 | 704 | va_end( arg_list ); 705 | 706 | return ret; 707 | } 708 | 709 | struct stCoSysEnv_t 710 | { 711 | char *name; 712 | char *value; 713 | }; 714 | struct stCoSysEnvArr_t 715 | { 716 | stCoSysEnv_t *data; 717 | size_t cnt; 718 | }; 719 | static stCoSysEnvArr_t *dup_co_sysenv_arr( stCoSysEnvArr_t * arr ) 720 | { 721 | stCoSysEnvArr_t *lp = (stCoSysEnvArr_t*)calloc( sizeof(stCoSysEnvArr_t),1 ); 722 | if( arr->cnt ) 723 | { 724 | lp->data = (stCoSysEnv_t*)calloc( sizeof(stCoSysEnv_t) * arr->cnt,1 ); 725 | lp->cnt = arr->cnt; 726 | memcpy( lp->data,arr->data,sizeof( stCoSysEnv_t ) * arr->cnt ); 727 | } 728 | return lp; 729 | } 730 | 731 | static int co_sysenv_comp(const void *a, const void *b) 732 | { 733 | return strcmp(((stCoSysEnv_t*)a)->name, ((stCoSysEnv_t*)b)->name); 734 | } 735 | static stCoSysEnvArr_t g_co_sysenv = { 0 }; 736 | 737 | 738 | 739 | void co_set_env_list( const char *name[],size_t cnt) 740 | { 741 | if( g_co_sysenv.data ) 742 | { 743 | return ; 744 | } 745 | g_co_sysenv.data = (stCoSysEnv_t*)calloc( 1,sizeof(stCoSysEnv_t) * cnt ); 746 | 747 | for(size_t i=0;i 1 ) 755 | { 756 | qsort( g_co_sysenv.data,g_co_sysenv.cnt,sizeof(stCoSysEnv_t),co_sysenv_comp ); 757 | stCoSysEnv_t *lp = g_co_sysenv.data; 758 | stCoSysEnv_t *lq = g_co_sysenv.data + 1; 759 | for(size_t i=1;iname,lq->name ) ) 762 | { 763 | ++lp; 764 | if( lq != lp ) 765 | { 766 | *lp = *lq; 767 | } 768 | } 769 | ++lq; 770 | } 771 | g_co_sysenv.cnt = lp - g_co_sysenv.data + 1; 772 | } 773 | 774 | } 775 | 776 | int setenv(const char *n, const char *value, int overwrite) 777 | { 778 | HOOK_SYS_FUNC( setenv ) 779 | if( co_is_enable_sys_hook() && g_co_sysenv.data ) 780 | { 781 | stCoRoutine_t *self = co_self(); 782 | if( self ) 783 | { 784 | if( !self->pvEnv ) 785 | { 786 | self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); 787 | } 788 | stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); 789 | 790 | stCoSysEnv_t name = { (char*)n,0 }; 791 | 792 | stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); 793 | 794 | if( e ) 795 | { 796 | if( overwrite || !e->value ) 797 | { 798 | if( e->value ) free( e->value ); 799 | e->value = ( value ? strdup( value ) : 0 ); 800 | } 801 | return 0; 802 | } 803 | } 804 | 805 | } 806 | return g_sys_setenv_func( n,value,overwrite ); 807 | } 808 | int unsetenv(const char *n) 809 | { 810 | HOOK_SYS_FUNC( unsetenv ) 811 | if( co_is_enable_sys_hook() && g_co_sysenv.data ) 812 | { 813 | stCoRoutine_t *self = co_self(); 814 | if( self ) 815 | { 816 | if( !self->pvEnv ) 817 | { 818 | self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); 819 | } 820 | stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); 821 | 822 | stCoSysEnv_t name = { (char*)n,0 }; 823 | 824 | stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); 825 | 826 | if( e ) 827 | { 828 | if( e->value ) 829 | { 830 | free( e->value ); 831 | e->value = 0; 832 | } 833 | return 0; 834 | } 835 | } 836 | 837 | } 838 | return g_sys_unsetenv_func( n ); 839 | } 840 | char *getenv( const char *n ) 841 | { 842 | HOOK_SYS_FUNC( getenv ) 843 | if( co_is_enable_sys_hook() && g_co_sysenv.data ) 844 | { 845 | stCoRoutine_t *self = co_self(); 846 | 847 | stCoSysEnv_t name = { (char*)n,0 }; 848 | 849 | if( !self->pvEnv ) 850 | { 851 | self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); 852 | } 853 | stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); 854 | 855 | stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); 856 | 857 | if( e ) 858 | { 859 | return e->value; 860 | } 861 | 862 | } 863 | return g_sys_getenv_func( n ); 864 | 865 | } 866 | struct hostent* co_gethostbyname(const char *name); 867 | 868 | struct hostent *gethostbyname(const char *name) 869 | { 870 | HOOK_SYS_FUNC( gethostbyname ); 871 | 872 | #ifdef __APPLE__ 873 | return g_sys_gethostbyname_func( name ); 874 | #else 875 | if (!co_is_enable_sys_hook()) 876 | { 877 | return g_sys_gethostbyname_func(name); 878 | } 879 | return co_gethostbyname(name); 880 | #endif 881 | 882 | } 883 | 884 | 885 | struct res_state_wrap 886 | { 887 | struct __res_state state; 888 | }; 889 | CO_ROUTINE_SPECIFIC(res_state_wrap, __co_state_wrap); 890 | 891 | extern "C" 892 | { 893 | res_state __res_state() 894 | { 895 | HOOK_SYS_FUNC(__res_state); 896 | 897 | if (!co_is_enable_sys_hook()) 898 | { 899 | return g_sys___res_state_func(); 900 | } 901 | 902 | return &(__co_state_wrap->state); 903 | } 904 | int __poll(struct pollfd fds[], nfds_t nfds, int timeout) 905 | { 906 | return poll(fds, nfds, timeout); 907 | } 908 | } 909 | 910 | struct hostbuf_wrap 911 | { 912 | struct hostent host; 913 | char* buffer; 914 | size_t iBufferSize; 915 | int host_errno; 916 | }; 917 | 918 | CO_ROUTINE_SPECIFIC(hostbuf_wrap, __co_hostbuf_wrap); 919 | 920 | #ifndef __APPLE__ 921 | struct hostent *co_gethostbyname(const char *name) 922 | { 923 | if (!name) 924 | { 925 | return NULL; 926 | } 927 | 928 | if (__co_hostbuf_wrap->buffer && __co_hostbuf_wrap->iBufferSize > 1024) 929 | { 930 | free(__co_hostbuf_wrap->buffer); 931 | __co_hostbuf_wrap->buffer = NULL; 932 | } 933 | if (!__co_hostbuf_wrap->buffer) 934 | { 935 | __co_hostbuf_wrap->buffer = (char*)malloc(1024); 936 | __co_hostbuf_wrap->iBufferSize = 1024; 937 | } 938 | 939 | struct hostent *host = &__co_hostbuf_wrap->host; 940 | struct hostent *result = NULL; 941 | int *h_errnop = &(__co_hostbuf_wrap->host_errno); 942 | 943 | int ret = -1; 944 | while (ret = gethostbyname_r(name, host, __co_hostbuf_wrap->buffer, 945 | __co_hostbuf_wrap->iBufferSize, &result, h_errnop) == ERANGE && 946 | *h_errnop == NETDB_INTERNAL ) 947 | { 948 | free(__co_hostbuf_wrap->buffer); 949 | __co_hostbuf_wrap->iBufferSize = __co_hostbuf_wrap->iBufferSize * 2; 950 | __co_hostbuf_wrap->buffer = (char*)malloc(__co_hostbuf_wrap->iBufferSize); 951 | } 952 | 953 | if (ret == 0 && (host == result)) 954 | { 955 | return host; 956 | } 957 | return NULL; 958 | } 959 | #endif 960 | 961 | 962 | void co_enable_hook_sys() //这函数必须在这里,否则本文件会被忽略!!! 963 | { 964 | stCoRoutine_t *co = GetCurrThreadCo(); 965 | if( co ) 966 | { 967 | co->cEnableSysHook = 1; 968 | } 969 | } 970 | 971 | -------------------------------------------------------------------------------- /src/co_routine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_routine.h" 20 | #include "co_routine_inner.h" 21 | #include "co_epoll.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | extern "C" 43 | { 44 | extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap"); 45 | }; 46 | using namespace std; 47 | stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ); 48 | struct stCoEpoll_t; 49 | 50 | struct stCoRoutineEnv_t 51 | { 52 | stCoRoutine_t *pCallStack[ 128 ]; 53 | int iCallStackSize; 54 | stCoEpoll_t *pEpoll; 55 | 56 | //for copy stack log lastco and nextco 57 | stCoRoutine_t* pending_co; 58 | stCoRoutine_t* ocupy_co; 59 | }; 60 | //int socket(int domain, int type, int protocol); 61 | void co_log_err( const char *fmt,... ) 62 | { 63 | } 64 | 65 | 66 | #if defined( __LIBCO_RDTSCP__) 67 | static unsigned long long counter(void)//获取已经经历的CPU周期数 (64位) 68 | { 69 | register uint32_t lo, hi; 70 | register unsigned long long o; 71 | //高32位存在hi里面,低32位存在lo里面 72 | __asm__ __volatile__ ( 73 | "rdtscp" : "=a"(lo), "=d"(hi) 74 | ); 75 | o = hi; 76 | o <<= 32; 77 | return (o | lo);还原成64位整型返回 78 | 79 | } 80 | // 已经历的时钟周期数除以CPU频率得到 已经历的时间 81 | 82 | static unsigned long long getCpuKhz()//获取CPU 时钟速率,用于计算时间 83 | { 84 | FILE *fp = fopen("/proc/cpuinfo","r"); 85 | if(!fp) return 1; 86 | char buf[4096] = {0}; 87 | fread(buf,1,sizeof(buf),fp); 88 | fclose(fp); 89 | 90 | char *lp = strstr(buf,"cpu MHz"); 91 | if(!lp) return 1; 92 | lp += strlen("cpu MHz"); 93 | while(*lp == ' ' || *lp == '\t' || *lp == ':') 94 | { 95 | ++lp; 96 | } 97 | 98 | double mhz = atof(lp); 99 | unsigned long long u = (unsigned long long)(mhz * 1000);//从MHz 转到 KHz 100 | return u; 101 | } 102 | #endif 103 | 104 | static unsigned long long GetTickMS() 105 | { 106 | #if defined( __LIBCO_RDTSCP__) 107 | static uint32_t khz = getCpuKhz();//这种方式更为准确 108 | return counter() / khz; 109 | #else 110 | struct timeval now = { 0 };//使用库函数获得时间 111 | gettimeofday( &now,NULL ); 112 | unsigned long long u = now.tv_sec; 113 | u *= 1000; 114 | u += now.tv_usec / 1000; 115 | return u; 116 | #endif 117 | } 118 | 119 | static pid_t GetPid()//获取进程ID 120 | { 121 | static __thread pid_t pid = 0; 122 | static __thread pid_t tid = 0; 123 | if( !pid || !tid || pid != getpid() ) 124 | { 125 | pid = getpid(); 126 | #if defined( __APPLE__ ) 127 | tid = syscall( SYS_gettid ); 128 | if( -1 == (long)tid ) 129 | { 130 | tid = pid; 131 | } 132 | #else 133 | tid = syscall( __NR_gettid ); 134 | #endif 135 | 136 | } 137 | return tid; 138 | 139 | } 140 | /* 141 | static pid_t GetPid() 142 | { 143 | char **p = (char**)pthread_self(); 144 | return p ? *(pid_t*)(p + 18) : getpid(); 145 | } 146 | */ 147 | //使用双向链表管理协程,下面是常规的链表操作 148 | template 149 | void RemoveFromLink(T *ap) 150 | { 151 | TLink *lst = ap->pLink; 152 | if(!lst) return ; 153 | assert( lst->head && lst->tail ); 154 | 155 | if( ap == lst->head ) 156 | { 157 | lst->head = ap->pNext; 158 | if(lst->head) 159 | { 160 | lst->head->pPrev = NULL; 161 | } 162 | } 163 | else 164 | { 165 | if(ap->pPrev) 166 | { 167 | ap->pPrev->pNext = ap->pNext; 168 | } 169 | } 170 | 171 | if( ap == lst->tail ) 172 | { 173 | lst->tail = ap->pPrev; 174 | if(lst->tail) 175 | { 176 | lst->tail->pNext = NULL; 177 | } 178 | } 179 | else 180 | { 181 | ap->pNext->pPrev = ap->pPrev; 182 | } 183 | 184 | ap->pPrev = ap->pNext = NULL; 185 | ap->pLink = NULL; 186 | } 187 | 188 | template 189 | void inline AddTail(TLink*apLink,TNode *ap) 190 | { 191 | if( ap->pLink ) 192 | { 193 | return ; 194 | } 195 | if(apLink->tail) 196 | { 197 | apLink->tail->pNext = (TNode*)ap; 198 | ap->pNext = NULL; 199 | ap->pPrev = apLink->tail; 200 | apLink->tail = ap; 201 | } 202 | else 203 | { 204 | apLink->head = apLink->tail = ap; 205 | ap->pNext = ap->pPrev = NULL; 206 | } 207 | ap->pLink = apLink; 208 | } 209 | template 210 | void inline PopHead( TLink*apLink ) 211 | { 212 | if( !apLink->head ) 213 | { 214 | return ; 215 | } 216 | TNode *lp = apLink->head; 217 | if( apLink->head == apLink->tail ) 218 | { 219 | apLink->head = apLink->tail = NULL; 220 | } 221 | else 222 | { 223 | apLink->head = apLink->head->pNext; 224 | } 225 | 226 | lp->pPrev = lp->pNext = NULL; 227 | lp->pLink = NULL; 228 | 229 | if( apLink->head ) 230 | { 231 | apLink->head->pPrev = NULL; 232 | } 233 | } 234 | 235 | template 236 | void inline Join( TLink*apLink,TLink *apOther ) 237 | { 238 | //printf("apOther %p\n",apOther); 239 | if( !apOther->head ) 240 | { 241 | return ; 242 | } 243 | TNode *lp = apOther->head; 244 | while( lp ) 245 | { 246 | lp->pLink = apLink; 247 | lp = lp->pNext; 248 | } 249 | lp = apOther->head; 250 | if(apLink->tail) 251 | { 252 | apLink->tail->pNext = (TNode*)lp; 253 | lp->pPrev = apLink->tail; 254 | apLink->tail = apOther->tail; 255 | } 256 | else 257 | { 258 | apLink->head = apOther->head; 259 | apLink->tail = apOther->tail; 260 | } 261 | 262 | apOther->head = apOther->tail = NULL; 263 | } 264 | 265 | /////////////////for copy stack ////////////////////////// 266 | /* 267 | 268 | 269 | */ 270 | stStackMem_t* co_alloc_stackmem(unsigned int stack_size) 271 | { 272 | stStackMem_t* stack_mem = (stStackMem_t*)malloc(sizeof(stStackMem_t));//申请一个stack_mem结构体的空间 273 | stack_mem->ocupy_co= NULL;//目前没有co_routine占用这个空间 274 | stack_mem->stack_size = stack_size;//设置栈的大小 275 | stack_mem->stack_buffer = (char*)malloc(stack_size);//从堆区初始化栈空间,堆区是从低地址往高地址分配,该操作返回分配的内存区域的起始地址, 276 | //从stack_mem->stack_buffer到 stack_mem->stack_buffer+stack_size 为此次分配到的内存空间 277 | stack_mem->stack_bp = stack_mem->stack_buffer + stack_size;//设置该栈区的基址,栈区地址从高往低走,sp 永远不会大于bp 278 | return stack_mem;//返回申请好的栈结构体 279 | } 280 | //创建一个共享栈区,共count个大小为stack_size的栈空间 281 | stShareStack_t* co_alloc_sharestack(int count, int stack_size) 282 | { 283 | stShareStack_t* share_stack = (stShareStack_t*)malloc(sizeof(stShareStack_t)); 284 | share_stack->alloc_idx = 0;//初始化起始的分配游标 285 | share_stack->stack_size = stack_size; 286 | 287 | //alloc stack array 288 | share_stack->count = count; 289 | //初始化栈空间 290 | stStackMem_t** stack_array = (stStackMem_t**)calloc(count, sizeof(stStackMem_t*)); 291 | for (int i = 0; i < count; i++) 292 | { 293 | stack_array[i] = co_alloc_stackmem(stack_size); 294 | } 295 | share_stack->stack_array = stack_array; 296 | return share_stack; 297 | } 298 | 299 | //从共享栈区取一个栈空间 。问题是这里是循环去取,怎么保证不会追尾? 300 | /* 301 | 答: 见co_swap部分对共享栈区的操作,如果分配出去的一个stack_buffer已经被另一个co_routine占用,那么额外申请一块空间保存那个已经存在的co_rountine的栈 302 | 303 | */ 304 | static stStackMem_t* co_get_stackmem(stShareStack_t* share_stack) 305 | { 306 | if (!share_stack) 307 | { 308 | return NULL; 309 | } 310 | int idx = share_stack->alloc_idx % share_stack->count;//循环使用 311 | share_stack->alloc_idx++; 312 | 313 | return share_stack->stack_array[idx]; 314 | } 315 | 316 | 317 | // ---------------------------------------------------------------------------- 318 | // timeout 时间管理,可以参照event_loop实现中的timeout实现, 319 | struct stTimeoutItemLink_t; 320 | struct stTimeoutItem_t; 321 | struct stCoEpoll_t 322 | { 323 | int iEpollFd; 324 | static const int _EPOLL_SIZE = 1024 * 10; 325 | 326 | struct stTimeout_t *pTimeout; 327 | 328 | struct stTimeoutItemLink_t *pstTimeoutList; 329 | 330 | struct stTimeoutItemLink_t *pstActiveList; 331 | 332 | co_epoll_res *result; 333 | 334 | }; 335 | typedef void (*OnPreparePfn_t)( stTimeoutItem_t *,struct epoll_event &ev, stTimeoutItemLink_t *active ); 336 | typedef void (*OnProcessPfn_t)( stTimeoutItem_t *); 337 | struct stTimeoutItem_t 338 | { 339 | 340 | enum 341 | { 342 | eMaxTimeout = 40 * 1000 //40s 343 | }; 344 | stTimeoutItem_t *pPrev; 345 | stTimeoutItem_t *pNext; 346 | stTimeoutItemLink_t *pLink; 347 | 348 | unsigned long long ullExpireTime; 349 | 350 | OnPreparePfn_t pfnPrepare; 351 | OnProcessPfn_t pfnProcess; 352 | 353 | void *pArg; // routine 354 | bool bTimeout; 355 | }; 356 | struct stTimeoutItemLink_t 357 | { 358 | stTimeoutItem_t *head; 359 | stTimeoutItem_t *tail; 360 | 361 | }; 362 | struct stTimeout_t 363 | { 364 | stTimeoutItemLink_t *pItems; 365 | int iItemSize; 366 | 367 | unsigned long long ullStart; 368 | long long llStartIdx; 369 | }; 370 | stTimeout_t *AllocTimeout( int iSize ) 371 | { 372 | stTimeout_t *lp = (stTimeout_t*)calloc( 1,sizeof(stTimeout_t) ); 373 | 374 | lp->iItemSize = iSize; 375 | lp->pItems = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) * lp->iItemSize ); 376 | 377 | lp->ullStart = GetTickMS(); 378 | lp->llStartIdx = 0; 379 | 380 | return lp; 381 | } 382 | void FreeTimeout( stTimeout_t *apTimeout ) 383 | { 384 | free( apTimeout->pItems ); 385 | free ( apTimeout ); 386 | } 387 | int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,unsigned long long allNow ) 388 | { 389 | if( apTimeout->ullStart == 0 ) 390 | { 391 | apTimeout->ullStart = allNow; 392 | apTimeout->llStartIdx = 0; 393 | } 394 | if( allNow < apTimeout->ullStart ) 395 | { 396 | co_log_err("CO_ERR: AddTimeout line %d allNow %llu apTimeout->ullStart %llu", 397 | __LINE__,allNow,apTimeout->ullStart); 398 | 399 | return __LINE__; 400 | } 401 | if( apItem->ullExpireTime < allNow ) 402 | { 403 | co_log_err("CO_ERR: AddTimeout line %d apItem->ullExpireTime %llu allNow %llu apTimeout->ullStart %llu", 404 | __LINE__,apItem->ullExpireTime,allNow,apTimeout->ullStart); 405 | 406 | return __LINE__; 407 | } 408 | int diff = apItem->ullExpireTime - apTimeout->ullStart; 409 | 410 | if( diff >= apTimeout->iItemSize ) 411 | { 412 | co_log_err("CO_ERR: AddTimeout line %d diff %d", 413 | __LINE__,diff); 414 | 415 | return __LINE__; 416 | } 417 | AddTail( apTimeout->pItems + ( apTimeout->llStartIdx + diff ) % apTimeout->iItemSize , apItem ); 418 | 419 | return 0; 420 | } 421 | inline void TakeAllTimeout( stTimeout_t *apTimeout,unsigned long long allNow,stTimeoutItemLink_t *apResult ) 422 | { 423 | if( apTimeout->ullStart == 0 ) 424 | { 425 | apTimeout->ullStart = allNow; 426 | apTimeout->llStartIdx = 0; 427 | } 428 | 429 | if( allNow < apTimeout->ullStart ) 430 | { 431 | return ; 432 | } 433 | int cnt = allNow - apTimeout->ullStart + 1; 434 | if( cnt > apTimeout->iItemSize ) 435 | { 436 | cnt = apTimeout->iItemSize; 437 | } 438 | if( cnt < 0 ) 439 | { 440 | return; 441 | } 442 | for( int i = 0;illStartIdx + i) % apTimeout->iItemSize; 445 | Join( apResult,apTimeout->pItems + idx ); 446 | } 447 | apTimeout->ullStart = allNow; 448 | apTimeout->llStartIdx += cnt - 1; 449 | 450 | 451 | } 452 | static int CoRoutineFunc( stCoRoutine_t *co,void * ) 453 | { 454 | if( co->pfn ) 455 | { 456 | co->pfn( co->arg ); 457 | } 458 | co->cEnd = 1; 459 | 460 | stCoRoutineEnv_t *env = co->env; 461 | 462 | co_yield_env( env ); 463 | 464 | return 0; 465 | } 466 | 467 | 468 | 469 | struct stCoRoutine_t *co_create_env( stCoRoutineEnv_t * env, const stCoRoutineAttr_t* attr,pfn_co_routine_t pfn,void *arg ){ 470 | 471 | stCoRoutineAttr_t at; 472 | if( attr ){ 473 | memcpy( &at,attr,sizeof(at) ); 474 | }if( at.stack_size <= 0 ){ 475 | at.stack_size = 128 * 1024;//太小则设成128kb 476 | }else if( at.stack_size > 1024 * 1024 * 8 ){ 477 | at.stack_size = 1024 * 1024 * 8;//最大8MB 478 | } 479 | 480 | if( at.stack_size & 0xFFF ){//1111 1111 1111 如果低12位非零,则将低十二位置零,并进一位,即stack_size应该是4kb的整数倍 x86一个内存页大小是4kb,这里考虑到内存对齐的问题 481 | at.stack_size &= ~0xFFF; 482 | at.stack_size += 0x1000; 483 | } 484 | 485 | stCoRoutine_t *lp = (stCoRoutine_t*)malloc( sizeof(stCoRoutine_t) ); 486 | 487 | 488 | lp->env = env;//记录下这个co_routine的上文 489 | lp->pfn = pfn;//记录下执行的函数 490 | lp->arg = arg;//记录下参数 491 | 492 | stStackMem_t* stack_mem = NULL; 493 | if( at.share_stack )//如果是使用共享栈,则从共享栈里面拿出一个作为这个co_routine的栈空间 494 | { 495 | stack_mem = co_get_stackmem( at.share_stack); 496 | at.stack_size = at.share_stack->stack_size; 497 | } 498 | else{//否则从堆区申请一块区域 499 | stack_mem = co_alloc_stackmem(at.stack_size); 500 | } 501 | lp->stack_mem = stack_mem;//设置该co_routine的运行栈空间 502 | 503 | lp->ctx.ss_sp = stack_mem->stack_buffer;//设置栈顶指针(相对于bp是低地址) 504 | lp->ctx.ss_size = at.stack_size;//记录下栈的大小 505 | 506 | //设置一些标志位 507 | lp->cStart = 0; 508 | lp->cEnd = 0; 509 | lp->cIsMain = 0; 510 | lp->cEnableSysHook = 0; 511 | lp->cIsShareStack = at.share_stack != NULL; 512 | 513 | lp->save_size = 0; 514 | lp->save_buffer = NULL; 515 | 516 | return lp; 517 | } 518 | 519 | /* 520 | 创建一个co_routine ,第一个参数是指向这个co_routine的指针,第二个参数是这个co_routine的一些配置信息,第三个参数是这个co_routine具体执行的函数,第四个是执行参数 521 | */ 522 | int co_create( stCoRoutine_t **ppco,const stCoRoutineAttr_t *attr,pfn_co_routine_t pfn,void *arg ) 523 | { 524 | if( !co_get_curr_thread_env() )//如果得不到当前线程的上下文 525 | { 526 | co_init_curr_thread_env();//则初始化上下文 527 | } 528 | stCoRoutine_t *co = co_create_env( co_get_curr_thread_env(), attr, pfn,arg ); 529 | *ppco = co; 530 | return 0; 531 | } 532 | void co_free( stCoRoutine_t *co ) 533 | { 534 | free( co ); 535 | } 536 | void co_release( stCoRoutine_t *co ) 537 | { 538 | if( co->cEnd ) 539 | { 540 | free( co ); 541 | } 542 | } 543 | 544 | void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co); 545 | 546 | //唤醒co 547 | void co_resume( stCoRoutine_t *co ) 548 | { 549 | stCoRoutineEnv_t *env = co->env; 550 | stCoRoutine_t *lpCurrRoutine = env->pCallStack[ env->iCallStackSize - 1 ];//得到当前的co_routine 551 | if( !co->cStart )//如果被唤醒的co没有开始过,则初始化他的CPU上下文 552 | { 553 | coctx_make( &co->ctx,(coctx_pfn_t)CoRoutineFunc,co,0 ); 554 | co->cStart = 1; 555 | } 556 | env->pCallStack[ env->iCallStackSize++ ] = co;//设置当前正在运行的co_routine为co 557 | co_swap( lpCurrRoutine, co );//切换co_routine 558 | } 559 | //挂起当前的co_routine,切换到上一个co_routine,将当前的co_routine设置为上一个co_routine 560 | void co_yield_env( stCoRoutineEnv_t *env ) 561 | { 562 | 563 | stCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ]; 564 | stCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ]; 565 | 566 | env->iCallStackSize--; 567 | 568 | co_swap( curr, last); 569 | } 570 | 571 | void co_yield_ct() 572 | { 573 | 574 | co_yield_env( co_get_curr_thread_env() ); 575 | } 576 | void co_yield( stCoRoutine_t *co ) 577 | { 578 | co_yield_env( co->env ); 579 | } 580 | 581 | void save_stack_buffer(stCoRoutine_t* ocupy_co) 582 | { 583 | ///copy out 584 | stStackMem_t* stack_mem = ocupy_co->stack_mem; 585 | int len = stack_mem->stack_bp - ocupy_co->stack_sp;//得到栈大小 ,这里一个问题是stack_sp是栈区的一个地址,而stack_mem->stackbp 的值是通过molloc函数返回的一个地址加上stack_size得到,是堆区的地址,这个两个如何能够相减??? 586 | 587 | //答案: 确实 stack_bp 是最初申请stack_mem得到的地址,属于堆区, stack_sp是在下面co_swap这个函数里面通过获取最后一个声明的局部变量的 588 | //地址得到,该变量的内存空间确实来自于栈区。 但是此时的栈区并非正常运行的栈区了,这个栈区的内存空间其实来自于堆区。 在初始化coctx结构体 589 | //的时候 ,也 即coctx_make函数里面,有设置“ctx->regs[ kESP ] = (char*)(sp) - sizeof(void*)” ,预置了ESP 的值,而该值表示的内存地址 590 | //来自于堆区。执行汇编代码时就会设置RESP寄存器的值为该值,这样运行时的栈区就不是原本的栈区了。所以这里的stack_bp stack_sp的操作是合理的。 591 | 592 | 593 | if (ocupy_co->save_buffer)//如果之前有保存过,则释放之前申请的内存,并将指针设为NULLt 594 | { 595 | free(ocupy_co->save_buffer), ocupy_co->save_buffer = NULL; 596 | } 597 | 598 | ocupy_co->save_buffer = (char*)malloc(len); //malloc buf;重新申请一个大小为len的内存区域用来保存栈区内容 599 | ocupy_co->save_size = len; 600 | 601 | memcpy(ocupy_co->save_buffer, ocupy_co->stack_sp, len);//将该栈帧存起来了,这里的copy操作无论是存还是取都是从低位到高位 602 | } 603 | 604 | void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co) 605 | { 606 | stCoRoutineEnv_t* env = co_get_curr_thread_env(); 607 | 608 | //get curr stack sp 609 | char c;//c 是co_swap函数里面最后一个声明的局部变量,c所在的内存地址就是当前栈顶地址,即ESP寄存器内保存的值 610 | curr->stack_sp= &c; 611 | 612 | if (!pending_co->cIsShareStack) 613 | { 614 | env->pending_co = NULL; 615 | env->ocupy_co = NULL; 616 | } 617 | else{//在共享栈区的情况下 618 | env->pending_co = pending_co; 619 | //get last occupy co on the same stack mem 620 | stCoRoutine_t* ocupy_co = pending_co->stack_mem->ocupy_co;//取出原本占用这块空间的corountine 621 | //set pending co to ocupy thest stack mem; 622 | pending_co->stack_mem->ocupy_co = pending_co;//将这块空间的占有者设置成将要运行的coroutine 623 | 624 | env->ocupy_co = ocupy_co; 625 | if (ocupy_co && ocupy_co != pending_co)//如果pending_co的栈区内存又被一个co_routine占用,并且该co_routine不是pending_co,则新申请一段内存区域保存下ocupy_co的stack_mem 626 | { 627 | save_stack_buffer(ocupy_co); 628 | } 629 | } 630 | 631 | //swap context 632 | coctx_swap(&(curr->ctx),&(pending_co->ctx));//这句代码执行完成后,CPU已经切换到pending_co 633 | 634 | //pending_co 退出,又回到curr 635 | //stack buffer may be overwrite, so get again; 636 | stCoRoutineEnv_t* curr_env = co_get_curr_thread_env();//得到当前pid对应的env,是当前pid的全局env 637 | stCoRoutine_t* update_ocupy_co = curr_env->ocupy_co; 638 | stCoRoutine_t* update_pending_co = curr_env->pending_co; 639 | 640 | if (update_ocupy_co && update_pending_co && update_ocupy_co != update_pending_co) 641 | { 642 | //resume stack buffer 643 | if (update_pending_co->save_buffer && update_pending_co->save_size > 0) 644 | { 645 | memcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size); 646 | } 647 | } 648 | } 649 | 650 | 651 | 652 | //int poll(struct pollfd fds[], nfds_t nfds, int timeout); 653 | // { fd,events,revents } 654 | struct stPollItem_t ; 655 | struct stPoll_t : public stTimeoutItem_t 656 | { 657 | struct pollfd *fds; 658 | nfds_t nfds; // typedef unsigned long int nfds_t; 659 | 660 | stPollItem_t *pPollItems; 661 | 662 | int iAllEventDetach; 663 | 664 | int iEpollFd; 665 | 666 | int iRaiseCnt; 667 | 668 | 669 | }; 670 | struct stPollItem_t : public stTimeoutItem_t 671 | { 672 | struct pollfd *pSelf; 673 | stPoll_t *pPoll; 674 | 675 | struct epoll_event stEvent; 676 | }; 677 | /* 678 | * EPOLLPRI POLLPRI // There is urgent data to read. 679 | * EPOLLMSG POLLMSG 680 | * 681 | * POLLREMOVE 682 | * POLLRDHUP 683 | * POLLNVAL 684 | * 685 | * */ 686 | /** 687 | poll函数的事件标志符值 688 | 689 | 常量 说明 690 | POLLIN 普通或优先级带数据可读 691 | POLLRDNORM 普通数据可读 692 | POLLRDBAND 优先级带数据可读 693 | POLLPRI 高优先级数据可读 694 | POLLOUT 普通数据可写 695 | POLLWRNORM 普通数据可写 696 | POLLWRBAND 优先级带数据可写 697 | POLLERR 发生错误 698 | POLLHUP 发生挂起 699 | POLLNVAL 描述字不是一个打开的文件 700 | 701 | 702 | */ 703 | static uint32_t PollEvent2Epoll( short events ) 704 | { 705 | uint32_t e = 0; 706 | if( events & POLLIN ) e |= EPOLLIN; 707 | if( events & POLLOUT ) e |= EPOLLOUT; 708 | if( events & POLLHUP ) e |= EPOLLHUP; 709 | if( events & POLLERR ) e |= EPOLLERR; 710 | if( events & POLLRDNORM ) e |= EPOLLRDNORM; 711 | if( events & POLLWRNORM ) e |= EPOLLWRNORM; 712 | return e; 713 | } 714 | static short EpollEvent2Poll( uint32_t events ) 715 | { 716 | short e = 0; 717 | if( events & EPOLLIN ) e |= POLLIN; 718 | if( events & EPOLLOUT ) e |= POLLOUT; 719 | if( events & EPOLLHUP ) e |= POLLHUP; 720 | if( events & EPOLLERR ) e |= POLLERR; 721 | if( events & EPOLLRDNORM ) e |= POLLRDNORM; 722 | if( events & EPOLLWRNORM ) e |= POLLWRNORM; 723 | return e; 724 | } 725 | 726 | static stCoRoutineEnv_t* g_arrCoEnvPerThread[ 204800 ] = { 0 };//存放上下文的全局静态变量 727 | 728 | /* 729 | 初始化当前线程的上下文 730 | */ 731 | void co_init_curr_thread_env() 732 | { 733 | pid_t pid = GetPid();//得到当前线程的上下文 734 | g_arrCoEnvPerThread[ pid ] = (stCoRoutineEnv_t*)calloc( 1,sizeof(stCoRoutineEnv_t) ); 735 | stCoRoutineEnv_t *env = g_arrCoEnvPerThread[ pid ]; 736 | 737 | env->iCallStackSize = 0; 738 | struct stCoRoutine_t *self = co_create_env( env, NULL, NULL,NULL ); 739 | self->cIsMain = 1; 740 | 741 | env->pending_co = NULL; 742 | env->ocupy_co = NULL; 743 | 744 | coctx_init( &self->ctx );//初始化寄存器和栈的信息,全部设为空 745 | 746 | env->pCallStack[ env->iCallStackSize++ ] = self;//设置调用栈,将第一个设成自己 747 | 748 | stCoEpoll_t *ev = AllocEpoll(); 749 | SetEpoll( env,ev ); 750 | } 751 | stCoRoutineEnv_t *co_get_curr_thread_env() 752 | { 753 | return g_arrCoEnvPerThread[ GetPid() ]; 754 | } 755 | 756 | void OnPollProcessEvent( stTimeoutItem_t * ap ) 757 | { 758 | stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; 759 | co_resume( co ); 760 | } 761 | 762 | void OnPollPreparePfn( stTimeoutItem_t * ap,struct epoll_event &e,stTimeoutItemLink_t *active ) 763 | { 764 | stPollItem_t *lp = (stPollItem_t *)ap; 765 | lp->pSelf->revents = EpollEvent2Poll( e.events ); 766 | 767 | 768 | stPoll_t *pPoll = lp->pPoll; 769 | pPoll->iRaiseCnt++; 770 | 771 | if( !pPoll->iAllEventDetach ) 772 | { 773 | pPoll->iAllEventDetach = 1; 774 | 775 | RemoveFromLink( pPoll ); 776 | 777 | AddTail( active,pPoll ); 778 | 779 | } 780 | } 781 | 782 | 783 | void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ) 784 | { 785 | if( !ctx->result ) 786 | { 787 | ctx->result = co_epoll_res_alloc( stCoEpoll_t::_EPOLL_SIZE ); 788 | } 789 | co_epoll_res *result = ctx->result; 790 | 791 | 792 | for(;;) 793 | { 794 | int ret = co_epoll_wait( ctx->iEpollFd,result,stCoEpoll_t::_EPOLL_SIZE, 1 ); 795 | 796 | stTimeoutItemLink_t *active = (ctx->pstActiveList); 797 | stTimeoutItemLink_t *timeout = (ctx->pstTimeoutList); 798 | 799 | memset( timeout,0,sizeof(stTimeoutItemLink_t) ); 800 | 801 | for(int i=0;ievents[i].data.ptr; 804 | if( item->pfnPrepare ) 805 | { 806 | item->pfnPrepare( item,result->events[i],active ); 807 | } 808 | else 809 | { 810 | AddTail( active,item ); 811 | } 812 | } 813 | 814 | 815 | unsigned long long now = GetTickMS(); 816 | TakeAllTimeout( ctx->pTimeout,now,timeout ); 817 | 818 | stTimeoutItem_t *lp = timeout->head; 819 | while( lp ) 820 | { 821 | //printf("raise timeout %p\n",lp); 822 | lp->bTimeout = true; 823 | lp = lp->pNext; 824 | } 825 | 826 | Join( active,timeout ); 827 | 828 | lp = active->head; 829 | while( lp ) 830 | { 831 | 832 | PopHead( active ); 833 | if( lp->pfnProcess ) 834 | { 835 | lp->pfnProcess( lp ); 836 | } 837 | 838 | lp = active->head; 839 | } 840 | if( pfn ) 841 | { 842 | if( -1 == pfn( arg ) ) 843 | { 844 | break; 845 | } 846 | } 847 | 848 | } 849 | } 850 | void OnCoroutineEvent( stTimeoutItem_t * ap ) 851 | { 852 | stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; 853 | co_resume( co ); 854 | } 855 | 856 | 857 | stCoEpoll_t *AllocEpoll() 858 | { 859 | stCoEpoll_t *ctx = (stCoEpoll_t*)calloc( 1,sizeof(stCoEpoll_t) ); 860 | 861 | ctx->iEpollFd = co_epoll_create( stCoEpoll_t::_EPOLL_SIZE ); 862 | ctx->pTimeout = AllocTimeout( 60 * 1000 ); 863 | 864 | ctx->pstActiveList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); 865 | ctx->pstTimeoutList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); 866 | 867 | 868 | return ctx; 869 | } 870 | 871 | void FreeEpoll( stCoEpoll_t *ctx ) 872 | { 873 | if( ctx ) 874 | { 875 | free( ctx->pstActiveList ); 876 | free( ctx->pstTimeoutList ); 877 | FreeTimeout( ctx->pTimeout ); 878 | co_epoll_res_free( ctx->result ); 879 | } 880 | free( ctx ); 881 | } 882 | 883 | stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ) 884 | { 885 | return env->pCallStack[ env->iCallStackSize - 1 ]; 886 | } 887 | stCoRoutine_t *GetCurrThreadCo( ) 888 | { 889 | stCoRoutineEnv_t *env = co_get_curr_thread_env(); 890 | if( !env ) return 0; 891 | return GetCurrCo(env); 892 | } 893 | 894 | 895 | 896 | typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); 897 | int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc) 898 | { 899 | 900 | if( timeout > stTimeoutItem_t::eMaxTimeout ) 901 | { 902 | timeout = stTimeoutItem_t::eMaxTimeout; 903 | } 904 | int epfd = ctx->iEpollFd; 905 | stCoRoutine_t* self = co_self(); 906 | 907 | //1.struct change 908 | stPoll_t& arg = *((stPoll_t*)malloc(sizeof(stPoll_t))); 909 | memset( &arg,0,sizeof(arg) ); 910 | 911 | arg.iEpollFd = epfd; 912 | arg.fds = (pollfd*)calloc(nfds, sizeof(pollfd)); 913 | arg.nfds = nfds; 914 | 915 | stPollItem_t arr[2]; 916 | if( nfds < sizeof(arr) / sizeof(arr[0]) && !self->cIsShareStack) 917 | { 918 | arg.pPollItems = arr; 919 | } 920 | else 921 | { 922 | arg.pPollItems = (stPollItem_t*)malloc( nfds * sizeof( stPollItem_t ) ); 923 | } 924 | memset( arg.pPollItems,0,nfds * sizeof(stPollItem_t) ); 925 | 926 | arg.pfnProcess = OnPollProcessEvent; 927 | arg.pArg = GetCurrCo( co_get_curr_thread_env() ); 928 | 929 | 930 | //2. add epoll 931 | for(nfds_t i=0;i -1 ) 940 | { 941 | ev.data.ptr = arg.pPollItems + i; 942 | ev.events = PollEvent2Epoll( fds[i].events ); 943 | 944 | int ret = co_epoll_ctl( epfd,EPOLL_CTL_ADD, fds[i].fd, &ev ); 945 | if (ret < 0 && errno == EPERM && nfds == 1 && pollfunc != NULL) 946 | { 947 | if( arg.pPollItems != arr ) 948 | { 949 | free( arg.pPollItems ); 950 | arg.pPollItems = NULL; 951 | } 952 | free(arg.fds); 953 | free(&arg); 954 | return pollfunc(fds, nfds, timeout); 955 | } 956 | } 957 | //if fail,the timeout would work 958 | } 959 | 960 | //3.add timeout 961 | 962 | unsigned long long now = GetTickMS(); 963 | arg.ullExpireTime = now + timeout; 964 | int ret = AddTimeout( ctx->pTimeout,&arg,now ); 965 | if( ret != 0 ) 966 | { 967 | co_log_err("CO_ERR: AddTimeout ret %d now %lld timeout %d arg.ullExpireTime %lld", 968 | ret,now,timeout,arg.ullExpireTime); 969 | errno = EINVAL; 970 | 971 | if( arg.pPollItems != arr ) 972 | { 973 | free( arg.pPollItems ); 974 | arg.pPollItems = NULL; 975 | } 976 | free(arg.fds); 977 | free(&arg); 978 | 979 | return -__LINE__; 980 | } 981 | 982 | co_yield_env( co_get_curr_thread_env() ); 983 | 984 | RemoveFromLink( &arg ); 985 | for(nfds_t i = 0;i < nfds;i++) 986 | { 987 | int fd = fds[i].fd; 988 | if( fd > -1 ) 989 | { 990 | co_epoll_ctl( epfd,EPOLL_CTL_DEL,fd,&arg.pPollItems[i].stEvent ); 991 | } 992 | fds[i].revents = arg.fds[i].revents; 993 | } 994 | 995 | 996 | int iRaiseCnt = arg.iRaiseCnt; 997 | if( arg.pPollItems != arr ) 998 | { 999 | free( arg.pPollItems ); 1000 | arg.pPollItems = NULL; 1001 | } 1002 | 1003 | free(arg.fds); 1004 | free(&arg); 1005 | 1006 | return iRaiseCnt; 1007 | } 1008 | 1009 | int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ) 1010 | { 1011 | return co_poll_inner(ctx, fds, nfds, timeout_ms, NULL); 1012 | } 1013 | 1014 | void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ) 1015 | { 1016 | env->pEpoll = ev; 1017 | } 1018 | stCoEpoll_t *co_get_epoll_ct() 1019 | { 1020 | if( !co_get_curr_thread_env() ) 1021 | { 1022 | co_init_curr_thread_env(); 1023 | } 1024 | return co_get_curr_thread_env()->pEpoll; 1025 | } 1026 | struct stHookPThreadSpec_t 1027 | { 1028 | stCoRoutine_t *co; 1029 | void *value; 1030 | 1031 | enum 1032 | { 1033 | size = 1024 1034 | }; 1035 | }; 1036 | void *co_getspecific(pthread_key_t key) 1037 | { 1038 | stCoRoutine_t *co = GetCurrThreadCo(); 1039 | if( !co || co->cIsMain ) 1040 | { 1041 | return pthread_getspecific( key ); 1042 | } 1043 | return co->aSpec[ key ].value; 1044 | } 1045 | int co_setspecific(pthread_key_t key, const void *value) 1046 | { 1047 | stCoRoutine_t *co = GetCurrThreadCo(); 1048 | if( !co || co->cIsMain ) 1049 | { 1050 | return pthread_setspecific( key,value ); 1051 | } 1052 | co->aSpec[ key ].value = (void*)value; 1053 | return 0; 1054 | } 1055 | 1056 | 1057 | 1058 | void co_disable_hook_sys() 1059 | { 1060 | stCoRoutine_t *co = GetCurrThreadCo(); 1061 | if( co ) 1062 | { 1063 | co->cEnableSysHook = 0; 1064 | } 1065 | } 1066 | bool co_is_enable_sys_hook() 1067 | { 1068 | stCoRoutine_t *co = GetCurrThreadCo(); 1069 | return ( co && co->cEnableSysHook ); 1070 | } 1071 | 1072 | stCoRoutine_t *co_self() 1073 | { 1074 | return GetCurrThreadCo(); 1075 | } 1076 | 1077 | //co cond 1078 | struct stCoCond_t; 1079 | struct stCoCondItem_t 1080 | { 1081 | stCoCondItem_t *pPrev; 1082 | stCoCondItem_t *pNext; 1083 | stCoCond_t *pLink; 1084 | 1085 | stTimeoutItem_t timeout; 1086 | }; 1087 | struct stCoCond_t 1088 | { 1089 | stCoCondItem_t *head; 1090 | stCoCondItem_t *tail; 1091 | }; 1092 | static void OnSignalProcessEvent( stTimeoutItem_t * ap ) 1093 | { 1094 | stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; 1095 | co_resume( co ); 1096 | } 1097 | 1098 | stCoCondItem_t *co_cond_pop( stCoCond_t *link ); 1099 | int co_cond_signal( stCoCond_t *si ) 1100 | { 1101 | stCoCondItem_t * sp = co_cond_pop( si ); 1102 | if( !sp ) 1103 | { 1104 | return 0; 1105 | } 1106 | RemoveFromLink( &sp->timeout ); 1107 | 1108 | AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); 1109 | 1110 | return 0; 1111 | } 1112 | int co_cond_broadcast( stCoCond_t *si ) 1113 | { 1114 | for(;;) 1115 | { 1116 | stCoCondItem_t * sp = co_cond_pop( si ); 1117 | if( !sp ) return 0; 1118 | 1119 | RemoveFromLink( &sp->timeout ); 1120 | 1121 | AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); 1122 | } 1123 | 1124 | return 0; 1125 | } 1126 | 1127 | 1128 | int co_cond_timedwait( stCoCond_t *link,int ms ) 1129 | { 1130 | stCoCondItem_t* psi = (stCoCondItem_t*)calloc(1, sizeof(stCoCondItem_t)); 1131 | psi->timeout.pArg = GetCurrThreadCo(); 1132 | psi->timeout.pfnProcess = OnSignalProcessEvent; 1133 | 1134 | if( ms > 0 ) 1135 | { 1136 | unsigned long long now = GetTickMS(); 1137 | psi->timeout.ullExpireTime = now + ms; 1138 | 1139 | int ret = AddTimeout( co_get_curr_thread_env()->pEpoll->pTimeout,&psi->timeout,now ); 1140 | if( ret != 0 ) 1141 | { 1142 | free(psi); 1143 | return ret; 1144 | } 1145 | } 1146 | AddTail( link, psi); 1147 | 1148 | co_yield_ct(); 1149 | 1150 | 1151 | RemoveFromLink( psi ); 1152 | free(psi); 1153 | 1154 | return 0; 1155 | } 1156 | stCoCond_t *co_cond_alloc() 1157 | { 1158 | return (stCoCond_t*)calloc( 1,sizeof(stCoCond_t) ); 1159 | } 1160 | int co_cond_free( stCoCond_t * cc ) 1161 | { 1162 | free( cc ); 1163 | return 0; 1164 | } 1165 | 1166 | 1167 | stCoCondItem_t *co_cond_pop( stCoCond_t *link ) 1168 | { 1169 | stCoCondItem_t *p = link->head; 1170 | if( p ) 1171 | { 1172 | PopHead( link ); 1173 | } 1174 | return p; 1175 | } 1176 | -------------------------------------------------------------------------------- /src/co_routine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_ROUTINE_H__ 20 | #define __CO_ROUTINE_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | //1.struct 27 | 28 | struct stCoRoutine_t; 29 | struct stShareStack_t; 30 | 31 | struct stCoRoutineAttr_t 32 | { 33 | int stack_size; 34 | stShareStack_t* share_stack; 35 | stCoRoutineAttr_t() 36 | { 37 | stack_size = 128 * 1024; 38 | share_stack = NULL; 39 | } 40 | }__attribute__ ((packed)); 41 | 42 | struct stCoEpoll_t; 43 | typedef int (*pfn_co_eventloop_t)(void *); 44 | typedef void *(*pfn_co_routine_t)( void * ); 45 | 46 | //2.co_routine 47 | 48 | int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg ); 49 | void co_resume( stCoRoutine_t *co ); 50 | void co_yield( stCoRoutine_t *co ); 51 | void co_yield_ct(); //ct = current thread 52 | void co_release( stCoRoutine_t *co ); 53 | 54 | stCoRoutine_t *co_self(); 55 | 56 | int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ); 57 | void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ); 58 | 59 | //3.specific 60 | 61 | int co_setspecific( pthread_key_t key, const void *value ); 62 | void * co_getspecific( pthread_key_t key ); 63 | 64 | //4.event 65 | 66 | stCoEpoll_t * co_get_epoll_ct(); //ct = current thread 67 | 68 | //5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto ) 69 | 70 | void co_enable_hook_sys(); 71 | void co_disable_hook_sys(); 72 | bool co_is_enable_sys_hook(); 73 | 74 | //6.sync 75 | struct stCoCond_t; 76 | 77 | stCoCond_t *co_cond_alloc(); 78 | int co_cond_free( stCoCond_t * cc ); 79 | 80 | int co_cond_signal( stCoCond_t * ); 81 | int co_cond_broadcast( stCoCond_t * ); 82 | int co_cond_timedwait( stCoCond_t *,int timeout_ms ); 83 | 84 | //7.share stack 85 | stShareStack_t* co_alloc_sharestack(int iCount, int iStackSize); 86 | 87 | //8.init envlist for hook get/set env 88 | void co_set_env_list( const char *name[],size_t cnt); 89 | 90 | void co_log_err( const char *fmt,... ); 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /src/co_routine_inner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | 20 | #ifndef __CO_ROUTINE_INNER_H__ 21 | 22 | #include "co_routine.h" 23 | #include "coctx.h" 24 | struct stCoRoutineEnv_t; 25 | struct stCoSpec_t 26 | { 27 | void *value; 28 | }; 29 | 30 | struct stStackMem_t 31 | { 32 | stCoRoutine_t* ocupy_co; 33 | int stack_size; 34 | char* stack_bp; //stack_buffer + stack_size 35 | char* stack_buffer; 36 | 37 | }; 38 | 39 | struct stShareStack_t 40 | { 41 | unsigned int alloc_idx; 42 | int stack_size; 43 | int count; 44 | stStackMem_t** stack_array; 45 | }; 46 | 47 | 48 | 49 | struct stCoRoutine_t 50 | { 51 | stCoRoutineEnv_t *env; 52 | pfn_co_routine_t pfn; 53 | void *arg; 54 | coctx_t ctx; 55 | 56 | char cStart; 57 | char cEnd; 58 | char cIsMain; 59 | char cEnableSysHook; 60 | char cIsShareStack; 61 | 62 | void *pvEnv; 63 | 64 | //char sRunStack[ 1024 * 128 ]; 65 | stStackMem_t* stack_mem; 66 | 67 | 68 | //save satck buffer while confilct on same stack_buffer; 69 | char* stack_sp; 70 | unsigned int save_size; 71 | char* save_buffer; 72 | 73 | stCoSpec_t aSpec[1024]; 74 | 75 | }; 76 | 77 | 78 | 79 | //1.env 80 | void co_init_curr_thread_env(); 81 | stCoRoutineEnv_t * co_get_curr_thread_env(); 82 | 83 | //2.coroutine 84 | void co_free( stCoRoutine_t * co ); 85 | void co_yield_env( stCoRoutineEnv_t *env ); 86 | 87 | //3.func 88 | 89 | 90 | 91 | //----------------------------------------------------------------------------------------------- 92 | 93 | struct stTimeout_t; 94 | struct stTimeoutItem_t ; 95 | 96 | stTimeout_t *AllocTimeout( int iSize ); 97 | void FreeTimeout( stTimeout_t *apTimeout ); 98 | int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow ); 99 | 100 | struct stCoEpoll_t; 101 | stCoEpoll_t * AllocEpoll(); 102 | void FreeEpoll( stCoEpoll_t *ctx ); 103 | 104 | stCoRoutine_t * GetCurrThreadCo(); 105 | void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ); 106 | 107 | typedef void (*pfnCoRoutineFunc_t)(); 108 | 109 | #endif 110 | 111 | #define __CO_ROUTINE_INNER_H__ 112 | -------------------------------------------------------------------------------- /src/co_routine_specific.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyrdl/libco-code-study/0fce7846e7e79a674fb5fdb16ddf34d78bff7853/src/co_routine_specific.h -------------------------------------------------------------------------------- /src/coctx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "coctx.h" 20 | #include 21 | 22 | 23 | #define ESP 0 //栈顶指针寄存器 24 | #define EIP 1 25 | #define EAX 2 26 | #define ECX 3 27 | // ----------- 28 | #define RSP 0 29 | #define RIP 1 30 | #define RBX 2 31 | #define RDI 3 32 | #define RSI 4 33 | 34 | #define RBP 5 35 | #define R12 6 36 | #define R13 7 37 | #define R14 8 38 | #define R15 9 39 | #define RDX 10 40 | #define RCX 11 41 | #define R8 12 42 | #define R9 13 43 | 44 | 45 | //----- -------- 46 | // 32 bit 47 | // | regs[0]: ret | 48 | // | regs[1]: ebx | 49 | // | regs[2]: ecx | 50 | // | regs[3]: edx | 51 | // | regs[4]: edi | 52 | // | regs[5]: esi | 53 | // | regs[6]: ebp | 54 | // | regs[7]: eax | = esp 55 | enum 56 | { 57 | kEIP = 0, 58 | kESP = 7, 59 | }; 60 | 61 | //------------- 62 | // 64 bit 63 | //low | regs[0]: r15 | 64 | // | regs[1]: r14 | 65 | // | regs[2]: r13 | 66 | // | regs[3]: r12 | 67 | // | regs[4]: r9 | 68 | // | regs[5]: r8 | 69 | // | regs[6]: rbp | 70 | // | regs[7]: rdi | 71 | // | regs[8]: rsi | 72 | // | regs[9]: ret | //ret func addr 73 | // | regs[10]: rdx | 74 | // | regs[11]: rcx | 75 | // | regs[12]: rbx | 76 | //hig | regs[13]: rsp | 77 | enum 78 | { 79 | kRDI = 7, 80 | kRSI = 8, 81 | kRETAddr = 9, 82 | kRSP = 13, 83 | }; 84 | 85 | //64 bit 86 | extern "C" 87 | { 88 | extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap"); 89 | }; 90 | #if defined(__i386__) 91 | int coctx_init( coctx_t *ctx ) 92 | { 93 | memset( ctx,0,sizeof(*ctx)); 94 | return 0; 95 | } 96 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ) 97 | { 98 | //make room for coctx_param 99 | char *sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t);//分配参数所需栈空间 100 | sp = (char*)((unsigned long)sp & -16L);//将地址低4位置零,地址应该是一个栈区一个存储单位的大小的整数倍 101 | 102 | //将参数存放在栈内,发生函数调用时,参数是从右往左压栈,即最右边的参数应该在高地址,第一个参数应该在相对的低地址区域 103 | coctx_param_t* param = (coctx_param_t*)sp ; 104 | //coctx_param_t 的两个参数 s1,s2由于其声明顺序,则s1的地址相对于s2是低地址(其实还会考虑的内存优化,当结构体内部是不同类型参数时,其存储顺序可能与声明顺序不一致,但这里不存在这个问题) 105 | param->s1 = s; 106 | param->s2 = s1; 107 | 108 | memset(ctx->regs, 0, sizeof(ctx->regs));//将寄存器信息初始化为0 109 | 110 | ctx->regs[ kESP ] = (char*)(sp) - sizeof(void*);//设置栈顶指针,并留出函数调用结束后返回地址的空间 111 | 112 | ctx->regs[ kEIP ] = (char*)pfn;//设置下一条指令的地址 113 | 114 | return 0; 115 | } 116 | #elif defined(__x86_64__) 117 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ) 118 | { 119 | char *sp = ctx->ss_sp + ctx->ss_size; 120 | sp = (char*) ((unsigned long)sp & -16LL ); 121 | 122 | memset(ctx->regs, 0, sizeof(ctx->regs)); 123 | 124 | ctx->regs[ kRSP ] = sp - 8; 125 | 126 | ctx->regs[ kRETAddr] = (char*)pfn; 127 | 128 | ctx->regs[ kRDI ] = (char*)s; 129 | ctx->regs[ kRSI ] = (char*)s1; 130 | return 0; 131 | } 132 | 133 | int coctx_init( coctx_t *ctx ) 134 | { 135 | memset( ctx,0,sizeof(*ctx)); 136 | return 0; 137 | } 138 | 139 | #endif 140 | 141 | -------------------------------------------------------------------------------- /src/coctx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __CO_CTX_H__ 20 | #define __CO_CTX_H__ 21 | #include 22 | typedef void* (*coctx_pfn_t)( void* s, void* s2 ); 23 | struct coctx_param_t 24 | { 25 | const void *s1; 26 | const void *s2; 27 | }; 28 | struct coctx_t 29 | { 30 | #if defined(__i386__) 31 | void *regs[ 8 ]; 32 | #else 33 | void *regs[ 14 ]; 34 | #endif 35 | size_t ss_size; 36 | char *ss_sp; 37 | 38 | }; 39 | 40 | int coctx_init( coctx_t *ctx ); 41 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ); 42 | #endif 43 | -------------------------------------------------------------------------------- /src/coctx_swap.S: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yyrdl/libco-code-study/0fce7846e7e79a674fb5fdb16ddf34d78bff7853/src/coctx_swap.S -------------------------------------------------------------------------------- /src/example_closure.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_closure.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | using namespace std; 26 | 27 | static void *thread_func( void * arg ) 28 | { 29 | stCoClosure_t *p = (stCoClosure_t*) arg; 30 | p->exec(); 31 | return 0; 32 | } 33 | static void batch_exec( vector &v ) 34 | { 35 | vector ths; 36 | for( size_t i=0;i v; 50 | 51 | pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 52 | 53 | int total = 100; 54 | vector v2; 55 | co_ref( ref,total,v2,m); 56 | for(int i=0;i<10;i++) 57 | { 58 | co_func( f,ref,i ) 59 | { 60 | printf("ref.total %d i %d\n",ref.total,i ); 61 | //lock 62 | pthread_mutex_lock(&ref.m); 63 | ref.v2.push_back( i ); 64 | pthread_mutex_unlock(&ref.m); 65 | //unlock 66 | } 67 | co_func_end; 68 | v.push_back( new f( ref,i ) ); 69 | } 70 | for(int i=0;i<2;i++) 71 | { 72 | co_func( f2,i ) 73 | { 74 | printf("i: %d\n",i); 75 | for(int j=0;j<2;j++) 76 | { 77 | usleep( 1000 ); 78 | printf("i %d j %d\n",i,j); 79 | } 80 | } 81 | co_func_end; 82 | v.push_back( new f2( i ) ); 83 | } 84 | 85 | batch_exec( v ); 86 | printf("done\n"); 87 | 88 | return 0; 89 | } 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/example_cond.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "co_routine.h" 24 | using namespace std; 25 | struct stTask_t 26 | { 27 | int id; 28 | }; 29 | struct stEnv_t 30 | { 31 | stCoCond_t* cond; 32 | queue task_queue; 33 | }; 34 | void* Producer(void* args) 35 | { 36 | co_enable_hook_sys(); 37 | stEnv_t* env= (stEnv_t*)args; 38 | int id = 0; 39 | while (true) 40 | { 41 | stTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t)); 42 | task->id = id++; 43 | env->task_queue.push(task); 44 | printf("%s:%d produce task %d\n", __func__, __LINE__, task->id); 45 | co_cond_signal(env->cond); 46 | poll(NULL, 0, 1000); 47 | } 48 | return NULL; 49 | } 50 | void* Consumer(void* args) 51 | { 52 | co_enable_hook_sys(); 53 | stEnv_t* env = (stEnv_t*)args; 54 | while (true) 55 | { 56 | if (env->task_queue.empty()) 57 | { 58 | co_cond_timedwait(env->cond, -1); 59 | continue; 60 | } 61 | stTask_t* task = env->task_queue.front(); 62 | env->task_queue.pop(); 63 | printf("%s:%d consume task %d\n", __func__, __LINE__, task->id); 64 | free(task); 65 | } 66 | return NULL; 67 | } 68 | int main() 69 | { 70 | stEnv_t* env = new stEnv_t; 71 | env->cond = co_cond_alloc(); 72 | 73 | stCoRoutine_t* consumer_routine; 74 | co_create(&consumer_routine, NULL, Consumer, env); 75 | co_resume(consumer_routine); 76 | 77 | stCoRoutine_t* producer_routine; 78 | co_create(&producer_routine, NULL, Producer, env); 79 | co_resume(producer_routine); 80 | 81 | co_eventloop(co_get_epoll_ct(), NULL, NULL); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /src/example_copystack.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "coctx.h" 27 | #include "co_routine.h" 28 | #include "co_routine_inner.h" 29 | 30 | void* RoutineFunc(void* args) 31 | { 32 | co_enable_hook_sys(); 33 | int* routineid = (int*)args; 34 | while (true) 35 | { 36 | char sBuff[128]; 37 | sprintf(sBuff, "from routineid %d stack addr %p\n", *routineid, sBuff); 38 | 39 | printf("%s", sBuff); 40 | poll(NULL, 0, 1000); //sleep 1s 41 | } 42 | return NULL; 43 | } 44 | 45 | int main() 46 | { 47 | stShareStack_t* share_stack= co_alloc_sharestack(1, 1024 * 128); 48 | stCoRoutineAttr_t attr; 49 | attr.stack_size = 0; 50 | attr.share_stack = share_stack; 51 | 52 | stCoRoutine_t* co[2]; 53 | int routineid[2]; 54 | for (int i = 0; i < 2; i++) 55 | { 56 | routineid[i] = i; 57 | co_create(&co[i], &attr, RoutineFunc, routineid + i); 58 | co_resume(co[i]); 59 | } 60 | co_eventloop(co_get_epoll_ct(), NULL, NULL); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /src/example_echocli.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_routine.h" 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | using namespace std; 39 | struct stEndPoint 40 | { 41 | char *ip; 42 | unsigned short int port; 43 | }; 44 | 45 | static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) 46 | { 47 | bzero(&addr,sizeof(addr)); 48 | addr.sin_family = AF_INET; 49 | addr.sin_port = htons(shPort); 50 | int nIP = 0; 51 | if( !pszIP || '\0' == *pszIP 52 | || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") 53 | || 0 == strcmp(pszIP,"*") 54 | ) 55 | { 56 | nIP = htonl(INADDR_ANY); 57 | } 58 | else 59 | { 60 | nIP = inet_addr(pszIP); 61 | } 62 | addr.sin_addr.s_addr = nIP; 63 | 64 | } 65 | 66 | static int iSuccCnt = 0; 67 | static int iFailCnt = 0; 68 | static int iTime = 0; 69 | 70 | void AddSuccCnt() 71 | { 72 | int now = time(NULL); 73 | if (now >iTime) 74 | { 75 | printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt); 76 | iTime = now; 77 | iSuccCnt = 0; 78 | iFailCnt = 0; 79 | } 80 | else 81 | { 82 | iSuccCnt++; 83 | } 84 | } 85 | void AddFailCnt() 86 | { 87 | int now = time(NULL); 88 | if (now >iTime) 89 | { 90 | printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt); 91 | iTime = now; 92 | iSuccCnt = 0; 93 | iFailCnt = 0; 94 | } 95 | else 96 | { 97 | iFailCnt++; 98 | } 99 | } 100 | 101 | static void *readwrite_routine( void *arg ) 102 | { 103 | 104 | co_enable_hook_sys(); 105 | 106 | stEndPoint *endpoint = (stEndPoint *)arg; 107 | char str[8]="sarlmol"; 108 | char buf[ 1024 * 16 ]; 109 | int fd = -1; 110 | int ret = 0; 111 | for(;;) 112 | { 113 | if ( fd < 0 ) 114 | { 115 | fd = socket(PF_INET, SOCK_STREAM, 0); 116 | struct sockaddr_in addr; 117 | SetAddr(endpoint->ip, endpoint->port, addr); 118 | ret = connect(fd,(struct sockaddr*)&addr,sizeof(addr)); 119 | 120 | if ( errno == EALREADY || errno == EINPROGRESS ) 121 | { 122 | struct pollfd pf = { 0 }; 123 | pf.fd = fd; 124 | pf.events = (POLLOUT|POLLERR|POLLHUP); 125 | co_poll( co_get_epoll_ct(),&pf,1,200); 126 | //check connect 127 | int error = 0; 128 | uint32_t socklen = sizeof(error); 129 | errno = 0; 130 | ret = getsockopt(fd, SOL_SOCKET, SO_ERROR,(void *)&error, &socklen); 131 | if ( ret == -1 ) 132 | { 133 | //printf("getsockopt ERROR ret %d %d:%s\n", ret, errno, strerror(errno)); 134 | close(fd); 135 | fd = -1; 136 | AddFailCnt(); 137 | continue; 138 | } 139 | if ( error ) 140 | { 141 | errno = error; 142 | //printf("connect ERROR ret %d %d:%s\n", error, errno, strerror(errno)); 143 | close(fd); 144 | fd = -1; 145 | AddFailCnt(); 146 | continue; 147 | } 148 | } 149 | 150 | } 151 | 152 | ret = write( fd,str, 8); 153 | if ( ret > 0 ) 154 | { 155 | ret = read( fd,buf, sizeof(buf) ); 156 | if ( ret <= 0 ) 157 | { 158 | //printf("co %p read ret %d errno %d (%s)\n", 159 | // co_self(), ret,errno,strerror(errno)); 160 | close(fd); 161 | fd = -1; 162 | AddFailCnt(); 163 | } 164 | else 165 | { 166 | //printf("echo %s fd %d\n", buf,fd); 167 | AddSuccCnt(); 168 | } 169 | } 170 | else 171 | { 172 | //printf("co %p write ret %d errno %d (%s)\n", 173 | // co_self(), ret,errno,strerror(errno)); 174 | close(fd); 175 | fd = -1; 176 | AddFailCnt(); 177 | } 178 | } 179 | return 0; 180 | } 181 | 182 | int main(int argc,char *argv[]) 183 | { 184 | stEndPoint endpoint; 185 | endpoint.ip = argv[1]; 186 | endpoint.port = atoi(argv[2]); 187 | int cnt = atoi( argv[3] ); 188 | int proccnt = atoi( argv[4] ); 189 | 190 | struct sigaction sa; 191 | sa.sa_handler = SIG_IGN; 192 | sigaction( SIGPIPE, &sa, NULL ); 193 | 194 | for(int k=0;k 0 ) 199 | { 200 | continue; 201 | } 202 | else if( pid < 0 ) 203 | { 204 | break; 205 | } 206 | for(int i=0;i 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | using namespace std; 37 | struct task_t 38 | { 39 | stCoRoutine_t *co; 40 | int fd; 41 | }; 42 | 43 | static stack g_readwrite; 44 | static int g_listen_fd = -1; 45 | static int SetNonBlock(int iSock) 46 | { 47 | int iFlags; 48 | 49 | iFlags = fcntl(iSock, F_GETFL, 0); 50 | iFlags |= O_NONBLOCK; 51 | iFlags |= O_NDELAY; 52 | int ret = fcntl(iSock, F_SETFL, iFlags); 53 | return ret; 54 | } 55 | 56 | static void *readwrite_routine( void *arg ) 57 | { 58 | 59 | co_enable_hook_sys(); 60 | 61 | task_t *co = (task_t*)arg; 62 | char buf[ 1024 * 16 ]; 63 | for(;;) 64 | { 65 | if( -1 == co->fd ) 66 | { 67 | g_readwrite.push( co ); 68 | co_yield_ct(); 69 | continue; 70 | } 71 | 72 | int fd = co->fd; 73 | co->fd = -1; 74 | 75 | for(;;) 76 | { 77 | struct pollfd pf = { 0 }; 78 | pf.fd = fd; 79 | pf.events = (POLLIN|POLLERR|POLLHUP); 80 | co_poll( co_get_epoll_ct(),&pf,1,1000); 81 | 82 | int ret = read( fd,buf,sizeof(buf) ); 83 | if( ret > 0 ) 84 | { 85 | ret = write( fd,buf,ret ); 86 | } 87 | if( ret <= 0 ) 88 | { 89 | close( fd ); 90 | break; 91 | } 92 | } 93 | 94 | } 95 | return 0; 96 | } 97 | int co_accept(int fd, struct sockaddr *addr, socklen_t *len ); 98 | static void *accept_routine( void * ) 99 | { 100 | co_enable_hook_sys(); 101 | printf("accept_routine\n"); 102 | fflush(stdout); 103 | for(;;) 104 | { 105 | //printf("pid %ld g_readwrite.size %ld\n",getpid(),g_readwrite.size()); 106 | if( g_readwrite.empty() ) 107 | { 108 | printf("empty\n"); //sleep 109 | struct pollfd pf = { 0 }; 110 | pf.fd = -1; 111 | poll( &pf,1,1000); 112 | 113 | continue; 114 | 115 | } 116 | struct sockaddr_in addr; //maybe sockaddr_un; 117 | memset( &addr,0,sizeof(addr) ); 118 | socklen_t len = sizeof(addr); 119 | 120 | int fd = co_accept(g_listen_fd, (struct sockaddr *)&addr, &len); 121 | if( fd < 0 ) 122 | { 123 | struct pollfd pf = { 0 }; 124 | pf.fd = g_listen_fd; 125 | pf.events = (POLLIN|POLLERR|POLLHUP); 126 | co_poll( co_get_epoll_ct(),&pf,1,1000 ); 127 | continue; 128 | } 129 | if( g_readwrite.empty() ) 130 | { 131 | close( fd ); 132 | continue; 133 | } 134 | SetNonBlock( fd ); 135 | task_t *co = g_readwrite.top(); 136 | co->fd = fd; 137 | g_readwrite.pop(); 138 | co_resume( co->co ); 139 | } 140 | return 0; 141 | } 142 | 143 | static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) 144 | { 145 | bzero(&addr,sizeof(addr)); 146 | addr.sin_family = AF_INET; 147 | addr.sin_port = htons(shPort); 148 | int nIP = 0; 149 | if( !pszIP || '\0' == *pszIP 150 | || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") 151 | || 0 == strcmp(pszIP,"*") 152 | ) 153 | { 154 | nIP = htonl(INADDR_ANY); 155 | } 156 | else 157 | { 158 | nIP = inet_addr(pszIP); 159 | } 160 | addr.sin_addr.s_addr = nIP; 161 | 162 | } 163 | 164 | static int CreateTcpSocket(const unsigned short shPort /* = 0 */,const char *pszIP /* = "*" */,bool bReuse /* = false */) 165 | { 166 | int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); 167 | if( fd >= 0 ) 168 | { 169 | if(shPort != 0) 170 | { 171 | if(bReuse) 172 | { 173 | int nReuseAddr = 1; 174 | setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr)); 175 | } 176 | struct sockaddr_in addr ; 177 | SetAddr(pszIP,shPort,addr); 178 | int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr)); 179 | if( ret != 0) 180 | { 181 | close(fd); 182 | return -1; 183 | } 184 | } 185 | } 186 | return fd; 187 | } 188 | 189 | 190 | int main(int argc,char *argv[]) 191 | { 192 | const char *ip = argv[1]; 193 | int port = atoi( argv[2] ); 194 | int cnt = atoi( argv[3] ); 195 | int proccnt = atoi( argv[4] ); 196 | 197 | g_listen_fd = CreateTcpSocket( port,ip,true ); 198 | listen( g_listen_fd,1024 ); 199 | printf("listen %d %s:%d\n",g_listen_fd,ip,port); 200 | 201 | SetNonBlock( g_listen_fd ); 202 | 203 | for(int k=0;k 0 ) 208 | { 209 | continue; 210 | } 211 | else if( pid < 0 ) 212 | { 213 | break; 214 | } 215 | for(int i=0;ifd = -1; 219 | 220 | co_create( &(task->co),NULL,readwrite_routine,task ); 221 | co_resume( task->co ); 222 | 223 | } 224 | stCoRoutine_t *accept_co = NULL; 225 | co_create( &accept_co,NULL,accept_routine,0 ); 226 | co_resume( accept_co ); 227 | 228 | co_eventloop( co_get_epoll_ct(),0,0 ); 229 | 230 | exit(0); 231 | } 232 | return 0; 233 | } 234 | 235 | -------------------------------------------------------------------------------- /src/example_poll.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_routine.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | using namespace std; 37 | 38 | struct task_t 39 | { 40 | stCoRoutine_t *co; 41 | int fd; 42 | struct sockaddr_in addr; 43 | }; 44 | 45 | static int SetNonBlock(int iSock) 46 | { 47 | int iFlags; 48 | 49 | iFlags = fcntl(iSock, F_GETFL, 0); 50 | iFlags |= O_NONBLOCK; 51 | iFlags |= O_NDELAY; 52 | int ret = fcntl(iSock, F_SETFL, iFlags); 53 | return ret; 54 | } 55 | 56 | 57 | 58 | static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) 59 | { 60 | bzero(&addr,sizeof(addr)); 61 | addr.sin_family = AF_INET; 62 | addr.sin_port = htons(shPort); 63 | int nIP = 0; 64 | if( !pszIP || '\0' == *pszIP 65 | || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") 66 | || 0 == strcmp(pszIP,"*") 67 | ) 68 | { 69 | nIP = htonl(INADDR_ANY); 70 | } 71 | else 72 | { 73 | nIP = inet_addr(pszIP); 74 | } 75 | addr.sin_addr.s_addr = nIP; 76 | 77 | } 78 | 79 | static int CreateTcpSocket(const unsigned short shPort = 0 ,const char *pszIP = "*" ,bool bReuse = false ) 80 | { 81 | int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); 82 | if( fd >= 0 ) 83 | { 84 | if(shPort != 0) 85 | { 86 | if(bReuse) 87 | { 88 | int nReuseAddr = 1; 89 | setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr)); 90 | } 91 | struct sockaddr_in addr ; 92 | SetAddr(pszIP,shPort,addr); 93 | int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr)); 94 | if( ret != 0) 95 | { 96 | close(fd); 97 | return -1; 98 | } 99 | } 100 | } 101 | return fd; 102 | } 103 | 104 | static void *poll_routine( void *arg ) 105 | { 106 | co_enable_hook_sys(); 107 | 108 | vector &v = *(vector*)arg; 109 | for(size_t i=0;i setRaiseFds; 127 | size_t iWaitCnt = v.size(); 128 | for(;;) 129 | { 130 | int ret = poll( pf,iWaitCnt,1000 ); 131 | printf("co %p poll wait %ld ret %d\n", 132 | co_self(),iWaitCnt,ret); 133 | for(int i=0;i v; 178 | for(int i=1;i v2 = v; 188 | poll_routine( &v2 ); 189 | printf("--------------------- routine -------------------\n"); 190 | 191 | for(int i=0;i<10;i++) 192 | { 193 | stCoRoutine_t *co = 0; 194 | vector *v2 = new vector(); 195 | *v2 = v; 196 | co_create( &co,NULL,poll_routine,v2 ); 197 | printf("routine i %d\n",i); 198 | co_resume( co ); 199 | } 200 | 201 | co_eventloop( co_get_epoll_ct(),0,0 ); 202 | 203 | return 0; 204 | } 205 | //./example_poll 127.0.0.1 12365 127.0.0.1 12222 192.168.1.1 1000 192.168.1.2 1111 206 | 207 | -------------------------------------------------------------------------------- /src/example_setenv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "co_routine.h" 26 | 27 | const char* CGI_ENV_HOOK_LIST [] = 28 | { 29 | "CGINAME", 30 | }; 31 | struct stRoutineArgs_t 32 | { 33 | int iRoutineID; 34 | }; 35 | void SetAndGetEnv(int iRoutineID) 36 | { 37 | printf("routineid %d begin\n", iRoutineID); 38 | 39 | //use poll as sleep 40 | poll(NULL, 0, 500); 41 | 42 | char sBuf[128]; 43 | sprintf(sBuf, "cgi_routine_%d", iRoutineID); 44 | int ret = setenv("CGINAME", sBuf, 1); 45 | if (ret) 46 | { 47 | printf("%s:%d set env err ret %d errno %d %s\n", __func__, __LINE__, 48 | ret, errno, strerror(errno)); 49 | return; 50 | } 51 | printf("routineid %d set env CGINAME %s\n", iRoutineID, sBuf); 52 | 53 | poll(NULL, 0, 500); 54 | 55 | char* env = getenv("CGINAME"); 56 | if (!env) 57 | { 58 | printf("%s:%d get env err errno %d %s\n", __func__, __LINE__, 59 | errno, strerror(errno)); 60 | return; 61 | } 62 | printf("routineid %d get env CGINAME %s\n", iRoutineID, env); 63 | } 64 | 65 | void* RoutineFunc(void* args) 66 | { 67 | co_enable_hook_sys(); 68 | 69 | stRoutineArgs_t* g = (stRoutineArgs_t*)args; 70 | 71 | SetAndGetEnv(g->iRoutineID); 72 | return NULL; 73 | } 74 | 75 | int main(int argc, char* argv[]) 76 | { 77 | co_set_env_list(CGI_ENV_HOOK_LIST, sizeof(CGI_ENV_HOOK_LIST) / sizeof(char*)); 78 | stRoutineArgs_t args[3]; 79 | for (int i = 0; i < 3; i++) 80 | { 81 | stCoRoutine_t* co = NULL; 82 | args[i].iRoutineID = i; 83 | co_create(&co, NULL, RoutineFunc, &args[i]); 84 | co_resume(co); 85 | } 86 | co_eventloop(co_get_epoll_ct(), NULL, NULL); 87 | return 0; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/example_specific.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_routine_specific.h" 20 | #include "co_routine.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | using namespace std; 26 | struct stRoutineArgs_t 27 | { 28 | stCoRoutine_t* co; 29 | int routine_id; 30 | }; 31 | struct stRoutineSpecificData_t 32 | { 33 | int idx; 34 | }; 35 | 36 | CO_ROUTINE_SPECIFIC(stRoutineSpecificData_t, __routine); 37 | 38 | void* RoutineFunc(void* args) 39 | { 40 | co_enable_hook_sys(); 41 | stRoutineArgs_t* routine_args = (stRoutineArgs_t*)args; 42 | __routine->idx = routine_args->routine_id; 43 | while (true) 44 | { 45 | printf("%s:%d routine specific data idx %d\n", __func__, __LINE__, __routine->idx); 46 | poll(NULL, 0, 1000); 47 | } 48 | return NULL; 49 | } 50 | int main() 51 | { 52 | stRoutineArgs_t args[10]; 53 | for (int i = 0; i < 10; i++) 54 | { 55 | args[i].routine_id = i; 56 | co_create(&args[i].co, NULL, RoutineFunc, (void*)&args[i]); 57 | co_resume(args[i].co); 58 | } 59 | co_eventloop(co_get_epoll_ct(), NULL, NULL); 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /src/example_thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | 20 | 21 | #include "co_routine.h" 22 | #include "co_routine_inner.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int loop(void *) 31 | { 32 | return 0; 33 | } 34 | static void *routine_func( void * ) 35 | { 36 | stCoEpoll_t * ev = co_get_epoll_ct(); //ct = current thread 37 | co_eventloop( ev,loop,0 ); 38 | return 0; 39 | } 40 | int main(int argc,char *argv[]) 41 | { 42 | int cnt = atoi( argv[1] ); 43 | 44 | pthread_t tid[ cnt ]; 45 | for(int i=0;i