1
0
mirror of https://github.com/Tencent/libco.git synced 2025-05-08 19:51:15 +08:00
Tencent libco
This commit is contained in:
leiffyli@tencent.com 2016-10-12 12:25:43 +08:00
commit 4b41ba0ce2
30 changed files with 6262 additions and 0 deletions

164
BUILD Normal file
View File

@ -0,0 +1,164 @@
cc_library(
name = 'colib',
target_bases = [ 'comm',],
srcs = [
'co_hook_sys_call.cpp',
'co_routine.cpp',
'coctx.cpp',
'coctx_swap.S',
'co_epoll.cpp',
],
deps = [
],
defs = [
'LINUX',
'_PTHREADS',
'TIXML_USE_STL',
],
optimize = [
#'O2',
],
extra_cppflags = [
#'-O2' ,
#'-Werror',
],
)
cc_binary(
name = 'global_sym',
srcs = [
'demangle.cpp',
'global_sym.cpp'
],
deps = [
#GEN_SOURCE_POS__
],
defs = [
'LINUX',
'_PTHREADS',
'TIXML_USE_STL',
'_NEW_LIC',
'_GNU_SOURCE',
'_REENTRANT',
],
optimize = [
'O2',
],
extra_cppflags = [
#'-Werror',
#'-Werror',
'-pipe',
'-fPIC',
'-Wno-deprecated',
],
incs = [
#INCS_POS__
],
)
cc_binary(
name = 'test_specific',
srcs = [
'test_specific.cpp',
],
deps = [
':colib',
'//comm2/core:core',
#GEN_SOURCE_POS__
],
defs = [
'LINUX',
'_PTHREADS',
'TIXML_USE_STL',
'_NEW_LIC',
'_GNU_SOURCE',
'_REENTRANT',
],
optimize = [
'O2',
],
extra_cppflags = [
#'-Werror',
#'-Werror',
'-pipe',
'-fPIC',
'-Wno-deprecated',
],
incs = [
#INCS_POS__
],
)
cc_binary(
name = 'echosvr',
srcs = [
'example_echosvr_copystack.cpp',
],
deps = [
':colib',
'//comm2/core:core',
#GEN_SOURCE_POS__
],
defs = [
'LINUX',
'_PTHREADS',
'TIXML_USE_STL',
'_NEW_LIC',
'_GNU_SOURCE',
'_REENTRANT',
],
optimize = [
'O2',
],
extra_cppflags = [
#'-Werror',
#'-Werror',
'-pipe',
'-fPIC',
'-Wno-deprecated',
],
incs = [
#INCS_POS__
],
)
cc_binary(
name = 'test_colib',
srcs = [
'test_colib.cpp',
'test_xmm.S',
],
deps = [
':colib',
'//mm3rd/gtest:gtest',
'#dl',
#GEN_SOURCE_POS__
],
defs = [
],
optimize = [
'O2',
],
extra_cppflags = [
#'-Werror',
#'-Werror',
'-pipe',
'-fPIC',
'-Wno-deprecated',
'-DLIBCO-USE-GETTICK',
],
incs = [
#INCS_POS__
],
)

BIN
LICENSE.txt Normal file

Binary file not shown.

77
Makefile Normal file
View File

@ -0,0 +1,77 @@
#
# Tencent is pleased to support the open source community by making Libco available.
#
# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
COMM_MAKE = 1
COMM_ECHO = 1
version=0.5
v=debug
include co.mk
########## options ##########
#CFLAGS += -g -fno-strict-aliasing -O2 -Wall -export-dynamic \
# -Wall -pipe -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64
LINKS += -g -L./lib -lcolib -lpthread -ldl
COLIB_OBJS=co_epoll.o co_routine.o co_hook_sys_call.o coctx_swap.o coctx.o
#co_swapcontext.o
PROGS = colib example_poll example_echosvr example_echocli example_thread example_cond example_specific example_copystack
all:$(PROGS)
colib:libcolib.a libcolib.so
libcolib.a: $(COLIB_OBJS)
$(ARSTATICLIB)
libcolib.so: $(COLIB_OBJS)
$(BUILDSHARELIB)
example_echosvr:example_echosvr.o
$(BUILDEXE)
example_echocli:example_echocli.o
$(BUILDEXE)
example_thread:example_thread.o
$(BUILDEXE)
example_poll:example_poll.o
$(BUILDEXE)
example_exit:example_exit.o
$(BUILDEXE)
example_cond:example_cond.o
$(BUILDEXE)
example_specific:example_specific.o
$(BUILDEXE)
example_copystack:example_copystack.o
$(BUILDEXE)
dist: clean libco-$(version).src.tar.gz
libco-$(version).src.tar.gz:
@find . -type f | grep -v CVS | grep -v .svn | sed s:^./:libco-$(version)/: > MANIFEST
@(cd ..; ln -s libco_pub libco-$(version))
(cd ..; tar cvf - `cat libco_pub/MANIFEST` | gzip > libco_pub/libco-$(version).src.tar.gz)
@(cd ..; rm libco-$(version))
clean:
$(CLEAN) *.o $(PROGS)
rm -fr MANIFEST lib solib libco-$(version).src.tar.gz libco-$(version)

86
co.mk Normal file
View File

