├── .gitignore ├── LICENSE.txt ├── Makefile ├── README.md ├── 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: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/52im/libco/a4a9675a30478fffbca5f092051c2cc6bfdabeca/LICENSE.txt -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Libco 2 | Libco is a c/c++ coroutine library that is widely used in WeChat services. It has been running on tens of thousands of machines since 2013. 3 | 4 | Author: sunnyxu(sunnyxu@tencent.com), leiffyli(leiffyli@tencent.com), dengoswei@gmail.com(dengoswei@tencent.com), sarlmolchen(sarlmolchen@tencent.com) 5 | 6 | By linking with libco, you can easily transform synchronous back-end service into coroutine service. The coroutine service will provide out-standing concurrency compare to multi-thread approach. With the system hook, You can easily coding in synchronous way but asynchronous executed. 7 | 8 | You can also use co_create/co_resume/co_yield interfaces to create asynchronous back-end service. These interface will give you more control of coroutines. 9 | 10 | By libco copy-stack mode, you can easily build a back-end service support tens of millions of tcp connection. 11 | *** 12 | ### 简介 13 | libco是微信后台大规模使用的c/c++协程库,2013年至今稳定运行在微信后台的数万台机器上。 14 | 15 | libco通过仅有的几个函数接口 co_create/co_resume/co_yield 再配合 co_poll,可以支持同步或者异步的写法,如线程库一样轻松。同时库里面提供了socket族函数的hook,使得后台逻辑服务几乎不用修改逻辑代码就可以完成异步化改造。 16 | 17 | 作者: sunnyxu(sunnyxu@tencent.com), leiffyli(leiffyli@tencent.com), dengoswei@gmail.com(dengoswei@tencent.com), sarlmolchen(sarlmolchen@tencent.com) 18 | 19 | ### libco的特性 20 | - 无需侵入业务逻辑,把多进程、多线程服务改造成协程服务,并发能力得到百倍提升; 21 | - 支持CGI框架,轻松构建web服务(New); 22 | - 支持gethostbyname、mysqlclient、ssl等常用第三库(New); 23 | - 可选的共享栈模式,单机轻松接入千万连接(New); 24 | - 完善简洁的协程编程接口 25 | * 类pthread接口设计,通过co_create、co_resume等简单清晰接口即可完成协程的创建与恢复; 26 | * __thread的协程私有变量、协程间通信的协程信号量co_signal (New); 27 | * 语言级别的lambda实现,结合协程原地编写并执行后台异步任务 (New); 28 | * 基于epoll/kqueue实现的小而轻的网络框架,基于时间轮盘实现的高性能定时器; 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /co_closure.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_CLOSURE_H__ 20 | #define __CO_CLOSURE_H__ 21 | struct stCoClosure_t 22 | { 23 | public: 24 | virtual void exec() = 0; 25 | }; 26 | 27 | //1.base 28 | //-- 1.1 comac_argc 29 | 30 | #define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ ) 31 | #define comac_arg_n( _1,_2,_3,_4,_5,_6,_7,N,...) N 32 | #define comac_args_seqs() 7,6,5,4,3,2,1,0 33 | #define comac_join_1( x,y ) x##y 34 | 35 | #define comac_argc( ... ) comac_get_args_cnt( __VA_ARGS__,comac_args_seqs() ) 36 | #define comac_join( x,y) comac_join_1( x,y ) 37 | 38 | //-- 1.2 repeat 39 | #define repeat_0( fun,a,... ) 40 | #define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ ) 41 | #define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ ) 42 | #define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ ) 43 | #define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ ) 44 | #define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ ) 45 | #define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ ) 46 | 47 | #define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__) 48 | 49 | //2.implement 50 | #define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a; 51 | #define impl_typeof( i,a,... ) typeof_##a & a; 52 | #define impl_typeof_cpy( i,a,... ) typeof_##a a; 53 | #define con_param_typeof( i,a,... ) typeof_##a & a##r, 54 | #define param_init_typeof( i,a,... ) a(a##r), 55 | 56 | 57 | //2.1 reference 58 | 59 | #define co_ref( name,... )\ 60 | repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ 61 | class type_##name\ 62 | {\ 63 | public:\ 64 | repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\ 65 | int _member_cnt;\ 66 | type_##name( \ 67 | repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ 68 | repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \ 69 | {}\ 70 | } name( __VA_ARGS__ ) ; 71 | 72 | 73 | //2.2 function 74 | 75 | #define co_func(name,...)\ 76 | repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ 77 | class name:public stCoClosure_t\ 78 | {\ 79 | public:\ 80 | repeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\ 81 | int _member_cnt;\ 82 | public:\ 83 | name( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ 84 | repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\ 85 | {}\ 86 | void exec() 87 | 88 | #define co_func_end } 89 | 90 | 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /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 = 44 | (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); 45 | 46 | ptr->size = n; 47 | ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); 48 | 49 | return ptr; 50 | 51 | } 52 | void co_epoll_res_free( struct co_epoll_res * ptr ) 53 | { 54 | if( !ptr ) return; 55 | if( ptr->events ) free( ptr->events ); 56 | free( ptr ); 57 | } 58 | 59 | #else 60 | class clsFdMap // million of fd , 1024 * 1024 61 | { 62 | private: 63 | static const int row_size = 1024; 64 | static const int col_size = 1024; 65 | 66 | void **m_pp[ 1024 ]; 67 | public: 68 | clsFdMap() 69 | { 70 | memset( m_pp,0,sizeof(m_pp) ); 71 | } 72 | ~clsFdMap() 73 | { 74 | for(int i=0;i= sizeof(m_pp)/sizeof(m_pp[0]) ) 92 | { 93 | assert( __LINE__ == 0 ); 94 | return -__LINE__; 95 | } 96 | if( !m_pp[ idx ] ) 97 | { 98 | m_pp[ idx ] = (void**)calloc( 1,sizeof(void*) * col_size ); 99 | } 100 | m_pp[ idx ][ fd % col_size ] = (void*)ptr; 101 | return 0; 102 | } 103 | inline void *get( int fd ) 104 | { 105 | int idx = fd / row_size; 106 | if( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) ) 107 | { 108 | return NULL; 109 | } 110 | void **lp = m_pp[ idx ]; 111 | if( !lp ) return NULL; 112 | 113 | return lp[ fd % col_size ]; 114 | } 115 | }; 116 | 117 | __thread clsFdMap *s_fd_map = NULL; 118 | 119 | static inline clsFdMap *get_fd_map() 120 | { 121 | if( !s_fd_map ) 122 | { 123 | s_fd_map = new clsFdMap(); 124 | } 125 | return s_fd_map; 126 | } 127 | 128 | struct kevent_pair_t 129 | { 130 | int fire_idx; 131 | int events; 132 | uint64_t u64; 133 | }; 134 | int co_epoll_create( int size ) 135 | { 136 | return kqueue(); 137 | } 138 | int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) 139 | { 140 | struct timespec t = { 0 }; 141 | if( timeout > 0 ) 142 | { 143 | t.tv_sec = timeout; 144 | } 145 | int ret = kevent( epfd, 146 | NULL, 0, //register null 147 | events->eventlist, maxevents,//just retrival 148 | ( -1 == timeout ) ? NULL : &t ); 149 | int j = 0; 150 | for(int i=0;ieventlist[i]; 153 | struct kevent_pair_t *ptr = (struct kevent_pair_t*)kev.udata; 154 | struct epoll_event *ev = events->events + i; 155 | if( 0 == ptr->fire_idx ) 156 | { 157 | ptr->fire_idx = i + 1; 158 | memset( ev,0,sizeof(*ev) ); 159 | ++j; 160 | } 161 | else 162 | { 163 | ev = events->events + ptr->fire_idx - 1; 164 | } 165 | if( EVFILT_READ == kev.filter ) 166 | { 167 | ev->events |= EPOLLIN; 168 | } 169 | else if( EVFILT_WRITE == kev.filter ) 170 | { 171 | ev->events |= EPOLLOUT; 172 | } 173 | ev->data.u64 = ptr->u64; 174 | } 175 | for(int i=0;ieventlist[i].udata) )->fire_idx = 0; 178 | } 179 | return j; 180 | } 181 | int co_epoll_del( int epfd,int fd ) 182 | { 183 | 184 | struct timespec t = { 0 }; 185 | struct kevent_pair_t *ptr = ( struct kevent_pair_t* )get_fd_map()->get( fd ); 186 | if( !ptr ) return 0; 187 | if( EPOLLIN & ptr->events ) 188 | { 189 | struct kevent kev = { 0 }; 190 | kev.ident = fd; 191 | kev.filter = EVFILT_READ; 192 | kev.flags = EV_DELETE; 193 | kevent( epfd,&kev,1, NULL,0,&t ); 194 | } 195 | if( EPOLLOUT & ptr->events ) 196 | { 197 | struct kevent kev = { 0 }; 198 | kev.ident = fd; 199 | kev.filter = EVFILT_WRITE; 200 | kev.flags = EV_DELETE; 201 | kevent( epfd,&kev,1, NULL,0,&t ); 202 | } 203 | get_fd_map()->clear( fd ); 204 | free( ptr ); 205 | return 0; 206 | } 207 | int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) 208 | { 209 | if( EPOLL_CTL_DEL == op ) 210 | { 211 | return co_epoll_del( epfd,fd ); 212 | } 213 | 214 | const int flags = ( EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP ); 215 | if( ev->events & ~flags ) 216 | { 217 | return -1; 218 | } 219 | 220 | if( EPOLL_CTL_ADD == op && get_fd_map()->get( fd ) ) 221 | { 222 | errno = EEXIST; 223 | return -1; 224 | } 225 | else if( EPOLL_CTL_MOD == op && !get_fd_map()->get( fd ) ) 226 | { 227 | errno = ENOENT; 228 | return -1; 229 | } 230 | 231 | struct kevent_pair_t *ptr = (struct kevent_pair_t*)get_fd_map()->get( fd ); 232 | if( !ptr ) 233 | { 234 | ptr = (kevent_pair_t*)calloc(1,sizeof(kevent_pair_t)); 235 | get_fd_map()->set( fd,ptr ); 236 | } 237 | 238 | int ret = 0; 239 | struct timespec t = { 0 }; 240 | 241 | printf("ptr->events 0x%X\n",ptr->events); 242 | 243 | if( EPOLL_CTL_MOD == op ) 244 | { 245 | //1.delete if exists 246 | if( ptr->events & EPOLLIN ) 247 | { 248 | struct kevent kev = { 0 }; 249 | EV_SET( &kev,fd,EVFILT_READ,EV_DELETE,0,0,NULL ); 250 | kevent( epfd, &kev,1, NULL,0, &t ); 251 | } 252 | //1.delete if exists 253 | if( ptr->events & EPOLLOUT ) 254 | { 255 | struct kevent kev = { 0 }; 256 | EV_SET( &kev,fd,EVFILT_WRITE,EV_DELETE,0,0,NULL ); 257 | ret = kevent( epfd, &kev,1, NULL,0, &t ); 258 | printf("delete write ret %d\n",ret ); 259 | } 260 | } 261 | 262 | do 263 | { 264 | if( ev->events & EPOLLIN ) 265 | { 266 | 267 | //2.add 268 | struct kevent kev = { 0 }; 269 | EV_SET( &kev,fd,EVFILT_READ,EV_ADD,0,0,ptr ); 270 | ret = kevent( epfd, &kev,1, NULL,0, &t ); 271 | if( ret ) break; 272 | } 273 | if( ev->events & EPOLLOUT ) 274 | { 275 | //2.add 276 | struct kevent kev = { 0 }; 277 | EV_SET( &kev,fd,EVFILT_WRITE,EV_ADD,0,0,ptr ); 278 | ret = kevent( epfd, &kev,1, NULL,0, &t ); 279 | if( ret ) break; 280 | } 281 | } while( 0 ); 282 | 283 | if( ret ) 284 | { 285 | get_fd_map()->clear( fd ); 286 | free( ptr ); 287 | return ret; 288 | } 289 | 290 | ptr->events = ev->events; 291 | ptr->u64 = ev->data.u64; 292 | 293 | 294 | return ret; 295 | } 296 | 297 | struct co_epoll_res *co_epoll_res_alloc( int n ) 298 | { 299 | struct co_epoll_res * ptr = 300 | (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); 301 | 302 | ptr->size = n; 303 | ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); 304 | ptr->eventlist = (struct kevent*)calloc( 1,n * sizeof( struct kevent) ); 305 | 306 | return ptr; 307 | } 308 | 309 | void co_epoll_res_free( struct co_epoll_res * ptr ) 310 | { 311 | if( !ptr ) return; 312 | if( ptr->events ) free( ptr->events ); 313 | if( ptr->eventlist ) free( ptr->eventlist ); 314 | free( ptr ); 315 | } 316 | 317 | #endif 318 | 319 | 320 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /co_hook_sys_call.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/52im/libco/a4a9675a30478fffbca5f092051c2cc6bfdabeca/co_hook_sys_call.cpp -------------------------------------------------------------------------------- /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) 68 | { 69 | register uint32_t lo, hi; 70 | register unsigned long long o; 71 | __asm__ __volatile__ ( 72 | "rdtscp" : "=a"(lo), "=d"(hi) 73 | ); 74 | o = hi; 75 | o <<= 32; 76 | return (o | lo); 77 | 78 | } 79 | static unsigned long long getCpuKhz() 80 | { 81 | FILE *fp = fopen("/proc/cpuinfo","r"); 82 | if(!fp) return 1; 83 | char buf[4096] = {0}; 84 | fread(buf,1,sizeof(buf),fp); 85 | fclose(fp); 86 | 87 | char *lp = strstr(buf,"cpu MHz"); 88 | if(!lp) return 1; 89 | lp += strlen("cpu MHz"); 90 | while(*lp == ' ' || *lp == '\t' || *lp == ':') 91 | { 92 | ++lp; 93 | } 94 | 95 | double mhz = atof(lp); 96 | unsigned long long u = (unsigned long long)(mhz * 1000); 97 | return u; 98 | } 99 | #endif 100 | 101 | static unsigned long long GetTickMS() 102 | { 103 | #if defined( __LIBCO_RDTSCP__) 104 | static uint32_t khz = getCpuKhz(); 105 | return counter() / khz; 106 | #else 107 | struct timeval now = { 0 }; 108 | gettimeofday( &now,NULL ); 109 | unsigned long long u = now.tv_sec; 110 | u *= 1000; 111 | u += now.tv_usec / 1000; 112 | return u; 113 | #endif 114 | } 115 | 116 | static pid_t GetPid() 117 | { 118 | static __thread pid_t pid = 0; 119 | static __thread pid_t tid = 0; 120 | if( !pid || !tid || pid != getpid() ) 121 | { 122 | pid = getpid(); 123 | #if defined( __APPLE__ ) 124 | tid = syscall( SYS_gettid ); 125 | if( -1 == (long)tid ) 126 | { 127 | tid = pid; 128 | } 129 | #else 130 | tid = syscall( __NR_gettid ); 131 | #endif 132 | 133 | } 134 | return tid; 135 | 136 | } 137 | /* 138 | static pid_t GetPid() 139 | { 140 | char **p = (char**)pthread_self(); 141 | return p ? *(pid_t*)(p + 18) : getpid(); 142 | } 143 | */ 144 | template 145 | void RemoveFromLink(T *ap) 146 | { 147 | TLink *lst = ap->pLink; 148 | if(!lst) return ; 149 | assert( lst->head && lst->tail ); 150 | 151 | if( ap == lst->head ) 152 | { 153 | lst->head = ap->pNext; 154 | if(lst->head) 155 | { 156 | lst->head->pPrev = NULL; 157 | } 158 | } 159 | else 160 | { 161 | if(ap->pPrev) 162 | { 163 | ap->pPrev->pNext = ap->pNext; 164 | } 165 | } 166 | 167 | if( ap == lst->tail ) 168 | { 169 | lst->tail = ap->pPrev; 170 | if(lst->tail) 171 | { 172 | lst->tail->pNext = NULL; 173 | } 174 | } 175 | else 176 | { 177 | ap->pNext->pPrev = ap->pPrev; 178 | } 179 | 180 | ap->pPrev = ap->pNext = NULL; 181 | ap->pLink = NULL; 182 | } 183 | 184 | template 185 | void inline AddTail(TLink*apLink,TNode *ap) 186 | { 187 | if( ap->pLink ) 188 | { 189 | return ; 190 | } 191 | if(apLink->tail) 192 | { 193 | apLink->tail->pNext = (TNode*)ap; 194 | ap->pNext = NULL; 195 | ap->pPrev = apLink->tail; 196 | apLink->tail = ap; 197 | } 198 | else 199 | { 200 | apLink->head = apLink->tail = ap; 201 | ap->pNext = ap->pPrev = NULL; 202 | } 203 | ap->pLink = apLink; 204 | } 205 | template 206 | void inline PopHead( TLink*apLink ) 207 | { 208 | if( !apLink->head ) 209 | { 210 | return ; 211 | } 212 | TNode *lp = apLink->head; 213 | if( apLink->head == apLink->tail ) 214 | { 215 | apLink->head = apLink->tail = NULL; 216 | } 217 | else 218 | { 219 | apLink->head = apLink->head->pNext; 220 | } 221 | 222 | lp->pPrev = lp->pNext = NULL; 223 | lp->pLink = NULL; 224 | 225 | if( apLink->head ) 226 | { 227 | apLink->head->pPrev = NULL; 228 | } 229 | } 230 | 231 | template 232 | void inline Join( TLink*apLink,TLink *apOther ) 233 | { 234 | //printf("apOther %p\n",apOther); 235 | if( !apOther->head ) 236 | { 237 | return ; 238 | } 239 | TNode *lp = apOther->head; 240 | while( lp ) 241 | { 242 | lp->pLink = apLink; 243 | lp = lp->pNext; 244 | } 245 | lp = apOther->head; 246 | if(apLink->tail) 247 | { 248 | apLink->tail->pNext = (TNode*)lp; 249 | lp->pPrev = apLink->tail; 250 | apLink->tail = apOther->tail; 251 | } 252 | else 253 | { 254 | apLink->head = apOther->head; 255 | apLink->tail = apOther->tail; 256 | } 257 | 258 | apOther->head = apOther->tail = NULL; 259 | } 260 | 261 | /////////////////for copy stack ////////////////////////// 262 | stStackMem_t* co_alloc_stackmem(unsigned int stack_size) 263 | { 264 | stStackMem_t* stack_mem = (stStackMem_t*)malloc(sizeof(stStackMem_t)); 265 | stack_mem->ocupy_co= NULL; 266 | stack_mem->stack_size = stack_size; 267 | stack_mem->stack_buffer = (char*)malloc(stack_size); 268 | stack_mem->stack_bp = stack_mem->stack_buffer + stack_size; 269 | return stack_mem; 270 | } 271 | 272 | stShareStack_t* co_alloc_sharestack(int count, int stack_size) 273 | { 274 | stShareStack_t* share_stack = (stShareStack_t*)malloc(sizeof(stShareStack_t)); 275 | share_stack->alloc_idx = 0; 276 | share_stack->stack_size = stack_size; 277 | 278 | //alloc stack array 279 | share_stack->count = count; 280 | stStackMem_t** stack_array = (stStackMem_t**)calloc(count, sizeof(stStackMem_t*)); 281 | for (int i = 0; i < count; i++) 282 | { 283 | stack_array[i] = co_alloc_stackmem(stack_size); 284 | } 285 | share_stack->stack_array = stack_array; 286 | return share_stack; 287 | } 288 | 289 | static stStackMem_t* co_get_stackmem(stShareStack_t* share_stack) 290 | { 291 | if (!share_stack) 292 | { 293 | return NULL; 294 | } 295 | int idx = share_stack->alloc_idx % share_stack->count; 296 | share_stack->alloc_idx++; 297 | 298 | return share_stack->stack_array[idx]; 299 | } 300 | 301 | 302 | // ---------------------------------------------------------------------------- 303 | struct stTimeoutItemLink_t; 304 | struct stTimeoutItem_t; 305 | struct stCoEpoll_t 306 | { 307 | int iEpollFd; 308 | static const int _EPOLL_SIZE = 1024 * 10; 309 | 310 | struct stTimeout_t *pTimeout; 311 | 312 | struct stTimeoutItemLink_t *pstTimeoutList; 313 | 314 | struct stTimeoutItemLink_t *pstActiveList; 315 | 316 | co_epoll_res *result; 317 | 318 | }; 319 | typedef void (*OnPreparePfn_t)( stTimeoutItem_t *,struct epoll_event &ev, stTimeoutItemLink_t *active ); 320 | typedef void (*OnProcessPfn_t)( stTimeoutItem_t *); 321 | struct stTimeoutItem_t 322 | { 323 | 324 | enum 325 | { 326 | eMaxTimeout = 40 * 1000 //20s 327 | }; 328 | stTimeoutItem_t *pPrev; 329 | stTimeoutItem_t *pNext; 330 | stTimeoutItemLink_t *pLink; 331 | 332 | unsigned long long ullExpireTime; 333 | 334 | OnPreparePfn_t pfnPrepare; 335 | OnProcessPfn_t pfnProcess; 336 | 337 | void *pArg; // routine 338 | bool bTimeout; 339 | }; 340 | struct stTimeoutItemLink_t 341 | { 342 | stTimeoutItem_t *head; 343 | stTimeoutItem_t *tail; 344 | 345 | }; 346 | struct stTimeout_t 347 | { 348 | stTimeoutItemLink_t *pItems; 349 | int iItemSize; 350 | 351 | unsigned long long ullStart; 352 | long long llStartIdx; 353 | }; 354 | stTimeout_t *AllocTimeout( int iSize ) 355 | { 356 | stTimeout_t *lp = (stTimeout_t*)calloc( 1,sizeof(stTimeout_t) ); 357 | 358 | lp->iItemSize = iSize; 359 | lp->pItems = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) * lp->iItemSize ); 360 | 361 | lp->ullStart = GetTickMS(); 362 | lp->llStartIdx = 0; 363 | 364 | return lp; 365 | } 366 | void FreeTimeout( stTimeout_t *apTimeout ) 367 | { 368 | free( apTimeout->pItems ); 369 | free ( apTimeout ); 370 | } 371 | int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,unsigned long long allNow ) 372 | { 373 | if( apTimeout->ullStart == 0 ) 374 | { 375 | apTimeout->ullStart = allNow; 376 | apTimeout->llStartIdx = 0; 377 | } 378 | if( allNow < apTimeout->ullStart ) 379 | { 380 | co_log_err("CO_ERR: AddTimeout line %d allNow %llu apTimeout->ullStart %llu", 381 | __LINE__,allNow,apTimeout->ullStart); 382 | 383 | return __LINE__; 384 | } 385 | if( apItem->ullExpireTime < allNow ) 386 | { 387 | co_log_err("CO_ERR: AddTimeout line %d apItem->ullExpireTime %llu allNow %llu apTimeout->ullStart %llu", 388 | __LINE__,apItem->ullExpireTime,allNow,apTimeout->ullStart); 389 | 390 | return __LINE__; 391 | } 392 | int diff = apItem->ullExpireTime - apTimeout->ullStart; 393 | 394 | if( diff >= apTimeout->iItemSize ) 395 | { 396 | co_log_err("CO_ERR: AddTimeout line %d diff %d", 397 | __LINE__,diff); 398 | 399 | return __LINE__; 400 | } 401 | AddTail( apTimeout->pItems + ( apTimeout->llStartIdx + diff ) % apTimeout->iItemSize , apItem ); 402 | 403 | return 0; 404 | } 405 | inline void TakeAllTimeout( stTimeout_t *apTimeout,unsigned long long allNow,stTimeoutItemLink_t *apResult ) 406 | { 407 | if( apTimeout->ullStart == 0 ) 408 | { 409 | apTimeout->ullStart = allNow; 410 | apTimeout->llStartIdx = 0; 411 | } 412 | 413 | if( allNow < apTimeout->ullStart ) 414 | { 415 | return ; 416 | } 417 | int cnt = allNow - apTimeout->ullStart + 1; 418 | if( cnt > apTimeout->iItemSize ) 419 | { 420 | cnt = apTimeout->iItemSize; 421 | } 422 | if( cnt < 0 ) 423 | { 424 | return; 425 | } 426 | for( int i = 0;illStartIdx + i) % apTimeout->iItemSize; 429 | Join( apResult,apTimeout->pItems + idx ); 430 | } 431 | apTimeout->ullStart = allNow; 432 | apTimeout->llStartIdx += cnt - 1; 433 | 434 | 435 | } 436 | static int CoRoutineFunc( stCoRoutine_t *co,void * ) 437 | { 438 | if( co->pfn ) 439 | { 440 | co->pfn( co->arg ); 441 | } 442 | co->cEnd = 1; 443 | 444 | stCoRoutineEnv_t *env = co->env; 445 | 446 | co_yield_env( env ); 447 | 448 | return 0; 449 | } 450 | 451 | 452 | 453 | struct stCoRoutine_t *co_create_env( stCoRoutineEnv_t * env, const stCoRoutineAttr_t* attr, 454 | pfn_co_routine_t pfn,void *arg ) 455 | { 456 | 457 | stCoRoutineAttr_t at; 458 | if( attr ) 459 | { 460 | memcpy( &at,attr,sizeof(at) ); 461 | } 462 | if( at.stack_size <= 0 ) 463 | { 464 | at.stack_size = 128 * 1024; 465 | } 466 | else if( at.stack_size > 1024 * 1024 * 8 ) 467 | { 468 | at.stack_size = 1024 * 1024 * 8; 469 | } 470 | 471 | if( at.stack_size & 0xFFF ) 472 | { 473 | at.stack_size &= ~0xFFF; 474 | at.stack_size += 0x1000; 475 | } 476 | 477 | stCoRoutine_t *lp = (stCoRoutine_t*)malloc( sizeof(stCoRoutine_t) ); 478 | 479 | 480 | lp->env = env; 481 | lp->pfn = pfn; 482 | lp->arg = arg; 483 | 484 | stStackMem_t* stack_mem = NULL; 485 | if( at.share_stack ) 486 | { 487 | stack_mem = co_get_stackmem( at.share_stack); 488 | at.stack_size = at.share_stack->stack_size; 489 | } 490 | else 491 | { 492 | stack_mem = co_alloc_stackmem(at.stack_size); 493 | } 494 | lp->stack_mem = stack_mem; 495 | 496 | lp->ctx.ss_sp = stack_mem->stack_buffer; 497 | lp->ctx.ss_size = at.stack_size; 498 | 499 | lp->cStart = 0; 500 | lp->cEnd = 0; 501 | lp->cIsMain = 0; 502 | lp->cEnableSysHook = 0; 503 | lp->cIsShareStack = at.share_stack != NULL; 504 | 505 | lp->save_size = 0; 506 | lp->save_buffer = NULL; 507 | 508 | return lp; 509 | } 510 | 511 | int co_create( stCoRoutine_t **ppco,const stCoRoutineAttr_t *attr,pfn_co_routine_t pfn,void *arg ) 512 | { 513 | if( !co_get_curr_thread_env() ) 514 | { 515 | co_init_curr_thread_env(); 516 | } 517 | stCoRoutine_t *co = co_create_env( co_get_curr_thread_env(), attr, pfn,arg ); 518 | *ppco = co; 519 | return 0; 520 | } 521 | void co_free( stCoRoutine_t *co ) 522 | { 523 | free( co ); 524 | } 525 | void co_release( stCoRoutine_t *co ) 526 | { 527 | if( co->cEnd ) 528 | { 529 | free( co ); 530 | } 531 | } 532 | 533 | void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co); 534 | 535 | void co_resume( stCoRoutine_t *co ) 536 | { 537 | stCoRoutineEnv_t *env = co->env; 538 | stCoRoutine_t *lpCurrRoutine = env->pCallStack[ env->iCallStackSize - 1 ]; 539 | if( !co->cStart ) 540 | { 541 | coctx_make( &co->ctx,(coctx_pfn_t)CoRoutineFunc,co,0 ); 542 | co->cStart = 1; 543 | } 544 | env->pCallStack[ env->iCallStackSize++ ] = co; 545 | co_swap( lpCurrRoutine, co ); 546 | 547 | 548 | } 549 | void co_yield_env( stCoRoutineEnv_t *env ) 550 | { 551 | 552 | stCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ]; 553 | stCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ]; 554 | 555 | env->iCallStackSize--; 556 | 557 | co_swap( curr, last); 558 | } 559 | 560 | void co_yield_ct() 561 | { 562 | 563 | co_yield_env( co_get_curr_thread_env() ); 564 | } 565 | void co_yield( stCoRoutine_t *co ) 566 | { 567 | co_yield_env( co->env ); 568 | } 569 | 570 | void save_stack_buffer(stCoRoutine_t* ocupy_co) 571 | { 572 | ///copy out 573 | stStackMem_t* stack_mem = ocupy_co->stack_mem; 574 | int len = stack_mem->stack_bp - ocupy_co->stack_sp; 575 | 576 | if (ocupy_co->save_buffer) 577 | { 578 | free(ocupy_co->save_buffer), ocupy_co->save_buffer = NULL; 579 | } 580 | 581 | ocupy_co->save_buffer = (char*)malloc(len); //malloc buf; 582 | ocupy_co->save_size = len; 583 | 584 | memcpy(ocupy_co->save_buffer, ocupy_co->stack_sp, len); 585 | } 586 | 587 | void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co) 588 | { 589 | stCoRoutineEnv_t* env = co_get_curr_thread_env(); 590 | 591 | //get curr stack sp 592 | char c; 593 | curr->stack_sp= &c; 594 | 595 | if (!pending_co->cIsShareStack) 596 | { 597 | env->pending_co = NULL; 598 | env->ocupy_co = NULL; 599 | } 600 | else 601 | { 602 | env->pending_co = pending_co; 603 | //get last occupy co on the same stack mem 604 | stCoRoutine_t* ocupy_co = pending_co->stack_mem->ocupy_co; 605 | //set pending co to ocupy thest stack mem; 606 | pending_co->stack_mem->ocupy_co = pending_co; 607 | 608 | env->ocupy_co = ocupy_co; 609 | if (ocupy_co && ocupy_co != pending_co) 610 | { 611 | save_stack_buffer(ocupy_co); 612 | } 613 | } 614 | 615 | //swap context 616 | coctx_swap(&(curr->ctx),&(pending_co->ctx) ); 617 | 618 | //stack buffer may be overwrite, so get again; 619 | stCoRoutineEnv_t* curr_env = co_get_curr_thread_env(); 620 | stCoRoutine_t* update_ocupy_co = curr_env->ocupy_co; 621 | stCoRoutine_t* update_pending_co = curr_env->pending_co; 622 | 623 | if (update_ocupy_co && update_pending_co && update_ocupy_co != update_pending_co) 624 | { 625 | //resume stack buffer 626 | if (update_pending_co->save_buffer && update_pending_co->save_size > 0) 627 | { 628 | memcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size); 629 | } 630 | } 631 | } 632 | 633 | 634 | 635 | //int poll(struct pollfd fds[], nfds_t nfds, int timeout); 636 | // { fd,events,revents } 637 | struct stPollItem_t ; 638 | struct stPoll_t : public stTimeoutItem_t 639 | { 640 | struct pollfd *fds; 641 | nfds_t nfds; // typedef unsigned long int nfds_t; 642 | 643 | stPollItem_t *pPollItems; 644 | 645 | int iAllEventDetach; 646 | 647 | int iEpollFd; 648 | 649 | int iRaiseCnt; 650 | 651 | 652 | }; 653 | struct stPollItem_t : public stTimeoutItem_t 654 | { 655 | struct pollfd *pSelf; 656 | stPoll_t *pPoll; 657 | 658 | struct epoll_event stEvent; 659 | }; 660 | /* 661 | * EPOLLPRI POLLPRI // There is urgent data to read. 662 | * EPOLLMSG POLLMSG 663 | * 664 | * POLLREMOVE 665 | * POLLRDHUP 666 | * POLLNVAL 667 | * 668 | * */ 669 | static uint32_t PollEvent2Epoll( short events ) 670 | { 671 | uint32_t e = 0; 672 | if( events & POLLIN ) e |= EPOLLIN; 673 | if( events & POLLOUT ) e |= EPOLLOUT; 674 | if( events & POLLHUP ) e |= EPOLLHUP; 675 | if( events & POLLERR ) e |= EPOLLERR; 676 | return e; 677 | } 678 | static short EpollEvent2Poll( uint32_t events ) 679 | { 680 | short e = 0; 681 | if( events & EPOLLIN ) e |= POLLIN; 682 | if( events & EPOLLOUT ) e |= POLLOUT; 683 | if( events & EPOLLHUP ) e |= POLLHUP; 684 | if( events & EPOLLERR ) e |= POLLERR; 685 | return e; 686 | } 687 | 688 | static stCoRoutineEnv_t* g_arrCoEnvPerThread[ 102400 ] = { 0 }; 689 | void co_init_curr_thread_env() 690 | { 691 | pid_t pid = GetPid(); 692 | g_arrCoEnvPerThread[ pid ] = (stCoRoutineEnv_t*)calloc( 1,sizeof(stCoRoutineEnv_t) ); 693 | stCoRoutineEnv_t *env = g_arrCoEnvPerThread[ pid ]; 694 | printf("init pid %ld env %p\n",(long)pid,env); 695 | 696 | env->iCallStackSize = 0; 697 | struct stCoRoutine_t *self = co_create_env( env, NULL, NULL,NULL ); 698 | self->cIsMain = 1; 699 | 700 | env->pending_co = NULL; 701 | env->ocupy_co = NULL; 702 | 703 | coctx_init( &self->ctx ); 704 | 705 | env->pCallStack[ env->iCallStackSize++ ] = self; 706 | 707 | stCoEpoll_t *ev = AllocEpoll(); 708 | SetEpoll( env,ev ); 709 | } 710 | stCoRoutineEnv_t *co_get_curr_thread_env() 711 | { 712 | return g_arrCoEnvPerThread[ GetPid() ]; 713 | } 714 | 715 | void OnPollProcessEvent( stTimeoutItem_t * ap ) 716 | { 717 | stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; 718 | co_resume( co ); 719 | } 720 | 721 | void OnPollPreparePfn( stTimeoutItem_t * ap,struct epoll_event &e,stTimeoutItemLink_t *active ) 722 | { 723 | stPollItem_t *lp = (stPollItem_t *)ap; 724 | lp->pSelf->revents = EpollEvent2Poll( e.events ); 725 | 726 | 727 | stPoll_t *pPoll = lp->pPoll; 728 | pPoll->iRaiseCnt++; 729 | 730 | if( !pPoll->iAllEventDetach ) 731 | { 732 | pPoll->iAllEventDetach = 1; 733 | 734 | RemoveFromLink( pPoll ); 735 | 736 | AddTail( active,pPoll ); 737 | 738 | } 739 | } 740 | 741 | 742 | void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ) 743 | { 744 | if( !ctx->result ) 745 | { 746 | ctx->result = co_epoll_res_alloc( stCoEpoll_t::_EPOLL_SIZE ); 747 | } 748 | co_epoll_res *result = ctx->result; 749 | 750 | 751 | for(;;) 752 | { 753 | int ret = co_epoll_wait( ctx->iEpollFd,result,stCoEpoll_t::_EPOLL_SIZE, 1 ); 754 | 755 | stTimeoutItemLink_t *active = (ctx->pstActiveList); 756 | stTimeoutItemLink_t *timeout = (ctx->pstTimeoutList); 757 | 758 | memset( timeout,0,sizeof(stTimeoutItemLink_t) ); 759 | 760 | for(int i=0;ievents[i].data.ptr; 763 | if( item->pfnPrepare ) 764 | { 765 | item->pfnPrepare( item,result->events[i],active ); 766 | } 767 | else 768 | { 769 | AddTail( active,item ); 770 | } 771 | } 772 | 773 | 774 | unsigned long long now = GetTickMS(); 775 | TakeAllTimeout( ctx->pTimeout,now,timeout ); 776 | 777 | stTimeoutItem_t *lp = timeout->head; 778 | while( lp ) 779 | { 780 | //printf("raise timeout %p\n",lp); 781 | lp->bTimeout = true; 782 | lp = lp->pNext; 783 | } 784 | 785 | Join( active,timeout ); 786 | 787 | lp = active->head; 788 | while( lp ) 789 | { 790 | 791 | PopHead( active ); 792 | if( lp->pfnProcess ) 793 | { 794 | lp->pfnProcess( lp ); 795 | } 796 | 797 | lp = active->head; 798 | } 799 | if( pfn ) 800 | { 801 | if( -1 == pfn( arg ) ) 802 | { 803 | break; 804 | } 805 | } 806 | 807 | } 808 | } 809 | void OnCoroutineEvent( stTimeoutItem_t * ap ) 810 | { 811 | stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; 812 | co_resume( co ); 813 | } 814 | 815 | 816 | stCoEpoll_t *AllocEpoll() 817 | { 818 | stCoEpoll_t *ctx = (stCoEpoll_t*)calloc( 1,sizeof(stCoEpoll_t) ); 819 | 820 | ctx->iEpollFd = co_epoll_create( stCoEpoll_t::_EPOLL_SIZE ); 821 | ctx->pTimeout = AllocTimeout( 60 * 1000 ); 822 | 823 | ctx->pstActiveList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); 824 | ctx->pstTimeoutList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); 825 | 826 | 827 | return ctx; 828 | } 829 | 830 | void FreeEpoll( stCoEpoll_t *ctx ) 831 | { 832 | if( ctx ) 833 | { 834 | free( ctx->pstActiveList ); 835 | free( ctx->pstTimeoutList ); 836 | FreeTimeout( ctx->pTimeout ); 837 | co_epoll_res_free( ctx->result ); 838 | } 839 | free( ctx ); 840 | } 841 | 842 | stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ) 843 | { 844 | return env->pCallStack[ env->iCallStackSize - 1 ]; 845 | } 846 | stCoRoutine_t *GetCurrThreadCo( ) 847 | { 848 | stCoRoutineEnv_t *env = co_get_curr_thread_env(); 849 | if( !env ) return 0; 850 | return GetCurrCo(env); 851 | } 852 | 853 | 854 | 855 | int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout ) 856 | { 857 | 858 | if( timeout > stTimeoutItem_t::eMaxTimeout ) 859 | { 860 | timeout = stTimeoutItem_t::eMaxTimeout; 861 | } 862 | int epfd = ctx->iEpollFd; 863 | stCoRoutine_t* self = co_self(); 864 | 865 | //1.struct change 866 | stPoll_t& arg = *((stPoll_t*)malloc(sizeof(stPoll_t))); 867 | memset( &arg,0,sizeof(arg) ); 868 | 869 | arg.iEpollFd = epfd; 870 | arg.fds = (pollfd*)calloc(nfds, sizeof(pollfd)); 871 | arg.nfds = nfds; 872 | 873 | stPollItem_t arr[2]; 874 | if( nfds < sizeof(arr) / sizeof(arr[0]) && !self->cIsShareStack) 875 | { 876 | arg.pPollItems = arr; 877 | } 878 | else 879 | { 880 | arg.pPollItems = (stPollItem_t*)malloc( nfds * sizeof( stPollItem_t ) ); 881 | } 882 | memset( arg.pPollItems,0,nfds * sizeof(stPollItem_t) ); 883 | 884 | arg.pfnProcess = OnPollProcessEvent; 885 | arg.pArg = GetCurrCo( co_get_curr_thread_env() ); 886 | 887 | //2.add timeout 888 | 889 | unsigned long long now = GetTickMS(); 890 | arg.ullExpireTime = now + timeout; 891 | int ret = AddTimeout( ctx->pTimeout,&arg,now ); 892 | if( ret != 0 ) 893 | { 894 | co_log_err("CO_ERR: AddTimeout ret %d now %lld timeout %d arg.ullExpireTime %lld", 895 | ret,now,timeout,arg.ullExpireTime); 896 | errno = EINVAL; 897 | 898 | if( arg.pPollItems != arr ) 899 | { 900 | free( arg.pPollItems ); 901 | arg.pPollItems = NULL; 902 | } 903 | free(arg.fds); 904 | free(&arg); 905 | 906 | return -__LINE__; 907 | } 908 | //3. add epoll 909 | 910 | for(nfds_t i=0;i -1 ) 919 | { 920 | ev.data.ptr = arg.pPollItems + i; 921 | ev.events = PollEvent2Epoll( fds[i].events ); 922 | 923 | co_epoll_ctl( epfd,EPOLL_CTL_ADD, fds[i].fd, &ev ); 924 | } 925 | //if fail,the timeout would work 926 | 927 | } 928 | 929 | co_yield_env( co_get_curr_thread_env() ); 930 | 931 | RemoveFromLink( &arg ); 932 | for(nfds_t i = 0;i < nfds;i++) 933 | { 934 | int fd = fds[i].fd; 935 | if( fd > -1 ) 936 | { 937 | co_epoll_ctl( epfd,EPOLL_CTL_DEL,fd,&arg.pPollItems[i].stEvent ); 938 | } 939 | fds[i].revents = arg.fds[i].revents; 940 | } 941 | 942 | 943 | if( arg.pPollItems != arr ) 944 | { 945 | free( arg.pPollItems ); 946 | arg.pPollItems = NULL; 947 | } 948 | 949 | free(arg.fds); 950 | free(&arg); 951 | 952 | return arg.iRaiseCnt; 953 | } 954 | 955 | void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ) 956 | { 957 | env->pEpoll = ev; 958 | } 959 | stCoEpoll_t *co_get_epoll_ct() 960 | { 961 | if( !co_get_curr_thread_env() ) 962 | { 963 | co_init_curr_thread_env(); 964 | } 965 | return co_get_curr_thread_env()->pEpoll; 966 | } 967 | struct stHookPThreadSpec_t 968 | { 969 | stCoRoutine_t *co; 970 | void *value; 971 | 972 | enum 973 | { 974 | size = 1024 975 | }; 976 | }; 977 | void *co_getspecific(pthread_key_t key) 978 | { 979 | stCoRoutine_t *co = GetCurrThreadCo(); 980 | if( !co || co->cIsMain ) 981 | { 982 | return pthread_getspecific( key ); 983 | } 984 | return co->aSpec[ key ].value; 985 | } 986 | int co_setspecific(pthread_key_t key, const void *value) 987 | { 988 | stCoRoutine_t *co = GetCurrThreadCo(); 989 | if( !co || co->cIsMain ) 990 | { 991 | return pthread_setspecific( key,value ); 992 | } 993 | co->aSpec[ key ].value = (void*)value; 994 | return 0; 995 | } 996 | 997 | 998 | 999 | void co_disable_hook_sys() 1000 | { 1001 | stCoRoutine_t *co = GetCurrThreadCo(); 1002 | if( co ) 1003 | { 1004 | co->cEnableSysHook = 0; 1005 | } 1006 | } 1007 | bool co_is_enable_sys_hook() 1008 | { 1009 | stCoRoutine_t *co = GetCurrThreadCo(); 1010 | return ( co && co->cEnableSysHook ); 1011 | } 1012 | 1013 | stCoRoutine_t *co_self() 1014 | { 1015 | return GetCurrThreadCo(); 1016 | } 1017 | 1018 | //co cond 1019 | struct stCoCond_t; 1020 | struct stCoCondItem_t 1021 | { 1022 | stCoCondItem_t *pPrev; 1023 | stCoCondItem_t *pNext; 1024 | stCoCond_t *pLink; 1025 | 1026 | stTimeoutItem_t timeout; 1027 | }; 1028 | struct stCoCond_t 1029 | { 1030 | stCoCondItem_t *head; 1031 | stCoCondItem_t *tail; 1032 | }; 1033 | static void OnSignalProcessEvent( stTimeoutItem_t * ap ) 1034 | { 1035 | stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; 1036 | co_resume( co ); 1037 | } 1038 | 1039 | stCoCondItem_t *co_cond_pop( stCoCond_t *link ); 1040 | int co_cond_signal( stCoCond_t *si ) 1041 | { 1042 | stCoCondItem_t * sp = co_cond_pop( si ); 1043 | if( !sp ) 1044 | { 1045 | return 0; 1046 | } 1047 | RemoveFromLink( &sp->timeout ); 1048 | 1049 | AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); 1050 | 1051 | return 0; 1052 | } 1053 | int co_cond_broadcast( stCoCond_t *si ) 1054 | { 1055 | for(;;) 1056 | { 1057 | stCoCondItem_t * sp = co_cond_pop( si ); 1058 | if( !sp ) return 0; 1059 | 1060 | RemoveFromLink( &sp->timeout ); 1061 | 1062 | AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); 1063 | } 1064 | 1065 | return 0; 1066 | } 1067 | 1068 | 1069 | int co_cond_timedwait( stCoCond_t *link,int ms ) 1070 | { 1071 | stCoCondItem_t* psi = (stCoCondItem_t*)calloc(1, sizeof(stCoCondItem_t)); 1072 | psi->timeout.pArg = GetCurrThreadCo(); 1073 | psi->timeout.pfnProcess = OnSignalProcessEvent; 1074 | 1075 | if( ms > 0 ) 1076 | { 1077 | unsigned long long now = GetTickMS(); 1078 | psi->timeout.ullExpireTime = now + ms; 1079 | 1080 | int ret = AddTimeout( co_get_curr_thread_env()->pEpoll->pTimeout,&psi->timeout,now ); 1081 | if( ret != 0 ) 1082 | { 1083 | free(psi); 1084 | return ret; 1085 | } 1086 | } 1087 | AddTail( link, psi); 1088 | 1089 | co_yield_ct(); 1090 | 1091 | 1092 | RemoveFromLink( psi ); 1093 | free(psi); 1094 | 1095 | return 0; 1096 | } 1097 | stCoCond_t *co_cond_alloc() 1098 | { 1099 | return (stCoCond_t*)calloc( 1,sizeof(stCoCond_t) ); 1100 | } 1101 | int co_cond_free( stCoCond_t * cc ) 1102 | { 1103 | free( cc ); 1104 | return 0; 1105 | } 1106 | 1107 | 1108 | stCoCondItem_t *co_cond_pop( stCoCond_t *link ) 1109 | { 1110 | stCoCondItem_t *p = link->head; 1111 | if( p ) 1112 | { 1113 | PopHead( link ); 1114 | } 1115 | return p; 1116 | } 1117 | 1118 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /co_routine_specific.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 | #pragma once 20 | #include 21 | #include 22 | 23 | /* 24 | invoke only once in the whole program 25 | CoRoutineSetSpecificCallBack(CoRoutineGetSpecificFunc_t pfnGet,CoRoutineSetSpecificFunc_t pfnSet) 26 | 27 | struct MyData_t 28 | { 29 | int iValue; 30 | char szValue[100]; 31 | }; 32 | CO_ROUTINE_SPECIFIC( MyData_t,__routine ); 33 | 34 | int main() 35 | { 36 | CoRoutineSetSpecificCallBack( co_getspecific,co_setspecific ); 37 | 38 | __routine->iValue = 10; 39 | strcpy( __routine->szValue,"hello world" ); 40 | 41 | return 0; 42 | } 43 | */ 44 | extern int co_setspecific( pthread_key_t key, const void *value ); 45 | extern void * co_getspecific( pthread_key_t key ); 46 | 47 | #define CO_ROUTINE_SPECIFIC( name,y ) \ 48 | \ 49 | static pthread_once_t _routine_once_##name = PTHREAD_ONCE_INIT; \ 50 | static pthread_key_t _routine_key_##name;\ 51 | static int _routine_init_##name = 0;\ 52 | static void _routine_make_key_##name() \ 53 | {\ 54 | (void) pthread_key_create(&_routine_key_##name, NULL); \ 55 | }\ 56 | template \ 57 | class clsRoutineData_routine_##name\ 58 | {\ 59 | public:\ 60 | inline T *operator->()\ 61 | {\ 62 | if( !_routine_init_##name ) \ 63 | {\ 64 | pthread_once( &_routine_once_##name,_routine_make_key_##name );\ 65 | _routine_init_##name = 1;\ 66 | }\ 67 | T* p = (T*)co_getspecific( _routine_key_##name );\ 68 | if( !p )\ 69 | {\ 70 | p = (T*)calloc(1,sizeof( T ));\ 71 | int ret = co_setspecific( _routine_key_##name,p) ;\ 72 | if ( ret )\ 73 | {\ 74 | if ( p )\ 75 | {\ 76 | free(p);\ 77 | p = NULL;\ 78 | }\ 79 | }\ 80 | }\ 81 | return p;\ 82 | }\ 83 | };\ 84 | \ 85 | static clsRoutineData_routine_##name y; 86 | 87 | -------------------------------------------------------------------------------- /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); 101 | 102 | 103 | coctx_param_t* param = (coctx_param_t*)sp ; 104 | param->s1 = s; 105 | param->s2 = s1; 106 | 107 | memset(ctx->regs, 0, sizeof(ctx->regs)); 108 | 109 | ctx->regs[ kESP ] = (char*)(sp) - sizeof(void*); 110 | ctx->regs[ kEIP ] = (char*)pfn; 111 | 112 | return 0; 113 | } 114 | #elif defined(__x86_64__) 115 | int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ) 116 | { 117 | char *sp = ctx->ss_sp + ctx->ss_size; 118 | sp = (char*) ((unsigned long)sp & -16LL ); 119 | 120 | memset(ctx->regs, 0, sizeof(ctx->regs)); 121 | 122 | ctx->regs[ kRSP ] = sp - 8; 123 | 124 | ctx->regs[ kRETAddr] = (char*)pfn; 125 | 126 | ctx->regs[ kRDI ] = (char*)s; 127 | ctx->regs[ kRSI ] = (char*)s1; 128 | return 0; 129 | } 130 | 131 | int coctx_init( coctx_t *ctx ) 132 | { 133 | memset( ctx,0,sizeof(*ctx)); 134 | return 0; 135 | } 136 | 137 | #endif 138 | 139 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /coctx_swap.S: -------------------------------------------------------------------------------- 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 | .globl coctx_swap 20 | #if !defined( __APPLE__ ) 21 | .type coctx_swap, @function 22 | #endif 23 | coctx_swap: 24 | 25 | #if defined(__i386__) 26 | leal 4(%esp), %eax //sp 27 | movl 4(%esp), %esp 28 | leal 32(%esp), %esp //parm a : ®s[7] + sizeof(void*) 29 | 30 | pushl %eax //esp ->parm a 31 | 32 | pushl %ebp 33 | pushl %esi 34 | pushl %edi 35 | pushl %edx 36 | pushl %ecx 37 | pushl %ebx 38 | pushl -4(%eax) 39 | 40 | 41 | movl 4(%eax), %esp //parm b -> ®s[0] 42 | 43 | popl %eax //ret func addr 44 | popl %ebx 45 | popl %ecx 46 | popl %edx 47 | popl %edi 48 | popl %esi 49 | popl %ebp 50 | popl %esp 51 | pushl %eax //set ret func addr 52 | 53 | xorl %eax, %eax 54 | ret 55 | 56 | #elif defined(__x86_64__) 57 | leaq 8(%rsp),%rax 58 | leaq 112(%rdi),%rsp 59 | pushq %rax 60 | pushq %rbx 61 | pushq %rcx 62 | pushq %rdx 63 | 64 | pushq -8(%rax) //ret func addr 65 | 66 | pushq %rsi 67 | pushq %rdi 68 | pushq %rbp 69 | pushq %r8 70 | pushq %r9 71 | pushq %r12 72 | pushq %r13 73 | pushq %r14 74 | pushq %r15 75 | 76 | movq %rsi, %rsp 77 | popq %r15 78 | popq %r14 79 | popq %r13 80 | popq %r12 81 | popq %r9 82 | popq %r8 83 | popq %rbp 84 | popq %rdi 85 | popq %rsi 86 | popq %rax //ret func addr 87 | popq %rdx 88 | popq %rcx 89 | popq %rbx 90 | popq %rsp 91 | pushq %rax 92 | 93 | xorl %eax, %eax 94 | ret 95 | #endif 96 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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