Exemple #1
0
static tb_size_t tb_list_itor_head(tb_iterator_ref_t iterator)
{
    // check
    tb_list_t* list = (tb_list_t*)iterator;
    tb_assert(list);

    // head
    return (tb_size_t)tb_list_entry_head(&list->head);
}
Exemple #2
0
tb_void_t tb_co_scheduler_loop(tb_co_scheduler_ref_t self, tb_bool_t exclusive)
{
    // check
    tb_co_scheduler_t* scheduler = (tb_co_scheduler_t*)self;
    tb_assert_and_check_return(scheduler);

#ifdef __tb_thread_local__
    g_scheduler_self_ex = scheduler;
#else
    // is exclusive mode?
    if (exclusive) g_scheduler_self_ex = scheduler;
    else
    {
        // init self scheduler local
        if (!tb_thread_local_init(&g_scheduler_self, tb_null)) return ;
     
        // update and overide the current scheduler
        tb_thread_local_set(&g_scheduler_self, self);
    }
#endif

    // schedule all ready coroutines
    while (tb_list_entry_size(&scheduler->coroutines_ready)) 
    {
        // check
        tb_assert(tb_coroutine_is_original(scheduler->running));

        // get the next entry from head
        tb_list_entry_ref_t entry = tb_list_entry_head(&scheduler->coroutines_ready);
        tb_assert(entry);

        // switch to the next coroutine 
        tb_co_scheduler_switch(scheduler, (tb_coroutine_t*)tb_list_entry0(entry));

        // trace
        tb_trace_d("[loop]: ready %lu", tb_list_entry_size(&scheduler->coroutines_ready));
    }

    // stop it
    scheduler->stopped = tb_true;
 
#ifdef __tb_thread_local__
    g_scheduler_self_ex = tb_null;
#else
    // is exclusive mode?
    if (exclusive) g_scheduler_self_ex = tb_null;
    else
    {
        // clear the current scheduler
        tb_thread_local_set(&g_scheduler_self, tb_null);
    }
#endif
}
Exemple #3
0
/* //////////////////////////////////////////////////////////////////////////////////////
 * private implementation
 */
static tb_void_t tb_lo_scheduler_free(tb_list_entry_head_ref_t coroutines)
{
    // check
    tb_assert(coroutines);

    // free all coroutines
    while (tb_list_entry_size(coroutines))
    {
        // get the next entry from head
        tb_list_entry_ref_t entry = tb_list_entry_head(coroutines);
        tb_assert(entry);

        // remove it from the ready coroutines
        tb_list_entry_remove_head(coroutines);

        // exit this coroutine
        tb_lo_coroutine_exit((tb_lo_coroutine_t*)tb_list_entry(coroutines, entry));
    }
}
Exemple #4
0
    // remove entries
    tb_list_entry_remove_head(&list);
    tb_list_entry_remove_last(&list);

    // walk it
    tb_trace_i("remove: %lu", tb_list_entry_size(&list));
    tb_for_all_if(tb_demo_entry_t*, item2, tb_list_entry_itor(&list), item2)
    {
        tb_trace_i("%lu", item2->data);
    }

    // trace
    tb_trace_i("");

    // moveto entries
    tb_list_entry_ref_t head = tb_list_entry_head(&list);
    tb_list_entry_moveto_head(&list, tb_list_entry_last(&list));
    tb_list_entry_moveto_tail(&list, head);

    // walk it
    tb_trace_i("moveto: %lu", tb_list_entry_size(&list));
    tb_for_all_if(tb_demo_entry_t*, item3, tb_list_entry_itor(&list), item3)
    {
        tb_trace_i("%lu", item3->data);
    }

    // trace
    tb_trace_i("");

    // clear entries
    tb_list_entry_clear(&list);