@ -0,0 +1,86 @@
#
# Tencent is pleased to support the open source community by making Libco available.
#
# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##### Makefile Rules ##########
MAIL_ROOT=.
SRCROOT=.
##define the compliers
CPP = g++
CC = gcc
AR = ar -rc
RANLIB = ranlib
CPPSHARE = $(CPP) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o
CSHARE = $(CC) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o
ifeq ($v,release)
CFLAGS= -O2 $(INCLS) -fPIC -DLINUX -pipe -Wno-deprecated -c
else
CFLAGS= -g $(INCLS) -fPIC -DLINUX -pipe -c -fno-inline
endif
ifneq ($v,release)
BFLAGS= -g
endif
STATICLIBPATH=$(SRCROOT)/lib
DYNAMICLIBPATH=$(SRCROOT)/solib
INCLS += -I$(SRCROOT)
## default links
ifeq ($(LINKS_DYNAMIC), 1)
LINKS += -L$(DYNAMICLIBPATH) -L$(STATICLIBPATH)
else
LINKS += -L$(STATICLIBPATH)
endif
CPPSRCS = $(wildcard *.cpp)
CSRCS = $(wildcard *.c)
CPPOBJS = $(patsubst %.cpp,%.o,$(CPPSRCS))
COBJS = $(patsubst %.c,%.o,$(CSRCS))
SRCS = $(CPPSRCS) $(CSRCS)
OBJS = $(CPPOBJS) $(COBJS)
CPPCOMPI=$(CPP) $(CFLAGS) -Wno-deprecated
CCCOMPI=$(CC) $(CFLAGS)
BUILDEXE = $(CPP) $(BFLAGS) -o $@ $^ $(LINKS)
CLEAN = rm -f *.o
CPPCOMPILE = $(CPPCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@
CCCOMPILE = $(CCCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@
ARSTATICLIB = $(AR) $@.tmp $^ $(AR_FLAGS); \
if [ $$? -ne 0 ]; then exit 1; fi; \
test -d $(STATICLIBPATH) || mkdir -p $(STATICLIBPATH); \
mv -f $@.tmp $(STATICLIBPATH)/$@;
BUILDSHARELIB = $(CPPSHARE) $@.tmp $^ $(BS_FLAGS); \
if [ $$? -ne 0 ]; then exit 1; fi; \
test -d $(DYNAMICLIBPATH) || mkdir -p $(DYNAMICLIBPATH); \
mv -f $@.tmp $(DYNAMICLIBPATH)/$@;
.cpp.o:
$(CPPCOMPILE)
.c.o:
$(CCCOMPILE)

92
co_closure.h Normal file
View File

@ -0,0 +1,92 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CO_CLOSURE_H__
#define __CO_CLOSURE_H__
struct stCoClosure_t
{
public:
virtual void exec() = 0;
};
//1.base
//-- 1.1 comac_argc
#define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ )
#define comac_arg_n( _1,_2,_3,_4,_5,_6,_7,N,...) N
#define comac_args_seqs() 7,6,5,4,3,2,1,0
#define comac_join_1( x,y ) x##y
#define comac_argc( ... ) comac_get_args_cnt( __VA_ARGS__,comac_args_seqs() )
#define comac_join( x,y) comac_join_1( x,y )
//-- 1.2 repeat
#define repeat_0( fun,a,... )
#define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ )
#define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ )
#define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ )
#define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ )
#define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ )
#define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ )
#define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__)
//2.implement
#define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a;
#define impl_typeof( i,a,... ) typeof_##a & a;
#define impl_typeof_cpy( i,a,... ) typeof_##a a;
#define con_param_typeof( i,a,... ) typeof_##a & a##r,
#define param_init_typeof( i,a,... ) a(a##r),
//2.1 reference
#define co_ref( name,... )\
repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\
class type_##name\
{\
public:\
repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\
int _member_cnt;\
type_##name( \
repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \
repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \
{}\
} name( __VA_ARGS__ ) ;
//2.2 function
#define co_func(name,...)\
repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\
class name:public stCoClosure_t\
{\
public:\
repeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\
int _member_cnt;\
public:\
name( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \
repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\
{}\
void exec()
#define co_func_end }
#endif

325
co_epoll.cpp Normal file
View File

@ -0,0 +1,325 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "co_epoll.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <string.h>
#ifndef __APPLE__
int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout )
{
return epoll_wait( epfd,events->events,maxevents,timeout );
}
int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev )
{
return epoll_ctl( epfd,op,fd,ev );
}
int co_epoll_create( int size )
{
return epoll_create( size );
}
struct co_epoll_res *co_epoll_res_alloc( int n )
{
struct co_epoll_res * ptr =
(struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) );
ptr->size = n;
ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) );
return ptr;
}
void co_epoll_res_free( struct co_epoll_res * ptr )
{
if( !ptr ) return;
if( ptr->events ) free( ptr->events );
free( ptr );
}
#else
class clsFdMap // million of fd , 1024 * 1024
{
private:
static const int row_size = 1024;
static const int col_size = 1024;
void **m_pp[ 1024 ];
public:
clsFdMap()
{
memset( m_pp,0,sizeof(m_pp) );
}
~clsFdMap()
{
for(int i=0;i<sizeof(m_pp)/sizeof(m_pp[0]);i++)
{
if( m_pp[i] )
{
free( m_pp[i] );
m_pp[i] = NULL;
}
}
}
inline int clear( int fd )
{
set( fd,NULL );
return 0;
}
inline int set( int fd,const void * ptr )
{
int idx = fd / row_size;
if( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) )
{
assert( __LINE__ == 0 );
return -__LINE__;
}
if( !m_pp[ idx ] )
{
m_pp[ idx ] = (void**)calloc( 1,sizeof(void*) * col_size );
}
m_pp[ idx ][ fd % col_size ] = (void*)ptr;
return 0;
}
inline void *get( int fd )
{
int idx = fd / row_size;
if( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) )
{
return NULL;
}
void **lp = m_pp[ idx ];
if( !lp ) return NULL;
return lp[ fd % col_size ];
}
};
__thread clsFdMap *s_fd_map = NULL;
static inline clsFdMap *get_fd_map()
{
if( !s_fd_map )
{
s_fd_map = new clsFdMap();
}
return s_fd_map;
}
struct kevent_pair_t
{
int fire_idx;
int events;
uint64_t u64;
};
int co_epoll_create( int size )
{
return kqueue();
}
int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout )
{
struct timespec t = { 0 };
if( timeout > 0 )
{
t.tv_sec = timeout;
}
int ret = kevent( epfd,
NULL, 0, //register null
events->eventlist, maxevents,//just retrival
( -1 == timeout ) ? NULL : &t );
int j = 0;
for(int i=0;i<ret;i++)
{
struct kevent &kev = events->eventlist[i];
struct kevent_pair_t *ptr = (struct kevent_pair_t*)kev.udata;
struct epoll_event *ev = events->events + i;
if( 0 == ptr->fire_idx )
{
ptr->fire_idx = i + 1;
memset( ev,0,sizeof(*ev) );
++j;
}
else
{
ev = events->events + ptr->fire_idx - 1;
}
if( EVFILT_READ == kev.filter )
{
ev->events |= EPOLLIN;
}
else if( EVFILT_WRITE == kev.filter )
{
ev->events |= EPOLLOUT;
}
ev->data.u64 = ptr->u64;
}
for(int i=0;i<ret;i++)
{
(( struct kevent_pair_t* )(events->eventlist[i].udata) )->fire_idx = 0;
}
return j;
}
int co_epoll_del( int epfd,int fd )
{
struct timespec t = { 0 };
struct kevent_pair_t *ptr = ( struct kevent_pair_t* )get_fd_map()->get( fd );
if( !ptr ) return 0;
if( EPOLLIN & ptr->events )
{
struct kevent kev = { 0 };
kev.ident = fd;
kev.filter = EVFILT_READ;
kev.flags = EV_DELETE;
kevent( epfd,&kev,1, NULL,0,&t );
}
if( EPOLLOUT & ptr->events )
{
struct kevent kev = { 0 };
kev.ident = fd;
kev.filter = EVFILT_WRITE;
kev.flags = EV_DELETE;
kevent( epfd,&kev,1, NULL,0,&t );
}
get_fd_map()->clear( fd );
free( ptr );
return 0;
}
int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev )
{
if( EPOLL_CTL_DEL == op )
{
return co_epoll_del( epfd,fd );
}
const int flags = ( EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP );
if( ev->events & ~flags )
{
return -1;
}
if( EPOLL_CTL_ADD == op && get_fd_map()->get( fd ) )
{
errno = EEXIST;
return -1;
}
else if( EPOLL_CTL_MOD == op && !get_fd_map()->get( fd ) )
{
errno = ENOENT;
return -1;
}
struct kevent_pair_t *ptr = (struct kevent_pair_t*)get_fd_map()->get( fd );
if( !ptr )
{
ptr = (kevent_pair_t*)calloc(1,sizeof(kevent_pair_t));
get_fd_map()->set( fd,ptr );
}
int ret = 0;
struct timespec t = { 0 };
printf("ptr->events 0x%X\n",ptr->events);
if( EPOLL_CTL_MOD == op )
{
//1.delete if exists
if( ptr->events & EPOLLIN )
{
struct kevent kev = { 0 };
EV_SET( &kev,fd,EVFILT_READ,EV_DELETE,0,0,NULL );
kevent( epfd, &kev,1, NULL,0, &t );
}
//1.delete if exists
if( ptr->events & EPOLLOUT )
{
struct kevent kev = { 0 };
EV_SET( &kev,fd,EVFILT_WRITE,EV_DELETE,0,0,NULL );
ret = kevent( epfd, &kev,1, NULL,0, &t );
printf("delete write ret %d\n",ret );
}
}
do
{
if( ev->events & EPOLLIN )
{
//2.add
struct kevent kev = { 0 };
EV_SET( &kev,fd,EVFILT_READ,EV_ADD,0,0,ptr );
ret = kevent( epfd, &kev,1, NULL,0, &t );
if( ret ) break;
}
if( ev->events & EPOLLOUT )
{
//2.add
struct kevent kev = { 0 };
EV_SET( &kev,fd,EVFILT_WRITE,EV_ADD,0,0,ptr );
ret = kevent( epfd, &kev,1, NULL,0, &t );
if( ret ) break;
}
} while( 0 );
if( ret )
{
get_fd_map()->clear( fd );
free( ptr );
return ret;
}
ptr->events = ev->events;
ptr->u64 = ev->data.u64;
return ret;
}
struct co_epoll_res *co_epoll_res_alloc( int n )
{
struct co_epoll_res * ptr =
(struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) );
ptr->size = n;
ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) );
ptr->eventlist = (struct kevent*)calloc( 1,n * sizeof( struct kevent) );
return ptr;
}
void co_epoll_res_free( struct co_epoll_res * ptr )
{
if( !ptr ) return;
if( ptr->events ) free( ptr->events );
if( ptr->eventlist ) free( ptr->eventlist );
free( ptr );
}
#endif
//gzrd_Lib_CPP_Version_ID--start
#ifndef GZRD_SVN_ATTR
#define GZRD_SVN_ATTR "0"
#endif
static char gzrd_Lib_CPP_Version_ID[] __attribute__((used))="$HeadURL: http://tc-svn.tencent.com/pub/pub_libco_rep/libco_proj/trunk/co_epoll.cpp $ $Id: co_epoll.cpp 39 2016-09-29 07:26:29Z leiffyli $ " GZRD_SVN_ATTR "__file__";
// gzrd_Lib_CPP_Version_ID--end

90
co_epoll.h Normal file
View File

@ -0,0 +1,90 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CO_EPOLL_H__
#define __CO_EPOLL_H__
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <time.h>
#ifndef __APPLE__
#include <sys/epoll.h>
struct co_epoll_res
{
int size;
struct epoll_event *events;
struct kevent *eventlist;
};
int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout );
int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * );
int co_epoll_create( int size );
struct co_epoll_res *co_epoll_res_alloc( int n );
void co_epoll_res_free( struct co_epoll_res * );
#else
#include <sys/event.h>
enum EPOLL_EVENTS
{
EPOLLIN = 0X001,
EPOLLPRI = 0X002,
EPOLLOUT = 0X004,
EPOLLERR = 0X008,
EPOLLHUP = 0X010,
};
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event
{
uint32_t events;
epoll_data_t data;
};
struct co_epoll_res
{
int size;
struct epoll_event *events;
struct kevent *eventlist;
};
int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout );
int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * );
int co_epoll_create( int size );
struct co_epoll_res *co_epoll_res_alloc( int n );
void co_epoll_res_free( struct co_epoll_res * );
#endif
#endif

734
co_hook_sys_call.cpp Normal file
View File

