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;
}
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;
}