Exemple #5
0
tb_bool_t tb_lo_scheduler_start(tb_lo_scheduler_t* scheduler, tb_lo_coroutine_func_t func, tb_cpointer_t priv, tb_lo_coroutine_free_t free)
{
    // check
    tb_assert(func);

    // done
    tb_bool_t           ok = tb_false;
    tb_lo_coroutine_t*  coroutine = tb_null;
    do
    {
        // trace
        tb_trace_d("start ..");

        // get the current scheduler
        if (!scheduler) scheduler = (tb_lo_scheduler_t*)tb_lo_scheduler_self_();
        tb_assert_and_check_break(scheduler);

        // have been stopped? do not continue to start new coroutines
        tb_check_break(!scheduler->stopped);

        // reuses dead coroutines in init function
        if (tb_list_entry_size(&scheduler->coroutines_dead))
        {
            // get the next entry from head
            tb_list_entry_ref_t entry = tb_list_entry_head(&scheduler->coroutines_dead);
            tb_assert_and_check_break(entry);

            // remove it from the ready coroutines
            tb_list_entry_remove_head(&scheduler->coroutines_dead);

            // get the dead coroutine
            coroutine = (tb_lo_coroutine_t*)tb_list_entry(&scheduler->coroutines_dead, entry);

            // reinit this coroutine
            tb_lo_coroutine_reinit(coroutine, func, priv, free);
        }

        // init coroutine
        if (!coroutine) coroutine = tb_lo_coroutine_init((tb_lo_scheduler_ref_t)scheduler, func, priv, free);
        tb_assert_and_check_break(coroutine);

        // ready coroutine
        tb_lo_scheduler_make_ready(scheduler, coroutine);

        // the dead coroutines is too much? free some coroutines
        while (tb_list_entry_size(&scheduler->coroutines_dead) > TB_SCHEDULER_DEAD_CACHE_MAXN)
        {
            // get the next entry from head
            tb_list_entry_ref_t entry = tb_list_entry_head(&scheduler->coroutines_dead);
            tb_assert(entry);

            // remove it from the ready coroutines
            tb_list_entry_remove_head(&scheduler->coroutines_dead);

            // exit this coroutine
            tb_lo_coroutine_exit((tb_lo_coroutine_t*)tb_list_entry(&scheduler->coroutines_dead, entry));
        }

        // ok
        ok = tb_true;

    } while (0);

    // trace
    tb_trace_d("start %s", ok? "ok" : "no");

    // ok?
    return ok;
}
Exemple #6
0
static __tb_inline__ tb_lo_coroutine_t* tb_lo_scheduler_next_ready(tb_lo_scheduler_t* scheduler)
{
    // check
    tb_assert(scheduler && tb_list_entry_size(&scheduler->coroutines_ready));

    // get the next entry 
    tb_list_entry_ref_t entry_next = scheduler->running? tb_list_entry_next(&scheduler->running->entry) : tb_list_entry_head(&scheduler->coroutines_ready);
    tb_assert(entry_next);

    // is list header? skip it and get the first entry
    if (entry_next == (tb_list_entry_ref_t)&scheduler->coroutines_ready)
        entry_next = tb_list_entry_next(entry_next);

    // get the next ready coroutine
    return (tb_lo_coroutine_t*)tb_list_entry(&scheduler->coroutines_ready, entry_next);
}
Exemple #7
0
tb_pointer_t tb_fixed_pool_malloc_(tb_fixed_pool_ref_t pool __tb_debug_decl__)
{
    // check
    tb_fixed_pool_impl_t* impl = (tb_fixed_pool_impl_t*)pool;
    tb_assert_and_check_return_val(impl, tb_null);

    // done
    tb_bool_t       ok = tb_false;
    tb_pointer_t    data = tb_null;
    do
    {
        // no current slot or the current slot is full? update the current slot
        if (!impl->current_slot || tb_static_fixed_pool_full(impl->current_slot->pool))
        {
            // move the current slot to the full slots if exists
            if (impl->current_slot) tb_list_entry_insert_tail(&impl->full_slots, &impl->current_slot->entry);

            // clear the current slot
            impl->current_slot = tb_null;

            // attempt to get a slot from the partial slots
            if (!tb_list_entry_is_null(&impl->partial_slots))
            {
                // the head entry
                tb_list_entry_ref_t entry = tb_list_entry_head(&impl->partial_slots);
                tb_assert_and_check_break(entry);

                // the head slot
                impl->current_slot = (tb_fixed_pool_slot_t*)tb_list_entry(&impl->partial_slots, entry);
                tb_assert_and_check_break(impl->current_slot);

                // remove this slot from the partial slots
                tb_list_entry_remove(&impl->partial_slots, entry);
            }
            // make a new slot
            else impl->current_slot = tb_fixed_pool_slot_init(impl);
        }

        // check
        tb_assert_and_check_break(impl->current_slot && impl->current_slot->pool);
        tb_assert_and_check_break(!tb_static_fixed_pool_full(impl->current_slot->pool));

        // make data from the current slot
        data = tb_static_fixed_pool_malloc(impl->current_slot->pool __tb_debug_args__);
        tb_assert_and_check_break(data);
        
        // done init
        if (impl->func_init && !impl->func_init(data, impl->func_priv)) break;

        // update the item count
        impl->item_count++;

        // ok
        ok = tb_true;

    } while (0);

    // failed?
    if (!ok)
    {
        // exit data
        if (data && impl->current_slot && impl->current_slot->pool) 
            tb_static_fixed_pool_free(impl->current_slot->pool, data __tb_debug_args__);
        data = tb_null;
    }

    // check
    tb_assertf_abort(data, "malloc(%lu) failed!", impl->item_size);

    // ok?
    return data;
}
Exemple #8
0
static tb_transfer_task_t* tb_transfer_task_init(tb_transfer_pool_impl_t* impl, tb_async_transfer_done_func_t done, tb_async_transfer_ctrl_func_t ctrl, tb_cpointer_t priv)
{
    // check
    tb_assert_and_check_return_val(impl, tb_null);

    // done
    tb_bool_t           ok = tb_false;
    tb_transfer_task_t* task = tb_null;
    do
    {
        // init task pool
        if (!impl->pool) impl->pool = tb_fixed_pool_init(tb_null, (impl->maxn >> 4) + 16, sizeof(tb_transfer_task_t), tb_null, tb_null, tb_null);
        tb_assert_and_check_break(impl->pool);

        // init task from the idle list first
        if (tb_list_entry_size(&impl->idle))
        {
            // get the head entry
            tb_list_entry_ref_t entry = tb_list_entry_head(&impl->idle);
            tb_assert_and_check_break(entry);

            // the task
            task = (tb_transfer_task_t*)tb_list_entry(&impl->idle, entry);
            tb_assert_and_check_break(task);

            // remove the last task
            tb_list_entry_remove(&impl->idle, entry);

            // check
            tb_assert_and_check_break(task->transfer);
        }
        // init task from the task pool
        else
        {
            // make task
            task = (tb_transfer_task_t*)tb_fixed_pool_malloc0(impl->pool);
            tb_assert_and_check_break(task);

            // init transfer
            task->transfer = tb_async_transfer_init(impl->aicp, tb_true);
            tb_assert_and_check_break(task->transfer);
        }

        // init ctrl
        if (ctrl && !tb_async_transfer_ctrl(task->transfer, ctrl, priv)) break;

        // init task
        task->func = done;
        task->priv = priv;
        task->pool = impl;

        // ok
        ok = tb_true;

    } while (0);

    // failed?
    if (!ok)
    {
        // exit it
        if (task) tb_transfer_task_exit(impl, task);
        task = tb_null;
    }

    // ok?
    return task;
}