@ -0,0 +1,734 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/un.h>
#include <dlfcn.h>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <pthread.h>
#include <resolv.h>
#include <netdb.h>
#include <time.h>
#include "co_routine.h"
#include "co_routine_inner.h"
#include "co_routine_specific.h"
typedef long long ll64_t;
struct rpchook_t
{
int user_flag;
struct sockaddr_in dest; //maybe sockaddr_un;
int domain; //AF_LOCAL , AF_INET
struct timeval read_timeout;
struct timeval write_timeout;
};
static inline pid_t GetPid()
{
char **p = (char**)pthread_self();
return p ? *(pid_t*)(p + 18) : getpid();
}
static rpchook_t *g_rpchook_socket_fd[ 102400 ] = { 0 };
typedef int (*socket_pfn_t)(int domain, int type, int protocol);
typedef int (*connect_pfn_t)(int socket, const struct sockaddr *address, socklen_t address_len);
typedef int (*close_pfn_t)(int fd);
typedef ssize_t (*read_pfn_t)(int fildes, void *buf, size_t nbyte);
typedef ssize_t (*write_pfn_t)(int fildes, const void *buf, size_t nbyte);
typedef ssize_t (*sendto_pfn_t)(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
typedef ssize_t (*recvfrom_pfn_t)(int socket, void *buffer, size_t length,
int flags, struct sockaddr *address,
socklen_t *address_len);
typedef size_t (*send_pfn_t)(int socket, const void *buffer, size_t length, int flags);
typedef ssize_t (*recv_pfn_t)(int socket, void *buffer, size_t length, int flags);
typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout);
typedef int (*setsockopt_pfn_t)(int socket, int level, int option_name,
const void *option_value, socklen_t option_len);
typedef int (*fcntl_pfn_t)(int fildes, int cmd, ...);
typedef struct tm *(*localtime_r_pfn_t)( const time_t *timep, struct tm *result );
typedef void *(*pthread_getspecific_pfn_t)(pthread_key_t key);
typedef int (*pthread_setspecific_pfn_t)(pthread_key_t key, const void *value);
typedef hostent* (*gethostbyname_pfn_t)(const char *name);
typedef res_state (*__res_state_pfn_t)();
typedef int (*__poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout);
static socket_pfn_t g_sys_socket_func = (socket_pfn_t)dlsym(RTLD_NEXT,"socket");
static connect_pfn_t g_sys_connect_func = (connect_pfn_t)dlsym(RTLD_NEXT,"connect");
static close_pfn_t g_sys_close_func = (close_pfn_t)dlsym(RTLD_NEXT,"close");
static read_pfn_t g_sys_read_func = (read_pfn_t)dlsym(RTLD_NEXT,"read");
static write_pfn_t g_sys_write_func = (write_pfn_t)dlsym(RTLD_NEXT,"write");
static sendto_pfn_t g_sys_sendto_func = (sendto_pfn_t)dlsym(RTLD_NEXT,"sendto");
static recvfrom_pfn_t g_sys_recvfrom_func = (recvfrom_pfn_t)dlsym(RTLD_NEXT,"recvfrom");
static send_pfn_t g_sys_send_func = (send_pfn_t)dlsym(RTLD_NEXT,"send");
static recv_pfn_t g_sys_recv_func = (recv_pfn_t)dlsym(RTLD_NEXT,"recv");
static poll_pfn_t g_sys_poll_func = (poll_pfn_t)dlsym(RTLD_NEXT,"poll");
static setsockopt_pfn_t g_sys_setsockopt_func
= (setsockopt_pfn_t)dlsym(RTLD_NEXT,"setsockopt");
static fcntl_pfn_t g_sys_fcntl_func = (fcntl_pfn_t)dlsym(RTLD_NEXT,"fcntl");
static __res_state_pfn_t g_sys___res_state_func = (__res_state_pfn_t)dlsym(RTLD_NEXT,"__res_state");
static gethostbyname_pfn_t g_sys_gethostbyname_func = (gethostbyname_pfn_t)dlsym(RTLD_NEXT, "gethostbyname");
static __poll_pfn_t g_sys___poll_func = (__poll_pfn_t)dlsym(RTLD_NEXT, "__poll");
/*
static pthread_getspecific_pfn_t g_sys_pthread_getspecific_func
= (pthread_getspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_getspecific");
static pthread_setspecific_pfn_t g_sys_pthread_setspecific_func
= (pthread_setspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_setspecific");
static pthread_rwlock_rdlock_pfn_t g_sys_pthread_rwlock_rdlock_func
= (pthread_rwlock_rdlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_rdlock");
static pthread_rwlock_wrlock_pfn_t g_sys_pthread_rwlock_wrlock_func
= (pthread_rwlock_wrlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_wrlock");
static pthread_rwlock_unlock_pfn_t g_sys_pthread_rwlock_unlock_func
= (pthread_rwlock_unlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_unlock");
*/
static inline unsigned long long get_tick_count()
{
uint32_t lo, hi;
__asm__ __volatile__ (
"rdtscp" : "=a"(lo), "=d"(hi)
);
return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
}
struct rpchook_connagent_head_t
{
unsigned char bVersion;
struct in_addr iIP;
unsigned short hPort;
unsigned int iBodyLen;
unsigned int iOssAttrID;
unsigned char bIsRespNotExist;
unsigned char sReserved[6];
}__attribute__((packed));
#define HOOK_SYS_FUNC(name) if( !g_sys_##name##_func ) { g_sys_##name##_func = (name##_pfn_t)dlsym(RTLD_NEXT,#name); }
static inline ll64_t diff_ms(struct timeval &begin,struct timeval &end)
{
ll64_t u = (end.tv_sec - begin.tv_sec) ;
u *= 1000 * 10;
u += ( end.tv_usec - begin.tv_usec ) / ( 100 );
return u;
}
static inline rpchook_t * get_by_fd( int fd )
{
if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) )
{
return g_rpchook_socket_fd[ fd ];
}
return NULL;
}
static inline rpchook_t * alloc_by_fd( int fd )
{
if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) )
{
rpchook_t *lp = (rpchook_t*)calloc( 1,sizeof(rpchook_t) );
lp->read_timeout.tv_sec = 1;
lp->write_timeout.tv_sec = 1;
g_rpchook_socket_fd[ fd ] = lp;
return lp;
}
return NULL;
}
static inline void free_by_fd( int fd )
{
if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) )
{
rpchook_t *lp = g_rpchook_socket_fd[ fd ];
if( lp )
{
g_rpchook_socket_fd[ fd ] = NULL;
free(lp);
}
}
return;
}
int socket(int domain, int type, int protocol)
{
HOOK_SYS_FUNC( socket );
if( !co_is_enable_sys_hook() )
{
return g_sys_socket_func( domain,type,protocol );
}
int fd = g_sys_socket_func(domain,type,protocol);
if( fd < 0 )
{
return fd;
}
rpchook_t *lp = alloc_by_fd( fd );
lp->domain = domain;
fcntl( fd, F_SETFL, g_sys_fcntl_func(fd, F_GETFL,0 ) );
return fd;
}
int co_accept( int fd, struct sockaddr *addr, socklen_t *len )
{
int cli = accept( fd,addr,len );
if( cli < 0 )
{
return cli;
}
alloc_by_fd( cli );
return cli;
}
int connect(int fd, const struct sockaddr *address, socklen_t address_len)
{
HOOK_SYS_FUNC( connect );
if( !co_is_enable_sys_hook() )
{
return g_sys_connect_func(fd,address,address_len);
}
int ret = g_sys_connect_func(fd,address,address_len);
if( address_len == sizeof(sockaddr_un))
{
const struct sockaddr_un *p = (const struct sockaddr_un *)address;
if( strstr( p->sun_path,"connagent_unix_domain_socket") ) ///tmp/connagent_unix_domain_socket
{
}
}
rpchook_t *lp = get_by_fd( fd );
if( lp )
{
if( sizeof(lp->dest) >= address_len )
{
memcpy( &(lp->dest),address,(int)address_len );
}
}
return ret;
}
int close(int fd)
{
HOOK_SYS_FUNC( close );
if( !co_is_enable_sys_hook() )
{
return g_sys_close_func( fd );
}
free_by_fd( fd );
int ret = g_sys_close_func(fd);
return ret;
}
ssize_t read( int fd, void *buf, size_t nbyte )
{
HOOK_SYS_FUNC( read );
if( !co_is_enable_sys_hook() )
{
return g_sys_read_func( fd,buf,nbyte );
}
rpchook_t *lp = get_by_fd( fd );
if( !lp || ( O_NONBLOCK & lp->user_flag ) )
{
ssize_t ret = g_sys_read_func( fd,buf,nbyte );
return ret;
}
int timeout = ( lp->read_timeout.tv_sec * 1000 )
+ ( lp->read_timeout.tv_usec / 1000 );
struct pollfd pf = { 0 };
pf.fd = fd;
pf.events = ( POLLIN | POLLERR | POLLHUP );
int pollret = poll( &pf,1,timeout );
ssize_t readret = g_sys_read_func( fd,(char*)buf ,nbyte );
if( readret < 0 )
{
co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d",
fd,readret,errno,pollret,timeout);
}
return readret;
}
ssize_t write( int fd, const void *buf, size_t nbyte )
{
HOOK_SYS_FUNC( write );
if( !co_is_enable_sys_hook() )
{
return g_sys_write_func( fd,buf,nbyte );
}
rpchook_t *lp = get_by_fd( fd );
if( !lp || ( O_NONBLOCK & lp->user_flag ) )
{
ssize_t ret = g_sys_write_func( fd,buf,nbyte );
return ret;
}
size_t wrotelen = 0;
int timeout = ( lp->write_timeout.tv_sec * 1000 )
+ ( lp->write_timeout.tv_usec / 1000 );
ssize_t writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen );
if( writeret > 0 )
{
wrotelen += writeret;
}
while( wrotelen < nbyte )
{
struct pollfd pf = { 0 };
pf.fd = fd;
pf.events = ( POLLOUT | POLLERR | POLLHUP );
poll( &pf,1,timeout );
writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen );
if( writeret <= 0 )
{
break;
}
wrotelen += writeret ;
}
return wrotelen;
}
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len)
{
/*
1.no enable sys call ? sys
2.( !lp || lp is non block ) ? sys
3.try
4.wait
5.try
*/
HOOK_SYS_FUNC( sendto );
if( !co_is_enable_sys_hook() )
{
return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );
}
rpchook_t *lp = get_by_fd( socket );
if( !lp || ( O_NONBLOCK & lp->user_flag ) )
{
return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );
}
ssize_t ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );
if( ret < 0 && EAGAIN == errno )
{
int timeout = ( lp->write_timeout.tv_sec * 1000 )
+ ( lp->write_timeout.tv_usec / 1000 );
struct pollfd pf = { 0 };
pf.fd = socket;
pf.events = ( POLLOUT | POLLERR | POLLHUP );
poll( &pf,1,timeout );
ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len );
}
return ret;
}
ssize_t recvfrom(int socket, void *buffer, size_t length,
int flags, struct sockaddr *address,
socklen_t *address_len)
{
HOOK_SYS_FUNC( recvfrom );
if( !co_is_enable_sys_hook() )
{
return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len );
}
rpchook_t *lp = get_by_fd( socket );
if( !lp || ( O_NONBLOCK & lp->user_flag ) )
{
return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len );
}
int timeout = ( lp->read_timeout.tv_sec * 1000 )
+ ( lp->read_timeout.tv_usec / 1000 );
struct pollfd pf = { 0 };
pf.fd = socket;
pf.events = ( POLLIN | POLLERR | POLLHUP );
poll( &pf,1,timeout );
ssize_t ret = g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len );
return ret;
}
ssize_t send(int socket, const void *buffer, size_t length, int flags)
{
HOOK_SYS_FUNC( send );
if( !co_is_enable_sys_hook() )
{
return g_sys_send_func( socket,buffer,length,flags );
}
rpchook_t *lp = get_by_fd( socket );
if( !lp || ( O_NONBLOCK & lp->user_flag ) )
{
return g_sys_send_func( socket,buffer,length,flags );
}
size_t wrotelen = 0;
int timeout = ( lp->write_timeout.tv_sec * 1000 )
+ ( lp->write_timeout.tv_usec / 1000 );
ssize_t writeret = g_sys_send_func( socket,buffer,length,flags );
if( writeret > 0 )
{
wrotelen += writeret;
}
while( wrotelen < length )
{
struct pollfd pf = { 0 };
pf.fd = socket;
pf.events = ( POLLOUT | POLLERR | POLLHUP );
poll( &pf,1,timeout );
writeret = g_sys_send_func( socket,(const char*)buffer + wrotelen,length - wrotelen,flags );
if( writeret <= 0 )
{
break;
}
wrotelen += writeret ;
}
return wrotelen;
}
ssize_t recv( int socket, void *buffer, size_t length, int flags )
{
HOOK_SYS_FUNC( recv );
if( !co_is_enable_sys_hook() )
{
return g_sys_recv_func( socket,buffer,length,flags );
}
rpchook_t *lp = get_by_fd( socket );
if( !lp || ( O_NONBLOCK & lp->user_flag ) )
{
return g_sys_recv_func( socket,buffer,length,flags );
}
int timeout = ( lp->read_timeout.tv_sec * 1000 )
+ ( lp->read_timeout.tv_usec / 1000 );
struct pollfd pf = { 0 };
pf.fd = socket;
pf.events = ( POLLIN | POLLERR | POLLHUP );
int pollret = poll( &pf,1,timeout );
ssize_t readret = g_sys_recv_func( socket,buffer,length,flags );
if( readret < 0 )
{
co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d",
socket,readret,errno,pollret,timeout);
}
return readret;
}
int poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
HOOK_SYS_FUNC( poll );
if( !co_is_enable_sys_hook() )
{
return g_sys_poll_func( fds,nfds,timeout );
}
return co_poll( co_get_epoll_ct(),fds,nfds,timeout );
}
int setsockopt(int fd, int level, int option_name,
const void *option_value, socklen_t option_len)
{
HOOK_SYS_FUNC( setsockopt );
if( !co_is_enable_sys_hook() )
{
return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len );
}
rpchook_t *lp = get_by_fd( fd );
if( lp && SOL_SOCKET == level )
{
struct timeval *val = (struct timeval*)option_value;
if( SO_RCVTIMEO == option_name )
{
memcpy( &lp->read_timeout,val,sizeof(*val) );
}
else if( SO_SNDTIMEO == option_name )
{
memcpy( &lp->write_timeout,val,sizeof(*val) );
}
}
return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len );
}
int fcntl(int fildes, int cmd, ...)
{
HOOK_SYS_FUNC( fcntl );
if( fildes < 0 )
{
return __LINE__;
}
va_list arg_list;
va_start( arg_list,cmd );
int ret = -1;
rpchook_t *lp = get_by_fd( fildes );
switch( cmd )
{
case F_DUPFD:
{
int param = va_arg(arg_list,int);
ret = g_sys_fcntl_func( fildes,cmd,param );
break;
}
case F_GETFD:
{
ret = g_sys_fcntl_func( fildes,cmd );
break;
}
case F_SETFD:
{
int param = va_arg(arg_list,int);
ret = g_sys_fcntl_func( fildes,cmd,param );
break;
}
case F_GETFL:
{
ret = g_sys_fcntl_func( fildes,cmd );
break;
}
case F_SETFL:
{
int param = va_arg(arg_list,int);
int flag = param;
if( co_is_enable_sys_hook() && lp )
{
flag |= O_NONBLOCK;
}
ret = g_sys_fcntl_func( fildes,cmd,flag );
if( 0 == ret && lp )
{
lp->user_flag = param;
}
break;
}
case F_GETOWN:
{
ret = g_sys_fcntl_func( fildes,cmd );
break;
}
case F_SETOWN:
{
int param = va_arg(arg_list,int);
ret = g_sys_fcntl_func( fildes,cmd,param );
break;
}
case F_GETLK:
{
struct flock *param = va_arg(arg_list,struct flock *);
ret = g_sys_fcntl_func( fildes,cmd,param );
break;
}
case F_SETLK:
{
struct flock *param = va_arg(arg_list,struct flock *);
ret = g_sys_fcntl_func( fildes,cmd,param );
break;
}
case F_SETLKW:
{
struct flock *param = va_arg(arg_list,struct flock *);
ret = g_sys_fcntl_func( fildes,cmd,param );
break;
}
}
va_end( arg_list );
return ret;
}
struct res_state_wrap
{
struct __res_state state;
};
CO_ROUTINE_SPECIFIC(res_state_wrap, __co_state_wrap);
extern "C"
{
res_state __res_state()
{
HOOK_SYS_FUNC(__res_state);
if (!co_is_enable_sys_hook())
{
return g_sys___res_state_func();
}
return &(__co_state_wrap->state);
}
int __poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
return poll(fds, nfds, timeout);
}
}
struct hostbuf_wrap
{
struct hostent host;
char* buffer;
size_t iBufferSize;
int host_errno;
};
CO_ROUTINE_SPECIFIC(hostbuf_wrap, __co_hostbuf_wrap);
struct hostent *co_gethostbyname(const char *name)
{
if (!name)
{
return NULL;
}
if (__co_hostbuf_wrap->buffer && __co_hostbuf_wrap->iBufferSize > 1024)
{
free(__co_hostbuf_wrap->buffer);
__co_hostbuf_wrap->buffer = NULL;
}
if (!__co_hostbuf_wrap->buffer)
{
__co_hostbuf_wrap->buffer = (char*)malloc(1024);
__co_hostbuf_wrap->iBufferSize = 1024;
}
struct hostent *host = &__co_hostbuf_wrap->host;
struct hostent *result = NULL;
int *h_errnop = &(__co_hostbuf_wrap->host_errno);
int ret = -1;
while (ret = gethostbyname_r(name, host, __co_hostbuf_wrap->buffer,
__co_hostbuf_wrap->iBufferSize, &result, h_errnop) == ERANGE &&
*h_errnop == NETDB_INTERNAL )
{
free(__co_hostbuf_wrap->buffer);
__co_hostbuf_wrap->iBufferSize = __co_hostbuf_wrap->iBufferSize * 2;
__co_hostbuf_wrap->buffer = (char*)malloc(__co_hostbuf_wrap->iBufferSize);
}
if (ret == 0 && (host == result))
{
return host;
}
return NULL;
}
void co_enable_hook_sys() //这函数必须在这里,否则本文件会被忽略!!!
{
stCoRoutine_t *co = GetCurrThreadCo();
if( co )
{
co->cEnableSysHook = 1;
}
}
//gzrd_Lib_CPP_Version_ID--start
#ifndef GZRD_SVN_ATTR
#define GZRD_SVN_ATTR "0"
#endif
static char gzrd_Lib_CPP_Version_ID[] __attribute__((used))="$HeadURL$ $Id$ " GZRD_SVN_ATTR "__file__";
// gzrd_Lib_CPP_Version_ID--end

