Exemple #1
0
static tb_void_t tb_aiop_ptor_kilo(tb_aicp_ptor_impl_t* ptor, tb_aico_impl_t* aico)
{
    // check
    tb_aiop_ptor_impl_t* impl = (tb_aiop_ptor_impl_t*)ptor;
    tb_assert_and_check_return(impl && impl->timer && impl->ltimer && impl->aiop && aico);

    // trace
    tb_trace_d("kilo: aico: %p, type: %u: ..", aico, aico->type);

    // the aiop aico
    tb_aiop_aico_t* aiop_aico = (tb_aiop_aico_t*)aico;

    // add timeout task for killing the accept socket
    if (aico->type == TB_AICO_TYPE_SOCK && aiop_aico->aice.code == TB_AICE_CODE_ACPT) 
    {
        // add task
        if (!aiop_aico->task) 
        {
            aiop_aico->task = tb_ltimer_task_init(impl->ltimer, 10000, tb_false, tb_aiop_spak_wait_timeout, aico);
            aiop_aico->bltimer = 1;
        }
    }

    // kill the task
    if (aiop_aico->task) 
    {
        // trace
        tb_trace_d("kilo: aico: %p, type: %u, task: %p: ..", aico, aico->type, aiop_aico->task);

        // kill task
        if (aiop_aico->bltimer) tb_ltimer_task_kill(impl->ltimer, aiop_aico->task);
        else tb_timer_task_kill(impl->timer, aiop_aico->task);
    }

    // kill sock
    if (aico->type == TB_AICO_TYPE_SOCK && aico->handle) 
    {
        // trace
        tb_trace_d("kilo: aico: %p, type: %u, sock: %p: ..", aico, aico->type, aico->handle);

        // kill it
        tb_socket_kill(aico->handle, TB_SOCKET_KILL_RW);
    }
    // kill file
    else if (aico->type == TB_AICO_TYPE_FILE)
    {
        // kill it
        tb_aicp_file_kilo(impl, aico);
    }

    /* the aiop will wait long time if the lastest task wait period is too long
     * so spak the aiop manually for spak the ltimer
     */
    tb_aiop_spak(impl->aiop);

    // trace
    tb_trace_d("kilo: aico: %p, type: %u: ok", aico, aico->type);
}
Exemple #2
0
static tb_void_t tb_aiop_spak_klist(tb_aiop_ptor_impl_t* impl)
{
    // check
    tb_assert_and_check_return(impl && impl->klist);

    // enter
    tb_spinlock_enter(&impl->klock);

    // kill it if exists the killing aico
    if (tb_vector_size(impl->klist))
    {
        // kill all
        tb_for_all_if (tb_aico_impl_t*, aico, impl->klist, aico)
        {
            // the aiop aico
            tb_aiop_aico_t* aiop_aico = (tb_aiop_aico_t*)aico;

            // sock?
            if (aico->type == TB_AICO_TYPE_SOCK)
            {
                // add it first if do not exists timeout task
                if (!aiop_aico->task)
                {
                    aiop_aico->task = tb_ltimer_task_init(impl->ltimer, 10000, tb_false, tb_aiop_spak_wait_timeout, aico);
                    aiop_aico->bltimer = 1;
                }

                // kill the task
                if (aiop_aico->task)
                {
                    // kill task
                    if (aiop_aico->bltimer) tb_ltimer_task_kill(impl->ltimer, aiop_aico->task);
                    else tb_timer_task_kill(impl->timer, aiop_aico->task);
                }
            }
            else if (aico->type == TB_AICO_TYPE_FILE)
            {
                // kill file
                tb_aicp_file_kilo(impl, aico);
            }

            // trace
            tb_trace_d("kill: aico: %p, type: %u: ok", aico, aico->type);
        }
    }
Exemple #3
0
static tb_bool_t tb_aiop_spak_wait(tb_aiop_ptor_impl_t* impl, tb_aice_ref_t aice)
{
    // check
    tb_assert_and_check_return_val(impl && impl->aiop && impl->ltimer && aice, tb_false);

    // the aico
    tb_aiop_aico_t* aico = (tb_aiop_aico_t*)aice->aico;
    tb_assert_and_check_return_val(aico && aico->base.handle && !aico->task, tb_false);

    // the aioe code
    tb_size_t code = tb_aiop_aioe_code(aice);
    tb_assert_and_check_return_val(code != TB_AIOE_CODE_NONE, tb_false);

    // trace
    tb_trace_d("wait: aico: %p, code: %lu: time: %lld: ..", aico, aice->code, tb_cache_time_mclock());

    // done
    tb_bool_t ok = tb_false;
    tb_aice_t prev = aico->aice;
    do
    {
        // wait it
        aico->aice = *aice;
        aico->waiting = 1;
        aico->wait_ok = 0;

        // wait once if not accept
        if (aice->code != TB_AICE_CODE_ACPT) code |= TB_AIOE_CODE_ONESHOT;

        // using the edge triggered mode
        if (tb_aiop_have(impl->aiop, TB_AIOE_CODE_CLEAR))
            code |= TB_AIOE_CODE_CLEAR;

        // have aioo?
        if (!aico->aioo)
        {
            // addo wait
            if (!(aico->aioo = tb_aiop_addo(impl->aiop, aico->base.handle, code, &aico->aice))) break;
        }
        else
        {
            // sete wait
            if (!tb_aiop_sete(impl->aiop, aico->aioo, code, &aico->aice)) break;
        }

        // add timeout task
        tb_long_t timeout = tb_aico_impl_timeout_from_code((tb_aico_impl_t*)aico, aice->code);
        if (timeout >= 0)
        {
            // add it
            aico->task = tb_ltimer_task_init(impl->ltimer, timeout, tb_false, tb_aiop_spak_wait_timeout, aico);
            tb_assert_and_check_break(aico->task);
            aico->bltimer = 1;
        }

        // ok
        ok = tb_true;

    } while (0);

    // failed? restore it
    if (!ok)
    {
        // trace
        tb_trace_d("wait: aico: %p, code: %lu: failed", aico, aice->code);

        // restore it
        aico->aice = prev;
        aico->waiting = 0;
    }

    // ok?
    return ok;
}
Exemple #4
0
tb_bool_t tb_lo_scheduler_io_wait(tb_lo_scheduler_io_ref_t scheduler_io, tb_socket_ref_t sock, tb_size_t events, tb_long_t timeout)
{
    // check
    tb_assert(scheduler_io && sock && scheduler_io->poller && scheduler_io->scheduler && events);

    // get the current coroutine
    tb_lo_coroutine_t* coroutine = tb_lo_scheduler_running(scheduler_io->scheduler);
    tb_assert(coroutine);

    // get the poller
    tb_poller_ref_t poller = scheduler_io->poller;
    tb_assert(poller);

    // trace
    tb_trace_d("coroutine(%p): wait events(%lu) with %ld ms for socket(%p) ..", coroutine, events, timeout, sock);

    // enable edge-trigger mode if be supported
    if (tb_poller_support(poller, TB_POLLER_EVENT_CLEAR))
        events |= TB_POLLER_EVENT_CLEAR;

    // exists this socket? only modify events 
    tb_socket_ref_t sock_prev = coroutine->rs.wait.sock;
    if (sock_prev == sock)
    {
        // return the cached events directly if the waiting events exists cache
        tb_size_t events_prev   = coroutine->rs.wait.events;
        tb_size_t events_cache  = coroutine->rs.wait.events_cache;
        if (events_cache && (events_prev & events))
        {
            // check error?
            if (events_cache & TB_POLLER_EVENT_ERROR)
            {
                coroutine->rs.wait.events_cache = 0;
                return -1;
            }

            // clear cache events
            coroutine->rs.wait.events_cache &= ~events;

            // return the cached events
            coroutine->rs.wait.events_result = events_cache & events;
            return tb_false;
        }

        // modify socket from poller for waiting events if the waiting events has been changed 
        if (events_prev != events && !tb_poller_modify(poller, sock, events, coroutine))
        {
            // trace
            tb_trace_e("failed to modify sock(%p) to poller on coroutine(%p)!", sock, coroutine);

            // failed
            coroutine->rs.wait.events_result = -1;
            return tb_false;
        }
    }
    else
    {
        // remove the previous socket first if exists
        if (sock_prev && !tb_poller_remove(poller, sock_prev))
        {
            // trace
            tb_trace_e("failed to remove sock(%p) to poller on coroutine(%p)!", sock_prev, coroutine);

            // failed
            coroutine->rs.wait.events_result = -1;
            return tb_false;
        }

        // insert socket to poller for waiting events
        if (!tb_poller_insert(poller, sock, events, coroutine))
        {
            // trace
            tb_trace_e("failed to insert sock(%p) to poller on coroutine(%p)!", sock, coroutine);

            // failed
            coroutine->rs.wait.events_result = -1;
            return tb_false;
        }
    }

#ifndef TB_CONFIG_MICRO_ENABLE
    // exists timeout?
    tb_cpointer_t   task = tb_null;
    tb_bool_t       is_ltimer = tb_false;
    if (timeout >= 0)
    {
        // high-precision interval?
        if (timeout % 1000)
        {
            // init task for timer
            task = tb_timer_task_init(scheduler_io->timer, timeout, tb_false, tb_lo_scheduler_io_timeout, coroutine);
            tb_assert_and_check_return_val(task, tb_false);
        }
        // low-precision interval?
        else
        {
            // init task for ltimer (faster)
            task = tb_ltimer_task_init(scheduler_io->ltimer, timeout, tb_false, tb_lo_scheduler_io_timeout, coroutine);
            tb_assert_and_check_return_val(task, tb_false);

            // mark as low-precision timer
            is_ltimer = tb_true;
        }
    }

    // check
    tb_assert(!((tb_size_t)(task) & 0x1));

    // save the timer task to coroutine
    coroutine->rs.wait.task = (is_ltimer || !task)? task : (tb_cpointer_t)((tb_size_t)(task) | 0x1);
#endif

    // save the socket to coroutine for the timer function
    coroutine->rs.wait.sock = sock;

    // save waiting events to coroutine
    coroutine->rs.wait.events        = (tb_sint32_t)events;
    coroutine->rs.wait.events_cache  = 0;
    coroutine->rs.wait.events_result = 0;

    // mark as waiting state
    coroutine->rs.wait.waiting       = 1;

    // suspend it
    return tb_true;
}