int32_t session_start_reconnect( struct session * self ) { evsets_t sets = self->evsets; if ( self->status&SESSION_EXITING ) { // 会话等待退出, return -1; } if ( self->status&SESSION_WRITING ) { // 正在等待写事件的情况下 return -2; } // 停止会话 _stop( self ); // 2秒后尝试重连, 避免忙等 event_set( self->evwrite, -1, 0 ); event_set_callback( self->evwrite, channel_on_reconnect, self ); evsets_add( sets, self->evwrite, TRY_RECONNECT_INTERVAL ); self->status |= SESSION_WRITING; // 让session忙起来 return 0; }
void trylock_accept_mutex( struct iothread * thr ) { struct acceptor * a = thr->core_acceptor; if ( pthread_mutex_trylock(&(a->lock)) == 0 ) { if ( a->holding == 0 ) { #if USE_LIBEVENT event_set( a->ev_accept, a->socketfd, EV_READ, accept_new_session, thr ); event_base_set( thr->core_sets, a->ev_accept ); event_add( a->ev_accept, 0 ); #else event_set( a->ev_accept, a->socketfd, EV_READ ); event_set_callback( a->ev_accept, accept_new_session, thr ); evsets_add(thr->core_sets, a->ev_accept, 0 ); #endif a->holding = 1; } //pthread_mutex_unlock( &(a->lock) ); } return; }
void accept_new_session( int32_t fd, int16_t ev, void * arg ) { evsets_t coreset = ( evsets_t )arg; if ( ev & EV_READ ) { char dsthost[20]; uint16_t dstport = 0; int32_t newfd = tcp_accept( fd, dsthost, &dstport ); if ( newfd > 0 ) { set_non_block( newfd ); event_t event = event_create(); if ( event == NULL ) { printf( "accept new fd failed .\n" ); return; } event_set( event, newfd, EV_READ|EV_PERSIST ); event_set_callback( event, process_message, event ); evsets_add( coreset, event, 0 ); } } }
void ev_timer_callback( int32_t fd, int16_t ev, void * arg ) { event_t e = (event_t)arg; evsets_t sets = event_get_sets( e ); printf("ev_timer_callback(handler=%p, fd=%d, ev=%d) : %d \n", e, fd, ev, time(NULL) ); evsets_add( sets, e, 2*1000 ); }
int32_t _listen_direct( evsets_t sets, struct acceptor * acceptor ) { // 开始关注accept事件 event_set( acceptor->event, acceptor->fd, EV_READ|EV_PERSIST ); event_set_callback( acceptor->event, channel_on_accept, acceptor ); evsets_add( sets, acceptor->event, 0 ); return 0; }
int32_t _connect_direct( evsets_t sets, struct connector * connector ) { // 开始关注连接事件 connector->evsets = sets; event_set( connector->event, connector->fd, EV_WRITE ); event_set_callback( connector->event, channel_on_connected, connector ); evsets_add( sets, connector->event, connector->mseconds ); return 0; }
void echoserver_process_message( int32_t fd, int16_t ev, void * arg ) { struct session * s = (struct session *)arg; if ( ev & EV_READ ) { char buf[16384]; int32_t readn = -1; readn = read( fd, buf, 16384 ); if ( readn <= 0 ) { #if __DEBUG printf( "Client[%ld, %d] is closed, BYTES:%d, TIME:%lld .\n", s->sid, s->fd, s->iobytes, mtime() ); #endif //evsets_del( event_get_sets(s->evread), s->evread ); event_destroy( s->evread ); close( s->fd ); free( s ); goto PROCESS_END; } else { #if __DEBUG printf("echoserver_process_message(ev:%d) : TIME:%lld .\n", ev, mtime() ); #endif readn = write( fd, buf, readn ); s->iobytes += readn; } #if USE_LIBEVENT { struct timeval tv = {TIMEOUT_MSECS/1000, 0}; event_add( s->evread, &tv ); } #else evsets_add( event_get_sets(s->evread), s->evread, TIMEOUT_MSECS ); #endif } else { #if __DEBUG printf("echoserver_process_message(ev:%d) : TIME:%lld .\n", ev, mtime() ); #endif } PROCESS_END : return; }
// 注册网络事件 void session_add_event( struct session * self, int16_t ev ) { int8_t status = self->status; evsets_t sets = self->evsets; // 注册读事件 // 不在等待读事件的正常会话 if ( !(status&SESSION_EXITING) && (ev&EV_READ) && !(status&SESSION_READING) ) { event_set( self->evread, self->fd, ev ); event_set_callback( self->evread, channel_on_read, self ); evsets_add( sets, self->evread, self->setting.timeout_msecs ); self->status |= SESSION_READING; } // 注册写事件 if ( (ev&EV_WRITE) && !(status&SESSION_WRITING) ) { int32_t wait_for_shutdown = 0; // 在等待退出的会话上总是会添加10s的定时器 if ( status&SESSION_EXITING ) { // 对端主机崩溃 + Socket缓冲区满的情况下 // 会一直等不到EV_WRITE发生, 这时libevlite就出现了会话泄漏 wait_for_shutdown = MAX_SECONDS_WAIT_FOR_SHUTDOWN; } event_set( self->evwrite, self->fd, ev ); event_set_callback( self->evwrite, channel_on_write, self ); evsets_add( sets, self->evwrite, wait_for_shutdown ); self->status |= SESSION_WRITING; } }
int32_t session_start_keepalive( struct session * self ) { int8_t status = self->status; evsets_t sets = self->evsets; if ( self->setting.keepalive_msecs > 0 && !(status&SESSION_KEEPALIVING) ) { event_set( self->evkeepalive, -1, 0 ); event_set_callback( self->evkeepalive, channel_on_keepalive, self ); evsets_add( sets, self->evkeepalive, self->setting.keepalive_msecs ); self->status |= SESSION_KEEPALIVING; } return 0; }
int32_t iolayer_reconnect( struct iolayer * self, struct connector * connector ) { // 首先必须先关闭以前的描述符 if ( connector->fd > 0 ) { close( connector->fd ); connector->fd = -1; } // 2秒后尝试重连, 避免忙等 event_set( connector->event, -1, 0 ); event_set_callback( connector->event, _reconnect_direct, connector ); evsets_add( connector->evsets, connector->event, TRY_RECONNECT_INTERVAL ); return 0; }
int32_t test_addtimer( evsets_t sets, event_t * events ) { int32_t i = 0; struct timeval tv_start, tv_end; gettimeofday( &tv_start, NULL ); for ( i = 0; i < NTEST; ++i ) { evsets_add( sets, events[i], 10000 ); } gettimeofday( &tv_end, NULL ); printf("evsets_add(%d) : %ld secs, %ld usecs .\n", NTEST, tv_end.tv_sec - tv_start.tv_sec, tv_end.tv_usec - tv_start.tv_usec ); return 0; }
int32_t iothread_start( struct iothread * self, uint8_t index, iothreads_t parent ) { self->index = index; self->parent = parent; self->sets = evsets_create(); if ( self->sets == NULL ) { iothread_stop(self); return -1; } self->cmdevent = event_create(); self->queue = msgqueue_create( MSGQUEUE_DEFAULT_SIZE ); if ( self->queue == NULL || self->cmdevent == NULL ) { iothread_stop(self); return -2; } // 初始化命令事件 event_set( self->cmdevent, msgqueue_popfd(self->queue), EV_READ|EV_PERSIST ); event_set_callback( self->cmdevent, iothread_on_command, self ); evsets_add( self->sets, self->cmdevent, 0 ); // 启动线程 pthread_attr_t attr; pthread_attr_init( &attr ); // assert( pthread_attr_setstacksize( &attr, THREAD_DEFAULT_STACK_SIZE ) ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); int32_t rc = pthread_create(&(self->id), &attr, iothread_main, self); pthread_attr_destroy( &attr ); if ( rc != 0 ) { iothread_stop(self); return -3; } return 0; }
int32_t test_evtimer() { evsets_t sets = NULL; event_t ev_timer = NULL; sets = evsets_create(); ev_timer = event_create(); event_set( ev_timer, -1, 0 ); event_set_callback( ev_timer, ev_timer_callback, ev_timer ); evsets_add( sets, ev_timer, 2*1000 ); while( 1 ) { evsets_dispatch( sets ); } event_destroy( ev_timer ); evsets_destroy( sets ); return 0; }
void accept_new_session( int32_t fd, int16_t ev, void * arg ) { struct iothread * thr = (struct iothread *)arg; struct acceptor * a = thr->core_acceptor; if ( ev & EV_READ ) { // // 接收新连接完毕后 // char srchost[20]; char dsthost[20]; uint16_t dstport = 0; int32_t newfd = tcp_accept( fd, srchost, dsthost, &dstport ); if ( newfd > 0 ) { uint64_t sid = 0; struct session * newsession = NULL; set_fd_nonblock( newfd ); newsession = (struct session *)malloc( sizeof(struct session) ); if ( newsession == NULL ) { printf("Out of memory, allocate for 'newsession' failed .\n"); goto ACCEPT_END; } newsession->evread = event_create(); if ( newsession->evread == NULL ) { printf("Out of memory, allocate for 'newsession->evread' failed .\n"); goto ACCEPT_END; } newsession->iobytes = 0; newsession->fd = newfd; sid = thr->key; sid <<= 32; sid += thr->index++; newsession->sid = sid; #if USE_LIBEVENT { struct timeval tv = {TIMEOUT_MSECS/1000, 0}; event_set( newsession->evread, newsession->fd, EV_READ, echoserver_process_message, newsession ); event_base_set( thr->core_sets, newsession->evread ); event_add( newsession->evread, &tv ); } #else event_set( newsession->evread, newsession->fd, EV_READ ); event_set_callback( newsession->evread, echoserver_process_message, newsession ); evsets_add( thr->core_sets, newsession->evread, TIMEOUT_MSECS ); #endif #if __DEBUG printf( "Thread[%d] accept a new Client[%lld, fd:%d, '%s':%d] .\n", thr->key, newsession->sid, newsession->fd, dsthost, dstport ); #endif } a->holding = 0; pthread_mutex_unlock( &(a->lock) ); } ACCEPT_END : return; }
int main( int argc, char ** argv ) { if ( argc != 2 ) { printf("echoserver [port] .\n"); return 0; } evsets_t coreset = evsets_create(); if ( coreset == NULL ) { printf( "create core event sets failed .\n" ); goto FINAL; } signal( SIGPIPE, SIG_IGN ); signal( SIGINT, echoserver_signal_handler ); signal( SIGTERM, echoserver_signal_handler ); // listen port uint16_t port = (uint16_t)atoi( argv[1] ); int32_t fd = tcp_listen( "127.0.0.1", port, listenfd_options ); if ( fd < 0 ) { printf( "listen failed %d .\n", port ); goto FINAL; } set_non_block( fd ); event_t evaccept = event_create(); if ( evaccept == NULL ) { printf( "create accept event failed .\n" ); goto FINAL; } event_set( evaccept, fd, EV_READ|EV_PERSIST ); event_set_callback( evaccept, accept_new_session, coreset ); evsets_add( coreset, evaccept, 0 ); // running ... isrunning = 1; while ( isrunning == 1 ) { evsets_dispatch( coreset ); } FINAL : if ( evaccept != NULL ) { event_destroy( evaccept ); } if ( fd > 0 ) { close( fd ); } if ( coreset != NULL ) { evsets_destroy( coreset ); } return 0; }
void echoserver_process_message( int32_t fd, int16_t ev, void * arg ) { struct session * s = (struct session *)arg; if ( ev & EV_READ ) { char buf[16384]; int32_t readn = -1; readn = read( fd, buf, 16384 ); if ( readn <= 0 ) { #if __DEBUG printf( "Client[%ld, %d] is closed, BYTES:%d, TIME:%lld .\n", s->sid, s->fd, s->iobytes, milliseconds() ); #endif //evsets_del( event_get_sets(s->evread), s->evread ); event_destroy( s->evread ); close( s->fd ); free( s ); goto PROCESS_END; } else { #if __DEBUG printf("echoserver_process_message(ev:%d) : TIME:%lld .\n", ev, milliseconds() ); #endif readn = write( fd, buf, readn ); s->iobytes += readn; } #if USE_LIBEVENT { struct timeval tv = {TIMEOUT_MSECS/1000, 0}; event_add( s->evread, &tv ); } #else evsets_add( event_get_sets(s->evread), s->evread, TIMEOUT_MSECS ); #endif } else { #if __DEBUG printf("echoserver_process_message(ev:%d) : TIME:%lld .\n", ev, milliseconds() ); #endif } PROCESS_END : } void accept_new_session( int32_t fd, int16_t ev, void * arg ) { struct iothread * thr = (struct iothread *)arg; struct acceptor * a = thr->core_acceptor; if ( ev & EV_READ ) { // // 接收新连接完毕后 // char srchost[20]; char dsthost[20]; uint16_t dstport = 0; int32_t newfd = tcp_accept( fd, srchost, dsthost, &dstport ); if ( newfd > 0 ) { uint64_t sid = 0; struct session * newsession = NULL; set_fd_nonblock( newfd ); newsession = (struct session *)malloc( sizeof(struct session) ); if ( newsession == NULL ) { printf("Out of memory, allocate for 'newsession' failed .\n"); goto ACCEPT_END; } newsession->evread = event_create(); if ( newsession->evread == NULL ) { printf("Out of memory, allocate for 'newsession->evread' failed .\n"); goto ACCEPT_END; } newsession->iobytes = 0; newsession->fd = newfd; sid = thr->key; sid <<= 32; sid += thr->index++; newsession->sid = sid; #if USE_LIBEVENT { struct timeval tv = {TIMEOUT_MSECS/1000, 0}; event_set( newsession->evread, newsession->fd, EV_READ, echoserver_process_message, newsession ); event_base_set( thr->core_sets, newsession->evread ); event_add( newsession->evread, &tv ); } #else event_set( newsession->evread, newsession->fd, EV_READ ); event_set_callback( newsession->evread, echoserver_process_message, newsession ); evsets_add( thr->core_sets, newsession->evread, TIMEOUT_MSECS ); #endif #if __DEBUG printf( "Thread[%d] accept a new Client[%lld, fd:%d, '%s':%d] .\n", thr->key, newsession->sid, newsession->fd, dsthost, dstport ); #endif } a->holding = 0; pthread_mutex_unlock( &(a->lock) ); } ACCEPT_END : } void trylock_accept_mutex( struct iothread * thr ) { struct acceptor * a = thr->core_acceptor; if ( pthread_mutex_trylock(&(a->lock)) == 0 ) { if ( a->holding == 0 ) { #if USE_LIBEVENT event_set( a->ev_accept, a->socketfd, EV_READ, accept_new_session, thr ); event_base_set( thr->core_sets, a->ev_accept ); event_add( a->ev_accept, 0 ); #else event_set( a->ev_accept, a->socketfd, EV_READ ); event_set_callback( a->ev_accept, accept_new_session, thr ); evsets_add(thr->core_sets, a->ev_accept, 0 ); #endif a->holding = 1; } //pthread_mutex_unlock( &(a->lock) ); } } void acceptor_destroy( struct acceptor * self ) { pthread_mutex_destroy( &(self->lock) ); if ( self->socketfd > 0 ) { close( self->socketfd ); } if ( self->ev_accept != NULL ) { event_destroy( self->ev_accept ); } free( self ); } struct acceptor * acceptor_create( const char * host, uint16_t port ) { struct acceptor * a = NULL; a = (struct acceptor *)malloc( sizeof(struct acceptor) ); if ( a ) { a->holding = 0; a->socketfd = 0; a->ev_accept = NULL; pthread_mutex_init( &(a->lock), NULL ); a->socketfd = tcp_listen( host, port ); if ( a->socketfd < 0 ) { acceptor_destroy( a ); return NULL; } set_fd_nonblock( a->socketfd ); a->ev_accept = event_create(); if ( a->ev_accept == NULL ) { acceptor_destroy( a ); return NULL; } } return a; } void * iothread_main( void * arg ) { struct iothread * thr = (struct iothread *)arg; thr->running = 1; while ( thr->running ) { // // 尝试加锁 // trylock_accept_mutex( thr ); // // 分发IO事件 // evsets_dispatch( thr->core_sets ); } return (void *)0; } struct iothread * iothread_create( uint8_t key, struct acceptor * a ) { pthread_t tid; struct iothread * thr = NULL; thr = (struct iothread *)malloc( sizeof(struct iothread) ); if ( thr ) { thr->key = key; thr->index = 0; thr->core_acceptor = a; thr->core_sets = evsets_create(); if ( thr->core_sets == NULL ) { #if __DEBUG printf( "out of memory, allocate for 'thr->core_sets' failed, Thread[%d] .\n", key ); #endif return NULL; } pthread_create( &tid, NULL, iothread_main, thr ); } return thr; }