1125
co_routine.cpp Normal file

File diff suppressed because it is too large Load Diff

89
co_routine.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CO_ROUTINE_H__
#define __CO_ROUTINE_H__
#include <stdint.h>
#include <sys/poll.h>
#include <pthread.h>
//1.struct
struct stCoRoutine_t;
struct stShareStack_t;
struct stCoRoutineAttr_t
{
int stack_size;
stShareStack_t* share_stack;
stCoRoutineAttr_t()
{
stack_size = 128 * 1024;
share_stack = NULL;
}
}__attribute__ ((packed));
struct stCoEpoll_t;
typedef int (*pfn_co_eventloop_t)(void *);
typedef void *(*pfn_co_routine_t)( void * );
//2.co_routine
int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg );
void co_resume( stCoRoutine_t *co );
void co_yield( stCoRoutine_t *co );
void co_yield_ct(); //ct = current thread
void co_release( stCoRoutine_t *co );
stCoRoutine_t *co_self();
int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms );
void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg );
//3.specific
int co_setspecific( pthread_key_t key, const void *value );
void * co_getspecific( pthread_key_t key );
//4.event
stCoEpoll_t * co_get_epoll_ct(); //ct = current thread
//5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto )
void co_enable_hook_sys();
void co_disable_hook_sys();
bool co_is_enable_sys_hook();
//6.sync
struct stCoCond_t;
stCoCond_t *co_cond_alloc();
int co_cond_free( stCoCond_t * cc );
int co_cond_signal( stCoCond_t * );
int co_cond_broadcast( stCoCond_t * );
int co_cond_timedwait( stCoCond_t *,int timeout_ms );
//7.share stack
stShareStack_t* co_alloc_sharestack(int iCount, int iStackSize);
void co_log_err( const char *fmt,... );
#endif

1631
co_routine.main.cpp Normal file

File diff suppressed because it is too large Load Diff

119
co_routine.main.h Normal file
View File

