[
  {
    "path": ".gitignore",
    "content": "README.md\n\n# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8)\nproject(libco)\n\n# This for mac osx only\nset(CMAKE_MACOSX_RPATH 0)\n\n# Set lib version\nset(LIBCO_VERSION   0.5)\n\n# Set cflags\nset(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -g -fno-strict-aliasing -O2 -Wall -export-dynamic -Wall -pipe  -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64)\n\n# Use c and asm\nenable_language(C ASM)\n\n# Add source files\nset(SOURCE_FILES\n        co_epoll.cpp\n        co_hook_sys_call.cpp\n        co_routine.cpp\n        coctx.cpp\n        coctx_swap.S)\n\n# Add static and shared library target\nadd_library(colib_static STATIC ${SOURCE_FILES})\nadd_library(colib_shared SHARED ${SOURCE_FILES})\n\n# Set library output name\nset_target_properties(colib_static PROPERTIES OUTPUT_NAME colib)\nset_target_properties(colib_shared PROPERTIES OUTPUT_NAME colib)\n\nset_target_properties(colib_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)\nset_target_properties(colib_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1)\n\n# Set shared library version, will generate libcolib.${LIBCO_VERSION}.so and a symbol link named libcolib.so\n# For mac osx, the extension name will be .dylib\nset_target_properties(colib_shared PROPERTIES VERSION ${LIBCO_VERSION} SOVERSION ${LIBCO_VERSION})\n\n\n\n# Macro for add example target\nmacro(add_example_target EXAMPLE_TARGET)\n    add_executable(\"example_${EXAMPLE_TARGET}\" \"example_${EXAMPLE_TARGET}.cpp\")\n    target_link_libraries(\"example_${EXAMPLE_TARGET}\" colib_static pthread dl)\nendmacro(add_example_target)\n\nadd_example_target(closure)\nadd_example_target(cond)\nadd_example_target(copystack)\nadd_example_target(echocli)\nadd_example_target(echosvr)\nadd_example_target(poll)\nadd_example_target(setenv)\nadd_example_target(specific)\nadd_example_target(thread)\n"
  },
  {
    "path": "Makefile",
    "content": "#\n# Tencent is pleased to support the open source community by making Libco available.\n# \n# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\"); \n# you may not use this file except in compliance with the License. \n# You may obtain a copy of the License at\n# \n#   http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, \n# software distributed under the License is distributed on an \"AS IS\" BASIS, \n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n# See the License for the specific language governing permissions and \n# limitations under the License.\n#\n\n\nCOMM_MAKE = 1\nCOMM_ECHO = 1\nversion=0.5\nv=debug\ninclude co.mk\n\n########## options ##########\nCFLAGS += -g -fno-strict-aliasing -O2 -Wall -export-dynamic \\\n\t-Wall -pipe  -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64\n\nUNAME := $(shell uname -s)\n\nifeq ($(UNAME), FreeBSD)\nLINKS += -g -L./lib -lcolib -lpthread\nelse\nLINKS += -g -L./lib -lcolib -lpthread -ldl\nendif\n\nCOLIB_OBJS=co_epoll.o co_routine.o co_hook_sys_call.o coctx_swap.o coctx.o co_comm.o\n#co_swapcontext.o\n\nPROGS = colib example_poll example_echosvr example_echocli example_thread  example_cond example_specific example_copystack example_closure example_setenv\n\nall:$(PROGS)\n\ncolib:libcolib.a libcolib.so\n\nlibcolib.a: $(COLIB_OBJS)\n\t$(ARSTATICLIB) \nlibcolib.so: $(COLIB_OBJS)\n\t$(BUILDSHARELIB) \n\nexample_echosvr:example_echosvr.o\n\t$(BUILDEXE) \nexample_echocli:example_echocli.o\n\t$(BUILDEXE) \nexample_thread:example_thread.o\n\t$(BUILDEXE) \nexample_poll:example_poll.o\n\t$(BUILDEXE) \nexample_exit:example_exit.o\n\t$(BUILDEXE) \nexample_cond:example_cond.o\n\t$(BUILDEXE)\nexample_specific:example_specific.o\n\t$(BUILDEXE)\nexample_copystack:example_copystack.o\n\t$(BUILDEXE)\nexample_setenv:example_setenv.o\n\t$(BUILDEXE)\nexample_closure:example_closure.o\n\t$(BUILDEXE)\n\ndist: clean libco-$(version).src.tar.gz\n\nlibco-$(version).src.tar.gz:\n\t@find . -type f | grep -v CVS | grep -v .svn | sed s:^./:libco-$(version)/: > MANIFEST\n\t@(cd ..; ln -s libco_pub libco-$(version))\n\t(cd ..; tar cvf - `cat libco_pub/MANIFEST` | gzip > libco_pub/libco-$(version).src.tar.gz)\n\t@(cd ..; rm libco-$(version))\n\nclean:\n\t$(CLEAN) *.o $(PROGS)\n\trm -fr MANIFEST lib solib libco-$(version).src.tar.gz libco-$(version)\n\n"
  },
  {
    "path": "co.mk",
    "content": "#\n# Tencent is pleased to support the open source community by making Libco available.\n#\n# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); \n# you may not use this file except in compliance with the License. \n# You may obtain a copy of the License at\n#\n#\thttp://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, \n# software distributed under the License is distributed on an \"AS IS\" BASIS, \n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n# See the License for the specific language governing permissions and \n# limitations under the License.\n#\n\n\n\n##### Makefile Rules ##########\nMAIL_ROOT=.\nSRCROOT=.\n\n##define the compliers\nCPP = $(CXX)\nAR = ar -rc\nRANLIB = ranlib\n\nCPPSHARE = $(CPP) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o \nCSHARE = $(CC) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o \n\nifeq ($v,release)\nCFLAGS= -O2 $(INCLS) -fPIC  -DLINUX -pipe -Wno-deprecated -c\nelse\nCFLAGS= -g $(INCLS) -fPIC -DLINUX -pipe -c -fno-inline\nendif\n\nifneq ($v,release)\nBFLAGS= -g\nendif\n\nSTATICLIBPATH=$(SRCROOT)/lib\nDYNAMICLIBPATH=$(SRCROOT)/solib\n\nINCLS += -I$(SRCROOT)\n\n## default links\nifeq ($(LINKS_DYNAMIC), 1)\nLINKS += -L$(DYNAMICLIBPATH) -L$(STATICLIBPATH)\nelse\nLINKS += -L$(STATICLIBPATH)\nendif\n\nCPPSRCS  = $(wildcard *.cpp)\nCSRCS  = $(wildcard *.c)\nCPPOBJS  = $(patsubst %.cpp,%.o,$(CPPSRCS))\nCOBJS  = $(patsubst %.c,%.o,$(CSRCS))\n\nSRCS = $(CPPSRCS) $(CSRCS)\nOBJS = $(CPPOBJS) $(COBJS)\n\nCPPCOMPI=$(CPP) $(CFLAGS) -Wno-deprecated\nCCCOMPI=$(CC) $(CFLAGS)\n\nBUILDEXE = $(CPP) $(BFLAGS) -o $@ $^ $(LINKS) \nCLEAN = rm -f *.o \n\nCPPCOMPILE = $(CPPCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@\nCCCOMPILE = $(CCCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@\n\nARSTATICLIB = $(AR) $@.tmp $^ $(AR_FLAGS); \\\n\t\t\t  if [ $$? -ne 0 ]; then exit 1; fi; \\\n\t\t\t  test -d $(STATICLIBPATH) || mkdir -p $(STATICLIBPATH); \\\n\t\t\t  mv -f $@.tmp $(STATICLIBPATH)/$@;\n\nBUILDSHARELIB = $(CPPSHARE) $@.tmp $^ $(BS_FLAGS); \\\n\t\t\t\tif [ $$? -ne 0 ]; then exit 1; fi; \\\n\t\t\t\ttest -d $(DYNAMICLIBPATH) || mkdir -p $(DYNAMICLIBPATH); \\\n\t\t\t\tmv -f $@.tmp $(DYNAMICLIBPATH)/$@;\n\n.cpp.o:\n\t$(CPPCOMPILE)\n.c.o:\n\t$(CCCOMPILE)\n"
  },
  {
    "path": "co_closure.h",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#ifndef __CO_CLOSURE_H__\n#define __CO_CLOSURE_H__\nstruct stCoClosure_t \n{\npublic:\n\tvirtual void exec() = 0;\n\tvirtual ~stCoClosure_t(){}\n};\n\n//1.base \n//-- 1.1 comac_argc\n\n#define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ )\n#define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,N,...) N\n#define comac_args_seqs() 7,6,5,4,3,2,1,0\n#define comac_join_1( x,y ) x##y\n\n#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() )\n#define comac_join( x,y) comac_join_1( x,y )\n\n//-- 1.2 repeat\n#define repeat_0( fun,a,... ) \n#define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ )\n#define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ )\n#define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ )\n#define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ )\n#define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ )\n#define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ )\n\n#define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__)\n\n//2.implement\n#if __cplusplus <= 199711L\n#define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a;\n#else\n#define decl_typeof( i,a,... ) typedef decltype( a ) typeof_##a;\n#endif\n#define impl_typeof( i,a,... ) typeof_##a & a;\n#define impl_typeof_cpy( i,a,... ) typeof_##a a;\n#define con_param_typeof( i,a,... ) typeof_##a & a##r,\n#define param_init_typeof( i,a,... ) a(a##r),\n\n\n//2.1 reference\n\n#define co_ref( name,... )\\\nrepeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\\\nclass type_##name\\\n{\\\npublic:\\\n\trepeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\\\n\tint _member_cnt;\\\n\ttype_##name( \\\n\t\trepeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \\\n\t\trepeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \\\n\t{}\\\n} name( __VA_ARGS__ ) ;\n\n\n//2.2 function\n\n#define co_func(name,...)\\\nrepeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\\\nclass name:public stCoClosure_t\\\n{\\\npublic:\\\n\trepeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\\\n\tint _member_cnt;\\\npublic:\\\n\tname( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \\\n\t\trepeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\\\n\t{}\\\n\tvoid exec()\n\n#define co_func_end }\n\n\n#endif\n\n"
  },
  {
    "path": "co_comm.cpp",
    "content": "#include \"co_comm.h\"\n\nclsCoMutex::clsCoMutex() {\n  m_ptCondSignal = co_cond_alloc();\n  m_iWaitItemCnt = 0;\n}\n\nclsCoMutex::~clsCoMutex() { co_cond_free(m_ptCondSignal); }\n\nvoid clsCoMutex::CoLock() {\n  if (m_iWaitItemCnt > 0) {\n    m_iWaitItemCnt++;\n    co_cond_timedwait(m_ptCondSignal, -1);\n  } else {\n    m_iWaitItemCnt++;\n  }\n}\n\nvoid clsCoMutex::CoUnLock() {\n  m_iWaitItemCnt--;\n  co_cond_signal(m_ptCondSignal);\n}\n\n"
  },
  {
    "path": "co_comm.h",
    "content": "#pragma once\n\n#include \"co_routine.h\"\n\nclass clsCoMutex {\n public:\n  clsCoMutex();\n  ~clsCoMutex();\n\n  void CoLock();\n  void CoUnLock();\n\n private:\n  stCoCond_t* m_ptCondSignal;\n  int m_iWaitItemCnt;\n};\n\nclass clsSmartLock {\n public:\n  clsSmartLock(clsCoMutex* m) {\n    m_ptMutex = m;\n    m_ptMutex->CoLock();\n  }\n  ~clsSmartLock() { m_ptMutex->CoUnLock(); }\n\n private:\n  clsCoMutex* m_ptMutex;\n};\n\n"
  },
  {
    "path": "co_epoll.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include \"co_epoll.h\"\n#include <stdlib.h>\n#include <stdio.h>\n#include <errno.h>\n#include <string.h>\n\n#if !defined( __APPLE__ ) && !defined( __FreeBSD__ )\n\nint\tco_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout )\n{\n\treturn epoll_wait( epfd,events->events,maxevents,timeout );\n}\nint\tco_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev )\n{\n\treturn epoll_ctl( epfd,op,fd,ev );\n}\nint\tco_epoll_create( int size )\n{\n\treturn epoll_create( size );\n}\n\nstruct co_epoll_res *co_epoll_res_alloc( int n )\n{\n\tstruct co_epoll_res * ptr = \n\t\t(struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) );\n\n\tptr->size = n;\n\tptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) );\n\n\treturn ptr;\n\n}\nvoid co_epoll_res_free( struct co_epoll_res * ptr )\n{\n\tif( !ptr ) return;\n\tif( ptr->events ) free( ptr->events );\n\tfree( ptr );\n}\n\n#else\nclass clsFdMap // million of fd , 1024 * 1024 \n{\nprivate:\n\tstatic const int row_size = 1024;\n\tstatic const int col_size = 1024;\n\n\tvoid **m_pp[ 1024 ];\npublic:\n\tclsFdMap()\n\t{\n\t\tmemset( m_pp,0,sizeof(m_pp) );\n\t}\n\t~clsFdMap()\n\t{\n\t\tfor(int i=0;i<sizeof(m_pp)/sizeof(m_pp[0]);i++)\n\t\t{\n\t\t\tif( m_pp[i] ) \n\t\t\t{\n\t\t\t\tfree( m_pp[i] );\n\t\t\t\tm_pp[i] = NULL;\n\t\t\t}\n\t\t}\n\t}\n\tinline int clear( int fd )\n\t{\n\t\tset( fd,NULL );\n\t\treturn 0;\n\t}\n\tinline int set( int fd,const void * ptr )\n\t{\n\t\tint idx = fd / row_size;\n\t\tif( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) )\n\t\t{\n\t\t\tassert( __LINE__ == 0 );\n\t\t\treturn -__LINE__;\n\t\t}\n\t\tif( !m_pp[ idx ] ) \n\t\t{\n\t\t\tm_pp[ idx ] = (void**)calloc( 1,sizeof(void*) * col_size );\n\t\t}\n\t\tm_pp[ idx ][ fd % col_size ] = (void*)ptr;\n\t\treturn 0;\n\t}\n\tinline void *get( int fd )\n\t{\n\t\tint idx = fd / row_size;\n\t\tif( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) )\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\t\tvoid **lp = m_pp[ idx ];\n\t\tif( !lp ) return NULL;\n\n\t\treturn lp[ fd % col_size ];\n\t}\n};\n\n__thread clsFdMap *s_fd_map = NULL;\n\nstatic inline clsFdMap *get_fd_map()\n{\n\tif( !s_fd_map )\n\t{\n\t\ts_fd_map = new clsFdMap();\n\t}\n\treturn s_fd_map;\n}\n\nstruct kevent_pair_t\n{\n\tint fire_idx;\n\tint events;\n\tuint64_t u64;\n};\nint co_epoll_create( int size )\n{\n\treturn kqueue();\n}\nint co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout )\n{\n\tstruct timespec t = { 0 };\n\tif( timeout > 0 )\n\t{\n\t\tt.tv_sec = timeout;\n\t}\n\tint ret = kevent( epfd, \n\t\t\t\t\tNULL, 0, //register null\n\t\t\t\t\tevents->eventlist, maxevents,//just retrival\n\t\t\t\t\t( -1 == timeout ) ? NULL : &t );\n\tint j = 0;\n\tfor(int i=0;i<ret;i++)\n\t{\n\t\tstruct kevent &kev = events->eventlist[i];\n\t\tstruct kevent_pair_t *ptr = (struct kevent_pair_t*)kev.udata;\n\t\tstruct epoll_event *ev = events->events + i;\n\t\tif( 0 == ptr->fire_idx )\n\t\t{\n\t\t\tptr->fire_idx = i + 1;\n\t\t\tmemset( ev,0,sizeof(*ev) );\n\t\t\t++j;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tev = events->events + ptr->fire_idx - 1;\n\t\t}\n\t\tif( EVFILT_READ == kev.filter )\n\t\t{\n\t\t\tev->events |= EPOLLIN;\n\t\t}\n\t\telse if( EVFILT_WRITE == kev.filter )\n\t\t{\n\t\t\tev->events |= EPOLLOUT;\n\t\t}\n\t\tev->data.u64 = ptr->u64;\n\t}\n\tfor(int i=0;i<ret;i++)\n\t{\n\t\t(( struct kevent_pair_t* )(events->eventlist[i].udata) )->fire_idx = 0;\n\t}\n\treturn j;\n}\nint co_epoll_del( int epfd,int fd )\n{\n\n\tstruct timespec t = { 0 };\n\tstruct kevent_pair_t *ptr = ( struct kevent_pair_t* )get_fd_map()->get( fd );\n\tif( !ptr ) return 0;\n\tif( EPOLLIN & ptr->events )\n\t{\n\t\tstruct kevent kev = { 0 };\n\t\tkev.ident = fd;\n\t\tkev.filter = EVFILT_READ;\n\t\tkev.flags = EV_DELETE;\n\t\tkevent( epfd,&kev,1, NULL,0,&t );\n\t}\n\tif( EPOLLOUT & ptr->events )\n\t{\n\t\tstruct kevent kev = { 0 };\n\t\tkev.ident = fd;\n\t\tkev.filter = EVFILT_WRITE;\n\t\tkev.flags = EV_DELETE;\n\t\tkevent( epfd,&kev,1, NULL,0,&t );\n\t}\n\tget_fd_map()->clear( fd );\n\tfree( ptr );\n\treturn 0;\n}\nint co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev )\n{\n\tif( EPOLL_CTL_DEL == op )\n\t{\n\t\treturn co_epoll_del( epfd,fd );\n\t}\n\n\tconst int flags = ( EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP );\n\tif( ev->events & ~flags ) \n\t{\n\t\treturn -1;\n\t}\n\n\tif( EPOLL_CTL_ADD == op && get_fd_map()->get( fd ) )\n\t{\n\t\terrno = EEXIST;\n\t\treturn -1;\n\t}\n\telse if( EPOLL_CTL_MOD == op && !get_fd_map()->get( fd ) )\n\t{\n\t\terrno = ENOENT;\n\t\treturn -1;\n\t}\n\n\tstruct kevent_pair_t *ptr = (struct kevent_pair_t*)get_fd_map()->get( fd );\n\tif( !ptr )\n\t{\n\t\tptr = (kevent_pair_t*)calloc(1,sizeof(kevent_pair_t));\n\t\tget_fd_map()->set( fd,ptr );\n\t}\n\n\tint ret = 0;\n\tstruct timespec t = { 0 };\n\n\t// printf(\"ptr->events 0x%X\\n\",ptr->events);\n\n\tif( EPOLL_CTL_MOD == op )\n\t{\n\t\t//1.delete if exists\n\t\tif( ptr->events & EPOLLIN ) \n\t\t{\n\t\t\tstruct kevent kev = { 0 };\n\t\t\tEV_SET( &kev,fd,EVFILT_READ,EV_DELETE,0,0,NULL );\n\t\t\tkevent( epfd, &kev,1, NULL,0, &t );\n\t\t}\t\n\t\t//1.delete if exists\n\t\tif( ptr->events & EPOLLOUT ) \n\t\t{\n\t\t\tstruct kevent kev = { 0 };\n\t\t\tEV_SET( &kev,fd,EVFILT_WRITE,EV_DELETE,0,0,NULL );\n\t\t\tret = kevent( epfd, &kev,1, NULL,0, &t );\n\t\t\t// printf(\"delete write ret %d\\n\",ret );\n\t\t}\n\t}\n\n\tdo\n\t{\n\t\tif( ev->events & EPOLLIN )\n\t\t{\n\t\t\t\n\t\t\t//2.add\n\t\t\tstruct kevent kev = { 0 };\n\t\t\tEV_SET( &kev,fd,EVFILT_READ,EV_ADD,0,0,ptr );\n\t\t\tret = kevent( epfd, &kev,1, NULL,0, &t );\n\t\t\tif( ret ) break;\n\t\t}\n\t\tif( ev->events & EPOLLOUT )\n\t\t{\n\t\t\t\t//2.add\n\t\t\tstruct kevent kev = { 0 };\n\t\t\tEV_SET( &kev,fd,EVFILT_WRITE,EV_ADD,0,0,ptr );\n\t\t\tret = kevent( epfd, &kev,1, NULL,0, &t );\n\t\t\tif( ret ) break;\n\t\t}\n\t} while( 0 );\n\t\n\tif( ret )\n\t{\n\t\tget_fd_map()->clear( fd );\n\t\tfree( ptr );\n\t\treturn ret;\n\t}\n\n\tptr->events = ev->events;\n\tptr->u64 = ev->data.u64;\n\t \n\n\treturn ret;\n}\n\nstruct co_epoll_res *co_epoll_res_alloc( int n )\n{\n\tstruct co_epoll_res * ptr = \n\t\t(struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) );\n\n\tptr->size = n;\n\tptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) );\n\tptr->eventlist = (struct kevent*)calloc( 1,n * sizeof( struct kevent) );\n\n\treturn ptr;\n}\n\nvoid co_epoll_res_free( struct co_epoll_res * ptr )\n{\n\tif( !ptr ) return;\n\tif( ptr->events ) free( ptr->events );\n\tif( ptr->eventlist ) free( ptr->eventlist );\n\tfree( ptr );\n}\n\n#endif\n\n\n"
  },
  {
    "path": "co_epoll.h",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#ifndef __CO_EPOLL_H__\n#define __CO_EPOLL_H__\n#include <stdint.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <string.h>\n#include <sys/types.h>\n#include <time.h>\n#include <time.h>\n\n#if !defined( __APPLE__ ) && !defined( __FreeBSD__ )\n\n#include <sys/epoll.h>\n\nstruct co_epoll_res\n{\n\tint size;\n\tstruct epoll_event *events;\n\tstruct kevent *eventlist;\n};\nint \tco_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout );\nint \tco_epoll_ctl( int epfd,int op,int fd,struct epoll_event * );\nint \tco_epoll_create( int size );\nstruct \tco_epoll_res *co_epoll_res_alloc( int n );\nvoid \tco_epoll_res_free( struct co_epoll_res * );\n\n#else\n\n#include <sys/event.h>\nenum EPOLL_EVENTS\n{\n\tEPOLLIN = 0X001,\n\tEPOLLPRI = 0X002,\n\tEPOLLOUT = 0X004,\n\n\tEPOLLERR = 0X008,\n\tEPOLLHUP = 0X010,\n\n    EPOLLRDNORM = 0x40,\n    EPOLLWRNORM = 0x004,\n};\n#define EPOLL_CTL_ADD 1\n#define EPOLL_CTL_DEL 2\n#define EPOLL_CTL_MOD 3\ntypedef union epoll_data\n{\n\tvoid *ptr;\n\tint fd;\n\tuint32_t u32;\n\tuint64_t u64;\n\n} epoll_data_t;\n\nstruct epoll_event\n{\n\tuint32_t events;\n\tepoll_data_t data;\n};\n\nstruct co_epoll_res\n{\n\tint size;\n\tstruct epoll_event *events;\n\tstruct kevent *eventlist;\n};\nint \tco_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout );\nint \tco_epoll_ctl( int epfd,int op,int fd,struct epoll_event * );\nint \tco_epoll_create( int size );\nstruct \tco_epoll_res *co_epoll_res_alloc( int n );\nvoid \tco_epoll_res_free( struct co_epoll_res * );\n\n#endif\n#endif\n\n\n"
  },
  {
    "path": "co_hook_sys_call.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <sys/syscall.h>\n#include <sys/un.h>\n\n#include <dlfcn.h>\n#include <poll.h>\n#include <unistd.h>\n#include <fcntl.h>\n\n#include <netinet/in.h>\n#include <errno.h>\n#include <time.h>\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <pthread.h>\n\n#include <resolv.h>\n#include <netdb.h>\n\n#include <time.h>\n#include <map>\n#include \"co_routine.h\"\n#include \"co_routine_inner.h\"\n#include \"co_routine_specific.h\"\n#include \"co_comm.h\"\n\ntypedef long long ll64_t;\n\nstruct rpchook_t\n{\n\tint user_flag;\n\tstruct sockaddr_in dest; //maybe sockaddr_un;\n\tint domain; //AF_LOCAL , AF_INET\n\n\tstruct timeval read_timeout;\n\tstruct timeval write_timeout;\n};\nstatic inline pid_t GetPid()\n{\n\tchar **p = (char**)pthread_self();\n\treturn p ? *(pid_t*)(p + 18) : getpid();\n}\nstatic rpchook_t *g_rpchook_socket_fd[ 102400 ] = { 0 };\n\ntypedef int (*socket_pfn_t)(int domain, int type, int protocol);\ntypedef int (*connect_pfn_t)(int socket, const struct sockaddr *address, socklen_t address_len);\ntypedef int (*close_pfn_t)(int fd);\n\ntypedef ssize_t (*read_pfn_t)(int fildes, void *buf, size_t nbyte);\ntypedef ssize_t (*write_pfn_t)(int fildes, const void *buf, size_t nbyte);\n\ntypedef ssize_t (*sendto_pfn_t)(int socket, const void *message, size_t length,\n\t                 int flags, const struct sockaddr *dest_addr,\n\t\t\t\t\t               socklen_t dest_len);\n\ntypedef ssize_t (*recvfrom_pfn_t)(int socket, void *buffer, size_t length,\n\t                 int flags, struct sockaddr *address,\n\t\t\t\t\t               socklen_t *address_len);\n\ntypedef ssize_t (*send_pfn_t)(int socket, const void *buffer, size_t length, int flags);\ntypedef ssize_t (*recv_pfn_t)(int socket, void *buffer, size_t length, int flags);\n\ntypedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout);\ntypedef int (*setsockopt_pfn_t)(int socket, int level, int option_name,\n\t\t\t                 const void *option_value, socklen_t option_len);\n\ntypedef int (*fcntl_pfn_t)(int fildes, int cmd, ...);\ntypedef struct tm *(*localtime_r_pfn_t)( const time_t *timep, struct tm *result );\n\ntypedef void *(*pthread_getspecific_pfn_t)(pthread_key_t key);\ntypedef int (*pthread_setspecific_pfn_t)(pthread_key_t key, const void *value);\n\ntypedef int (*setenv_pfn_t)(const char *name, const char *value, int overwrite);\ntypedef int (*unsetenv_pfn_t)(const char *name);\ntypedef char *(*getenv_pfn_t)(const char *name);\ntypedef hostent* (*gethostbyname_pfn_t)(const char *name);\ntypedef res_state (*__res_state_pfn_t)();\ntypedef int (*__poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout);\ntypedef int (*gethostbyname_r_pfn_t)(const char* __restrict name, struct hostent* __restrict __result_buf, char* __restrict __buf, size_t __buflen, struct hostent** __restrict __result, int* __restrict __h_errnop);\n\nstatic socket_pfn_t g_sys_socket_func \t= (socket_pfn_t)dlsym(RTLD_NEXT,\"socket\");\nstatic connect_pfn_t g_sys_connect_func = (connect_pfn_t)dlsym(RTLD_NEXT,\"connect\");\nstatic close_pfn_t g_sys_close_func \t= (close_pfn_t)dlsym(RTLD_NEXT,\"close\");\n\nstatic read_pfn_t g_sys_read_func \t\t= (read_pfn_t)dlsym(RTLD_NEXT,\"read\");\nstatic write_pfn_t g_sys_write_func \t= (write_pfn_t)dlsym(RTLD_NEXT,\"write\");\n\nstatic sendto_pfn_t g_sys_sendto_func \t= (sendto_pfn_t)dlsym(RTLD_NEXT,\"sendto\");\nstatic recvfrom_pfn_t g_sys_recvfrom_func = (recvfrom_pfn_t)dlsym(RTLD_NEXT,\"recvfrom\");\n\nstatic send_pfn_t g_sys_send_func \t\t= (send_pfn_t)dlsym(RTLD_NEXT,\"send\");\nstatic recv_pfn_t g_sys_recv_func \t\t= (recv_pfn_t)dlsym(RTLD_NEXT,\"recv\");\n\nstatic poll_pfn_t g_sys_poll_func \t\t= (poll_pfn_t)dlsym(RTLD_NEXT,\"poll\");\n\nstatic setsockopt_pfn_t g_sys_setsockopt_func \n\t\t\t\t\t\t\t\t\t\t= (setsockopt_pfn_t)dlsym(RTLD_NEXT,\"setsockopt\");\nstatic fcntl_pfn_t g_sys_fcntl_func \t= (fcntl_pfn_t)dlsym(RTLD_NEXT,\"fcntl\");\n\nstatic setenv_pfn_t g_sys_setenv_func   = (setenv_pfn_t)dlsym(RTLD_NEXT,\"setenv\");\nstatic unsetenv_pfn_t g_sys_unsetenv_func = (unsetenv_pfn_t)dlsym(RTLD_NEXT,\"unsetenv\");\nstatic getenv_pfn_t g_sys_getenv_func   =  (getenv_pfn_t)dlsym(RTLD_NEXT,\"getenv\");\nstatic __res_state_pfn_t g_sys___res_state_func  = (__res_state_pfn_t)dlsym(RTLD_NEXT,\"__res_state\");\n\nstatic gethostbyname_pfn_t g_sys_gethostbyname_func = (gethostbyname_pfn_t)dlsym(RTLD_NEXT, \"gethostbyname\");\nstatic gethostbyname_r_pfn_t g_sys_gethostbyname_r_func = (gethostbyname_r_pfn_t)dlsym(RTLD_NEXT, \"gethostbyname_r\");\n\nstatic __poll_pfn_t g_sys___poll_func = (__poll_pfn_t)dlsym(RTLD_NEXT, \"__poll\");\n\n\n/*\nstatic pthread_getspecific_pfn_t g_sys_pthread_getspecific_func \n\t\t\t= (pthread_getspecific_pfn_t)dlsym(RTLD_NEXT,\"pthread_getspecific\");\n\nstatic pthread_setspecific_pfn_t g_sys_pthread_setspecific_func \n\t\t\t= (pthread_setspecific_pfn_t)dlsym(RTLD_NEXT,\"pthread_setspecific\");\n\nstatic pthread_rwlock_rdlock_pfn_t g_sys_pthread_rwlock_rdlock_func  \n\t\t\t= (pthread_rwlock_rdlock_pfn_t)dlsym(RTLD_NEXT,\"pthread_rwlock_rdlock\");\n\nstatic pthread_rwlock_wrlock_pfn_t g_sys_pthread_rwlock_wrlock_func  \n\t\t\t= (pthread_rwlock_wrlock_pfn_t)dlsym(RTLD_NEXT,\"pthread_rwlock_wrlock\");\n\nstatic pthread_rwlock_unlock_pfn_t g_sys_pthread_rwlock_unlock_func  \n\t\t\t= (pthread_rwlock_unlock_pfn_t)dlsym(RTLD_NEXT,\"pthread_rwlock_unlock\");\n*/\n\n\n\nstatic inline unsigned long long get_tick_count()\n{\n\tuint32_t lo, hi;\n\t__asm__ __volatile__ (\n\t\t\t\"rdtscp\" : \"=a\"(lo), \"=d\"(hi)\n\t\t\t);\n\treturn ((unsigned long long)lo) | (((unsigned long long)hi) << 32);\n}\n\nstruct rpchook_connagent_head_t\n{\n    unsigned char    bVersion;\n    struct in_addr   iIP;\n    unsigned short   hPort;\n    unsigned int     iBodyLen;\n    unsigned int     iOssAttrID;\n    unsigned char    bIsRespNotExist;\n\tunsigned char    sReserved[6];\n}__attribute__((packed));\n\n\n#define HOOK_SYS_FUNC(name) if( !g_sys_##name##_func ) { g_sys_##name##_func = (name##_pfn_t)dlsym(RTLD_NEXT,#name); }\n\nstatic inline ll64_t diff_ms(struct timeval &begin,struct timeval &end)\n{\n\tll64_t u = (end.tv_sec - begin.tv_sec) ;\n\tu *= 1000 * 10;\n\tu += ( end.tv_usec - begin.tv_usec ) / (  100 );\n\treturn u;\n}\n\n\n\nstatic inline rpchook_t * get_by_fd( int fd )\n{\n\tif( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) )\n\t{\n\t\treturn g_rpchook_socket_fd[ fd ];\n\t}\n\treturn NULL;\n}\nstatic inline rpchook_t * alloc_by_fd( int fd )\n{\n\tif( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) )\n\t{\n\t\trpchook_t *lp = (rpchook_t*)calloc( 1,sizeof(rpchook_t) );\n\t\tlp->read_timeout.tv_sec = 1;\n\t\tlp->write_timeout.tv_sec = 1;\n\t\tg_rpchook_socket_fd[ fd ] = lp;\n\t\treturn lp;\n\t}\n\treturn NULL;\n}\nstatic inline void free_by_fd( int fd )\n{\n\tif( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) )\n\t{\n\t\trpchook_t *lp = g_rpchook_socket_fd[ fd ];\n\t\tif( lp )\n\t\t{\n\t\t\tg_rpchook_socket_fd[ fd ] = NULL;\n\t\t\tfree(lp);\t\n\t\t}\n\t}\n\treturn;\n\n}\nint socket(int domain, int type, int protocol)\n{\n\tHOOK_SYS_FUNC( socket );\n\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_socket_func( domain,type,protocol );\n\t}\n\tint fd = g_sys_socket_func(domain,type,protocol);\n\tif( fd < 0 )\n\t{\n\t\treturn fd;\n\t}\n\n\trpchook_t *lp = alloc_by_fd( fd );\n\tlp->domain = domain;\n\t\n\tfcntl( fd, F_SETFL, g_sys_fcntl_func(fd, F_GETFL,0 ) );\n\n\treturn fd;\n}\n\nint co_accept( int fd, struct sockaddr *addr, socklen_t *len )\n{\n\tint cli = accept( fd,addr,len );\n\tif( cli < 0 )\n\t{\n\t\treturn cli;\n\t}\n\talloc_by_fd( cli );\n\treturn cli;\n}\nint connect(int fd, const struct sockaddr *address, socklen_t address_len)\n{\n\tHOOK_SYS_FUNC( connect );\n\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_connect_func(fd,address,address_len);\n\t}\n\n\t//1.sys call\n\tint ret = g_sys_connect_func( fd,address,address_len );\n\n\trpchook_t *lp = get_by_fd( fd );\n\tif( !lp ) return ret;\n\n\tif( sizeof(lp->dest) >= address_len )\n\t{\n\t\t memcpy( &(lp->dest),address,(int)address_len );\n\t}\n\tif( O_NONBLOCK & lp->user_flag ) \n\t{\n\t\treturn ret;\n\t}\n\t\n\tif (!(ret < 0 && errno == EINPROGRESS))\n\t{\n\t\treturn ret;\n\t}\n\n\t//2.wait\n\tint pollret = 0;\n\tstruct pollfd pf = { 0 };\n\n\tfor(int i=0;i<3;i++) //25s * 3 = 75s\n\t{\n\t\tmemset( &pf,0,sizeof(pf) );\n\t\tpf.fd = fd;\n\t\tpf.events = ( POLLOUT | POLLERR | POLLHUP );\n\n\t\tpollret = poll( &pf,1,25000 );\n\n\t\tif( 1 == pollret  )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif( pf.revents & POLLOUT ) //connect succ\n\t{\n    // 3.check getsockopt ret\n    int err = 0;\n    socklen_t errlen = sizeof(err);\n    ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen);\n    if (ret < 0) {\n      return ret;\n    } else if (err != 0) {\n      errno = err;\n      return -1;\n    }\n    errno = 0;\n    return 0;\n  }\n\n  errno = ETIMEDOUT;\n\treturn ret;\n}\n\n\nint close(int fd)\n{\n\tHOOK_SYS_FUNC( close );\n\t\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_close_func( fd );\n\t}\n\n\tfree_by_fd( fd );\n\tint ret = g_sys_close_func(fd);\n\n\treturn ret;\n}\nssize_t read( int fd, void *buf, size_t nbyte )\n{\n\tHOOK_SYS_FUNC( read );\n\t\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_read_func( fd,buf,nbyte );\n\t}\n\trpchook_t *lp = get_by_fd( fd );\n\n\tif( !lp || ( O_NONBLOCK & lp->user_flag ) ) \n\t{\n\t\tssize_t ret = g_sys_read_func( fd,buf,nbyte );\n\t\treturn ret;\n\t}\n\tint timeout = ( lp->read_timeout.tv_sec * 1000 ) \n\t\t\t\t+ ( lp->read_timeout.tv_usec / 1000 );\n\n\tstruct pollfd pf = { 0 };\n\tpf.fd = fd;\n\tpf.events = ( POLLIN | POLLERR | POLLHUP );\n\n\tint pollret = poll( &pf,1,timeout );\n\n\tssize_t readret = g_sys_read_func( fd,(char*)buf ,nbyte );\n\n\tif( readret < 0 )\n\t{\n\t\tco_log_err(\"CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d\",\n\t\t\t\t\tfd,readret,errno,pollret,timeout);\n\t}\n\n\treturn readret;\n\t\n}\nssize_t write( int fd, const void *buf, size_t nbyte )\n{\n\tHOOK_SYS_FUNC( write );\n\t\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_write_func( fd,buf,nbyte );\n\t}\n\trpchook_t *lp = get_by_fd( fd );\n\n\tif( !lp || ( O_NONBLOCK & lp->user_flag ) )\n\t{\n\t\tssize_t ret = g_sys_write_func( fd,buf,nbyte );\n\t\treturn ret;\n\t}\n\tsize_t wrotelen = 0;\n\tint timeout = ( lp->write_timeout.tv_sec * 1000 ) \n\t\t\t\t+ ( lp->write_timeout.tv_usec / 1000 );\n\n\tssize_t writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen );\n\n\tif (writeret == 0)\n\t{\n\t\treturn writeret;\n\t}\n\n\tif( writeret > 0 )\n\t{\n\t\twrotelen += writeret;\t\n\t}\n\twhile( wrotelen < nbyte )\n\t{\n\n\t\tstruct pollfd pf = { 0 };\n\t\tpf.fd = fd;\n\t\tpf.events = ( POLLOUT | POLLERR | POLLHUP );\n\t\tpoll( &pf,1,timeout );\n\n\t\twriteret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen );\n\t\t\n\t\tif( writeret <= 0 )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\twrotelen += writeret ;\n\t}\n\tif (writeret <= 0 && wrotelen == 0)\n\t{\n\t\treturn writeret;\n\t}\n\treturn wrotelen;\n}\n\nssize_t sendto(int socket, const void *message, size_t length,\n\t                 int flags, const struct sockaddr *dest_addr,\n\t\t\t\t\t               socklen_t dest_len)\n{\n\t/*\n\t\t1.no enable sys call ? sys\n\t\t2.( !lp || lp is non block ) ? sys\n\t\t3.try\n\t\t4.wait\n\t\t5.try\n\t*/\n\tHOOK_SYS_FUNC( sendto );\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );\n\t}\n\n\trpchook_t *lp = get_by_fd( socket );\n\tif( !lp || ( O_NONBLOCK & lp->user_flag ) )\n\t{\n\t\treturn g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );\n\t}\n\n\tssize_t ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );\n\tif( ret < 0 && EAGAIN == errno )\n\t{\n\t\tint timeout = ( lp->write_timeout.tv_sec * 1000 ) \n\t\t\t\t\t+ ( lp->write_timeout.tv_usec / 1000 );\n\n\n\t\tstruct pollfd pf = { 0 };\n\t\tpf.fd = socket;\n\t\tpf.events = ( POLLOUT | POLLERR | POLLHUP );\n\t\tpoll( &pf,1,timeout );\n\n\t\tret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );\n\n\t}\n\treturn ret;\n}\n\nssize_t recvfrom(int socket, void *buffer, size_t length,\n\t                 int flags, struct sockaddr *address,\n\t\t\t\t\t               socklen_t *address_len)\n{\n\tHOOK_SYS_FUNC( recvfrom );\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len );\n\t}\n\n\trpchook_t *lp = get_by_fd( socket );\n\tif( !lp || ( O_NONBLOCK & lp->user_flag ) )\n\t{\n\t\treturn g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len );\n\t}\n\n\tint timeout = ( lp->read_timeout.tv_sec * 1000 ) \n\t\t\t\t+ ( lp->read_timeout.tv_usec / 1000 );\n\n\n\tstruct pollfd pf = { 0 };\n\tpf.fd = socket;\n\tpf.events = ( POLLIN | POLLERR | POLLHUP );\n\tpoll( &pf,1,timeout );\n\n\tssize_t ret = g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len );\n\treturn ret;\n}\n\nssize_t send(int socket, const void *buffer, size_t length, int flags)\n{\n\tHOOK_SYS_FUNC( send );\n\t\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_send_func( socket,buffer,length,flags );\n\t}\n\trpchook_t *lp = get_by_fd( socket );\n\n\tif( !lp || ( O_NONBLOCK & lp->user_flag ) )\n\t{\n\t\treturn g_sys_send_func( socket,buffer,length,flags );\n\t}\n\tsize_t wrotelen = 0;\n\tint timeout = ( lp->write_timeout.tv_sec * 1000 ) \n\t\t\t\t+ ( lp->write_timeout.tv_usec / 1000 );\n\n\tssize_t writeret = g_sys_send_func( socket,buffer,length,flags );\n\tif (writeret == 0)\n\t{\n\t\treturn writeret;\n\t}\n\n\tif( writeret > 0 )\n\t{\n\t\twrotelen += writeret;\t\n\t}\n\twhile( wrotelen < length )\n\t{\n\n\t\tstruct pollfd pf = { 0 };\n\t\tpf.fd = socket;\n\t\tpf.events = ( POLLOUT | POLLERR | POLLHUP );\n\t\tpoll( &pf,1,timeout );\n\n\t\twriteret = g_sys_send_func( socket,(const char*)buffer + wrotelen,length - wrotelen,flags );\n\t\t\n\t\tif( writeret <= 0 )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\twrotelen += writeret ;\n\t}\n\tif (writeret <= 0 && wrotelen == 0)\n\t{\n\t\treturn writeret;\n\t}\n\treturn wrotelen;\n}\n\nssize_t recv( int socket, void *buffer, size_t length, int flags )\n{\n\tHOOK_SYS_FUNC( recv );\n\t\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_recv_func( socket,buffer,length,flags );\n\t}\n\trpchook_t *lp = get_by_fd( socket );\n\n\tif( !lp || ( O_NONBLOCK & lp->user_flag ) ) \n\t{\n\t\treturn g_sys_recv_func( socket,buffer,length,flags );\n\t}\n\tint timeout = ( lp->read_timeout.tv_sec * 1000 ) \n\t\t\t\t+ ( lp->read_timeout.tv_usec / 1000 );\n\n\tstruct pollfd pf = { 0 };\n\tpf.fd = socket;\n\tpf.events = ( POLLIN | POLLERR | POLLHUP );\n\n\tint pollret = poll( &pf,1,timeout );\n\n\tssize_t readret = g_sys_recv_func( socket,buffer,length,flags );\n\n\tif( readret < 0 )\n\t{\n\t\tco_log_err(\"CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d\",\n\t\t\t\t\tsocket,readret,errno,pollret,timeout);\n\t}\n\n\treturn readret;\n\t\n}\n\nextern int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc);\n\nint poll(struct pollfd fds[], nfds_t nfds, int timeout)\n{\n\tHOOK_SYS_FUNC( poll );\n\n\tif (!co_is_enable_sys_hook() || timeout == 0) {\n\t\treturn g_sys_poll_func(fds, nfds, timeout);\n\t}\n\tpollfd *fds_merge = NULL;\n\tnfds_t nfds_merge = 0;\n\tstd::map<int, int> m;  // fd --> idx\n\tstd::map<int, int>::iterator it;\n\tif (nfds > 1) {\n\t\tfds_merge = (pollfd *)malloc(sizeof(pollfd) * nfds);\n\t\tfor (size_t i = 0; i < nfds; i++) {\n\t\t\tif ((it = m.find(fds[i].fd)) == m.end()) {\n\t\t\t\tfds_merge[nfds_merge] = fds[i];\n\t\t\t\tm[fds[i].fd] = nfds_merge;\n\t\t\t\tnfds_merge++;\n\t\t\t} else {\n\t\t\t\tint j = it->second;\n\t\t\t\tfds_merge[j].events |= fds[i].events;  // merge in j slot\n\t\t\t}\n\t\t}\n\t}\n\n\tint ret = 0;\n\tif (nfds_merge == nfds || nfds == 1) {\n\t\tret = co_poll_inner(co_get_epoll_ct(), fds, nfds, timeout, g_sys_poll_func);\n\t} else {\n\t\tret = co_poll_inner(co_get_epoll_ct(), fds_merge, nfds_merge, timeout,\n\t\t\t\tg_sys_poll_func);\n\t\tif (ret > 0) {\n\t\t\tfor (size_t i = 0; i < nfds; i++) {\n\t\t\t\tit = m.find(fds[i].fd);\n\t\t\t\tif (it != m.end()) {\n\t\t\t\t\tint j = it->second;\n\t\t\t\t\tfds[i].revents = fds_merge[j].revents & fds[i].events;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfree(fds_merge);\n\treturn ret;\n\n\n}\nint setsockopt(int fd, int level, int option_name,\n\t\t\t                 const void *option_value, socklen_t option_len)\n{\n\tHOOK_SYS_FUNC( setsockopt );\n\n\tif( !co_is_enable_sys_hook() )\n\t{\n\t\treturn g_sys_setsockopt_func( fd,level,option_name,option_value,option_len );\n\t}\n\trpchook_t *lp = get_by_fd( fd );\n\n\tif( lp && SOL_SOCKET == level )\n\t{\n\t\tstruct timeval *val = (struct timeval*)option_value;\n\t\tif( SO_RCVTIMEO == option_name  ) \n\t\t{\n\t\t\tmemcpy( &lp->read_timeout,val,sizeof(*val) );\n\t\t}\n\t\telse if( SO_SNDTIMEO == option_name )\n\t\t{\n\t\t\tmemcpy( &lp->write_timeout,val,sizeof(*val) );\n\t\t}\n\t}\n\treturn g_sys_setsockopt_func( fd,level,option_name,option_value,option_len );\n}\n\n\nint fcntl(int fildes, int cmd, ...)\n{\n\tHOOK_SYS_FUNC( fcntl );\n\n\tif( fildes < 0 )\n\t{\n\t\treturn __LINE__;\n\t}\n\n\tva_list arg_list;\n\tva_start( arg_list,cmd );\n\n\tint ret = -1;\n\trpchook_t *lp = get_by_fd( fildes );\n\tswitch( cmd )\n\t{\n\t\tcase F_DUPFD:\n\t\t{\n\t\t\tint param = va_arg(arg_list,int);\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,param );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_GETFD:\n\t\t{\n\t\t\tret = g_sys_fcntl_func( fildes,cmd );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_SETFD:\n\t\t{\n\t\t\tint param = va_arg(arg_list,int);\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,param );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_GETFL:\n\t\t{\n\t\t\tret = g_sys_fcntl_func( fildes,cmd );\n\t\t\tif (lp && !(lp->user_flag & O_NONBLOCK)) {\n\t\t\t\tret = ret & (~O_NONBLOCK);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase F_SETFL:\n\t\t{\n\t\t\tint param = va_arg(arg_list,int);\n\t\t\tint flag = param;\n\t\t\tif( co_is_enable_sys_hook() && lp )\n\t\t\t{\n\t\t\t\tflag |= O_NONBLOCK;\n\t\t\t}\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,flag );\n\t\t\tif( 0 == ret && lp )\n\t\t\t{\n\t\t\t\tlp->user_flag = param;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase F_GETOWN:\n\t\t{\n\t\t\tret = g_sys_fcntl_func( fildes,cmd );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_SETOWN:\n\t\t{\n\t\t\tint param = va_arg(arg_list,int);\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,param );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_GETLK:\n\t\t{\n\t\t\tstruct flock *param = va_arg(arg_list,struct flock *);\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,param );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_SETLK:\n\t\t{\n\t\t\tstruct flock *param = va_arg(arg_list,struct flock *);\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,param );\n\t\t\tbreak;\n\t\t}\n\t\tcase F_SETLKW:\n\t\t{\n\t\t\tstruct flock *param = va_arg(arg_list,struct flock *);\n\t\t\tret = g_sys_fcntl_func( fildes,cmd,param );\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tva_end( arg_list );\n\n\treturn ret;\n}\n\nstruct stCoSysEnv_t\n{\n\tchar *name;\t\n\tchar *value;\n};\nstruct stCoSysEnvArr_t\n{\n\tstCoSysEnv_t *data;\n\tsize_t cnt;\n};\nstatic stCoSysEnvArr_t *dup_co_sysenv_arr( stCoSysEnvArr_t * arr )\n{\n\tstCoSysEnvArr_t *lp = (stCoSysEnvArr_t*)calloc( sizeof(stCoSysEnvArr_t),1 );\t\n\tif( arr->cnt )\n\t{\n\t\tlp->data = (stCoSysEnv_t*)calloc( sizeof(stCoSysEnv_t) * arr->cnt,1 );\n\t\tlp->cnt = arr->cnt;\n\t\tmemcpy( lp->data,arr->data,sizeof( stCoSysEnv_t ) * arr->cnt );\n\t}\n\treturn lp;\n}\n\nstatic int co_sysenv_comp(const void *a, const void *b)\n{\n\treturn strcmp(((stCoSysEnv_t*)a)->name, ((stCoSysEnv_t*)b)->name); \n}\nstatic stCoSysEnvArr_t g_co_sysenv = { 0 };\n\n\n  \nvoid co_set_env_list( const char *name[],size_t cnt)\n{\n\tif( g_co_sysenv.data )\n\t{\n\t\treturn ;\n\t}\n\tg_co_sysenv.data = (stCoSysEnv_t*)calloc( 1,sizeof(stCoSysEnv_t) * cnt  );\n\n\tfor(size_t i=0;i<cnt;i++)\n\t{\n\t\tif( name[i] && name[i][0] )\n\t\t{\n\t\t\tg_co_sysenv.data[ g_co_sysenv.cnt++ ].name = strdup( name[i] );\n\t\t}\n\t}\n\tif( g_co_sysenv.cnt > 1 )\n\t{\n\t\tqsort( g_co_sysenv.data,g_co_sysenv.cnt,sizeof(stCoSysEnv_t),co_sysenv_comp );\n\t\tstCoSysEnv_t *lp = g_co_sysenv.data;\n\t\tstCoSysEnv_t *lq = g_co_sysenv.data + 1;\n\t\tfor(size_t i=1;i<g_co_sysenv.cnt;i++)\n\t\t{\n\t\t\tif( strcmp( lp->name,lq->name ) )\n\t\t\t{\n\t\t\t\t++lp;\n\t\t\t\tif( lq != lp  )\n\t\t\t\t{\n\t\t\t\t\t*lp = *lq;\n\t\t\t\t}\n\t\t\t}\n\t\t\t++lq;\n\t\t}\n\t\tg_co_sysenv.cnt = lp - g_co_sysenv.data + 1;\n\t}\n\n}\n\nint setenv(const char *n, const char *value, int overwrite)\n{\n\tHOOK_SYS_FUNC( setenv )\n\tif( co_is_enable_sys_hook() && g_co_sysenv.data )\n\t{\n\t\tstCoRoutine_t *self = co_self();\n\t\tif( self )\n\t\t{\n\t\t\tif( !self->pvEnv )\n\t\t\t{\n\t\t\t\tself->pvEnv = dup_co_sysenv_arr( &g_co_sysenv );\n\t\t\t}\n\t\t\tstCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv);\n\n\t\t\tstCoSysEnv_t name = { (char*)n,0 };\n\n\t\t\tstCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp );\n\n\t\t\tif( e )\n\t\t\t{\n\t\t\t\tif( overwrite || !e->value  )\n\t\t\t\t{\n\t\t\t\t\tif( e->value ) free( e->value );\n\t\t\t\t\te->value = ( value ? strdup( value ) : 0 );\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t}\n\treturn g_sys_setenv_func( n,value,overwrite );\n}\nint unsetenv(const char *n)\n{\n\tHOOK_SYS_FUNC( unsetenv )\n\tif( co_is_enable_sys_hook() && g_co_sysenv.data )\n\t{\n\t\tstCoRoutine_t *self = co_self();\n\t\tif( self )\n\t\t{\n\t\t\tif( !self->pvEnv )\n\t\t\t{\n\t\t\t\tself->pvEnv = dup_co_sysenv_arr( &g_co_sysenv );\n\t\t\t}\n\t\t\tstCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv);\n\n\t\t\tstCoSysEnv_t name = { (char*)n,0 };\n\n\t\t\tstCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp );\n\n\t\t\tif( e )\n\t\t\t{\n\t\t\t\tif( e->value )\n\t\t\t\t{\n\t\t\t\t\tfree( e->value );\n\t\t\t\t\te->value = 0;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t}\n\treturn g_sys_unsetenv_func( n );\n}\nchar *getenv( const char *n )\n{\n\tHOOK_SYS_FUNC( getenv )\n\tif( co_is_enable_sys_hook() && g_co_sysenv.data )\n\t{\n\t\tstCoRoutine_t *self = co_self();\n\n\t\tstCoSysEnv_t name = { (char*)n,0 };\n\n\t\tif( !self->pvEnv )\n\t\t{\n\t\t\tself->pvEnv = dup_co_sysenv_arr( &g_co_sysenv );\n\t\t}\n\t\tstCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv);\n\n\t\tstCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp );\n\n\t\tif( e )\n\t\t{\n\t\t\treturn e->value;\n\t\t}\n\n\t}\n\treturn g_sys_getenv_func( n );\n\n}\nstruct hostent* co_gethostbyname(const char *name);\n\nstruct hostent *gethostbyname(const char *name)\n{\n\tHOOK_SYS_FUNC( gethostbyname );\n\n#if defined( __APPLE__ ) || defined( __FreeBSD__ )\n\treturn g_sys_gethostbyname_func( name );\n#else\n\tif (!co_is_enable_sys_hook())\n\t{\n\t\treturn g_sys_gethostbyname_func(name);\n\t}\n\treturn co_gethostbyname(name);\n#endif\n\n}\n\nint co_gethostbyname_r(const char* __restrict name,\n                       struct hostent* __restrict __result_buf,\n                       char* __restrict __buf, size_t __buflen,\n                       struct hostent** __restrict __result,\n                       int* __restrict __h_errnop) {\n  static __thread clsCoMutex* tls_leaky_dns_lock = NULL; \n  if(tls_leaky_dns_lock == NULL) {\n    tls_leaky_dns_lock = new clsCoMutex();\n  }\n  clsSmartLock auto_lock(tls_leaky_dns_lock);\n  return g_sys_gethostbyname_r_func(name, __result_buf, __buf, __buflen,\n                                    __result, __h_errnop);\n}\n\nint gethostbyname_r(const char* __restrict name,\n                    struct hostent* __restrict __result_buf,\n                    char* __restrict __buf, size_t __buflen,\n                    struct hostent** __restrict __result,\n                    int* __restrict __h_errnop) {\n  HOOK_SYS_FUNC(gethostbyname_r);\n\n#if defined( __APPLE__ ) || defined( __FreeBSD__ )\n\treturn g_sys_gethostbyname_r_func( name );\n#else\n  if (!co_is_enable_sys_hook()) {\n    return g_sys_gethostbyname_r_func(name, __result_buf, __buf, __buflen,\n                                      __result, __h_errnop);\n  }\n\n  return co_gethostbyname_r(name, __result_buf, __buf, __buflen, __result,\n                            __h_errnop);\n#endif\n}\n\nstruct res_state_wrap\n{\n\tstruct __res_state state;\n};\nCO_ROUTINE_SPECIFIC(res_state_wrap, __co_state_wrap);\n\nextern \"C\"\n{\n\tres_state __res_state() \n\t{\n\t\tHOOK_SYS_FUNC(__res_state);\n\n\t\tif (!co_is_enable_sys_hook()) \n\t\t{\n\t\t\treturn g_sys___res_state_func();\n\t\t}\n\n\t\treturn &(__co_state_wrap->state);\n\t}\n\tint __poll(struct pollfd fds[], nfds_t nfds, int timeout)\n\t{\n\t\treturn poll(fds, nfds, timeout);\n\t}\n}\n\nstruct hostbuf_wrap \n{\n\tstruct hostent host;\n\tchar* buffer;\n\tsize_t iBufferSize;\n\tint host_errno;\n};\n\nCO_ROUTINE_SPECIFIC(hostbuf_wrap, __co_hostbuf_wrap);\n\n#if !defined( __APPLE__ ) && !defined( __FreeBSD__ )\nstruct hostent *co_gethostbyname(const char *name)\n{\n\tif (!name)\n\t{\n\t\treturn NULL;\n\t}\n\n\tif (__co_hostbuf_wrap->buffer && __co_hostbuf_wrap->iBufferSize > 1024)\n\t{\n\t\tfree(__co_hostbuf_wrap->buffer);\n\t\t__co_hostbuf_wrap->buffer = NULL;\n\t}\n\tif (!__co_hostbuf_wrap->buffer)\n\t{\n\t\t__co_hostbuf_wrap->buffer = (char*)malloc(1024);\n\t\t__co_hostbuf_wrap->iBufferSize = 1024;\n\t}\n\n\tstruct hostent *host = &__co_hostbuf_wrap->host;\n\tstruct hostent *result = NULL;\n\tint *h_errnop = &(__co_hostbuf_wrap->host_errno);\n\n\tint ret = -1;\n\twhile (ret = gethostbyname_r(name, host, __co_hostbuf_wrap->buffer, \n\t\t\t\t__co_hostbuf_wrap->iBufferSize, &result, h_errnop) == ERANGE && \n\t\t\t\t*h_errnop == NETDB_INTERNAL )\n\t{\n\t\tfree(__co_hostbuf_wrap->buffer);\n\t\t__co_hostbuf_wrap->iBufferSize = __co_hostbuf_wrap->iBufferSize * 2;\n\t\t__co_hostbuf_wrap->buffer = (char*)malloc(__co_hostbuf_wrap->iBufferSize);\n\t}\n\n\tif (ret == 0 && (host == result)) \n\t{\n\t\treturn host;\n\t}\n\treturn NULL;\n}\n#endif\n\n\nvoid co_enable_hook_sys() //这函数必须在这里,否则本文件会被忽略！！！\n{\n\tstCoRoutine_t *co = GetCurrThreadCo();\n\tif( co )\n\t{\n\t\tco->cEnableSysHook = 1;\n\t}\n}\n\n"
  },
  {
    "path": "co_routine.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include \"co_routine.h\"\n#include \"co_routine_inner.h\"\n#include \"co_epoll.h\"\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string>\n#include <map>\n\n#include <poll.h>\n#include <sys/time.h>\n#include <errno.h>\n\n#include <assert.h>\n\n#include <fcntl.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <sys/syscall.h>\n#include <unistd.h>\n#include <limits.h>\n\nextern \"C\"\n{\n\textern void coctx_swap( coctx_t *,coctx_t* ) asm(\"coctx_swap\");\n};\nusing namespace std;\nstCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env );\nstruct stCoEpoll_t;\n\nstruct stCoRoutineEnv_t\n{\n\tstCoRoutine_t *pCallStack[ 128 ];\n\tint iCallStackSize;\n\tstCoEpoll_t *pEpoll;\n\n\t//for copy stack log lastco and nextco\n\tstCoRoutine_t* pending_co;\n\tstCoRoutine_t* occupy_co;\n};\n//int socket(int domain, int type, int protocol);\nvoid co_log_err( const char *fmt,... )\n{\n}\n\n\n#if defined( __LIBCO_RDTSCP__) \nstatic unsigned long long counter(void)\n{\n\tregister uint32_t lo, hi;\n\tregister unsigned long long o;\n\t__asm__ __volatile__ (\n\t\t\t\"rdtscp\" : \"=a\"(lo), \"=d\"(hi)::\"%rcx\"\n\t\t\t);\n\to = hi;\n\to <<= 32;\n\treturn (o | lo);\n\n}\nstatic unsigned long long getCpuKhz()\n{\n\tFILE *fp = fopen(\"/proc/cpuinfo\",\"r\");\n\tif(!fp) return 1;\n\tchar buf[4096] = {0};\n\tfread(buf,1,sizeof(buf),fp);\n\tfclose(fp);\n\n\tchar *lp = strstr(buf,\"cpu MHz\");\n\tif(!lp) return 1;\n\tlp += strlen(\"cpu MHz\");\n\twhile(*lp == ' ' || *lp == '\\t' || *lp == ':')\n\t{\n\t\t++lp;\n\t}\n\n\tdouble mhz = atof(lp);\n\tunsigned long long u = (unsigned long long)(mhz * 1000);\n\treturn u;\n}\n#endif\n\nstatic unsigned long long GetTickMS()\n{\n#if defined( __LIBCO_RDTSCP__) \n\tstatic uint32_t khz = getCpuKhz();\n\treturn counter() / khz;\n#else\n\tstruct timeval now = { 0 };\n\tgettimeofday( &now,NULL );\n\tunsigned long long u = now.tv_sec;\n\tu *= 1000;\n\tu += now.tv_usec / 1000;\n\treturn u;\n#endif\n}\n\n/* no longer use\nstatic pid_t GetPid()\n{\n    static __thread pid_t pid = 0;\n    static __thread pid_t tid = 0;\n    if( !pid || !tid || pid != getpid() )\n    {\n        pid = getpid();\n#if defined( __APPLE__ )\n\t\ttid = syscall( SYS_gettid );\n\t\tif( -1 == (long)tid )\n\t\t{\n\t\t\ttid = pid;\n\t\t}\n#elif defined( __FreeBSD__ )\n\t\tsyscall(SYS_thr_self, &tid);\n\t\tif( tid < 0 )\n\t\t{\n\t\t\ttid = pid;\n\t\t}\n#else \n        tid = syscall( __NR_gettid );\n#endif\n\n    }\n    return tid;\n\n}\nstatic pid_t GetPid()\n{\n\tchar **p = (char**)pthread_self();\n\treturn p ? *(pid_t*)(p + 18) : getpid();\n}\n*/\ntemplate <class T,class TLink>\nvoid RemoveFromLink(T *ap)\n{\n\tTLink *lst = ap->pLink;\n\tif(!lst) return ;\n\tassert( lst->head && lst->tail );\n\n\tif( ap == lst->head )\n\t{\n\t\tlst->head = ap->pNext;\n\t\tif(lst->head)\n\t\t{\n\t\t\tlst->head->pPrev = NULL;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif(ap->pPrev)\n\t\t{\n\t\t\tap->pPrev->pNext = ap->pNext;\n\t\t}\n\t}\n\n\tif( ap == lst->tail )\n\t{\n\t\tlst->tail = ap->pPrev;\n\t\tif(lst->tail)\n\t\t{\n\t\t\tlst->tail->pNext = NULL;\n\t\t}\n\t}\n\telse\n\t{\n\t\tap->pNext->pPrev = ap->pPrev;\n\t}\n\n\tap->pPrev = ap->pNext = NULL;\n\tap->pLink = NULL;\n}\n\ntemplate <class TNode,class TLink>\nvoid inline AddTail(TLink*apLink,TNode *ap)\n{\n\tif( ap->pLink )\n\t{\n\t\treturn ;\n\t}\n\tif(apLink->tail)\n\t{\n\t\tapLink->tail->pNext = (TNode*)ap;\n\t\tap->pNext = NULL;\n\t\tap->pPrev = apLink->tail;\n\t\tapLink->tail = ap;\n\t}\n\telse\n\t{\n\t\tapLink->head = apLink->tail = ap;\n\t\tap->pNext = ap->pPrev = NULL;\n\t}\n\tap->pLink = apLink;\n}\ntemplate <class TNode,class TLink>\nvoid inline PopHead( TLink*apLink )\n{\n\tif( !apLink->head ) \n\t{\n\t\treturn ;\n\t}\n\tTNode *lp = apLink->head;\n\tif( apLink->head == apLink->tail )\n\t{\n\t\tapLink->head = apLink->tail = NULL;\n\t}\n\telse\n\t{\n\t\tapLink->head = apLink->head->pNext;\n\t}\n\n\tlp->pPrev = lp->pNext = NULL;\n\tlp->pLink = NULL;\n\n\tif( apLink->head )\n\t{\n\t\tapLink->head->pPrev = NULL;\n\t}\n}\n\ntemplate <class TNode,class TLink>\nvoid inline Join( TLink*apLink,TLink *apOther )\n{\n\t//printf(\"apOther %p\\n\",apOther);\n\tif( !apOther->head )\n\t{\n\t\treturn ;\n\t}\n\tTNode *lp = apOther->head;\n\twhile( lp )\n\t{\n\t\tlp->pLink = apLink;\n\t\tlp = lp->pNext;\n\t}\n\tlp = apOther->head;\n\tif(apLink->tail)\n\t{\n\t\tapLink->tail->pNext = (TNode*)lp;\n\t\tlp->pPrev = apLink->tail;\n\t\tapLink->tail = apOther->tail;\n\t}\n\telse\n\t{\n\t\tapLink->head = apOther->head;\n\t\tapLink->tail = apOther->tail;\n\t}\n\n\tapOther->head = apOther->tail = NULL;\n}\n\n/////////////////for copy stack //////////////////////////\nstStackMem_t* co_alloc_stackmem(unsigned int stack_size)\n{\n\tstStackMem_t* stack_mem = (stStackMem_t*)malloc(sizeof(stStackMem_t));\n\tstack_mem->occupy_co= NULL;\n\tstack_mem->stack_size = stack_size;\n\tstack_mem->stack_buffer = (char*)malloc(stack_size);\n\tstack_mem->stack_bp = stack_mem->stack_buffer + stack_size;\n\treturn stack_mem;\n}\n\nstShareStack_t* co_alloc_sharestack(int count, int stack_size)\n{\n\tstShareStack_t* share_stack = (stShareStack_t*)malloc(sizeof(stShareStack_t));\n\tshare_stack->alloc_idx = 0;\n\tshare_stack->stack_size = stack_size;\n\n\t//alloc stack array\n\tshare_stack->count = count;\n\tstStackMem_t** stack_array = (stStackMem_t**)calloc(count, sizeof(stStackMem_t*));\n\tfor (int i = 0; i < count; i++)\n\t{\n\t\tstack_array[i] = co_alloc_stackmem(stack_size);\n\t}\n\tshare_stack->stack_array = stack_array;\n\treturn share_stack;\n}\n\nstatic stStackMem_t* co_get_stackmem(stShareStack_t* share_stack)\n{\n\tif (!share_stack)\n\t{\n\t\treturn NULL;\n\t}\n\tint idx = share_stack->alloc_idx % share_stack->count;\n\tshare_stack->alloc_idx++;\n\n\treturn share_stack->stack_array[idx];\n}\n\n\n// ----------------------------------------------------------------------------\nstruct stTimeoutItemLink_t;\nstruct stTimeoutItem_t;\nstruct stCoEpoll_t\n{\n\tint iEpollFd;\n\tstatic const int _EPOLL_SIZE = 1024 * 10;\n\n\tstruct stTimeout_t *pTimeout;\n\n\tstruct stTimeoutItemLink_t *pstTimeoutList;\n\n\tstruct stTimeoutItemLink_t *pstActiveList;\n\n\tco_epoll_res *result; \n\n};\ntypedef void (*OnPreparePfn_t)( stTimeoutItem_t *,struct epoll_event &ev, stTimeoutItemLink_t *active );\ntypedef void (*OnProcessPfn_t)( stTimeoutItem_t *);\nstruct stTimeoutItem_t\n{\n\n\tenum\n\t{\n\t\teMaxTimeout = 40 * 1000 //40s\n\t};\n\tstTimeoutItem_t *pPrev;\n\tstTimeoutItem_t *pNext;\n\tstTimeoutItemLink_t *pLink;\n\n\tunsigned long long ullExpireTime;\n\n\tOnPreparePfn_t pfnPrepare;\n\tOnProcessPfn_t pfnProcess;\n\n\tvoid *pArg; // routine \n\tbool bTimeout;\n};\nstruct stTimeoutItemLink_t\n{\n\tstTimeoutItem_t *head;\n\tstTimeoutItem_t *tail;\n\n};\nstruct stTimeout_t\n{\n\tstTimeoutItemLink_t *pItems;\n\tint iItemSize;\n\n\tunsigned long long ullStart;\n\tlong long llStartIdx;\n};\nstTimeout_t *AllocTimeout( int iSize )\n{\n\tstTimeout_t *lp = (stTimeout_t*)calloc( 1,sizeof(stTimeout_t) );\t\n\n\tlp->iItemSize = iSize;\n\tlp->pItems = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) * lp->iItemSize );\n\n\tlp->ullStart = GetTickMS();\n\tlp->llStartIdx = 0;\n\n\treturn lp;\n}\nvoid FreeTimeout( stTimeout_t *apTimeout )\n{\n\tfree( apTimeout->pItems );\n\tfree ( apTimeout );\n}\nint AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,unsigned long long allNow )\n{\n\tif( apTimeout->ullStart == 0 )\n\t{\n\t\tapTimeout->ullStart = allNow;\n\t\tapTimeout->llStartIdx = 0;\n\t}\n\tif( allNow < apTimeout->ullStart )\n\t{\n\t\tco_log_err(\"CO_ERR: AddTimeout line %d allNow %llu apTimeout->ullStart %llu\",\n\t\t\t\t\t__LINE__,allNow,apTimeout->ullStart);\n\n\t\treturn __LINE__;\n\t}\n\tif( apItem->ullExpireTime < allNow )\n\t{\n\t\tco_log_err(\"CO_ERR: AddTimeout line %d apItem->ullExpireTime %llu allNow %llu apTimeout->ullStart %llu\",\n\t\t\t\t\t__LINE__,apItem->ullExpireTime,allNow,apTimeout->ullStart);\n\n\t\treturn __LINE__;\n\t}\n\tunsigned long long diff = apItem->ullExpireTime - apTimeout->ullStart;\n\n\tif( diff >= (unsigned long long)apTimeout->iItemSize )\n\t{\n\t\tdiff = apTimeout->iItemSize - 1;\n\t\tco_log_err(\"CO_ERR: AddTimeout line %d diff %d\",\n\t\t\t\t\t__LINE__,diff);\n\n\t\t//return __LINE__;\n\t}\n\tAddTail( apTimeout->pItems + ( apTimeout->llStartIdx + diff ) % apTimeout->iItemSize , apItem );\n\n\treturn 0;\n}\ninline void TakeAllTimeout( stTimeout_t *apTimeout,unsigned long long allNow,stTimeoutItemLink_t *apResult )\n{\n\tif( apTimeout->ullStart == 0 )\n\t{\n\t\tapTimeout->ullStart = allNow;\n\t\tapTimeout->llStartIdx = 0;\n\t}\n\n\tif( allNow < apTimeout->ullStart )\n\t{\n\t\treturn ;\n\t}\n\tint cnt = allNow - apTimeout->ullStart + 1;\n\tif( cnt > apTimeout->iItemSize )\n\t{\n\t\tcnt = apTimeout->iItemSize;\n\t}\n\tif( cnt < 0 )\n\t{\n\t\treturn;\n\t}\n\tfor( int i = 0;i<cnt;i++)\n\t{\n\t\tint idx = ( apTimeout->llStartIdx + i) % apTimeout->iItemSize;\n\t\tJoin<stTimeoutItem_t,stTimeoutItemLink_t>( apResult,apTimeout->pItems + idx  );\n\t}\n\tapTimeout->ullStart = allNow;\n\tapTimeout->llStartIdx += cnt - 1;\n\n\n}\nstatic int CoRoutineFunc( stCoRoutine_t *co,void * )\n{\n\tif( co->pfn )\n\t{\n\t\tco->pfn( co->arg );\n\t}\n\tco->cEnd = 1;\n\n\tstCoRoutineEnv_t *env = co->env;\n\n\tco_yield_env( env );\n\n\treturn 0;\n}\n\n\n\nstruct stCoRoutine_t *co_create_env( stCoRoutineEnv_t * env, const stCoRoutineAttr_t* attr,\n\t\tpfn_co_routine_t pfn,void *arg )\n{\n\n\tstCoRoutineAttr_t at;\n\tif( attr )\n\t{\n\t\tmemcpy( &at,attr,sizeof(at) );\n\t}\n\tif( at.stack_size <= 0 )\n\t{\n\t\tat.stack_size = 128 * 1024;\n\t}\n\telse if( at.stack_size > 1024 * 1024 * 8 )\n\t{\n\t\tat.stack_size = 1024 * 1024 * 8;\n\t}\n\n\tif( at.stack_size & 0xFFF ) \n\t{\n\t\tat.stack_size &= ~0xFFF;\n\t\tat.stack_size += 0x1000;\n\t}\n\n\tstCoRoutine_t *lp = (stCoRoutine_t*)malloc( sizeof(stCoRoutine_t) );\n\t\n\tmemset( lp,0,(long)(sizeof(stCoRoutine_t))); \n\n\n\tlp->env = env;\n\tlp->pfn = pfn;\n\tlp->arg = arg;\n\n\tstStackMem_t* stack_mem = NULL;\n\tif( at.share_stack )\n\t{\n\t\tstack_mem = co_get_stackmem( at.share_stack);\n\t\tat.stack_size = at.share_stack->stack_size;\n\t}\n\telse\n\t{\n\t\tstack_mem = co_alloc_stackmem(at.stack_size);\n\t}\n\tlp->stack_mem = stack_mem;\n\n\tlp->ctx.ss_sp = stack_mem->stack_buffer;\n\tlp->ctx.ss_size = at.stack_size;\n\n\tlp->cStart = 0;\n\tlp->cEnd = 0;\n\tlp->cIsMain = 0;\n\tlp->cEnableSysHook = 0;\n\tlp->cIsShareStack = at.share_stack != NULL;\n\n\tlp->save_size = 0;\n\tlp->save_buffer = NULL;\n\n\treturn lp;\n}\n\nint co_create( stCoRoutine_t **ppco,const stCoRoutineAttr_t *attr,pfn_co_routine_t pfn,void *arg )\n{\n\tif( !co_get_curr_thread_env() ) \n\t{\n\t\tco_init_curr_thread_env();\n\t}\n\tstCoRoutine_t *co = co_create_env( co_get_curr_thread_env(), attr, pfn,arg );\n\t*ppco = co;\n\treturn 0;\n}\nvoid co_free( stCoRoutine_t *co )\n{\n    if (!co->cIsShareStack) \n    {    \n        free(co->stack_mem->stack_buffer);\n        free(co->stack_mem);\n    }   \n    //walkerdu fix at 2018-01-20\n    //存在内存泄漏\n    else \n    {\n        if(co->save_buffer)\n            free(co->save_buffer);\n\n        if(co->stack_mem->occupy_co == co)\n            co->stack_mem->occupy_co = NULL;\n    }\n\n    free( co );\n}\nvoid co_release( stCoRoutine_t *co )\n{\n    co_free( co );\n}\n\nvoid co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co);\n\nvoid co_resume( stCoRoutine_t *co )\n{\n\tstCoRoutineEnv_t *env = co->env;\n\tstCoRoutine_t *lpCurrRoutine = env->pCallStack[ env->iCallStackSize - 1 ];\n\tif( !co->cStart )\n\t{\n\t\tcoctx_make( &co->ctx,(coctx_pfn_t)CoRoutineFunc,co,0 );\n\t\tco->cStart = 1;\n\t}\n\tenv->pCallStack[ env->iCallStackSize++ ] = co;\n\tco_swap( lpCurrRoutine, co );\n\n\n}\n\n\n// walkerdu 2018-01-14                                                                              \n// 用于reset超时无法重复使用的协程                                                                  \nvoid co_reset(stCoRoutine_t * co)\n{\n    if(!co->cStart || co->cIsMain)\n        return;\n\n    co->cStart = 0;\n    co->cEnd = 0;\n\n    // 如果当前协程有共享栈被切出的buff，要进行释放\n    if(co->save_buffer)\n    {\n        free(co->save_buffer);\n        co->save_buffer = NULL;\n        co->save_size = 0;\n    }\n\n    // 如果共享栈被当前协程占用，要释放占用标志，否则被切换，会执行save_stack_buffer()\n    if(co->stack_mem->occupy_co == co)\n        co->stack_mem->occupy_co = NULL;\n}\n\nvoid co_yield_env( stCoRoutineEnv_t *env )\n{\n\t\n\tstCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ];\n\tstCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ];\n\n\tenv->iCallStackSize--;\n\n\tco_swap( curr, last);\n}\n\nvoid co_yield_ct()\n{\n\n\tco_yield_env( co_get_curr_thread_env() );\n}\nvoid co_yield( stCoRoutine_t *co )\n{\n\tco_yield_env( co->env );\n}\n\nvoid save_stack_buffer(stCoRoutine_t* occupy_co)\n{\n\t///copy out\n\tstStackMem_t* stack_mem = occupy_co->stack_mem;\n\tint len = stack_mem->stack_bp - occupy_co->stack_sp;\n\n\tif (occupy_co->save_buffer)\n\t{\n\t\tfree(occupy_co->save_buffer), occupy_co->save_buffer = NULL;\n\t}\n\n\toccupy_co->save_buffer = (char*)malloc(len); //malloc buf;\n\toccupy_co->save_size = len;\n\n\tmemcpy(occupy_co->save_buffer, occupy_co->stack_sp, len);\n}\n\nvoid co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co)\n{\n \tstCoRoutineEnv_t* env = co_get_curr_thread_env();\n\n\t//get curr stack sp\n\tchar c;\n\tcurr->stack_sp= &c;\n\n\tif (!pending_co->cIsShareStack)\n\t{\n\t\tenv->pending_co = NULL;\n\t\tenv->occupy_co = NULL;\n\t}\n\telse \n\t{\n\t\tenv->pending_co = pending_co;\n\t\t//get last occupy co on the same stack mem\n\t\tstCoRoutine_t* occupy_co = pending_co->stack_mem->occupy_co;\n\t\t//set pending co to occupy thest stack mem;\n\t\tpending_co->stack_mem->occupy_co = pending_co;\n\n\t\tenv->occupy_co = occupy_co;\n\t\tif (occupy_co && occupy_co != pending_co)\n\t\t{\n\t\t\tsave_stack_buffer(occupy_co);\n\t\t}\n\t}\n\n\t//swap context\n\tcoctx_swap(&(curr->ctx),&(pending_co->ctx) );\n\n\t//stack buffer may be overwrite, so get again;\n\tstCoRoutineEnv_t* curr_env = co_get_curr_thread_env();\n\tstCoRoutine_t* update_occupy_co =  curr_env->occupy_co;\n\tstCoRoutine_t* update_pending_co = curr_env->pending_co;\n\t\n\tif (update_occupy_co && update_pending_co && update_occupy_co != update_pending_co)\n\t{\n\t\t//resume stack buffer\n\t\tif (update_pending_co->save_buffer && update_pending_co->save_size > 0)\n\t\t{\n\t\t\tmemcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size);\n\t\t}\n\t}\n}\n\n\n\n//int poll(struct pollfd fds[], nfds_t nfds, int timeout);\n// { fd,events,revents }\nstruct stPollItem_t ;\nstruct stPoll_t : public stTimeoutItem_t \n{\n\tstruct pollfd *fds;\n\tnfds_t nfds; // typedef unsigned long int nfds_t;\n\n\tstPollItem_t *pPollItems;\n\n\tint iAllEventDetach;\n\n\tint iEpollFd;\n\n\tint iRaiseCnt;\n\n\n};\nstruct stPollItem_t : public stTimeoutItem_t\n{\n\tstruct pollfd *pSelf;\n\tstPoll_t *pPoll;\n\n\tstruct epoll_event stEvent;\n};\n/*\n *   EPOLLPRI \t\tPOLLPRI    // There is urgent data to read.  \n *   EPOLLMSG \t\tPOLLMSG\n *\n *   \t\t\t\tPOLLREMOVE\n *   \t\t\t\tPOLLRDHUP\n *   \t\t\t\tPOLLNVAL\n *\n * */\nstatic uint32_t PollEvent2Epoll( short events )\n{\n\tuint32_t e = 0;\t\n\tif( events & POLLIN ) \te |= EPOLLIN;\n\tif( events & POLLOUT )  e |= EPOLLOUT;\n\tif( events & POLLHUP ) \te |= EPOLLHUP;\n\tif( events & POLLERR )\te |= EPOLLERR;\n\tif( events & POLLRDNORM ) e |= EPOLLRDNORM;\n\tif( events & POLLWRNORM ) e |= EPOLLWRNORM;\n\treturn e;\n}\nstatic short EpollEvent2Poll( uint32_t events )\n{\n\tshort e = 0;\t\n\tif( events & EPOLLIN ) \te |= POLLIN;\n\tif( events & EPOLLOUT ) e |= POLLOUT;\n\tif( events & EPOLLHUP ) e |= POLLHUP;\n\tif( events & EPOLLERR ) e |= POLLERR;\n\tif( events & EPOLLRDNORM ) e |= POLLRDNORM;\n\tif( events & EPOLLWRNORM ) e |= POLLWRNORM;\n\treturn e;\n}\n\nstatic __thread stCoRoutineEnv_t* gCoEnvPerThread = NULL;\n\nvoid co_init_curr_thread_env()\n{\n\tgCoEnvPerThread = (stCoRoutineEnv_t*)calloc( 1, sizeof(stCoRoutineEnv_t) );\n\tstCoRoutineEnv_t *env = gCoEnvPerThread;\n\n\tenv->iCallStackSize = 0;\n\tstruct stCoRoutine_t *self = co_create_env( env, NULL, NULL,NULL );\n\tself->cIsMain = 1;\n\n\tenv->pending_co = NULL;\n\tenv->occupy_co = NULL;\n\n\tcoctx_init( &self->ctx );\n\n\tenv->pCallStack[ env->iCallStackSize++ ] = self;\n\n\tstCoEpoll_t *ev = AllocEpoll();\n\tSetEpoll( env,ev );\n}\nstCoRoutineEnv_t *co_get_curr_thread_env()\n{\n\treturn gCoEnvPerThread;\n}\n\nvoid OnPollProcessEvent( stTimeoutItem_t * ap )\n{\n\tstCoRoutine_t *co = (stCoRoutine_t*)ap->pArg;\n\tco_resume( co );\n}\n\nvoid OnPollPreparePfn( stTimeoutItem_t * ap,struct epoll_event &e,stTimeoutItemLink_t *active )\n{\n\tstPollItem_t *lp = (stPollItem_t *)ap;\n\tlp->pSelf->revents = EpollEvent2Poll( e.events );\n\n\n\tstPoll_t *pPoll = lp->pPoll;\n\tpPoll->iRaiseCnt++;\n\n\tif( !pPoll->iAllEventDetach )\n\t{\n\t\tpPoll->iAllEventDetach = 1;\n\n\t\tRemoveFromLink<stTimeoutItem_t,stTimeoutItemLink_t>( pPoll );\n\n\t\tAddTail( active,pPoll );\n\n\t}\n}\n\n\nvoid co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg )\n{\n\tif( !ctx->result )\n\t{\n\t\tctx->result =  co_epoll_res_alloc( stCoEpoll_t::_EPOLL_SIZE );\n\t}\n\tco_epoll_res *result = ctx->result;\n\n\n\tfor(;;)\n\t{\n\t\tint ret = co_epoll_wait( ctx->iEpollFd,result,stCoEpoll_t::_EPOLL_SIZE, 1 );\n\n\t\tstTimeoutItemLink_t *active = (ctx->pstActiveList);\n\t\tstTimeoutItemLink_t *timeout = (ctx->pstTimeoutList);\n\n\t\tmemset( timeout,0,sizeof(stTimeoutItemLink_t) );\n\n\t\tfor(int i=0;i<ret;i++)\n\t\t{\n\t\t\tstTimeoutItem_t *item = (stTimeoutItem_t*)result->events[i].data.ptr;\n\t\t\tif( item->pfnPrepare )\n\t\t\t{\n\t\t\t\titem->pfnPrepare( item,result->events[i],active );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tAddTail( active,item );\n\t\t\t}\n\t\t}\n\n\n\t\tunsigned long long now = GetTickMS();\n\t\tTakeAllTimeout( ctx->pTimeout,now,timeout );\n\n\t\tstTimeoutItem_t *lp = timeout->head;\n\t\twhile( lp )\n\t\t{\n\t\t\t//printf(\"raise timeout %p\\n\",lp);\n\t\t\tlp->bTimeout = true;\n\t\t\tlp = lp->pNext;\n\t\t}\n\n\t\tJoin<stTimeoutItem_t,stTimeoutItemLink_t>( active,timeout );\n\n\t\tlp = active->head;\n\t\twhile( lp )\n\t\t{\n\n\t\t\tPopHead<stTimeoutItem_t,stTimeoutItemLink_t>( active );\n            if (lp->bTimeout && now < lp->ullExpireTime) \n\t\t\t{\n\t\t\t\tint ret = AddTimeout(ctx->pTimeout, lp, now);\n\t\t\t\tif (!ret) \n\t\t\t\t{\n\t\t\t\t\tlp->bTimeout = false;\n\t\t\t\t\tlp = active->head;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif( lp->pfnProcess )\n\t\t\t{\n\t\t\t\tlp->pfnProcess( lp );\n\t\t\t}\n\n\t\t\tlp = active->head;\n\t\t}\n\t\tif( pfn )\n\t\t{\n\t\t\tif( -1 == pfn( arg ) )\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t}\n}\nvoid OnCoroutineEvent( stTimeoutItem_t * ap )\n{\n\tstCoRoutine_t *co = (stCoRoutine_t*)ap->pArg;\n\tco_resume( co );\n}\n\n\nstCoEpoll_t *AllocEpoll()\n{\n\tstCoEpoll_t *ctx = (stCoEpoll_t*)calloc( 1,sizeof(stCoEpoll_t) );\n\n\tctx->iEpollFd = co_epoll_create( stCoEpoll_t::_EPOLL_SIZE );\n\tctx->pTimeout = AllocTimeout( 60 * 1000 );\n\t\n\tctx->pstActiveList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) );\n\tctx->pstTimeoutList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) );\n\n\n\treturn ctx;\n}\n\nvoid FreeEpoll( stCoEpoll_t *ctx )\n{\n\tif( ctx )\n\t{\n\t\tfree( ctx->pstActiveList );\n\t\tfree( ctx->pstTimeoutList );\n\t\tFreeTimeout( ctx->pTimeout );\n\t\tco_epoll_res_free( ctx->result );\n\t}\n\tfree( ctx );\n}\n\nstCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env )\n{\n\treturn env->pCallStack[ env->iCallStackSize - 1 ];\n}\nstCoRoutine_t *GetCurrThreadCo( )\n{\n\tstCoRoutineEnv_t *env = co_get_curr_thread_env();\n\tif( !env ) return 0;\n\treturn GetCurrCo(env);\n}\n\n\n\ntypedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout);\nint co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc)\n{\n    if (timeout == 0)\n\t{\n\t\treturn pollfunc(fds, nfds, timeout);\n\t}\n\tif (timeout < 0)\n\t{\n\t\ttimeout = INT_MAX;\n\t}\n\tint epfd = ctx->iEpollFd;\n\tstCoRoutine_t* self = co_self();\n\n\t//1.struct change\n\tstPoll_t& arg = *((stPoll_t*)malloc(sizeof(stPoll_t)));\n\tmemset( &arg,0,sizeof(arg) );\n\n\targ.iEpollFd = epfd;\n\targ.fds = (pollfd*)calloc(nfds, sizeof(pollfd));\n\targ.nfds = nfds;\n\n\tstPollItem_t arr[2];\n\tif( nfds < sizeof(arr) / sizeof(arr[0]) && !self->cIsShareStack)\n\t{\n\t\targ.pPollItems = arr;\n\t}\t\n\telse\n\t{\n\t\targ.pPollItems = (stPollItem_t*)malloc( nfds * sizeof( stPollItem_t ) );\n\t}\n\tmemset( arg.pPollItems,0,nfds * sizeof(stPollItem_t) );\n\n\targ.pfnProcess = OnPollProcessEvent;\n\targ.pArg = GetCurrCo( co_get_curr_thread_env() );\n\t\n\t\n\t//2. add epoll\n\tfor(nfds_t i=0;i<nfds;i++)\n\t{\n\t\targ.pPollItems[i].pSelf = arg.fds + i;\n\t\targ.pPollItems[i].pPoll = &arg;\n\n\t\targ.pPollItems[i].pfnPrepare = OnPollPreparePfn;\n\t\tstruct epoll_event &ev = arg.pPollItems[i].stEvent;\n\n\t\tif( fds[i].fd > -1 )\n\t\t{\n\t\t\tev.data.ptr = arg.pPollItems + i;\n\t\t\tev.events = PollEvent2Epoll( fds[i].events );\n\n\t\t\tint ret = co_epoll_ctl( epfd,EPOLL_CTL_ADD, fds[i].fd, &ev );\n\t\t\tif (ret < 0 && errno == EPERM && nfds == 1 && pollfunc != NULL)\n\t\t\t{\n\t\t\t\tif( arg.pPollItems != arr )\n\t\t\t\t{\n\t\t\t\t\tfree( arg.pPollItems );\n\t\t\t\t\targ.pPollItems = NULL;\n\t\t\t\t}\n\t\t\t\tfree(arg.fds);\n\t\t\t\tfree(&arg);\n\t\t\t\treturn pollfunc(fds, nfds, timeout);\n\t\t\t}\n\t\t}\n\t\t//if fail,the timeout would work\n\t}\n\n\t//3.add timeout\n\n\tunsigned long long now = GetTickMS();\n\targ.ullExpireTime = now + timeout;\n\tint ret = AddTimeout( ctx->pTimeout,&arg,now );\n\tint iRaiseCnt = 0;\n\tif( ret != 0 )\n\t{\n\t\tco_log_err(\"CO_ERR: AddTimeout ret %d now %lld timeout %d arg.ullExpireTime %lld\",\n\t\t\t\tret,now,timeout,arg.ullExpireTime);\n\t\terrno = EINVAL;\n\t\tiRaiseCnt = -1;\n\n\t}\n    else\n\t{\n\t\tco_yield_env( co_get_curr_thread_env() );\n\t\tiRaiseCnt = arg.iRaiseCnt;\n\t}\n\n    {\n\t\t//clear epoll status and memory\n\t\tRemoveFromLink<stTimeoutItem_t,stTimeoutItemLink_t>( &arg );\n\t\tfor(nfds_t i = 0;i < nfds;i++)\n\t\t{\n\t\t\tint fd = fds[i].fd;\n\t\t\tif( fd > -1 )\n\t\t\t{\n\t\t\t\tco_epoll_ctl( epfd,EPOLL_CTL_DEL,fd,&arg.pPollItems[i].stEvent );\n\t\t\t}\n\t\t\tfds[i].revents = arg.fds[i].revents;\n\t\t}\n\n\n\t\tif( arg.pPollItems != arr )\n\t\t{\n\t\t\tfree( arg.pPollItems );\n\t\t\targ.pPollItems = NULL;\n\t\t}\n\n\t\tfree(arg.fds);\n\t\tfree(&arg);\n\t}\n\n\treturn iRaiseCnt;\n}\n\nint\tco_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms )\n{\n\treturn co_poll_inner(ctx, fds, nfds, timeout_ms, NULL);\n}\n\nvoid SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev )\n{\n\tenv->pEpoll = ev;\n}\nstCoEpoll_t *co_get_epoll_ct()\n{\n\tif( !co_get_curr_thread_env() )\n\t{\n\t\tco_init_curr_thread_env();\n\t}\n\treturn co_get_curr_thread_env()->pEpoll;\n}\nstruct stHookPThreadSpec_t\n{\n\tstCoRoutine_t *co;\n\tvoid *value;\n\n\tenum \n\t{\n\t\tsize = 1024\n\t};\n};\nvoid *co_getspecific(pthread_key_t key)\n{\n\tstCoRoutine_t *co = GetCurrThreadCo();\n\tif( !co || co->cIsMain )\n\t{\n\t\treturn pthread_getspecific( key );\n\t}\n\treturn co->aSpec[ key ].value;\n}\nint co_setspecific(pthread_key_t key, const void *value)\n{\n\tstCoRoutine_t *co = GetCurrThreadCo();\n\tif( !co || co->cIsMain )\n\t{\n\t\treturn pthread_setspecific( key,value );\n\t}\n\tco->aSpec[ key ].value = (void*)value;\n\treturn 0;\n}\n\n\n\nvoid co_disable_hook_sys()\n{\n\tstCoRoutine_t *co = GetCurrThreadCo();\n\tif( co )\n\t{\n\t\tco->cEnableSysHook = 0;\n\t}\n}\nbool co_is_enable_sys_hook()\n{\n\tstCoRoutine_t *co = GetCurrThreadCo();\n\treturn ( co && co->cEnableSysHook );\n}\n\nstCoRoutine_t *co_self()\n{\n\treturn GetCurrThreadCo();\n}\n\n//co cond\nstruct stCoCond_t;\nstruct stCoCondItem_t \n{\n\tstCoCondItem_t *pPrev;\n\tstCoCondItem_t *pNext;\n\tstCoCond_t *pLink;\n\n\tstTimeoutItem_t timeout;\n};\nstruct stCoCond_t\n{\n\tstCoCondItem_t *head;\n\tstCoCondItem_t *tail;\n};\nstatic void OnSignalProcessEvent( stTimeoutItem_t * ap )\n{\n\tstCoRoutine_t *co = (stCoRoutine_t*)ap->pArg;\n\tco_resume( co );\n}\n\nstCoCondItem_t *co_cond_pop( stCoCond_t *link );\nint co_cond_signal( stCoCond_t *si )\n{\n\tstCoCondItem_t * sp = co_cond_pop( si );\n\tif( !sp ) \n\t{\n\t\treturn 0;\n\t}\n\tRemoveFromLink<stTimeoutItem_t,stTimeoutItemLink_t>( &sp->timeout );\n\n\tAddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout );\n\n\treturn 0;\n}\nint co_cond_broadcast( stCoCond_t *si )\n{\n\tfor(;;)\n\t{\n\t\tstCoCondItem_t * sp = co_cond_pop( si );\n\t\tif( !sp ) return 0;\n\n\t\tRemoveFromLink<stTimeoutItem_t,stTimeoutItemLink_t>( &sp->timeout );\n\n\t\tAddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout );\n\t}\n\n\treturn 0;\n}\n\n\nint co_cond_timedwait( stCoCond_t *link,int ms )\n{\n\tstCoCondItem_t* psi = (stCoCondItem_t*)calloc(1, sizeof(stCoCondItem_t));\n\tpsi->timeout.pArg = GetCurrThreadCo();\n\tpsi->timeout.pfnProcess = OnSignalProcessEvent;\n\n\tif( ms > 0 )\n\t{\n\t\tunsigned long long now = GetTickMS();\n\t\tpsi->timeout.ullExpireTime = now + ms;\n\n\t\tint ret = AddTimeout( co_get_curr_thread_env()->pEpoll->pTimeout,&psi->timeout,now );\n\t\tif( ret != 0 )\n\t\t{\n\t\t\tfree(psi);\n\t\t\treturn ret;\n\t\t}\n\t}\n\tAddTail( link, psi);\n\n\tco_yield_ct();\n\n\n\tRemoveFromLink<stCoCondItem_t,stCoCond_t>( psi );\n\tfree(psi);\n\n\treturn 0;\n}\nstCoCond_t *co_cond_alloc()\n{\n\treturn (stCoCond_t*)calloc( 1,sizeof(stCoCond_t) );\n}\nint co_cond_free( stCoCond_t * cc )\n{\n\tfree( cc );\n\treturn 0;\n}\n\n\nstCoCondItem_t *co_cond_pop( stCoCond_t *link )\n{\n\tstCoCondItem_t *p = link->head;\n\tif( p )\n\t{\n\t\tPopHead<stCoCondItem_t,stCoCond_t>( link );\n\t}\n\treturn p;\n}\n"
  },
  {
    "path": "co_routine.h",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#ifndef __CO_ROUTINE_H__\n#define __CO_ROUTINE_H__\n\n#include <stdint.h>\n#include <sys/poll.h>\n#include <pthread.h>\n\n//1.struct\n\nstruct stCoRoutine_t;\nstruct stShareStack_t;\n\nstruct stCoRoutineAttr_t\n{\n\tint stack_size;\n\tstShareStack_t*  share_stack;\n\tstCoRoutineAttr_t()\n\t{\n\t\tstack_size = 128 * 1024;\n\t\tshare_stack = NULL;\n\t}\n}__attribute__ ((packed));\n\nstruct stCoEpoll_t;\ntypedef int (*pfn_co_eventloop_t)(void *);\ntypedef void *(*pfn_co_routine_t)( void * );\n\n//2.co_routine\n\nint \tco_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg );\nvoid    co_resume( stCoRoutine_t *co );\nvoid    co_yield( stCoRoutine_t *co );\nvoid    co_yield_ct(); //ct = current thread\nvoid    co_release( stCoRoutine_t *co );\nvoid    co_reset(stCoRoutine_t * co); \n\nstCoRoutine_t *co_self();\n\nint\t\tco_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms );\nvoid \tco_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg );\n\n//3.specific\n\nint \tco_setspecific( pthread_key_t key, const void *value );\nvoid *\tco_getspecific( pthread_key_t key );\n\n//4.event\n\nstCoEpoll_t * \tco_get_epoll_ct(); //ct = current thread\n\n//5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto )\n\nvoid \tco_enable_hook_sys();  \nvoid \tco_disable_hook_sys();  \nbool \tco_is_enable_sys_hook();\n\n//6.sync\nstruct stCoCond_t;\n\nstCoCond_t *co_cond_alloc();\nint co_cond_free( stCoCond_t * cc );\n\nint co_cond_signal( stCoCond_t * );\nint co_cond_broadcast( stCoCond_t * );\nint co_cond_timedwait( stCoCond_t *,int timeout_ms );\n\n//7.share stack\nstShareStack_t* co_alloc_sharestack(int iCount, int iStackSize);\n\n//8.init envlist for hook get/set env\nvoid co_set_env_list( const char *name[],size_t cnt);\n\nvoid co_log_err( const char *fmt,... );\n#endif\n\n"
  },
  {
    "path": "co_routine_inner.h",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n\n#ifndef __CO_ROUTINE_INNER_H__\n\n#include \"co_routine.h\"\n#include \"coctx.h\"\nstruct stCoRoutineEnv_t;\nstruct stCoSpec_t\n{\n\tvoid *value;\n};\n\nstruct stStackMem_t\n{\n\tstCoRoutine_t* occupy_co;\n\tint stack_size;\n\tchar* stack_bp; //stack_buffer + stack_size\n\tchar* stack_buffer;\n\n};\n\nstruct stShareStack_t\n{\n\tunsigned int alloc_idx;\n\tint stack_size;\n\tint count;\n\tstStackMem_t** stack_array;\n};\n\n\n\nstruct stCoRoutine_t\n{\n\tstCoRoutineEnv_t *env;\n\tpfn_co_routine_t pfn;\n\tvoid *arg;\n\tcoctx_t ctx;\n\n\tchar cStart;\n\tchar cEnd;\n\tchar cIsMain;\n\tchar cEnableSysHook;\n\tchar cIsShareStack;\n\n\tvoid *pvEnv;\n\n\t//char sRunStack[ 1024 * 128 ];\n\tstStackMem_t* stack_mem;\n\n\n\t//save satck buffer while confilct on same stack_buffer;\n\tchar* stack_sp; \n\tunsigned int save_size;\n\tchar* save_buffer;\n\n\tstCoSpec_t aSpec[1024];\n\n};\n\n\n\n//1.env\nvoid \t\t\t\tco_init_curr_thread_env();\nstCoRoutineEnv_t *\tco_get_curr_thread_env();\n\n//2.coroutine\nvoid    co_free( stCoRoutine_t * co );\nvoid    co_yield_env(  stCoRoutineEnv_t *env );\n\n//3.func\n\n\n\n//-----------------------------------------------------------------------------------------------\n\nstruct stTimeout_t;\nstruct stTimeoutItem_t ;\n\nstTimeout_t *AllocTimeout( int iSize );\nvoid \tFreeTimeout( stTimeout_t *apTimeout );\nint  \tAddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow );\n\nstruct stCoEpoll_t;\nstCoEpoll_t * AllocEpoll();\nvoid \t\tFreeEpoll( stCoEpoll_t *ctx );\n\nstCoRoutine_t *\t\tGetCurrThreadCo();\nvoid \t\t\t\tSetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev );\n\ntypedef void (*pfnCoRoutineFunc_t)();\n\n#endif\n\n#define __CO_ROUTINE_INNER_H__\n"
  },
  {
    "path": "co_routine_specific.h",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#pragma once\n#include <pthread.h>\n#include <stdlib.h>\n\n/*\ninvoke only once in the whole program\nCoRoutineSetSpecificCallBack(CoRoutineGetSpecificFunc_t pfnGet,CoRoutineSetSpecificFunc_t pfnSet)\n\nstruct MyData_t\n{\n\tint iValue;\n\tchar szValue[100];\n};\nCO_ROUTINE_SPECIFIC( MyData_t,__routine );\n\nint main()\n{\n\tCoRoutineSetSpecificCallBack( co_getspecific,co_setspecific );\n\n\t__routine->iValue = 10;\n\tstrcpy( __routine->szValue,\"hello world\" );\n\n\treturn 0;\n}\n*/\nextern int \tco_setspecific( pthread_key_t key, const void *value );\nextern void *\tco_getspecific( pthread_key_t key );\n\n#define CO_ROUTINE_SPECIFIC( name,y ) \\\n\\\nstatic pthread_once_t _routine_once_##name = PTHREAD_ONCE_INIT; \\\nstatic pthread_key_t _routine_key_##name;\\\nstatic int _routine_init_##name = 0;\\\nstatic void _routine_make_key_##name() \\\n{\\\n \t(void) pthread_key_create(&_routine_key_##name, NULL); \\\n}\\\ntemplate <class T>\\\nclass clsRoutineData_routine_##name\\\n{\\\npublic:\\\n\tinline T *operator->()\\\n\t{\\\n\t\tif( !_routine_init_##name ) \\\n\t\t{\\\n\t\t\tpthread_once( &_routine_once_##name,_routine_make_key_##name );\\\n\t\t\t_routine_init_##name = 1;\\\n\t\t}\\\n\t\tT* p = (T*)co_getspecific( _routine_key_##name );\\\n\t\tif( !p )\\\n\t\t{\\\n\t\t\tp = (T*)calloc(1,sizeof( T ));\\\n\t\t\tint ret = co_setspecific( _routine_key_##name,p) ;\\\n            if ( ret )\\\n            {\\\n                if ( p )\\\n                {\\\n                    free(p);\\\n                    p = NULL;\\\n                }\\\n            }\\\n\t\t}\\\n\t\treturn p;\\\n\t}\\\n};\\\n\\\nstatic clsRoutineData_routine_##name<name> y;\n\n"
  },
  {
    "path": "coctx.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco\navailable.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n#include \"coctx.h\"\n#include <stdio.h>\n#include <string.h>\n\n#define ESP 0\n#define EIP 1\n#define EAX 2\n#define ECX 3\n// -----------\n#define RSP 0\n#define RIP 1\n#define RBX 2\n#define RDI 3\n#define RSI 4\n\n#define RBP 5\n#define R12 6\n#define R13 7\n#define R14 8\n#define R15 9\n#define RDX 10\n#define RCX 11\n#define R8 12\n#define R9 13\n\n//----- --------\n// 32 bit\n// | regs[0]: ret |\n// | regs[1]: ebx |\n// | regs[2]: ecx |\n// | regs[3]: edx |\n// | regs[4]: edi |\n// | regs[5]: esi |\n// | regs[6]: ebp |\n// | regs[7]: eax |  = esp\nenum {\n  kEIP = 0,\n  kEBP = 6,\n  kESP = 7,\n};\n\n//-------------\n// 64 bit\n// low | regs[0]: r15 |\n//    | regs[1]: r14 |\n//    | regs[2]: r13 |\n//    | regs[3]: r12 |\n//    | regs[4]: r9  |\n//    | regs[5]: r8  |\n//    | regs[6]: rbp |\n//    | regs[7]: rdi |\n//    | regs[8]: rsi |\n//    | regs[9]: ret |  //ret func addr\n//    | regs[10]: rdx |\n//    | regs[11]: rcx |\n//    | regs[12]: rbx |\n// hig | regs[13]: rsp |\nenum {\n  kRDI = 7,\n  kRSI = 8,\n  kRETAddr = 9,\n  kRSP = 13,\n};\n\n// 64 bit\nextern \"C\" {\nextern void coctx_swap(coctx_t*, coctx_t*) asm(\"coctx_swap\");\n};\n#if defined(__i386__)\nint coctx_init(coctx_t* ctx) {\n  memset(ctx, 0, sizeof(*ctx));\n  return 0;\n}\nint coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) {\n  // make room for coctx_param\n  char* sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t);\n  sp = (char*)((unsigned long)sp & -16L);\n\n  coctx_param_t* param = (coctx_param_t*)sp;\n  void** ret_addr = (void**)(sp - sizeof(void*) * 2);\n  *ret_addr = (void*)pfn;\n  param->s1 = s;\n  param->s2 = s1;\n\n  memset(ctx->regs, 0, sizeof(ctx->regs));\n\n  ctx->regs[kESP] = (char*)(sp) - sizeof(void*) * 2;\n  return 0;\n}\n#elif defined(__x86_64__)\nint coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) {\n  char* sp = ctx->ss_sp + ctx->ss_size - sizeof(void*);\n  sp = (char*)((unsigned long)sp & -16LL);\n\n  memset(ctx->regs, 0, sizeof(ctx->regs));\n  void** ret_addr = (void**)(sp);\n  *ret_addr = (void*)pfn;\n\n  ctx->regs[kRSP] = sp;\n\n  ctx->regs[kRETAddr] = (char*)pfn;\n\n  ctx->regs[kRDI] = (char*)s;\n  ctx->regs[kRSI] = (char*)s1;\n  return 0;\n}\n\nint coctx_init(coctx_t* ctx) {\n  memset(ctx, 0, sizeof(*ctx));\n  return 0;\n}\n\n#endif\n"
  },
  {
    "path": "coctx.h",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#ifndef __CO_CTX_H__\n#define __CO_CTX_H__\n#include <stdlib.h>\ntypedef void* (*coctx_pfn_t)( void* s, void* s2 );\nstruct coctx_param_t\n{\n\tconst void *s1;\n\tconst void *s2;\n};\nstruct coctx_t\n{\n#if defined(__i386__)\n\tvoid *regs[ 8 ];\n#else\n\tvoid *regs[ 14 ];\n#endif\n\tsize_t ss_size;\n\tchar *ss_sp;\n\t\n};\n\nint coctx_init( coctx_t *ctx );\nint coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 );\n#endif\n"
  },
  {
    "path": "coctx_swap.S",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n.globl coctx_swap\n#if !defined( __APPLE__ )\n.type  coctx_swap, @function\n#endif\ncoctx_swap:\n\n#if defined(__i386__)\n    movl 4(%esp), %eax\n    movl %esp,  28(%eax)\n    movl %ebp, 24(%eax)\n    movl %esi, 20(%eax)\n    movl %edi, 16(%eax)\n    movl %edx, 12(%eax)\n    movl %ecx, 8(%eax)\n    movl %ebx, 4(%eax)\n\n\n    movl 8(%esp), %eax\n    movl 4(%eax), %ebx\n    movl 8(%eax), %ecx\n    movl 12(%eax), %edx\n    movl 16(%eax), %edi\n    movl 20(%eax), %esi\n    movl 24(%eax), %ebp\n    movl 28(%eax), %esp\n\n\tret\n\n#elif defined(__x86_64__)\n\tleaq (%rsp),%rax\n    movq %rax, 104(%rdi)\n    movq %rbx, 96(%rdi)\n    movq %rcx, 88(%rdi)\n    movq %rdx, 80(%rdi)\n\t  movq 0(%rax), %rax\n\t  movq %rax, 72(%rdi) \n    movq %rsi, 64(%rdi)\n\t  movq %rdi, 56(%rdi)\n    movq %rbp, 48(%rdi)\n    movq %r8, 40(%rdi)\n    movq %r9, 32(%rdi)\n    movq %r12, 24(%rdi)\n    movq %r13, 16(%rdi)\n    movq %r14, 8(%rdi)\n    movq %r15, (%rdi)\n\t  xorq %rax, %rax\n\n    movq 48(%rsi), %rbp\n    movq 104(%rsi), %rsp\n    movq (%rsi), %r15\n    movq 8(%rsi), %r14\n    movq 16(%rsi), %r13\n    movq 24(%rsi), %r12\n    movq 32(%rsi), %r9\n    movq 40(%rsi), %r8\n    movq 56(%rsi), %rdi\n    movq 80(%rsi), %rdx\n    movq 88(%rsi), %rcx\n    movq 96(%rsi), %rbx\n\t\tleaq 8(%rsp), %rsp\n\t\tpushq 72(%rsi)\n\n    movq 64(%rsi), %rsi\n\tret\n#endif\n"
  },
  {
    "path": "example_closure.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include \"co_closure.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <vector>\n#include <pthread.h>\n#include <unistd.h>\nusing namespace std;\n\nstatic void *thread_func( void * arg )\n{\n\tstCoClosure_t *p = (stCoClosure_t*) arg;\n\tp->exec();\n\treturn 0;\n}\nstatic void batch_exec( vector<stCoClosure_t*> &v )\n{\n\tvector<pthread_t> ths;\n\tfor( size_t i=0;i<v.size();i++ )\n\t{\n\t\tpthread_t tid;\n\t\tpthread_create( &tid,0,thread_func,v[i] );\n\t\tths.push_back( tid );\n\t}\n\tfor( size_t i=0;i<v.size();i++ )\n\t{\n\t\tpthread_join( ths[i],0 );\n\t}\n}\nint main( int argc,char *argv[] )\n{\n\tvector< stCoClosure_t* > v;\n\n\tpthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;\n\n\tint total = 100;\n\tvector<int> v2;\n\tco_ref( ref,total,v2,m);\n\tfor(int i=0;i<10;i++)\n\t{\n\t\tco_func( f,ref,i )\n\t\t{\n\t\t\tprintf(\"ref.total %d i %d\\n\",ref.total,i );\n\t\t\t//lock\n\t\t\tpthread_mutex_lock(&ref.m);\n\t\t\tref.v2.push_back( i );\n\t\t\tpthread_mutex_unlock(&ref.m);\n\t\t\t//unlock\n\t\t}\n\t\tco_func_end;\n\t\tv.push_back( new f( ref,i ) );\n\t}\n\tfor(int i=0;i<2;i++)\n\t{\n\t\tco_func( f2,i )\n\t\t{\n\t\t\tprintf(\"i: %d\\n\",i);\n\t\t\tfor(int j=0;j<2;j++)\n\t\t\t{\n\t\t\t\tusleep( 1000 );\n\t\t\t\tprintf(\"i %d j %d\\n\",i,j);\n\t\t\t}\n\t\t}\n\t\tco_func_end;\n\t\tv.push_back( new f2( i ) );\n\t}\n\n\tbatch_exec( v );\n\tprintf(\"done\\n\");\n\n\treturn 0;\n}\n\n\n"
  },
  {
    "path": "example_cond.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include <unistd.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <queue>\n#include \"co_routine.h\"\nusing namespace std;\nstruct stTask_t\n{\n\tint id;\n};\nstruct stEnv_t\n{\n\tstCoCond_t* cond;\n\tqueue<stTask_t*> task_queue;\n};\nvoid* Producer(void* args)\n{\n\tco_enable_hook_sys();\n\tstEnv_t* env=  (stEnv_t*)args;\n\tint id = 0;\n\twhile (true)\n\t{\n\t\tstTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t));\n\t\ttask->id = id++;\n\t\tenv->task_queue.push(task);\n\t\tprintf(\"%s:%d produce task %d\\n\", __func__, __LINE__, task->id);\n\t\tco_cond_signal(env->cond);\n\t\tpoll(NULL, 0, 1000);\n\t}\n\treturn NULL;\n}\nvoid* Consumer(void* args)\n{\n\tco_enable_hook_sys();\n\tstEnv_t* env = (stEnv_t*)args;\n\twhile (true)\n\t{\n\t\tif (env->task_queue.empty())\n\t\t{\n\t\t\tco_cond_timedwait(env->cond, -1);\n\t\t\tcontinue;\n\t\t}\n\t\tstTask_t* task = env->task_queue.front();\n\t\tenv->task_queue.pop();\n\t\tprintf(\"%s:%d consume task %d\\n\", __func__, __LINE__, task->id);\n\t\tfree(task);\n\t}\n\treturn NULL;\n}\nint main()\n{\n\tstEnv_t* env = new stEnv_t;\n\tenv->cond = co_cond_alloc();\n\n\tstCoRoutine_t* consumer_routine;\n\tco_create(&consumer_routine, NULL, Consumer, env);\n\tco_resume(consumer_routine);\n\n\tstCoRoutine_t* producer_routine;\n\tco_create(&producer_routine, NULL, Producer, env);\n\tco_resume(producer_routine);\n\t\n\tco_eventloop(co_get_epoll_ct(), NULL, NULL);\n\treturn 0;\n}\n"
  },
  {
    "path": "example_copystack.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <sys/time.h>\n#include <errno.h>\n#include <string.h>\n#include \"coctx.h\"\n#include \"co_routine.h\"\n#include \"co_routine_inner.h\"\n\nvoid* RoutineFunc(void* args)\n{\n\tco_enable_hook_sys();\n\tint* routineid = (int*)args;\n\twhile (true)\n\t{\n\t\tchar sBuff[128];\n\t\tsprintf(sBuff, \"from routineid %d stack addr %p\\n\", *routineid, sBuff);\n\n\t\tprintf(\"%s\", sBuff);\n\t\tpoll(NULL, 0, 1000); //sleep 1s\n\t}\n\treturn NULL;\n}\n\nint main()\n{\n\tstShareStack_t* share_stack= co_alloc_sharestack(1, 1024 * 128);\n\tstCoRoutineAttr_t attr;\n\tattr.stack_size = 0;\n\tattr.share_stack = share_stack;\n\n\tstCoRoutine_t* co[2];\n\tint routineid[2];\n\tfor (int i = 0; i < 2; i++)\n\t{\n\t\troutineid[i] = i;\n\t\tco_create(&co[i], &attr, RoutineFunc, routineid + i);\n\t\tco_resume(co[i]);\n\t}\n\tco_eventloop(co_get_epoll_ct(), NULL, NULL);\n\treturn 0;\n}\n"
  },
  {
    "path": "example_echocli.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include \"co_routine.h\"\n\n#include <errno.h>\n#include <string.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <time.h>\n#include <stack>\n\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <sys/un.h>\n#include <fcntl.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#include <signal.h>\n\nusing namespace std;\nstruct stEndPoint\n{\n\tchar *ip;\n\tunsigned short int port;\n};\n\nstatic void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr)\n{\n\tbzero(&addr,sizeof(addr));\n\taddr.sin_family = AF_INET;\n\taddr.sin_port = htons(shPort);\n\tint nIP = 0;\n\tif( !pszIP || '\\0' == *pszIP   \n\t\t\t|| 0 == strcmp(pszIP,\"0\") || 0 == strcmp(pszIP,\"0.0.0.0\") \n\t\t\t|| 0 == strcmp(pszIP,\"*\") \n\t  )\n\t{\n\t\tnIP = htonl(INADDR_ANY);\n\t}\n\telse\n\t{\n\t\tnIP = inet_addr(pszIP);\n\t}\n\taddr.sin_addr.s_addr = nIP;\n\n}\n\nstatic int iSuccCnt = 0;\nstatic int iFailCnt = 0;\nstatic int iTime = 0;\n\nvoid AddSuccCnt()\n{\n\tint now = time(NULL);\n\tif (now >iTime)\n\t{\n\t\tprintf(\"time %d Succ Cnt %d Fail Cnt %d\\n\", iTime, iSuccCnt, iFailCnt);\n\t\tiTime = now;\n\t\tiSuccCnt = 0;\n\t\tiFailCnt = 0;\n\t}\n\telse\n\t{\n\t\tiSuccCnt++;\n\t}\n}\nvoid AddFailCnt()\n{\n\tint now = time(NULL);\n\tif (now >iTime)\n\t{\n\t\tprintf(\"time %d Succ Cnt %d Fail Cnt %d\\n\", iTime, iSuccCnt, iFailCnt);\n\t\tiTime = now;\n\t\tiSuccCnt = 0;\n\t\tiFailCnt = 0;\n\t}\n\telse\n\t{\n\t\tiFailCnt++;\n\t}\n}\n\nstatic void *readwrite_routine( void *arg )\n{\n\n\tco_enable_hook_sys();\n\n\tstEndPoint *endpoint = (stEndPoint *)arg;\n\tchar str[8]=\"sarlmol\";\n\tchar buf[ 1024 * 16 ];\n\tint fd = -1;\n\tint ret = 0;\n\tfor(;;)\n\t{\n\t\tif ( fd < 0 )\n\t\t{\n\t\t\tfd = socket(PF_INET, SOCK_STREAM, 0);\n\t\t\tstruct sockaddr_in addr;\n\t\t\tSetAddr(endpoint->ip, endpoint->port, addr);\n\t\t\tret = connect(fd,(struct sockaddr*)&addr,sizeof(addr));\n\t\t\t\t\t\t\n\t\t\tif ( errno == EALREADY || errno == EINPROGRESS )\n\t\t\t{       \n\t\t\t\tstruct pollfd pf = { 0 };\n\t\t\t\tpf.fd = fd;\n\t\t\t\tpf.events = (POLLOUT|POLLERR|POLLHUP);\n\t\t\t\tco_poll( co_get_epoll_ct(),&pf,1,200);\n\t\t\t\t//check connect\n\t\t\t\tint error = 0;\n\t\t\t\tuint32_t socklen = sizeof(error);\n\t\t\t\terrno = 0;\n\t\t\t\tret = getsockopt(fd, SOL_SOCKET, SO_ERROR,(void *)&error,  &socklen);\n\t\t\t\tif ( ret == -1 ) \n\t\t\t\t{       \n\t\t\t\t\t//printf(\"getsockopt ERROR ret %d %d:%s\\n\", ret, errno, strerror(errno));\n\t\t\t\t\tclose(fd);\n\t\t\t\t\tfd = -1;\n\t\t\t\t\tAddFailCnt();\n\t\t\t\t\tcontinue;\n\t\t\t\t}       \n\t\t\t\tif ( error ) \n\t\t\t\t{       \n\t\t\t\t\terrno = error;\n\t\t\t\t\t//printf(\"connect ERROR ret %d %d:%s\\n\", error, errno, strerror(errno));\n\t\t\t\t\tclose(fd);\n\t\t\t\t\tfd = -1;\n\t\t\t\t\tAddFailCnt();\n\t\t\t\t\tcontinue;\n\t\t\t\t}       \n\t\t\t} \n\t  \t\t\t\n\t\t}\n\t\t\n\t\tret = write( fd,str, 8);\n\t\tif ( ret > 0 )\n\t\t{\n\t\t\tret = read( fd,buf, sizeof(buf) );\n\t\t\tif ( ret <= 0 )\n\t\t\t{\n\t\t\t\t//printf(\"co %p read ret %d errno %d (%s)\\n\",\n\t\t\t\t//\t\tco_self(), ret,errno,strerror(errno));\n\t\t\t\tclose(fd);\n\t\t\t\tfd = -1;\n\t\t\t\tAddFailCnt();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//printf(\"echo %s fd %d\\n\", buf,fd);\n\t\t\t\tAddSuccCnt();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//printf(\"co %p write ret %d errno %d (%s)\\n\",\n\t\t\t//\t\tco_self(), ret,errno,strerror(errno));\n\t\t\tclose(fd);\n\t\t\tfd = -1;\n\t\t\tAddFailCnt();\n\t\t}\n\t}\n\treturn 0;\n}\n\nint main(int argc,char *argv[])\n{\n\tstEndPoint endpoint;\n\tendpoint.ip = argv[1];\n\tendpoint.port = atoi(argv[2]);\n\tint cnt = atoi( argv[3] );\n\tint proccnt = atoi( argv[4] );\n\t\n\tstruct sigaction sa;\n\tsa.sa_handler = SIG_IGN;\n\tsigaction( SIGPIPE, &sa, NULL );\n\t\n\tfor(int k=0;k<proccnt;k++)\n\t{\n\n\t\tpid_t pid = fork();\n\t\tif( pid > 0 )\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\telse if( pid < 0 )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tfor(int i=0;i<cnt;i++)\n\t\t{\n\t\t\tstCoRoutine_t *co = 0;\n\t\t\tco_create( &co,NULL,readwrite_routine, &endpoint);\n\t\t\tco_resume( co );\n\t\t}\n\t\tco_eventloop( co_get_epoll_ct(),0,0 );\n\n\t\texit(0);\n\t}\n\treturn 0;\n}\n/*./example_echosvr 127.0.0.1 10000 100 50*/\n"
  },
  {
    "path": "example_echosvr.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n\n\n#include \"co_routine.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <sys/time.h>\n#include <stack>\n\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <sys/un.h>\n#include <fcntl.h>\n#include <arpa/inet.h>\n#include <unistd.h>\n#include <errno.h>\n#include <sys/wait.h>\n\n#ifdef __FreeBSD__\n#include <cstring>\n#include <sys/types.h>\n#include <sys/wait.h>\n#endif\n\nusing namespace std;\nstruct task_t\n{\n\tstCoRoutine_t *co;\n\tint fd;\n};\n\nstatic stack<task_t*> g_readwrite;\nstatic int g_listen_fd = -1;\nstatic int SetNonBlock(int iSock)\n{\n    int iFlags;\n\n    iFlags = fcntl(iSock, F_GETFL, 0);\n    iFlags |= O_NONBLOCK;\n    iFlags |= O_NDELAY;\n    int ret = fcntl(iSock, F_SETFL, iFlags);\n    return ret;\n}\n\nstatic void *readwrite_routine( void *arg )\n{\n\n\tco_enable_hook_sys();\n\n\ttask_t *co = (task_t*)arg;\n\tchar buf[ 1024 * 16 ];\n\tfor(;;)\n\t{\n\t\tif( -1 == co->fd )\n\t\t{\n\t\t\tg_readwrite.push( co );\n\t\t\tco_yield_ct();\n\t\t\tcontinue;\n\t\t}\n\n\t\tint fd = co->fd;\n\t\tco->fd = -1;\n\n\t\tfor(;;)\n\t\t{\n\t\t\tstruct pollfd pf = { 0 };\n\t\t\tpf.fd = fd;\n\t\t\tpf.events = (POLLIN|POLLERR|POLLHUP);\n\t\t\tco_poll( co_get_epoll_ct(),&pf,1,1000);\n\n\t\t\tint ret = read( fd,buf,sizeof(buf) );\n\t\t\tif( ret > 0 )\n\t\t\t{\n\t\t\t\tret = write( fd,buf,ret );\n\t\t\t}\n\t\t\tif( ret > 0 || ( -1 == ret && EAGAIN == errno ) )\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tclose( fd );\n\t\t\tbreak;\n\t\t}\n\n\t}\n\treturn 0;\n}\nint co_accept(int fd, struct sockaddr *addr, socklen_t *len );\nstatic void *accept_routine( void * )\n{\n\tco_enable_hook_sys();\n\tprintf(\"accept_routine\\n\");\n\tfflush(stdout);\n\tfor(;;)\n\t{\n\t\t//printf(\"pid %ld g_readwrite.size %ld\\n\",getpid(),g_readwrite.size());\n\t\tif( g_readwrite.empty() )\n\t\t{\n\t\t\tprintf(\"empty\\n\"); //sleep\n\t\t\tstruct pollfd pf = { 0 };\n\t\t\tpf.fd = -1;\n\t\t\tpoll( &pf,1,1000);\n\n\t\t\tcontinue;\n\n\t\t}\n\t\tstruct sockaddr_in addr; //maybe sockaddr_un;\n\t\tmemset( &addr,0,sizeof(addr) );\n\t\tsocklen_t len = sizeof(addr);\n\n\t\tint fd = co_accept(g_listen_fd, (struct sockaddr *)&addr, &len);\n\t\tif( fd < 0 )\n\t\t{\n\t\t\tstruct pollfd pf = { 0 };\n\t\t\tpf.fd = g_listen_fd;\n\t\t\tpf.events = (POLLIN|POLLERR|POLLHUP);\n\t\t\tco_poll( co_get_epoll_ct(),&pf,1,1000 );\n\t\t\tcontinue;\n\t\t}\n\t\tif( g_readwrite.empty() )\n\t\t{\n\t\t\tclose( fd );\n\t\t\tcontinue;\n\t\t}\n\t\tSetNonBlock( fd );\n\t\ttask_t *co = g_readwrite.top();\n\t\tco->fd = fd;\n\t\tg_readwrite.pop();\n\t\tco_resume( co->co );\n\t}\n\treturn 0;\n}\n\nstatic void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr)\n{\n\tbzero(&addr,sizeof(addr));\n\taddr.sin_family = AF_INET;\n\taddr.sin_port = htons(shPort);\n\tint nIP = 0;\n\tif( !pszIP || '\\0' == *pszIP   \n\t    || 0 == strcmp(pszIP,\"0\") || 0 == strcmp(pszIP,\"0.0.0.0\") \n\t\t|| 0 == strcmp(pszIP,\"*\") \n\t  )\n\t{\n\t\tnIP = htonl(INADDR_ANY);\n\t}\n\telse\n\t{\n\t\tnIP = inet_addr(pszIP);\n\t}\n\taddr.sin_addr.s_addr = nIP;\n\n}\n\nstatic int CreateTcpSocket(const unsigned short shPort /* = 0 */,const char *pszIP /* = \"*\" */,bool bReuse /* = false */)\n{\n\tint fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);\n\tif( fd >= 0 )\n\t{\n\t\tif(shPort != 0)\n\t\t{\n\t\t\tif(bReuse)\n\t\t\t{\n\t\t\t\tint nReuseAddr = 1;\n\t\t\t\tsetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr));\n\t\t\t}\n\t\t\tstruct sockaddr_in addr ;\n\t\t\tSetAddr(pszIP,shPort,addr);\n\t\t\tint ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));\n\t\t\tif( ret != 0)\n\t\t\t{\n\t\t\t\tclose(fd);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn fd;\n}\n\n\nint main(int argc,char *argv[])\n{\n\tif(argc<5){\n\t\tprintf(\"Usage:\\n\"\n               \"example_echosvr [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT]\\n\"\n               \"example_echosvr [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT] -d   # daemonize mode\\n\");\n\t\treturn -1;\n\t}\n\tconst char *ip = argv[1];\n\tint port = atoi( argv[2] );\n\tint cnt = atoi( argv[3] );\n\tint proccnt = atoi( argv[4] );\n\tbool deamonize = argc >= 6 && strcmp(argv[5], \"-d\") == 0;\n\n\tg_listen_fd = CreateTcpSocket( port,ip,true );\n\tlisten( g_listen_fd,1024 );\n\tif(g_listen_fd==-1){\n\t\tprintf(\"Port %d is in use\\n\", port);\n\t\treturn -1;\n\t}\n\tprintf(\"listen %d %s:%d\\n\",g_listen_fd,ip,port);\n\n\tSetNonBlock( g_listen_fd );\n\n\tfor(int k=0;k<proccnt;k++)\n\t{\n\n\t\tpid_t pid = fork();\n\t\tif( pid > 0 )\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\telse if( pid < 0 )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tfor(int i=0;i<cnt;i++)\n\t\t{\n\t\t\ttask_t * task = (task_t*)calloc( 1,sizeof(task_t) );\n\t\t\ttask->fd = -1;\n\n\t\t\tco_create( &(task->co),NULL,readwrite_routine,task );\n\t\t\tco_resume( task->co );\n\n\t\t}\n\t\tstCoRoutine_t *accept_co = NULL;\n\t\tco_create( &accept_co,NULL,accept_routine,0 );\n\t\tco_resume( accept_co );\n\n\t\tco_eventloop( co_get_epoll_ct(),0,0 );\n\n\t\texit(0);\n\t}\n\tif(!deamonize) wait(NULL);\n\treturn 0;\n}\n\n"
  },
  {
    "path": "example_poll.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include \"co_routine.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <sys/time.h>\n#include <stack>\n\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <sys/un.h>\n#include <fcntl.h>\n#include <arpa/inet.h>\n#include <errno.h>\n#include <vector>\n#include <set>\n#include <unistd.h>\n\n#ifdef __FreeBSD__\n#include <cstring>\n#endif\n\nusing namespace std;\n\nstruct task_t\n{\n\tstCoRoutine_t *co;\n\tint fd;\n\tstruct sockaddr_in addr;\n};\n\nstatic int SetNonBlock(int iSock)\n{\n    int iFlags;\n\n    iFlags = fcntl(iSock, F_GETFL, 0);\n    iFlags |= O_NONBLOCK;\n    iFlags |= O_NDELAY;\n    int ret = fcntl(iSock, F_SETFL, iFlags);\n    return ret;\n}\n\n\n\nstatic void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr)\n{\n\tbzero(&addr,sizeof(addr));\n\taddr.sin_family = AF_INET;\n\taddr.sin_port = htons(shPort);\n\tint nIP = 0;\n\tif( !pszIP || '\\0' == *pszIP   \n\t    || 0 == strcmp(pszIP,\"0\") || 0 == strcmp(pszIP,\"0.0.0.0\") \n\t\t|| 0 == strcmp(pszIP,\"*\") \n\t  )\n\t{\n\t\tnIP = htonl(INADDR_ANY);\n\t}\n\telse\n\t{\n\t\tnIP = inet_addr(pszIP);\n\t}\n\taddr.sin_addr.s_addr = nIP;\n\n}\n\nstatic int CreateTcpSocket(const unsigned short shPort  = 0 ,const char *pszIP  = \"*\" ,bool bReuse  = false )\n{\n\tint fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);\n\tif( fd >= 0 )\n\t{\n\t\tif(shPort != 0)\n\t\t{\n\t\t\tif(bReuse)\n\t\t\t{\n\t\t\t\tint nReuseAddr = 1;\n\t\t\t\tsetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr));\n\t\t\t}\n\t\t\tstruct sockaddr_in addr ;\n\t\t\tSetAddr(pszIP,shPort,addr);\n\t\t\tint ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));\n\t\t\tif( ret != 0)\n\t\t\t{\n\t\t\t\tclose(fd);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\treturn fd;\n}\n\nstatic void *poll_routine( void *arg )\n{\n\tco_enable_hook_sys();\n\n\tvector<task_t> &v = *(vector<task_t>*)arg;\n\tfor(size_t i=0;i<v.size();i++)\n\t{\n\t\tint fd = CreateTcpSocket();\n\t\tSetNonBlock( fd );\n\t\tv[i].fd = fd;\n\n\t\tint ret = connect(fd,(struct sockaddr*)&v[i].addr,sizeof( v[i].addr )); \n\t\tprintf(\"co %p connect i %ld ret %d errno %d (%s)\\n\",\n\t\t\tco_self(),i,ret,errno,strerror(errno));\n\t}\n\tstruct pollfd *pf = (struct pollfd*)calloc( 1,sizeof(struct pollfd) * v.size() );\n\n\tfor(size_t i=0;i<v.size();i++)\n\t{\n\t\tpf[i].fd = v[i].fd;\n\t\tpf[i].events = ( POLLOUT | POLLERR | POLLHUP );\n\t}\n\tset<int> setRaiseFds;\n\tsize_t iWaitCnt = v.size();\n\tfor(;;)\n\t{\n\t\tint ret = poll( pf,iWaitCnt,1000 );\n\t\tprintf(\"co %p poll wait %ld ret %d\\n\",\n\t\t\t\tco_self(),iWaitCnt,ret);\n\t\tfor(int i=0;i<(int)iWaitCnt;i++)\n\t\t{\n\t\t\tprintf(\"co %p fire fd %d revents 0x%X POLLOUT 0x%X POLLERR 0x%X POLLHUP 0x%X\\n\",\n\t\t\t\t\tco_self(),\n\t\t\t\t\tpf[i].fd,\n\t\t\t\t\tpf[i].revents,\n\t\t\t\t\tPOLLOUT,\n\t\t\t\t\tPOLLERR,\n\t\t\t\t\tPOLLHUP\n\t\t\t\t\t);\n\t\t\tsetRaiseFds.insert( pf[i].fd );\n\t\t}\n\t\tif( setRaiseFds.size() == v.size())\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tif( ret <= 0 )\n\t\t{\n\t\t\tbreak;\n\t\t}\n\n\t\tiWaitCnt = 0;\n\t\tfor(size_t i=0;i<v.size();i++)\n\t\t{\n\t\t\tif( setRaiseFds.find( v[i].fd ) == setRaiseFds.end() )\n\t\t\t{\n\t\t\t\tpf[ iWaitCnt ].fd = v[i].fd;\n\t\t\t\tpf[ iWaitCnt ].events = ( POLLOUT | POLLERR | POLLHUP );\n\t\t\t\t++iWaitCnt;\n\t\t\t}\n\t\t}\n\t}\n\tfor(size_t i=0;i<v.size();i++)\n\t{\n\t\tclose( v[i].fd );\n\t\tv[i].fd = -1;\n\t}\n\n\tprintf(\"co %p task cnt %ld fire %ld\\n\",\n\t\t\tco_self(),v.size(),setRaiseFds.size() );\n\treturn 0;\n}\nint main(int argc,char *argv[])\n{\n\tvector<task_t> v;\n\tfor(int i=1;i<argc;i+=2)\n\t{\n\t\ttask_t task = { 0 };\n\t\tSetAddr( argv[i],atoi(argv[i+1]),task.addr );\n\t\tv.push_back( task );\n\t}\n\n//------------------------------------------------------------------------------------\n\tprintf(\"--------------------- main -------------------\\n\");\n\tvector<task_t> v2 = v;\n\tpoll_routine( &v2 );\n\tprintf(\"--------------------- routine -------------------\\n\");\n\n\tfor(int i=0;i<10;i++)\n\t{\n\t\tstCoRoutine_t *co = 0;\n\t\tvector<task_t> *v2 = new vector<task_t>();\n\t\t*v2 = v;\n\t\tco_create( &co,NULL,poll_routine,v2 );\n\t\tprintf(\"routine i %d\\n\",i);\n\t\tco_resume( co );\n\t}\n\n\tco_eventloop( co_get_epoll_ct(),0,0 );\n\n\treturn 0;\n}\n//./example_poll 127.0.0.1 12365 127.0.0.1 12222 192.168.1.1 1000 192.168.1.2 1111\n\n"
  },
  {
    "path": "example_setenv.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include <unistd.h>\n#include <stdio.h>\n#include <errno.h>\n#include <string.h>\n#include <stdlib.h>\n#include <queue>\n#include \"co_routine.h\"\n\nconst char* CGI_ENV_HOOK_LIST [] = \n{\n\t\"CGINAME\",\n};\nstruct stRoutineArgs_t\n{\n\tint iRoutineID;\n};\nvoid SetAndGetEnv(int iRoutineID)\n{\n\tprintf(\"routineid %d begin\\n\", iRoutineID);\n\n\t//use poll as sleep\n\tpoll(NULL, 0, 500);\n\n\tchar sBuf[128];\n\tsprintf(sBuf, \"cgi_routine_%d\", iRoutineID);\n\tint ret = setenv(\"CGINAME\", sBuf, 1);\n\tif (ret)\n\t{\n\t\tprintf(\"%s:%d set env err ret %d errno %d %s\\n\", __func__, __LINE__,\n\t\t\t\tret, errno, strerror(errno));\n\t\treturn;\n\t}\n\tprintf(\"routineid %d set env CGINAME %s\\n\", iRoutineID, sBuf);\n\n\tpoll(NULL, 0, 500);\n\n\tchar* env = getenv(\"CGINAME\");\n\tif (!env)\n\t{\n\t\tprintf(\"%s:%d get env err errno %d %s\\n\", __func__, __LINE__,\n\t\t\t\terrno, strerror(errno));\n\t\treturn;\n\t}\n\tprintf(\"routineid %d get env CGINAME %s\\n\", iRoutineID, env);\n}\n\nvoid* RoutineFunc(void* args)\n{\n\tco_enable_hook_sys();\n\n\tstRoutineArgs_t* g = (stRoutineArgs_t*)args;\n\n\tSetAndGetEnv(g->iRoutineID);\n\treturn NULL;\n}\n\nint main(int argc, char* argv[])\n{\n\tco_set_env_list(CGI_ENV_HOOK_LIST, sizeof(CGI_ENV_HOOK_LIST) / sizeof(char*));\n\tstRoutineArgs_t  args[3];\n\tfor (int i = 0; i < 3; i++)\n\t{\n\t\tstCoRoutine_t* co = NULL;\n\t\targs[i].iRoutineID = i;\n\t\tco_create(&co, NULL, RoutineFunc, &args[i]);\n\t\tco_resume(co);\n\t}\n\tco_eventloop(co_get_epoll_ct(), NULL, NULL);\n\treturn 0;\n}\n\n"
  },
  {
    "path": "example_specific.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n#include \"co_routine_specific.h\"\n#include \"co_routine.h\"\n#include <unistd.h>\n#include <stdio.h>\n#include <vector>\n#include <iostream>\nusing namespace std;\nstruct stRoutineArgs_t\n{\n\tstCoRoutine_t* co;\n\tint routine_id;\n};\nstruct stRoutineSpecificData_t\n{\n\tint idx;\n};\n\nCO_ROUTINE_SPECIFIC(stRoutineSpecificData_t, __routine);\n\nvoid* RoutineFunc(void* args)\n{\n\tco_enable_hook_sys();\n\tstRoutineArgs_t* routine_args = (stRoutineArgs_t*)args;\n\t__routine->idx = routine_args->routine_id;\n\twhile (true)\n\t{\n\t\tprintf(\"%s:%d routine specific data idx %d\\n\", __func__, __LINE__, __routine->idx);\n\t\tpoll(NULL, 0, 1000);\n\t}\n\treturn NULL;\n}\nint main()\n{\n\tstRoutineArgs_t args[10];\n\tfor (int i = 0; i < 10; i++)\n\t{\n\t\targs[i].routine_id = i;\n\t\tco_create(&args[i].co, NULL, RoutineFunc, (void*)&args[i]);\n\t\tco_resume(args[i].co);\n\t}\n\tco_eventloop(co_get_epoll_ct(), NULL, NULL);\n\treturn 0;\n}\n"
  },
  {
    "path": "example_thread.cpp",
    "content": "/*\n* Tencent is pleased to support the open source community by making Libco available.\n\n* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\"); \n* you may not use this file except in compliance with the License. \n* You may obtain a copy of the License at\n*\n*\thttp://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, \n* software distributed under the License is distributed on an \"AS IS\" BASIS, \n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \n* See the License for the specific language governing permissions and \n* limitations under the License.\n*/\n\n\n\n#include \"co_routine.h\"\n#include \"co_routine_inner.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <pthread.h>\n#include <unistd.h>\n\nint loop(void *)\n{\n\treturn 0;\n}\nstatic void *routine_func( void * )\n{\n\tstCoEpoll_t * ev = co_get_epoll_ct(); //ct = current thread\n\tco_eventloop( ev,loop,0 );\n\treturn 0;\n}\nint main(int argc,char *argv[])\n{\n\tint cnt = atoi( argv[1] );\n\n\tpthread_t tid[ cnt ];\n\tfor(int i=0;i<cnt;i++)\n\t{\n\t\tpthread_create( tid + i,NULL,routine_func,0);\n\t}\n\tfor(;;)\n\t{\n\t\tsleep(1);\n\t}\n\t\n\treturn 0;\n}\n\n"
  }
]