| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 | /* * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd *  * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2014-04-16     Grissiom     first version */struct rt_watermark_queue{    /* Current water level. */    unsigned int level;    unsigned int high_mark;    unsigned int low_mark;    rt_list_t suspended_threads;};/** Init the struct rt_watermark_queue. */void rt_wm_que_init(struct rt_watermark_queue *wg,                    unsigned int low, unsigned int high);void rt_wm_que_set_mark(struct rt_watermark_queue *wg,                        unsigned int low, unsigned int high);void rt_wm_que_dump(struct rt_watermark_queue *wg);/* Water marks are often used in performance critical places. Benchmark shows * inlining functions will have 10% performance gain in some situation(for * example, VBus). So keep the inc/dec compact and inline. *//** Increase the water level. * * It should be called in the thread that want to raise the water level. If the * current level is above the high mark, the thread will be suspended up to * @timeout ticks. * * @return RT_EOK if water level increased successfully. -RT_EFULL on @timeout * is zero and the level is above water mark. -RT_ETIMEOUT if timeout occurred. */rt_inline rt_err_t rt_wm_que_inc(struct rt_watermark_queue *wg,                                 int timeout){    rt_base_t ilvl;    /* Assert as early as possible. */    if (timeout != 0)    {        RT_DEBUG_IN_THREAD_CONTEXT;    }    ilvl = rt_hw_interrupt_disable();    while (wg->level > wg->high_mark)    {        rt_thread_t thread;        if (timeout == 0)        {            rt_hw_interrupt_enable(ilvl);            return -RT_EFULL;        }        thread = rt_thread_self();        thread->error = RT_EOK;        rt_thread_suspend(thread);        rt_list_insert_after(&wg->suspended_threads, &thread->tlist);        if (timeout > 0)        {            rt_timer_control(&(thread->thread_timer),                             RT_TIMER_CTRL_SET_TIME,                             &timeout);            rt_timer_start(&(thread->thread_timer));        }        rt_hw_interrupt_enable(ilvl);        rt_schedule();        if (thread->error != RT_EOK)            return thread->error;        ilvl = rt_hw_interrupt_disable();    }    wg->level++;    if (wg->level == 0)    {        wg->level = ~0;    }    rt_hw_interrupt_enable(ilvl);    return RT_EOK;}/** Decrease the water level. * * It should be called by the consumer that drain the water out. If the water * level reached low mark, all the thread suspended in this queue will be waken * up. It's safe to call this function in interrupt context. */rt_inline void rt_wm_que_dec(struct rt_watermark_queue *wg){    int need_sched = 0;    rt_base_t ilvl;    if (wg->level == 0)        return;    ilvl = rt_hw_interrupt_disable();    wg->level--;    if (wg->level == wg->low_mark)    {        /* There should be spaces between the low mark and high mark, so it's         * safe to resume all the threads. */        while (!rt_list_isempty(&wg->suspended_threads))        {            rt_thread_t thread;            thread = rt_list_entry(wg->suspended_threads.next,                                   struct rt_thread,                                   tlist);            rt_thread_resume(thread);            need_sched = 1;        }    }    rt_hw_interrupt_enable(ilvl);    if (need_sched)        rt_schedule();}
 |