@ -0,0 +1,119 @@
/*
Author:sunny
Date:2013.8
*/
#ifndef __CO_ROUTINE_H__
#define __CO_ROUTINE_H__
#include <ucontext.h>
#include <stdint.h>
#include <sys/poll.h>
//1.struct
struct stCoRoutine_t;
struct stStackMemEnv_t;
struct stCoRoutineAttr_t
{
int stack_size;
char no_protect_stack;
char use_share_stack;
stStackMemEnv_t* stack_env;
//char reserve[ 58 ];
}__attribute__ ((packed));
struct stCoRoutineStat_t
{
unsigned long long hit_count;
unsigned long long not_hit_count;
unsigned long long alloc_buffer_size;
unsigned long long copy_out_size;
unsigned long long copy_out_count;
unsigned long long copy_in_size;
unsigned long long copy_in_count;
unsigned long long copy_resume_count;
unsigned long long normal_resume_count;
unsigned long long yield_cnt;
unsigned long long use_share_stack_cnt;
};
struct stCoEpoll_t;
typedef int (*pfn_co_eventloop_t)(void *);
typedef void *(*pfn_co_routine_t)( void * );
typedef void *(*pfn_sys_getspecific_t)( pthread_key_t key );
typedef int (*pfn_sys_setspecific_t)( pthread_key_t key,const void *value );
typedef void (*pfn_co_eventloop_start_t)(int iEventCnt);
typedef void (*pfn_co_eventloop_end_t)();
typedef void (*pfn_before_yield_cb_t)(void *);
//2.co_routine
int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg );
void co_resume( stCoRoutine_t *co );
void co_yield( stCoRoutine_t *co );
void co_yield_ct(); //ct = current thread
void co_yield_resume_ct( stCoRoutine_t *dest ); //ct = current thread
void co_release( stCoRoutine_t *co );
int co_add_persist_event( stCoEpoll_t *ctx, int fd , int events);
int co_yield_timeout(int timeout = 30000);
stCoRoutine_t *co_self();
bool co_is_main();
int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms );
void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg );
void co_reset_epolltimeout();
//3.specific
int co_setspecific( pthread_key_t key, const void *value );
void * co_getspecific( pthread_key_t key );
void co_set_sys_specific_func(pfn_sys_getspecific_t get, pfn_sys_setspecific_t set);
void co_set_eventloop_stat(pfn_co_eventloop_start_t start, pfn_co_eventloop_end_t end);
void co_set_before_yield_cb( pfn_before_yield_cb_t cb,void *arg );
//4.event
stCoEpoll_t * co_get_epoll_ct(); //ct = current thread
//5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto )
void co_enable_hook_sys();
void co_disable_hook_sys();
bool co_is_enable_sys_hook();
void co_log_err( const char *fmt,... );
void co_set_env_list( const char *name[],size_t cnt);
//6.sync
struct stCoCond_t;
stCoCond_t *co_cond_alloc();
int co_cond_free( stCoCond_t * cc );
int co_cond_signal( stCoCond_t * );
int co_cond_broadcast( stCoCond_t * );
int co_cond_timedwait( stCoCond_t *,int timeout_ms );
typedef void (*pfn_co_before_yield)();
typedef void (*pfn_co_after_yield)();
void co_set_yield_func(pfn_co_after_yield before, pfn_co_after_yield after);
//protect
void SetUseProtect(bool bUseProtect);
void co_enable_share_stack(bool bEnableShareStack);
//for copy stack
stCoRoutineStat_t* co_get_curr_stat();
stStackMemEnv_t* co_alloc_stackmemenv(int iCount, int iStackSize);
#endif

109
co_routine_inner.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CO_ROUTINE_INNER_H__
#include "co_routine.h"
#include "coctx.h"
struct stCoRoutineEnv_t;
struct stCoSpec_t
{
void *value;
};
struct stStackMem_t
{
stCoRoutine_t* ocupy_co;
int stack_size;
char* stack_bp; //stack_buffer + stack_size
char* stack_buffer;
};
struct stShareStack_t
{
unsigned int alloc_idx;
int stack_size;
int count;
stStackMem_t** stack_array;
};
struct stCoRoutine_t
{
stCoRoutineEnv_t *env;
pfn_co_routine_t pfn;
void *arg;
coctx_t ctx;
char cStart;
char cEnd;
char cIsMain;
char cEnableSysHook;
char cIsShareStack;
//char sRunStack[ 1024 * 128 ];
stStackMem_t* stack_mem;
//save satck buffer while confilct on same stack_buffer;
char* stack_sp;
unsigned int save_size;
char* save_buffer;
stCoSpec_t aSpec[1024];
};
//1.env
void co_init_curr_thread_env();
stCoRoutineEnv_t * co_get_curr_thread_env();
//2.coroutine
void co_free( stCoRoutine_t * co );
void co_yield_env( stCoRoutineEnv_t *env );
//3.func
//-----------------------------------------------------------------------------------------------
struct stTimeout_t;
struct stTimeoutItem_t ;
stTimeout_t *AllocTimeout( int iSize );
void FreeTimeout( stTimeout_t *apTimeout );
int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow );
struct stCoEpoll_t;
stCoEpoll_t * AllocEpoll();
void FreeEpoll( stCoEpoll_t *ctx );
stCoRoutine_t * GetCurrThreadCo();
void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev );
typedef void (*pfnCoRoutineFunc_t)();
#endif
#define __CO_ROUTINE_INNER_H__

97
co_routine_inner.main.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef __CO_ROUTINE_INNER_H__
#define __CO_ROUTINE_INNER_H__
#include "co_routine.h"
#include "coctx.h"
#include <sys/types.h>
#include <sys/socket.h>
struct stCoRoutineEnv_t;
struct stCoSpec_t
{
void *value;
};
struct stStackMem_t;
struct stStackMemEnv_t;
struct stCoRoutine_t
{
stCoRoutineEnv_t *env;
pfn_co_routine_t pfn;
void *arg;
//ucontext_t ctx;
coctx_t ctx;
char cStart;
char cEnd;
//stCoSpec_t aSpecInner[ 128 ];
//stCoSpec_t aSpecInner2[ 128 ];
//stCoSpec_t *aSpecPtr[ 4096 / 128 ];// 2 ^ 7
stCoSpec_t **aSpecPtr;
char cIsMain;
char cEnableSysHook;
void *pvEnv;
char cNoProtectStack;
stStackMem_t* pDynamicStack;
//for copy stack;
stStackMemEnv_t* pStackEnv;
char *pRunStackSP;
char *pBuffer;
int iStackCapacity;
int iStackLen;
//char sRunStack[ 1 ]; //the last field!!
/*************/
/* forbidden */
/*************/
//in the hell
char *pRunStack;
};
//1.env
void co_init_curr_thread_env();
stCoRoutineEnv_t * co_get_curr_thread_env();
//2.coroutine
void co_free( stCoRoutine_t * co );
void co_yield_env( stCoRoutineEnv_t *env );
//3.func
//-----------------------------------------------------------------------------------------------
struct stTimeout_t;
struct stTimeoutItem_t ;
stTimeout_t *AllocTimeout( int iSize );
void FreeTimeout( stTimeout_t *apTimeout );
int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow );
struct stCoEpoll_t;
stCoEpoll_t * AllocEpoll();
void FreeEpoll( stCoEpoll_t *ctx );
stCoRoutine_t * GetCurrThreadCo();
void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev );
typedef void (*pfnCoRoutineFunc_t)();
//event
struct stCoEvent_t;
typedef void* (*pfn_co_event_call_back)(int fd, int revent, void* args);
stCoEvent_t* co_alloc_event();
int co_free_event(stCoEvent_t* coevent);
int co_get_eventfd(stCoEvent_t* coevent);
int co_add_event(stCoEvent_t* coevent, int fd, pfn_co_event_call_back pfn, void* args, unsigned int events, int timeout);
int co_accept( int fd, struct sockaddr *addr, socklen_t *len );
#endif

68
co_routine_specific.h Normal file
View File

