diff options
| author | Shell <[email protected]> | 2024-02-23 17:49:15 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-02-23 17:49:15 +0800 |
| commit | 71560bafb5735220696ca24a42ba4a668b55949b (patch) | |
| tree | 236df5973a1fd5b6f0cc9f6c6b6a2d71fd069203 /components/drivers | |
| parent | 6fe69d7431ed54fcea863ed68d7c4f9746e771b0 (diff) | |
🎯 Sync smart & scheduler codes (#8537)
Signed-off-by: Shell <[email protected]>
Co-authored-by: xqyjlj <[email protected]>
Diffstat (limited to 'components/drivers')
| -rw-r--r-- | components/drivers/audio/audio_pipe.c | 12 | ||||
| -rw-r--r-- | components/drivers/include/ipc/completion.h | 16 | ||||
| -rw-r--r-- | components/drivers/ipc/SConscript | 2 | ||||
| -rw-r--r-- | components/drivers/ipc/completion.c | 115 | ||||
| -rw-r--r-- | components/drivers/ipc/dataqueue.c | 151 | ||||
| -rw-r--r-- | components/drivers/ipc/workqueue.c | 21 |
6 files changed, 140 insertions, 177 deletions
diff --git a/components/drivers/audio/audio_pipe.c b/components/drivers/audio/audio_pipe.c index 1901f7b38b..d4d24b844d 100644 --- a/components/drivers/audio/audio_pipe.c +++ b/components/drivers/audio/audio_pipe.c @@ -21,9 +21,7 @@ static void _rt_pipe_resume_writer(struct rt_audio_pipe *pipe) RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_WR); /* get suspended thread */ - thread = rt_list_entry(pipe->suspended_write_list.next, - struct rt_thread, - tlist); + thread = RT_THREAD_LIST_NODE_ENTRY(pipe->suspended_write_list.next); /* resume the write thread */ rt_thread_resume(thread); @@ -73,7 +71,7 @@ static rt_ssize_t rt_pipe_read(rt_device_t dev, rt_thread_suspend(thread); /* waiting on suspended read list */ rt_list_insert_before(&(pipe->suspended_read_list), - &(thread->tlist)); + &RT_THREAD_LIST_NODE(thread)); rt_hw_interrupt_enable(level); rt_schedule(); @@ -103,9 +101,7 @@ static void _rt_pipe_resume_reader(struct rt_audio_pipe *pipe) RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_RD); /* get suspended thread */ - thread = rt_list_entry(pipe->suspended_read_list.next, - struct rt_thread, - tlist); + thread = RT_THREAD_LIST_NODE_ENTRY(pipe->suspended_read_list.next); /* resume the read thread */ rt_thread_resume(thread); @@ -161,7 +157,7 @@ static rt_ssize_t rt_pipe_write(rt_device_t dev, rt_thread_suspend(thread); /* waiting on suspended read list */ rt_list_insert_before(&(pipe->suspended_write_list), - &(thread->tlist)); + &RT_THREAD_LIST_NODE(thread)); rt_hw_interrupt_enable(level); rt_schedule(); diff --git a/components/drivers/include/ipc/completion.h b/components/drivers/include/ipc/completion.h index b8d765027e..efa2b7840d 100644 --- a/components/drivers/include/ipc/completion.h +++ b/components/drivers/include/ipc/completion.h @@ -13,18 +13,22 @@ #include <rtconfig.h> /** - * Completion + * Completion - A tiny IPC implementation for resource-constrained scenarios + * + * It's an IPC using one CPU word with the encoding: + * + * BIT | MAX-1 ----------------- 1 | 0 | + * CONTENT | suspended_thread & ~1 | completed flag | */ struct rt_completion { - rt_uint32_t flag; - - /* suspended list */ - rt_list_t suspended_list; - struct rt_spinlock spinlock; + /* suspended thread, and completed flag */ + rt_base_t susp_thread_n_flag; }; +#define RT_COMPLETION_INIT(comp) {0} + void rt_completion_init(struct rt_completion *completion); rt_err_t rt_completion_wait(struct rt_completion *completion, rt_int32_t timeout); diff --git a/components/drivers/ipc/SConscript b/components/drivers/ipc/SConscript index fad4f5fb72..ba14b4bb0f 100644 --- a/components/drivers/ipc/SConscript +++ b/components/drivers/ipc/SConscript @@ -8,6 +8,6 @@ if not GetDepend('RT_USING_HEAP'): SrcRemove(src, 'dataqueue.c') SrcRemove(src, 'pipe.c') -group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE_IPC'], CPPPATH = CPPPATH) +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE_IPC'], CPPPATH = CPPPATH, LOCAL_CPPDEFINES=['__RT_IPC_SOURCE__']) Return('group') diff --git a/components/drivers/ipc/completion.c b/components/drivers/ipc/completion.c index 2c9b2797a3..d74fcdc8d1 100644 --- a/components/drivers/ipc/completion.c +++ b/components/drivers/ipc/completion.c @@ -8,13 +8,24 @@ * 2012-09-30 Bernard first version. * 2021-08-18 chenyingchun add comments * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable + * 2024-01-25 Shell reduce resource usage in completion for better synchronization + * and smaller footprint. */ +#define DBG_TAG "drivers.ipc" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + #include <rthw.h> #include <rtdevice.h> #define RT_COMPLETED 1 #define RT_UNCOMPLETED 0 +#define RT_COMPLETION_FLAG(comp) ((comp)->susp_thread_n_flag & 1) +#define RT_COMPLETION_THREAD(comp) ((rt_thread_t)((comp)->susp_thread_n_flag & ~1)) +#define RT_COMPLETION_NEW_STAT(thread, flag) (((flag) & 1) | (((rt_base_t)thread) & ~1)) + +static struct rt_spinlock _completion_lock = RT_SPINLOCK_INIT; /** * @brief This function will initialize a completion object. @@ -23,14 +34,9 @@ */ void rt_completion_init(struct rt_completion *completion) { - rt_base_t level; RT_ASSERT(completion != RT_NULL); - rt_spin_lock_init(&(completion->spinlock)); - level = rt_spin_lock_irqsave(&(completion->spinlock)); - completion->flag = RT_UNCOMPLETED; - rt_list_init(&completion->suspended_list); - rt_spin_unlock_irqrestore(&(completion->spinlock), level); + completion->susp_thread_n_flag = RT_COMPLETION_NEW_STAT(RT_NULL, RT_UNCOMPLETED); } RTM_EXPORT(rt_completion_init); @@ -64,11 +70,11 @@ rt_err_t rt_completion_wait(struct rt_completion *completion, result = RT_EOK; thread = rt_thread_self(); - level = rt_spin_lock_irqsave(&(completion->spinlock)); - if (completion->flag != RT_COMPLETED) + level = rt_spin_lock_irqsave(&_completion_lock); + if (RT_COMPLETION_FLAG(completion) != RT_COMPLETED) { /* only one thread can suspend on complete */ - RT_ASSERT(rt_list_isempty(&(completion->suspended_list))); + RT_ASSERT(RT_COMPLETION_THREAD(completion) == RT_NULL); if (timeout == 0) { @@ -81,40 +87,43 @@ rt_err_t rt_completion_wait(struct rt_completion *completion, thread->error = RT_EOK; /* suspend thread */ - rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); - /* add to suspended list */ - rt_list_insert_before(&(completion->suspended_list), - &(thread->tlist)); + result = rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); + if (result == RT_EOK) + { + /* add to suspended thread */ + completion->susp_thread_n_flag = RT_COMPLETION_NEW_STAT(thread, RT_UNCOMPLETED); - /* current context checking */ - RT_DEBUG_NOT_IN_INTERRUPT; + /* current context checking */ + RT_DEBUG_NOT_IN_INTERRUPT; - /* start timer */ - if (timeout > 0) - { - /* reset the timeout of thread timer and start it */ - rt_timer_control(&(thread->thread_timer), - RT_TIMER_CTRL_SET_TIME, - &timeout); - rt_timer_start(&(thread->thread_timer)); - } - /* enable interrupt */ - rt_spin_unlock_irqrestore(&(completion->spinlock), level); + /* start timer */ + if (timeout > 0) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + /* enable interrupt */ + rt_spin_unlock_irqrestore(&_completion_lock, level); - /* do schedule */ - rt_schedule(); + /* do schedule */ + rt_schedule(); - /* thread is waked up */ - result = thread->error; + /* thread is waked up */ + result = thread->error; - level = rt_spin_lock_irqsave(&(completion->spinlock)); + level = rt_spin_lock_irqsave(&_completion_lock); + } } } - /* clean completed flag */ - completion->flag = RT_UNCOMPLETED; + + /* clean completed flag & remove susp_thread on the case of waking by timeout */ + completion->susp_thread_n_flag = RT_COMPLETION_NEW_STAT(RT_NULL, RT_UNCOMPLETED); __exit: - rt_spin_unlock_irqrestore(&(completion->spinlock), level); + rt_spin_unlock_irqrestore(&_completion_lock, level); return result; } @@ -128,35 +137,33 @@ RTM_EXPORT(rt_completion_wait); void rt_completion_done(struct rt_completion *completion) { rt_base_t level; + rt_err_t error; + rt_thread_t suspend_thread; RT_ASSERT(completion != RT_NULL); - if (completion->flag == RT_COMPLETED) + level = rt_spin_lock_irqsave(&_completion_lock); + if (RT_COMPLETION_FLAG(completion) == RT_COMPLETED) + { + rt_spin_unlock_irqrestore(&_completion_lock, level); return; + } - level = rt_spin_lock_irqsave(&(completion->spinlock)); - completion->flag = RT_COMPLETED; - - if (!rt_list_isempty(&(completion->suspended_list))) + suspend_thread = RT_COMPLETION_THREAD(completion); + if (suspend_thread) { /* there is one thread in suspended list */ - struct rt_thread *thread; - - /* get thread entry */ - thread = rt_list_entry(completion->suspended_list.next, - struct rt_thread, - tlist); /* resume it */ - rt_thread_resume(thread); - rt_spin_unlock_irqrestore(&(completion->spinlock), level); - - /* perform a schedule */ - rt_schedule(); - } - else - { - rt_spin_unlock_irqrestore(&(completion->spinlock), level); + error = rt_thread_resume(suspend_thread); + if (error) + { + LOG_D("%s: failed to resume thread", __func__); + } } + + completion->susp_thread_n_flag = RT_COMPLETION_NEW_STAT(RT_NULL, RT_COMPLETED); + + rt_spin_unlock_irqrestore(&_completion_lock, level); } RTM_EXPORT(rt_completion_done); diff --git a/components/drivers/ipc/dataqueue.c b/components/drivers/ipc/dataqueue.c index bd3fce0c6e..b62730617c 100644 --- a/components/drivers/ipc/dataqueue.c +++ b/components/drivers/ipc/dataqueue.c @@ -8,6 +8,7 @@ * 2012-09-30 Bernard first version. * 2016-10-31 armink fix some resume push and pop thread bugs * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable + * 2024-01-25 Shell porting to susp_list API */ #include <rthw.h> @@ -121,27 +122,32 @@ rt_err_t rt_data_queue_push(struct rt_data_queue *queue, thread->error = RT_EOK; /* suspend thread on the push list */ - rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); - rt_list_insert_before(&(queue->suspended_push_list), &(thread->tlist)); - /* start timer */ - if (timeout > 0) + result = rt_thread_suspend_to_list(thread, &queue->suspended_push_list, + RT_IPC_FLAG_FIFO, RT_UNINTERRUPTIBLE); + if (result == RT_EOK) { - /* reset the timeout of thread timer and start it */ - rt_timer_control(&(thread->thread_timer), - RT_TIMER_CTRL_SET_TIME, - &timeout); - rt_timer_start(&(thread->thread_timer)); - } + /* start timer */ + if (timeout > 0) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } - /* enable interrupt */ - rt_spin_unlock_irqrestore(&(queue->spinlock), level); + /* enable interrupt */ + rt_spin_unlock_irqrestore(&(queue->spinlock), level); - /* do schedule */ - rt_schedule(); + /* do schedule */ + rt_schedule(); + + /* thread is waked up */ + level = rt_spin_lock_irqsave(&(queue->spinlock)); - /* thread is waked up */ - result = thread->error; - level = rt_spin_lock_irqsave(&(queue->spinlock)); + /* error may be modified by waker, so take the lock before accessing it */ + result = thread->error; + } if (result != RT_EOK) goto __exit; } @@ -159,15 +165,10 @@ rt_err_t rt_data_queue_push(struct rt_data_queue *queue, } /* there is at least one thread in suspended list */ - if (!rt_list_isempty(&(queue->suspended_pop_list))) + if (rt_susp_list_dequeue(&queue->suspended_push_list, + RT_THREAD_RESUME_RES_THR_ERR)) { - /* get thread entry */ - thread = rt_list_entry(queue->suspended_pop_list.next, - struct rt_thread, - tlist); - - /* resume it */ - rt_thread_resume(thread); + /* unlock and perform a schedule */ rt_spin_unlock_irqrestore(&(queue->spinlock), level); /* perform a schedule */ @@ -239,29 +240,32 @@ rt_err_t rt_data_queue_pop(struct rt_data_queue *queue, thread->error = RT_EOK; /* suspend thread on the pop list */ - rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); - rt_list_insert_before(&(queue->suspended_pop_list), &(thread->tlist)); - /* start timer */ - if (timeout > 0) + result = rt_thread_suspend_to_list(thread, &queue->suspended_pop_list, + RT_IPC_FLAG_FIFO, RT_UNINTERRUPTIBLE); + if (result == RT_EOK) { - /* reset the timeout of thread timer and start it */ - rt_timer_control(&(thread->thread_timer), - RT_TIMER_CTRL_SET_TIME, - &timeout); - rt_timer_start(&(thread->thread_timer)); - } + /* start timer */ + if (timeout > 0) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } - /* enable interrupt */ - rt_spin_unlock_irqrestore(&(queue->spinlock), level); + /* enable interrupt */ + rt_spin_unlock_irqrestore(&(queue->spinlock), level); - /* do schedule */ - rt_schedule(); + /* do schedule */ + rt_schedule(); - /* thread is waked up */ - result = thread->error; - level = rt_spin_lock_irqsave(&(queue->spinlock)); - if (result != RT_EOK) - goto __exit; + /* thread is waked up */ + level = rt_spin_lock_irqsave(&(queue->spinlock)); + result = thread->error; + if (result != RT_EOK) + goto __exit; + } } *data_ptr = queue->queue[queue->get_index].data_ptr; @@ -280,15 +284,10 @@ rt_err_t rt_data_queue_pop(struct rt_data_queue *queue, if (rt_data_queue_len(queue) <= queue->lwm) { /* there is at least one thread in suspended list */ - if (!rt_list_isempty(&(queue->suspended_push_list))) + if (rt_susp_list_dequeue(&queue->suspended_push_list, + RT_THREAD_RESUME_RES_THR_ERR)) { - /* get thread entry */ - thread = rt_list_entry(queue->suspended_push_list.next, - struct rt_thread, - tlist); - - /* resume it */ - rt_thread_resume(thread); + /* unlock and perform a schedule */ rt_spin_unlock_irqrestore(&(queue->spinlock), level); /* perform a schedule */ @@ -364,7 +363,6 @@ RTM_EXPORT(rt_data_queue_peek); void rt_data_queue_reset(struct rt_data_queue *queue) { rt_base_t level; - struct rt_thread *thread; RT_ASSERT(queue != RT_NULL); RT_ASSERT(queue->magic == DATAQUEUE_MAGIC); @@ -382,52 +380,13 @@ void rt_data_queue_reset(struct rt_data_queue *queue) /* wakeup all suspend threads */ /* resume on pop list */ - while (!rt_list_isempty(&(queue->suspended_pop_list))) - { - /* disable interrupt */ - level = rt_spin_lock_irqsave(&(queue->spinlock)); - - /* get next suspend thread */ - thread = rt_list_entry(queue->suspended_pop_list.next, - struct rt_thread, - tlist); - /* set error code to -RT_ERROR */ - thread->error = -RT_ERROR; - - /* - * resume thread - * In rt_thread_resume function, it will remove current thread from - * suspend list - */ - rt_thread_resume(thread); - - /* enable interrupt */ - rt_spin_unlock_irqrestore(&(queue->spinlock), level); - } + rt_susp_list_resume_all_irq(&queue->suspended_pop_list, RT_ERROR, + &(queue->spinlock)); /* resume on push list */ - while (!rt_list_isempty(&(queue->suspended_push_list))) - { - /* disable interrupt */ - level = rt_spin_lock_irqsave(&(queue->spinlock)); - - /* get next suspend thread */ - thread = rt_list_entry(queue->suspended_push_list.next, - struct rt_thread, - tlist); - /* set error code to -RT_ERROR */ - thread->error = -RT_ERROR; + rt_susp_list_resume_all_irq(&queue->suspended_push_list, RT_ERROR, + &(queue->spinlock)); - /* - * resume thread - * In rt_thread_resume function, it will remove current thread from - * suspend list - */ - rt_thread_resume(thread); - - /* enable interrupt */ - rt_spin_unlock_irqrestore(&(queue->spinlock), level); - } rt_exit_critical(); rt_schedule(); diff --git a/components/drivers/ipc/workqueue.c b/components/drivers/ipc/workqueue.c index 3f191fb9e2..cb958c8710 100644 --- a/components/drivers/ipc/workqueue.c +++ b/components/drivers/ipc/workqueue.c @@ -64,7 +64,10 @@ static void _workqueue_thread_entry(void *parameter) { /* no software timer exist, suspend self. */ rt_thread_suspend_with_flag(rt_thread_self(), RT_UNINTERRUPTIBLE); + + /* release lock after suspend so we will not lost any wakeups */ rt_spin_unlock_irqrestore(&(queue->spinlock), level); + rt_schedule(); continue; } @@ -105,13 +108,11 @@ static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue, work->workqueue = queue; /* whether the workqueue is doing work */ - if (queue->work_current == RT_NULL && - ((queue->work_thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)) + if (queue->work_current == RT_NULL) { - /* resume work thread */ + /* resume work thread, and do a re-schedule if succeed */ rt_thread_resume(queue->work_thread); rt_spin_unlock_irqrestore(&(queue->spinlock), level); - rt_schedule(); } else { @@ -187,13 +188,11 @@ static void _delayed_work_timeout_handler(void *parameter) work->flags |= RT_WORK_STATE_PENDING; } /* whether the workqueue is doing work */ - if (queue->work_current == RT_NULL && - ((queue->work_thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)) + if (queue->work_current == RT_NULL) { - /* resume work thread */ + /* resume work thread, and do a re-schedule if succeed */ rt_thread_resume(queue->work_thread); rt_spin_unlock_irqrestore(&(queue->spinlock), level); - rt_schedule(); } else { @@ -346,13 +345,11 @@ rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *wo rt_list_remove(&(work->list)); rt_list_insert_after(&queue->work_list, &(work->list)); /* whether the workqueue is doing work */ - if (queue->work_current == RT_NULL && - ((queue->work_thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)) + if (queue->work_current == RT_NULL) { - /* resume work thread */ + /* resume work thread, and do a re-schedule if succeed */ rt_thread_resume(queue->work_thread); rt_spin_unlock_irqrestore(&(queue->spinlock), level); - rt_schedule(); } else { |
