| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 | /* * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd *  * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date           Author       Notes * 2013-11-04     Grissiom     add comment */#include <rthw.h>#include <rtthread.h>#include "prio_queue.h"struct rt_prio_queue_item {    struct rt_prio_queue_item *next;    /* data follows */};static void _do_push(struct rt_prio_queue *que,                     rt_uint8_t prio,                     struct rt_prio_queue_item *item){    if (que->head[prio] == RT_NULL)    {        que->head[prio] = item;        que->bitmap |= 1 << prio;    }    else    {        RT_ASSERT(que->tail[prio]);        que->tail[prio]->next = item;    }    que->tail[prio] = item;}static struct rt_prio_queue_item* _do_pop(struct rt_prio_queue *que){    int ffs;    struct rt_prio_queue_item *item;    ffs = __rt_ffs(que->bitmap);    if (ffs == 0)        return RT_NULL;    ffs--;    item = que->head[ffs];    RT_ASSERT(item);    que->head[ffs] = item->next;    if (que->head[ffs] == RT_NULL)    {        que->bitmap &= ~(1 << ffs);    }    return item;}rt_err_t rt_prio_queue_init(struct rt_prio_queue *que,                            const char *name,                            void *buf,                            rt_size_t bufsz,                            rt_size_t itemsz){    RT_ASSERT(que);    rt_memset(que, 0, sizeof(*que));    rt_list_init(&(que->suspended_pop_list));    rt_mp_init(&que->pool, name, buf, bufsz,               sizeof(struct rt_prio_queue_item) + itemsz);    que->item_sz = itemsz;    return RT_EOK;}void rt_prio_queue_detach(struct rt_prio_queue *que){    /* wake up all suspended pop threads, push thread is suspended on mempool.     */    while (!rt_list_isempty(&(que->suspended_pop_list)))    {        rt_thread_t thread;        /* disable interrupt */        rt_ubase_t temp = rt_hw_interrupt_disable();        /* get next suspend thread */        thread = rt_list_entry(que->suspended_pop_list.next, struct rt_thread, tlist);        /* set error code to RT_ERROR */        thread->error = -RT_ERROR;        rt_thread_resume(thread);        /* enable interrupt */        rt_hw_interrupt_enable(temp);    }    rt_mp_detach(&que->pool);}#ifdef RT_USING_HEAPstruct rt_prio_queue* rt_prio_queue_create(const char *name,                                           rt_size_t item_nr,                                           rt_size_t item_sz){    struct rt_prio_queue *que;    rt_size_t bufsz;    bufsz = item_nr * (sizeof(struct rt_prio_queue_item)                       + item_sz                       + sizeof(void*));    RT_ASSERT(item_nr);    que = rt_malloc(sizeof(*que) + bufsz);    if (!que)        return RT_NULL;    rt_prio_queue_init(que, name, que+1, bufsz, item_sz);    return que;}void rt_prio_queue_delete(struct rt_prio_queue *que){    rt_prio_queue_detach(que);    rt_free(que);}#endifrt_err_t rt_prio_queue_push(struct rt_prio_queue *que,                            rt_uint8_t prio,                            void *data,                            rt_int32_t timeout){    rt_ubase_t level;    struct rt_prio_queue_item *item;    RT_ASSERT(que);    if (prio >= RT_PRIO_QUEUE_PRIO_MAX)        return -RT_ERROR;    item = rt_mp_alloc(&que->pool, timeout);    if (item == RT_NULL)        return -RT_ENOMEM;    rt_memcpy(item+1, data, que->item_sz);    item->next = RT_NULL;    level = rt_hw_interrupt_disable();    _do_push(que, prio, item);    if (!rt_list_isempty(&(que->suspended_pop_list)))    {        rt_thread_t thread;        /* get thread entry */        thread = rt_list_entry(que->suspended_pop_list.next,                               struct rt_thread,                               tlist);        /* resume it */        rt_thread_resume(thread);        rt_hw_interrupt_enable(level);        /* perform a schedule */        rt_schedule();        return RT_EOK;    }    rt_hw_interrupt_enable(level);    return RT_EOK;}rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que,                           void *data,                           rt_int32_t timeout){    rt_ubase_t level;    struct rt_prio_queue_item *item;    RT_ASSERT(que);    RT_ASSERT(data);    level = rt_hw_interrupt_disable();    for (item = _do_pop(que);         item == RT_NULL;         item = _do_pop(que))    {        rt_thread_t thread;        if (timeout == 0)        {            rt_hw_interrupt_enable(level);            return -RT_ETIMEOUT;        }        RT_DEBUG_NOT_IN_INTERRUPT;        thread = rt_thread_self();        thread->error = RT_EOK;        rt_thread_suspend(thread);        rt_list_insert_before(&(que->suspended_pop_list), &(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(level);        rt_schedule();        /* thread is waked up */        if (thread->error != RT_EOK)            return thread->error;        level = rt_hw_interrupt_disable();    }    rt_hw_interrupt_enable(level);    rt_memcpy(data, item+1, que->item_sz);    rt_mp_free(item);    return RT_EOK;}void rt_prio_queue_dump(struct rt_prio_queue *que){    int level = 0;    rt_kprintf("bitmap: %08x\n", que->bitmap);    for (level = 0; level < RT_PRIO_QUEUE_PRIO_MAX; level++)    {        struct rt_prio_queue_item *item;        rt_kprintf("%2d: ", level);        for (item = que->head[level];             item;             item = item->next)        {            rt_kprintf("%p, ", item);        }        rt_kprintf("\n");    }}
 |