@ -0,0 +1,68 @@
#pragma once
#include <pthread.h>
#include <stdlib.h>
/*
invoke only once in the whole program
CoRoutineSetSpecificCallBack(CoRoutineGetSpecificFunc_t pfnGet,CoRoutineSetSpecificFunc_t pfnSet)
struct MyData_t
{
int iValue;
char szValue[100];
};
CO_ROUTINE_SPECIFIC( MyData_t,__routine );
int main()
{
CoRoutineSetSpecificCallBack( co_getspecific,co_setspecific );
__routine->iValue = 10;
strcpy( __routine->szValue,"hello world" );
return 0;
}
*/
extern int co_setspecific( pthread_key_t key, const void *value );
extern void * co_getspecific( pthread_key_t key );
#define CO_ROUTINE_SPECIFIC( name,y ) \
\
static pthread_once_t _routine_once_##name = PTHREAD_ONCE_INIT; \
static pthread_key_t _routine_key_##name;\
static int _routine_init_##name = 0;\
static void _routine_make_key_##name() \
{\
(void) pthread_key_create(&_routine_key_##name, NULL); \
}\
template <class T>\
class clsRoutineData_routine_##name\
{\
public:\
inline T *operator->()\
{\
if( !_routine_init_##name ) \
{\
pthread_once( &_routine_once_##name,_routine_make_key_##name );\
_routine_init_##name = 1;\
}\
T* p = (T*)co_getspecific( _routine_key_##name );\
if( !p )\
{\
p = (T*)calloc(1,sizeof( T ));\
int ret = co_setspecific( _routine_key_##name,p) ;\
if ( ret )\
{\
if ( p )\
{\
free(p);\
p = NULL;\
}\
}\
}\
return p;\
}\
};\
\
static clsRoutineData_routine_##name<name> y;

146
coctx.cpp Normal file
View File

@ -0,0 +1,146 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "coctx.h"
#include <string.h>
#define ESP 0
#define EIP 1
#define EAX 2
#define ECX 3
// -----------
#define RSP 0
#define RIP 1
#define RBX 2
#define RDI 3
#define RSI 4
#define RBP 5
#define R12 6
#define R13 7
#define R14 8
#define R15 9
#define RDX 10
#define RCX 11
#define R8 12
#define R9 13
//----- --------
// 32 bit
// | regs[0]: ret |
// | regs[1]: ebx |
// | regs[2]: ecx |
// | regs[3]: edx |
// | regs[4]: edi |
// | regs[5]: esi |
// | regs[6]: ebp |
// | regs[7]: eax | = esp
enum
{
kEIP = 0,
kESP = 7,
};
//-------------
// 64 bit
//low | regs[0]: r15 |
// | regs[1]: r14 |
// | regs[2]: r13 |
// | regs[3]: r12 |
// | regs[4]: r9 |
// | regs[5]: r8 |
// | regs[6]: rbp |
// | regs[7]: rdi |
// | regs[8]: rsi |
// | regs[9]: ret | //ret func addr
// | regs[10]: rdx |
// | regs[11]: rcx |
// | regs[12]: rbx |
//hig | regs[13]: rsp |
enum
{
kRDI = 7,
kRSI = 8,
kRETAddr = 9,
kRSP = 13,
};
//64 bit
extern "C"
{
extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap");
};
#if defined(__i386__)
int coctx_init( coctx_t *ctx )
{
memset( ctx,0,sizeof(*ctx));
return 0;
}
int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 )
{
//make room for coctx_param
char *sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t);
sp = (char*)((unsigned long)sp & -16L);
coctx_param_t* param = (coctx_param_t*)sp ;
param->s1 = s;
param->s2 = s1;
memset(ctx->regs, 0, sizeof(ctx->regs));
ctx->regs[ kESP ] = (char*)(sp) - sizeof(void*);
ctx->regs[ kEIP ] = (char*)pfn;
return 0;
}
#elif defined(__x86_64__)
int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 )
{
char *sp = ctx->ss_sp + ctx->ss_size;
sp = (char*) ((unsigned long)sp & -16LL );
memset(ctx->regs, 0, sizeof(ctx->regs));
ctx->regs[ kRSP ] = sp - 8;
ctx->regs[ kRETAddr] = (char*)pfn;
ctx->regs[ kRDI ] = (char*)s;
ctx->regs[ kRSI ] = (char*)s1;
return 0;
}
int coctx_init( coctx_t *ctx )
{
memset( ctx,0,sizeof(*ctx));
return 0;
}
#endif
//gzrd_Lib_CPP_Version_ID--start
#ifndef GZRD_SVN_ATTR
#define GZRD_SVN_ATTR "0"
#endif
static char gzrd_Lib_CPP_Version_ID[] __attribute__((used))="$HeadURL: http://tc-svn.tencent.com/pub/pub_libco_rep/libco_proj/trunk/coctx.cpp $ $Id: coctx.cpp 39 2016-09-29 07:26:29Z leiffyli $ " GZRD_SVN_ATTR "__file__";
// gzrd_Lib_CPP_Version_ID--end

42
coctx.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CO_CTX_H__
#define __CO_CTX_H__
#include <stdlib.h>
typedef void* (*coctx_pfn_t)( void* s, void* s2 );
struct coctx_param_t
{
const void *s1;
const void *s2;
};
struct coctx_t
{
#if defined(__i386__)
void *regs[ 8 ];
#else
void *regs[ 14 ];
#endif
size_t ss_size;
char *ss_sp;
};
int coctx_init( coctx_t *ctx );
int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 );
#endif

95
coctx_swap.S Normal file
View File

@ -0,0 +1,95 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.globl coctx_swap
#if !defined( __APPLE__ )
.type coctx_swap, @function
#endif
coctx_swap:
#if defined(__i386__)
leal 4(%esp), %eax //sp
movl 4(%esp), %esp
leal 32(%esp), %esp //parm a : &regs[7] + sizeof(void*)
pushl %eax //esp ->parm a
pushl %ebp
pushl %esi
pushl %edi
pushl %edx
pushl %ecx
pushl %ebx
pushl -4(%eax)
movl 4(%eax), %esp //parm b -> &regs[0]
popl %eax //ret func addr
popl %ebx
popl %ecx
popl %edx
popl %edi
popl %esi
popl %ebp
popl %esp
pushl %eax //set ret func addr
xorl %eax, %eax
ret
#elif defined(__x86_64__)
leaq 8(%rsp),%rax
leaq 112(%rdi),%rsp
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq -8(%rax) //ret func addr
pushq %rsi
pushq %rdi
pushq %rbp
pushq %r8
pushq %r9
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsi, %rsp
popq %r15
popq %r14
popq %r13
popq %r12
popq %r9
popq %r8
popq %rbp
popq %rdi
popq %rsi
popq %rax //ret func addr
popq %rdx
popq %rcx
popq %rbx
popq %rsp
pushq %rax
xorl %eax, %eax
ret
#endif

69
example_closure.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "co_closure.h"
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <pthread.h>
#include <unistd.h>
using namespace std;
static void *thread_func( void * arg )
{
stCoClosure_t *p = (stCoClosure_t*) arg;
p->exec();
return 0;
}
static void batch_exec( vector<stCoClosure_t*> &v )
{
vector<pthread_t> ths;
for( size_t i=0;i<v.size();i++ )
{
pthread_t tid;
pthread_create( &tid,0,thread_func,v[i] );
ths.push_back( tid );
}
for( size_t i=0;i<v.size();i++ )
{
pthread_join( ths[i],0 );
}
}
int main( int argc,char *argv[] )
{
vector< stCoClosure_t* > v;
int total = 100;
vector<int> v2;
co_ref( ref,total,v2 );
for(int i=0;i<10;i++)
{
co_func( f,ref,i )
{
printf("ref.total %d i %d\n",ref.total,i );
//lock
ref.v2.push_back( i );
//unlock
}
co_func_end;
v.push_back( new f( ref,i ) );
}
for(int i=0;i<2;i++)
{
co_func( f2,i )
{
printf("i: %d\n",i);
for(int j=0;j<2;j++)
{
usleep( 1000 );
printf("i %d j %d\n",i,j);
}
}
co_func_end;
v.push_back( new f2( i ) );
}
batch_exec( v );
printf("done\n");
return 0;
}

65
example_cond.cpp Normal file
View File

@ -0,0 +1,65 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include "co_routine.h"
using namespace std;
struct stTask_t
{
int id;
};
struct stEnv_t
{
stCoCond_t* cond;
queue<stTask_t*> task_queue;
};
void* Producer(void* args)
{
co_enable_hook_sys();
stEnv_t* env= (stEnv_t*)args;
int id = 0;
while (true)
{
stTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t));
task->id = id++;
env->task_queue.push(task);
printf("%s:%d produce task %d\n", __func__, __LINE__, task->id);
co_cond_signal(env->cond);
poll(NULL, 0, 1000);
}
return NULL;
}
void* Consumer(void* args)
{
co_enable_hook_sys();
stEnv_t* env = (stEnv_t*)args;
while (true)
{
if (env->task_queue.empty())
{
co_cond_timedwait(env->cond, -1);
continue;
}
stTask_t* task = env->task_queue.front();
env->task_queue.pop();
printf("%s:%d consume task %d\n", __func__, __LINE__, task->id);
free(task);
}
return NULL;
}
int main()
{
stEnv_t* env = new stEnv_t;
env->cond = co_cond_alloc();
stCoRoutine_t* consumer_routine;
co_create(&consumer_routine, NULL, Consumer, env);
co_resume(consumer_routine);
stCoRoutine_t* producer_routine;
co_create(&producer_routine, NULL, Producer, env);
co_resume(producer_routine);
co_eventloop(co_get_epoll_ct(), NULL, NULL);
return 0;
}

44
example_copystack.cpp Normal file
View File

@ -0,0 +1,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <errno.h>
#include <string.h>
#include "coctx.h"
#include "co_routine.h"
#include "co_routine_inner.h"
void* RoutineFunc(void* args)
{
co_enable_hook_sys();
int* routineid = (int*)args;
while (true)
{
char sBuff[128];
sprintf(sBuff, "from routineid %d stack addr %p\n", *routineid, sBuff);
printf("%s", sBuff);
poll(NULL, 0, 1000); //sleep 1s
}
return NULL;
}
int main()
{
stShareStack_t* share_stack= co_alloc_sharestack(1, 1024 * 128);
stCoRoutineAttr_t attr;
attr.stack_size = 0;
attr.share_stack = share_stack;
stCoRoutine_t* co[2];
int routineid[2];
for (int i = 0; i < 3; i++)
{
routineid[i] = i;
co_create(&co[i], &attr, RoutineFunc, routineid + i);
co_resume(co[i]);
}
co_eventloop(co_get_epoll_ct(), NULL, NULL);
return 0;
}

218
example_echocli.cpp Normal file
View File

@ -0,0 +1,218 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "co_routine.h"
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <stack>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
using namespace std;
struct stEndPoint
{
char *ip;
unsigned short int port;
};
static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr)
{
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(shPort);
int nIP = 0;
if( !pszIP || '\0' == *pszIP
|| 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0")
|| 0 == strcmp(pszIP,"*")
)
{
nIP = htonl(INADDR_ANY);
}
else
{
nIP = inet_addr(pszIP);
}
addr.sin_addr.s_addr = nIP;
}
static int iSuccCnt = 0;
static int iFailCnt = 0;
static int iTime = 0;
void AddSuccCnt()
{
int now = time(NULL);
if (now >iTime)
{
printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt);
iTime = now;
iSuccCnt = 0;
iFailCnt = 0;
}
else
{
iSuccCnt++;
}
}
void AddFailCnt()
{
int now = time(NULL);
if (now >iTime)
{
printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt);
iTime = now;
iSuccCnt = 0;
iFailCnt = 0;
}
else
{
iFailCnt++;
}
}
static void *readwrite_routine( void *arg )
{
co_enable_hook_sys();
stEndPoint *endpoint = (stEndPoint *)arg;
char str[8]="sarlmol";
char buf[ 1024 * 16 ];
int fd = -1;
int ret = 0;
for(;;)
{
if ( fd < 0 )
{
fd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
SetAddr(endpoint->ip, endpoint->port, addr);
ret = connect(fd,(struct sockaddr*)&addr,sizeof(addr));
if ( errno == EALREADY || errno == EINPROGRESS )
{
struct pollfd pf = { 0 };
pf.fd = fd;
pf.events = (POLLOUT|POLLERR|POLLHUP);
co_poll( co_get_epoll_ct(),&pf,1,200);
//check connect
int error = 0;
uint32_t socklen = sizeof(error);
errno = 0;
ret = getsockopt(fd, SOL_SOCKET, SO_ERROR,(void *)&error, &socklen);
if ( ret == -1 )
{
//printf("getsockopt ERROR ret %d %d:%s\n", ret, errno, strerror(errno));
close(fd);
fd = -1;
AddFailCnt();
continue;
}
if ( error )
{
errno = error;
//printf("connect ERROR ret %d %d:%s\n", error, errno, strerror(errno));
close(fd);
fd = -1;
AddFailCnt();
continue;
}
}
}
ret = write( fd,str, 8);
if ( ret > 0 )
{
ret = read( fd,buf, sizeof(buf) );
if ( ret <= 0 )
{
//printf("co %p read ret %d errno %d (%s)\n",
// co_self(), ret,errno,strerror(errno));
close(fd);
fd = -1;
AddFailCnt();
}
else
{
//printf("echo %s fd %d\n", buf,fd);
AddSuccCnt();
}
}
else
{
//printf("co %p write ret %d errno %d (%s)\n",
// co_self(), ret,errno,strerror(errno));
close(fd);
fd = -1;
AddFailCnt();
}
}
return 0;
}
int main(int argc,char *argv[])
{
stEndPoint endpoint;
endpoint.ip = argv[1];
endpoint.port = atoi(argv[2]);
int cnt = atoi( argv[3] );
int proccnt = atoi( argv[4] );
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sa, NULL );
for(int k=0;k<proccnt;k++)
{
pid_t pid = fork();
if( pid > 0 )
{
continue;
}
else if( pid < 0 )
{
break;
}
for(int i=0;i<cnt;i++)
{
stCoRoutine_t *co = 0;
co_create( &co,NULL,readwrite_routine, &endpoint);
co_resume( co );
}
co_eventloop( co_get_epoll_ct(),0,0 );
exit(0);
}
return 0;
}
/*./example_echosvr 127.0.0.1 10000 100 50*/

234
example_echosvr.cpp Normal file
View File

@ -0,0 +1,234 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "co_routine.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/time.h>
#include <stack>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
struct task_t
{
stCoRoutine_t *co;
int fd;
};
static stack<task_t*> g_readwrite;
static int g_listen_fd = -1;
static int SetNonBlock(int iSock)
{
int iFlags;
iFlags = fcntl(iSock, F_GETFL, 0);
iFlags |= O_NONBLOCK;
iFlags |= O_NDELAY;
int ret = fcntl(iSock, F_SETFL, iFlags);
return ret;
}
static void *readwrite_routine( void *arg )
{
co_enable_hook_sys();
task_t *co = (task_t*)arg;
char buf[ 1024 * 16 ];
for(;;)
{
if( -1 == co->fd )
{
g_readwrite.push( co );
co_yield_ct();
continue;
}
int fd = co->fd;
co->fd = -1;
for(;;)
{
struct pollfd pf = { 0 };
pf.fd = fd;
pf.events = (POLLIN|POLLERR|POLLHUP);
co_poll( co_get_epoll_ct(),&pf,1,1000);
int ret = read( fd,buf,sizeof(buf) );
if( ret > 0 )
{
ret = write( fd,buf,ret );
}
if( ret <= 0 )
{
close( fd );
break;
}
}
}
return 0;
}
int co_accept(int fd, struct sockaddr *addr, socklen_t *len );
static void *accept_routine( void * )
{
co_enable_hook_sys();
printf("accept_routine\n");
fflush(stdout);
for(;;)
{
//printf("pid %ld g_readwrite.size %ld\n",getpid(),g_readwrite.size());
if( g_readwrite.empty() )
{
printf("empty\n"); //sleep
struct pollfd pf = { 0 };
pf.fd = -1;
poll( &pf,1,1000);
continue;
}
struct sockaddr_in addr; //maybe sockaddr_un;
memset( &addr,0,sizeof(addr) );
socklen_t len = sizeof(addr);
int fd = co_accept(g_listen_fd, (struct sockaddr *)&addr, &len);
if( fd < 0 )
{
struct pollfd pf = { 0 };
pf.fd = g_listen_fd;
pf.events = (POLLIN|POLLERR|POLLHUP);
co_poll( co_get_epoll_ct(),&pf,1,1000 );
continue;
}
if( g_readwrite.empty() )
{
close( fd );
continue;
}
SetNonBlock( fd );
task_t *co = g_readwrite.top();
co->fd = fd;
g_readwrite.pop();
co_resume( co->co );
}
return 0;
}
static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr)
{
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(shPort);
int nIP = 0;
if( !pszIP || '\0' == *pszIP
|| 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0")
|| 0 == strcmp(pszIP,"*")
)
{
nIP = htonl(INADDR_ANY);
}
else
{
nIP = inet_addr(pszIP);
}
addr.sin_addr.s_addr = nIP;
}
static int CreateTcpSocket(const unsigned short shPort /* = 0 */,const char *pszIP /* = "*" */,bool bReuse /* = false */)
{
int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if( fd >= 0 )
{
if(shPort != 0)
{
if(bReuse)
{
int nReuseAddr = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr));
}
struct sockaddr_in addr ;
SetAddr(pszIP,shPort,addr);
int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));
if( ret != 0)
{
close(fd);
return -1;
}
}
}
return fd;
}
int main(int argc,char *argv[])
{
const char *ip = argv[1];
int port = atoi( argv[2] );
int cnt = atoi( argv[3] );
int proccnt = atoi( argv[4] );
g_listen_fd = CreateTcpSocket( port,ip,true );
listen( g_listen_fd,1024 );
printf("listen %d %s:%d\n",g_listen_fd,ip,port);
SetNonBlock( g_listen_fd );
for(int k=0;k<proccnt;k++)
{
pid_t pid = fork();
if( pid > 0 )
{
continue;
}
else if( pid < 0 )
{
break;
}
for(int i=0;i<cnt;i++)
{
task_t * task = (task_t*)calloc( 1,sizeof(task_t) );
task->fd = -1;
co_create( &(task->co),NULL,readwrite_routine,task );
co_resume( task->co );
}
stCoRoutine_t *accept_co = NULL;
co_create( &accept_co,NULL,accept_routine,0 );
co_resume( accept_co );
co_eventloop( co_get_epoll_ct(),0,0 );
exit(0);
}
return 0;
}

206
example_poll.cpp Normal file
View File

@ -0,0 +1,206 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "co_routine.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/time.h>
#include <stack>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <errno.h>
#include <vector>
#include <set>
#include <unistd.h>
using namespace std;
struct task_t
{
stCoRoutine_t *co;
int fd;
struct sockaddr_in addr;
};
static int SetNonBlock(int iSock)
{
int iFlags;
iFlags = fcntl(iSock, F_GETFL, 0);
iFlags |= O_NONBLOCK;
iFlags |= O_NDELAY;
int ret = fcntl(iSock, F_SETFL, iFlags);
return ret;
}
static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr)
{
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(shPort);
int nIP = 0;
if( !pszIP || '\0' == *pszIP
|| 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0")
|| 0 == strcmp(pszIP,"*")
)
{
nIP = htonl(INADDR_ANY);
}
else
{
nIP = inet_addr(pszIP);
}
addr.sin_addr.s_addr = nIP;
}
static int CreateTcpSocket(const unsigned short shPort = 0 ,const char *pszIP = "*" ,bool bReuse = false )
{
int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if( fd >= 0 )
{
if(shPort != 0)
{
if(bReuse)
{
int nReuseAddr = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr));
}
struct sockaddr_in addr ;
SetAddr(pszIP,shPort,addr);
int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));
if( ret != 0)
{
close(fd);
return -1;
}
}
}
return fd;
}
static void *poll_routine( void *arg )
{
co_enable_hook_sys();
vector<task_t> &v = *(vector<task_t>*)arg;
for(size_t i=0;i<v.size();i++)
{
int fd = CreateTcpSocket();
SetNonBlock( fd );
v[i].fd = fd;
int ret = connect(fd,(struct sockaddr*)&v[i].addr,sizeof( v[i].addr ));
printf("co %p connect i %ld ret %d errno %d (%s)\n",
co_self(),i,ret,errno,strerror(errno));
}
struct pollfd *pf = (struct pollfd*)calloc( 1,sizeof(struct pollfd) * v.size() );
for(size_t i=0;i<v.size();i++)
{
pf[i].fd = v[i].fd;
pf[i].events = ( POLLOUT | POLLERR | POLLHUP );
}
set<int> setRaiseFds;
size_t iWaitCnt = v.size();
for(;;)
{
int ret = poll( pf,iWaitCnt,1000 );
printf("co %p poll wait %ld ret %d\n",
co_self(),iWaitCnt,ret);
for(int i=0;i<ret;i++)
{
printf("co %p fire fd %d revents 0x%X POLLOUT 0x%X POLLERR 0x%X POLLHUP 0x%X\n",
co_self(),
pf[i].fd,
pf[i].revents,
POLLOUT,
POLLERR,
POLLHUP
);
setRaiseFds.insert( pf[i].fd );
}
if( setRaiseFds.size() == v.size())
{
break;
}
if( ret <= 0 )
{
break;
}
iWaitCnt = 0;
for(size_t i=0;i<v.size();i++)
{
if( setRaiseFds.find( v[i].fd ) == setRaiseFds.end() )
{
pf[ iWaitCnt ].fd = v[i].fd;
pf[ iWaitCnt ].events = ( POLLOUT | POLLERR | POLLHUP );
++iWaitCnt;
}
}
}
for(size_t i=0;i<v.size();i++)
{
close( v[i].fd );
v[i].fd = -1;
}
printf("co %p task cnt %ld fire %ld\n",
co_self(),v.size(),setRaiseFds.size() );
return 0;
}
int main(int argc,char *argv[])
{
vector<task_t> v;
for(int i=1;i<argc;i+=2)
{
task_t task = { 0 };
SetAddr( argv[i],atoi(argv[i+1]),task.addr );
v.push_back( task );
}
//------------------------------------------------------------------------------------
printf("--------------------- main -------------------\n");
vector<task_t> v2 = v;
poll_routine( &v2 );
printf("--------------------- routine -------------------\n");
for(int i=0;i<10;i++)
{
stCoRoutine_t *co = 0;
vector<task_t> *v2 = new vector<task_t>();
*v2 = v;
co_create( &co,NULL,poll_routine,v2 );
printf("routine i %d\n",i);
co_resume( co );
}
co_eventloop( co_get_epoll_ct(),0,0 );
return 0;
}
//./example_poll 127.0.0.1 12365 127.0.0.1 12222 192.168.1.1 1000 192.168.1.2 1111

43
example_specific.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "co_routine_specific.h"
#include "co_routine.h"
#include <unistd.h>
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
struct stRoutineArgs_t
{
stCoRoutine_t* co;
int routine_id;
};
struct stRoutineSpecificData_t
{
int idx;
};
CO_ROUTINE_SPECIFIC(stRoutineSpecificData_t, __routine);
void* RoutineFunc(void* args)
{
co_enable_hook_sys();
stRoutineArgs_t* routine_args = (stRoutineArgs_t*)args;
__routine->idx = routine_args->routine_id;
while (true)
{
printf("%s:%d routine specific data idx %d\n", __func__, __LINE__, __routine->idx);
poll(NULL, 0, 1000);
}
return NULL;
}
int main()
{
stRoutineArgs_t args[10];
for (int i = 0; i < 10; i++)
{
args[i].routine_id = i;
co_create(&args[i].co, NULL, RoutineFunc, (void*)&args[i]);
co_resume(args[i].co);
}
co_eventloop(co_get_epoll_ct(), NULL, NULL);
return 0;
}

56
example_thread.cpp Normal file
View File

@ -0,0 +1,56 @@
/*
* Tencent is pleased to support the open source community by making Libco available.
* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "co_routine.h"
#include "co_routine_inner.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
int loop(void *)
{
return 0;
}
static void *routine_func( void * )
{
stCoEpoll_t * ev = co_get_epoll_ct(); //ct = current thread
co_eventloop( ev,loop,0 );
return 0;
}
int main(int argc,char *argv[])
{
int cnt = atoi( argv[1] );
pthread_t tid[ cnt ];
for(int i=0;i<cnt;i++)
{
pthread_create( tid + i,NULL,routine_func,0);
}
for(;;)
{
sleep(1);
}
return 0;
}

BIN
lib/libcolib.a Normal file

Binary file not shown.

BIN
solib/libcolib.so Normal file

Binary file not shown.

224
test_colib.cpp Normal file
View File

@ -0,0 +1,224 @@
#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "coctx.h"
#include "co_routine.h"
#include "co_routine_inner.h"
#include <unistd.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <errno.h>
#include <string.h>
extern "C"
{
extern void coctx_swap(coctx_t*, coctx_t*) asm("coctx_swap");
extern void test_xmm(char*, char*) asm("test_xmm");
}
void Test1()
{
char a16[16] __attribute__ ((aligned (16)))= "0123456789abcde";
char b16[16] __attribute__ ((aligned (16))) = "abcde012345789";
test_xmm( a16, b16);
printf("(%p : %s) (%p : %s) \n", &a16, a16, &b16, b16);
return;
}
void* RoutineFunc(void* args1, void* args2)
{
coctx_t* main = (coctx_t*)(args1);
coctx_t* self = (coctx_t*)args2;
printf("%s:%d args1 %p args2 %p main %p self %p\n", __func__, __LINE__, &args1, &args2, main ,self);
coctx_swap(self, main);
return NULL;
}
void* TestXMMFunc(void* args1, void* args2)
{
Test1();
coctx_t* main = (coctx_t*)(args1);
coctx_t* self = (coctx_t*)args2;
char s = 's';
printf("%s:%d args1 %p args2 %p main %p self %p\n", __func__, __LINE__, &args1, &args2, main ,self);
coctx_swap(self, main);
}
TEST(Coctx, normal)
{
coctx_t main;
coctx_init(&main);
int i = 5;
coctx_t ctx;
coctx_init(&ctx);
ctx.ss_size = 1024 * 128;
ctx.ss_sp = (char*)malloc(ctx.ss_size);
coctx_make(&ctx, RoutineFunc, (void*)&main, (void*)&ctx);
coctx_swap(&main, &ctx);
return;
}
TEST(Coctx, xmm)
{
coctx_t main;
coctx_init(&main);
coctx_t self;
coctx_init(&self);
self.ss_size = 1024 * 128;
self.ss_sp = (char*)malloc(self.ss_size);
coctx_make(&self, TestXMMFunc, (void*)&main, (void*)&self);
coctx_swap(&main, &self);
printf("%s:%d end\n", __func__, __LINE__);
}
int g_iExitEventLoop = 0;
int TickFunc(void* args)
{
if (g_iExitEventLoop == 0)
{
return -1;
}
return 0;
}
void* RoutineFunc1(void* args)
{
co_enable_hook_sys();
int* piRoutineID = (int*)args;
int iRoutinedID = *piRoutineID;
for (int i = 0; i < 2; i++)
{
poll(NULL, 0, 1000);
printf("%s:%d iRoutinedID (%p:%d)\n", __func__, __LINE__, &iRoutinedID, iRoutinedID);
}
g_iExitEventLoop--;
return NULL;
}
TEST(CopyStack, ResumeFromMain)
{
stShareStack_t* env = co_alloc_sharestack(1, 1024 * 128);
int iCount = 2;
g_iExitEventLoop = iCount;
stCoRoutine_t* co[2];
int iRoutineID[2];
for (int i = 0; i < iCount; i++)
{
stCoRoutineAttr_t attr;
attr.share_stack = env;
iRoutineID[i] = i;
co_create(&co[0], &attr, RoutineFunc1, iRoutineID + i);
co_resume(co[0]);
}
co_eventloop(co_get_epoll_ct(), TickFunc, NULL);
}
void* Sender(void* ptArgs)
{
co_enable_hook_sys();
stCoRoutine_t* recever = (stCoRoutine_t*)ptArgs;
while (true)
{
char s[128];
strcpy(s, "from sender\n");
co_resume(recever);
poll(NULL, 0, 1000);
printf("%s:%d %p %s", __func__, __LINE__, s, s);
g_iExitEventLoop--;
if (g_iExitEventLoop == 0)
{
break;
}
}
return NULL;
}
void* Recever(void* ptArgs)
{
co_enable_hook_sys();
while (true)
{
char s[128];
strcpy(s, "from recever\n");
co_yield_ct();
printf("%s:%d %p %s", __func__, __LINE__, s, s);
}
}
TEST(CopyStack, ResumeFromSender)
{
g_iExitEventLoop = 2;
stShareStack_t* env = co_alloc_sharestack(1, 1024 * 128);
stCoRoutineAttr_t attr;
attr.share_stack = env;
stCoRoutine_t* recever;
co_create(&recever, &attr, Recever, NULL);
co_resume(recever);
stCoRoutine_t* sender;
co_create(&sender, &attr, Sender, (void*)recever);
co_resume(sender);
co_eventloop(co_get_epoll_ct(), TickFunc, NULL);
}
TEST(NoCopyStack, ResumeFromMain)
{
stShareStack_t* env = co_alloc_sharestack(1, 1024 * 128);
int iCount = 2;
g_iExitEventLoop = iCount;
stCoRoutine_t* co[2];
int iRoutineID[2];
for (int i = 0; i < iCount; i++)
{
stCoRoutineAttr_t attr;
attr.share_stack = env;
iRoutineID[i] = i;
co_create(&co[0], &attr, RoutineFunc1, iRoutineID + i);
co_resume(co[0]);
}
co_eventloop(co_get_epoll_ct(), TickFunc, NULL);
}
TEST(NoCopyStack, ResumeFromSender)
{
g_iExitEventLoop = 2;
stShareStack_t* env = co_alloc_sharestack(1, 1024 * 128);
stCoRoutineAttr_t attr;
attr.share_stack = env;
stCoRoutine_t* recever;
co_create(&recever, &attr, Recever, NULL);
co_resume(recever);
stCoRoutine_t* sender;
co_create(&sender, &attr, Sender, (void*)recever);
co_resume(sender);
co_eventloop(co_get_epoll_ct(), TickFunc, NULL);
}
int main(int argc, char* argv[])
{
printf("size %d\n", sizeof(stCoRoutine_t));
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
//gzrd_Lib_CPP_Version_ID--start
#ifndef GZRD_SVN_ATTR
#define GZRD_SVN_ATTR "0"
#endif
static char gzrd_Lib_CPP_Version_ID[] __attribute__((used))="$HeadURL: http://scm-gy.tencent.com/gzrd/gzrd_mail_rep/QQMailcore_proj/trunk/basic/colib/test/test_colib.cpp $ $Id: test_colib.cpp 1650485 2016-06-28 06:34:38Z leiffyli $ " GZRD_SVN_ATTR "__file__";
// gzrd_Lib_CPP_Version_ID--end

14
test_xmm.S Normal file
View File

@ -0,0 +1,14 @@
.globl test_xmm
test_xmm:
#if defined(__i386__)
movl 4(%esp), %eax
movl 8(%esp), %ecx
movaps (%eax),%xmm0
movaps %xmm0,(%ecx)
#elif defined(__x86_64__)
movaps (%rdi),%xmm0
movaps %xmm0,(%rsi)
#endif
ret