mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-18 11:53:05 +08:00
🎯 Sync smart & scheduler codes (#8537)
Signed-off-by: Shell <smokewood@qq.com> Co-authored-by: xqyjlj <xqyjlj@126.com>
This commit is contained in:
@@ -10,11 +10,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("Hello RT-Thread!\n");
|
||||
rt_kprintf("Hello RT-Thread!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ void rt_hw_secondary_cpu_up(void)
|
||||
*plat_boot_reg-- = (void *)(size_t)-1;
|
||||
*plat_boot_reg = (void *)entry;
|
||||
rt_hw_dsb();
|
||||
rt_hw_ipi_send(0, 1 << 1);
|
||||
rt_hw_ipi_send(0, RT_CPU_MASK ^ (1 << rt_hw_cpu_id()));
|
||||
}
|
||||
|
||||
/* Interface */
|
||||
|
||||
@@ -352,7 +352,7 @@ static int dfs_romfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32
|
||||
|
||||
d->d_namlen = rt_strlen(name);
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, name, DFS_PATH_MAX);
|
||||
rt_strncpy(d->d_name, name, DIRENT_NAME_MAX);
|
||||
|
||||
/* move to next position */
|
||||
++ file->fpos;
|
||||
|
||||
@@ -822,7 +822,10 @@ static int dfs_page_insert(struct dfs_page *page)
|
||||
rt_list_insert_before(&aspace->list_inactive, &page->space_node);
|
||||
aspace->pages_count ++;
|
||||
|
||||
RT_ASSERT(_dfs_page_insert(aspace, page) == 0);
|
||||
if (_dfs_page_insert(aspace, page))
|
||||
{
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
if (aspace->pages_count > RT_PAGECACHE_ASPACE_COUNT)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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));
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* start timer */
|
||||
if (timeout > 0)
|
||||
result = rt_thread_suspend_with_flag(thread, 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));
|
||||
/* add to suspended thread */
|
||||
completion->susp_thread_n_flag = RT_COMPLETION_NEW_STAT(thread, RT_UNCOMPLETED);
|
||||
|
||||
/* 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_lock, level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
|
||||
level = rt_spin_lock_irqsave(&_completion_lock);
|
||||
}
|
||||
/* enable interrupt */
|
||||
rt_spin_unlock_irqrestore(&(completion->spinlock), level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
|
||||
level = rt_spin_lock_irqsave(&(completion->spinlock));
|
||||
}
|
||||
}
|
||||
/* 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);
|
||||
error = rt_thread_resume(suspend_thread);
|
||||
if (error)
|
||||
{
|
||||
LOG_D("%s: failed to resume thread", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* perform a schedule */
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&(completion->spinlock), level);
|
||||
}
|
||||
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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||
|
||||
/* error may be modified by waker, so take the lock before accessing it */
|
||||
result = thread->error;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||
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);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||
result = thread->error;
|
||||
if (result != RT_EOK)
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
|
||||
/* thread is waked up */
|
||||
result = thread->error;
|
||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||
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));
|
||||
rt_susp_list_resume_all_irq(&queue->suspended_push_list, RT_ERROR,
|
||||
&(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;
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
+20
-27
@@ -216,15 +216,23 @@ long list_thread(void)
|
||||
rt_uint8_t *ptr;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
if (thread->oncpu != RT_CPU_DETACHED)
|
||||
rt_kprintf("%-*.*s %3d %3d %4d ", maxlen, RT_NAME_MAX, thread->parent.name, thread->oncpu, thread->bind_cpu, thread->current_priority);
|
||||
/* no synchronization applied since it's only for debug */
|
||||
if (RT_SCHED_CTX(thread).oncpu != RT_CPU_DETACHED)
|
||||
rt_kprintf("%-*.*s %3d %3d %4d ", maxlen, RT_NAME_MAX,
|
||||
thread->parent.name, RT_SCHED_CTX(thread).oncpu,
|
||||
RT_SCHED_CTX(thread).bind_cpu,
|
||||
RT_SCHED_PRIV(thread).current_priority);
|
||||
else
|
||||
rt_kprintf("%-*.*s N/A %3d %4d ", maxlen, RT_NAME_MAX, thread->parent.name, thread->bind_cpu, thread->current_priority);
|
||||
rt_kprintf("%-*.*s N/A %3d %4d ", maxlen, RT_NAME_MAX,
|
||||
thread->parent.name,
|
||||
RT_SCHED_CTX(thread).bind_cpu,
|
||||
RT_SCHED_PRIV(thread).current_priority);
|
||||
|
||||
#else
|
||||
rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->parent.name, thread->current_priority);
|
||||
/* no synchronization applied since it's only for debug */
|
||||
rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->parent.name, RT_SCHED_PRIV(thread).current_priority);
|
||||
#endif /*RT_USING_SMP*/
|
||||
stat = (thread->stat & RT_THREAD_STAT_MASK);
|
||||
stat = (RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK);
|
||||
if (stat == RT_THREAD_READY) rt_kprintf(" ready ");
|
||||
else if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) rt_kprintf(" suspend");
|
||||
else if (stat == RT_THREAD_INIT) rt_kprintf(" init ");
|
||||
@@ -250,7 +258,7 @@ long list_thread(void)
|
||||
thread->stack_size,
|
||||
(thread->stack_size - ((rt_ubase_t) ptr - (rt_ubase_t) thread->stack_addr)) * 100
|
||||
/ thread->stack_size,
|
||||
thread->remaining_tick,
|
||||
RT_SCHED_PRIV(thread).remaining_tick,
|
||||
rt_strerror(thread->error),
|
||||
thread);
|
||||
#endif
|
||||
@@ -263,21 +271,6 @@ long list_thread(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_wait_queue(struct rt_list_node *list)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
struct rt_list_node *node;
|
||||
|
||||
for (node = list->next; node != list; node = node->next)
|
||||
{
|
||||
thread = rt_list_entry(node, struct rt_thread, tlist);
|
||||
rt_kprintf("%.*s", RT_NAME_MAX, thread->parent.name);
|
||||
|
||||
if (node->next != list)
|
||||
rt_kprintf("/");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
long list_sem(void)
|
||||
{
|
||||
@@ -326,7 +319,7 @@ long list_sem(void)
|
||||
sem->parent.parent.name,
|
||||
sem->value,
|
||||
rt_list_len(&sem->parent.suspend_thread));
|
||||
show_wait_queue(&(sem->parent.suspend_thread));
|
||||
rt_susp_list_print(&(sem->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
@@ -395,7 +388,7 @@ long list_event(void)
|
||||
e->parent.parent.name,
|
||||
e->set,
|
||||
rt_list_len(&e->parent.suspend_thread));
|
||||
show_wait_queue(&(e->parent.suspend_thread));
|
||||
rt_susp_list_print(&(e->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
@@ -464,7 +457,7 @@ long list_mutex(void)
|
||||
m->hold,
|
||||
m->priority,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
show_wait_queue(&(m->parent.suspend_thread));
|
||||
rt_susp_list_print(&(m->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
@@ -537,7 +530,7 @@ long list_mailbox(void)
|
||||
m->entry,
|
||||
m->size,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
show_wait_queue(&(m->parent.suspend_thread));
|
||||
rt_susp_list_print(&(m->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
@@ -607,7 +600,7 @@ long list_msgqueue(void)
|
||||
m->parent.parent.name,
|
||||
m->entry,
|
||||
rt_list_len(&m->parent.suspend_thread));
|
||||
show_wait_queue(&(m->parent.suspend_thread));
|
||||
rt_susp_list_print(&(m->parent.suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
@@ -744,7 +737,7 @@ long list_mempool(void)
|
||||
mp->block_total_count,
|
||||
mp->block_free_count,
|
||||
suspend_thread_count);
|
||||
show_wait_queue(&(mp->suspend_thread));
|
||||
rt_susp_list_print(&(mp->suspend_thread));
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -46,7 +46,17 @@ int8_t rt_tz_is_dst(void);
|
||||
|
||||
struct itimerspec;
|
||||
|
||||
#if defined(_GNU_SOURCE) && (defined(__x86_64__) || defined(__i386__))
|
||||
/* 'struct timeval' is defined on __x86_64__ toolchain */
|
||||
#if !defined(__x86_64__) && !defined(_TIMEVAL_DEFINED)
|
||||
#define _TIMEVAL_DEFINED
|
||||
struct timeval
|
||||
{
|
||||
time_t tv_sec; /* seconds */
|
||||
suseconds_t tv_usec; /* and microseconds */
|
||||
};
|
||||
#endif /* _TIMEVAL_DEFINED */
|
||||
|
||||
#if defined(_GNU_SOURCE) && (defined(__x86_64__) || defined(__i386__) || defined(RT_USING_SMART))
|
||||
/* linux x86 platform gcc use! */
|
||||
#define _TIMEVAL_DEFINED
|
||||
/* Values for the first argument to `getitimer' and `setitimer'. */
|
||||
@@ -71,16 +81,7 @@ struct itimerval
|
||||
/* Time to the next timer expiration. */
|
||||
struct timeval it_value;
|
||||
};
|
||||
#endif /* defined(_GNU_SOURCE) && (defined(__x86_64__) || defined(__i386__)) */
|
||||
|
||||
#ifndef _TIMEVAL_DEFINED
|
||||
#define _TIMEVAL_DEFINED
|
||||
struct timeval
|
||||
{
|
||||
time_t tv_sec; /* seconds */
|
||||
suseconds_t tv_usec; /* and microseconds */
|
||||
};
|
||||
#endif /* _TIMEVAL_DEFINED */
|
||||
#endif /* defined(_GNU_SOURCE) && (defined(__x86_64__) || defined(__i386__)) || defined(RT_USING_SMART) */
|
||||
|
||||
#if defined(__ARMCC_VERSION) || defined(_WIN32) || (defined(__ICCARM__) && (__VER__ < 8010001))
|
||||
struct timespec
|
||||
|
||||
@@ -203,7 +203,7 @@ void dlmodule_destroy_subthread(struct rt_dlmodule *module, rt_thread_t thread)
|
||||
rt_enter_critical();
|
||||
|
||||
/* remove thread from thread_list (ready or defunct thread list) */
|
||||
rt_list_remove(&(thread->tlist));
|
||||
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
|
||||
|
||||
if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE &&
|
||||
(thread->thread_timer.parent.type == (RT_Object_Class_Static | RT_Object_Class_Timer)))
|
||||
|
||||
@@ -285,7 +285,7 @@ rt_err_t _pthread_cond_timedwait(pthread_cond_t *cond,
|
||||
rt_thread_suspend(thread);
|
||||
|
||||
/* Only support FIFO */
|
||||
rt_list_insert_before(&(sem->parent.suspend_thread), &(thread->tlist));
|
||||
rt_list_insert_before(&(sem->parent.suspend_thread), &RT_THREAD_LIST_NODE(thread));
|
||||
|
||||
/**
|
||||
rt_ipc_list_suspend(&(sem->parent.suspend_thread),
|
||||
|
||||
@@ -28,6 +28,22 @@
|
||||
|
||||
#define FUTEX_CLOCK_REALTIME 256
|
||||
|
||||
#define FUTEX_WAITERS 0x80000000
|
||||
#define FUTEX_OWNER_DIED 0x40000000
|
||||
#define FUTEX_TID_MASK 0x3fffffff
|
||||
|
||||
struct robust_list
|
||||
{
|
||||
struct robust_list *next;
|
||||
};
|
||||
|
||||
struct robust_list_head
|
||||
{
|
||||
struct robust_list list;
|
||||
long futex_offset;
|
||||
struct robust_list *list_op_pending;
|
||||
};
|
||||
|
||||
/* for pmutex op */
|
||||
#define PMUTEX_INIT 0
|
||||
#define PMUTEX_LOCK 1
|
||||
|
||||
+3
-46
@@ -168,7 +168,6 @@ enum lwp_exit_request_type
|
||||
struct termios *get_old_termios(void);
|
||||
void lwp_setcwd(char *buf);
|
||||
char *lwp_getcwd(void);
|
||||
void lwp_request_thread_exit(rt_thread_t thread_to_exit);
|
||||
int lwp_check_exit_request(void);
|
||||
void lwp_terminate(struct rt_lwp *lwp);
|
||||
|
||||
@@ -213,52 +212,10 @@ pid_t exec(char *filename, int debug, int argc, char **argv);
|
||||
/* ctime lwp API */
|
||||
int timer_list_free(rt_list_t *timer_list);
|
||||
|
||||
struct rt_futex;
|
||||
rt_err_t lwp_futex(struct rt_lwp *lwp, struct rt_futex *futex, int *uaddr, int op, int val, const struct timespec *timeout);
|
||||
rt_err_t lwp_futex_init(void);
|
||||
rt_err_t lwp_futex(struct rt_lwp *lwp, int *uaddr, int op, int val,
|
||||
const struct timespec *timeout, int *uaddr2, int val3);
|
||||
|
||||
#ifdef ARCH_MM_MMU
|
||||
struct __pthread {
|
||||
/* Part 1 -- these fields may be external or
|
||||
* * internal (accessed via asm) ABI. Do not change. */
|
||||
struct pthread *self;
|
||||
uintptr_t *dtv;
|
||||
struct pthread *prev, *next; /* non-ABI */
|
||||
uintptr_t sysinfo;
|
||||
uintptr_t canary, canary2;
|
||||
|
||||
/* Part 2 -- implementation details, non-ABI. */
|
||||
int tid;
|
||||
int errno_val;
|
||||
volatile int detach_state;
|
||||
volatile int cancel;
|
||||
volatile unsigned char canceldisable, cancelasync;
|
||||
unsigned char tsd_used:1;
|
||||
unsigned char dlerror_flag:1;
|
||||
unsigned char *map_base;
|
||||
size_t map_size;
|
||||
void *stack;
|
||||
size_t stack_size;
|
||||
size_t guard_size;
|
||||
void *result;
|
||||
struct __ptcb *cancelbuf;
|
||||
void **tsd;
|
||||
struct {
|
||||
volatile void *volatile head;
|
||||
long off;
|
||||
volatile void *volatile pending;
|
||||
} robust_list;
|
||||
volatile int timer_id;
|
||||
locale_t locale;
|
||||
volatile int killlock[1];
|
||||
char *dlerror_buf;
|
||||
void *stdio_locks;
|
||||
|
||||
/* Part 3 -- the positions of these fields relative to
|
||||
* * the end of the structure is external and internal ABI. */
|
||||
uintptr_t canary_at_end;
|
||||
uintptr_t *dtv_copy;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+727
-145
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-01 Shell Init ver.
|
||||
*/
|
||||
#ifndef __LWP_FUTEX_INTERNAL_H__
|
||||
#define __LWP_FUTEX_INTERNAL_H__
|
||||
|
||||
#define DBG_TAG "lwp.futex"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "rt_uthash.h"
|
||||
#include "lwp_internal.h"
|
||||
#include "lwp_pid.h"
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <lwp.h>
|
||||
|
||||
#ifdef ARCH_MM_MMU
|
||||
#include <lwp_user_mm.h>
|
||||
#endif /* ARCH_MM_MMU */
|
||||
|
||||
struct shared_futex_key
|
||||
{
|
||||
rt_mem_obj_t mobj;
|
||||
rt_base_t offset;
|
||||
};
|
||||
DEFINE_RT_UTHASH_TYPE(shared_futex_entry, struct shared_futex_key, key);
|
||||
|
||||
struct rt_futex
|
||||
{
|
||||
union {
|
||||
/* for private futex */
|
||||
struct lwp_avl_struct node;
|
||||
/* for shared futex */
|
||||
struct shared_futex_entry entry;
|
||||
};
|
||||
|
||||
rt_list_t waiting_thread;
|
||||
struct rt_object *custom_obj;
|
||||
rt_mutex_t mutex;
|
||||
};
|
||||
typedef struct rt_futex *rt_futex_t;
|
||||
|
||||
rt_err_t futex_global_table_add(struct shared_futex_key *key, rt_futex_t futex);
|
||||
rt_err_t futex_global_table_find(struct shared_futex_key *key, rt_futex_t *futex);
|
||||
rt_err_t futex_global_table_delete(struct shared_futex_key *key);
|
||||
|
||||
#endif /* __LWP_FUTEX_INTERNAL_H__ */
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-01 Shell Init ver.
|
||||
*/
|
||||
|
||||
#include "lwp_futex_internal.h"
|
||||
|
||||
static struct shared_futex_entry *_futex_hash_head;
|
||||
|
||||
rt_err_t futex_global_table_add(struct shared_futex_key *key, rt_futex_t futex)
|
||||
{
|
||||
rt_err_t rc = 0;
|
||||
struct shared_futex_entry *entry = &futex->entry;
|
||||
futex->entry.key.mobj = key->mobj;
|
||||
futex->entry.key.offset = key->offset;
|
||||
|
||||
RT_UTHASH_ADD(_futex_hash_head, key, sizeof(struct shared_futex_key), entry);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rt_err_t futex_global_table_find(struct shared_futex_key *key, rt_futex_t *futex)
|
||||
{
|
||||
rt_err_t rc;
|
||||
rt_futex_t found_futex;
|
||||
struct shared_futex_entry *entry;
|
||||
|
||||
RT_UTHASH_FIND(_futex_hash_head, key, sizeof(struct shared_futex_key), entry);
|
||||
if (entry)
|
||||
{
|
||||
rc = RT_EOK;
|
||||
found_futex = rt_container_of(entry, struct rt_futex, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = -RT_ENOENT;
|
||||
found_futex = RT_NULL;
|
||||
}
|
||||
|
||||
*futex = found_futex;
|
||||
return rc;
|
||||
}
|
||||
|
||||
rt_err_t futex_global_table_delete(struct shared_futex_key *key)
|
||||
{
|
||||
rt_err_t rc;
|
||||
struct shared_futex_entry *entry;
|
||||
|
||||
RT_UTHASH_FIND(_futex_hash_head, key, sizeof(struct shared_futex_key), entry);
|
||||
if (entry)
|
||||
{
|
||||
RT_UTHASH_DELETE(_futex_hash_head, entry);
|
||||
rc = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = -RT_ENOENT;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t interruptable)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
int retry;
|
||||
rt_int32_t effect_timeout;
|
||||
|
||||
@@ -92,19 +92,19 @@ static rt_err_t _mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t i
|
||||
RT_ASSERT(0);
|
||||
}
|
||||
|
||||
RETURN(rc);
|
||||
LWP_RETURN(rc);
|
||||
}
|
||||
|
||||
rt_err_t lwp_mutex_take_safe(rt_mutex_t mtx, rt_int32_t timeout, rt_bool_t interruptable)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
rc = _mutex_take_safe(mtx, timeout, interruptable);
|
||||
RETURN(rc);
|
||||
LWP_RETURN(rc);
|
||||
}
|
||||
|
||||
rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
|
||||
rc = rt_mutex_release(mtx);
|
||||
if (rc)
|
||||
@@ -113,7 +113,7 @@ rt_err_t lwp_mutex_release_safe(rt_mutex_t mtx)
|
||||
rt_backtrace();
|
||||
}
|
||||
|
||||
RETURN(rc);
|
||||
LWP_RETURN(rc);
|
||||
}
|
||||
|
||||
rt_err_t lwp_critical_enter(struct rt_lwp *lwp)
|
||||
|
||||
@@ -86,13 +86,13 @@ rt_err_t lwp_critical_exit(struct rt_lwp *lwp);
|
||||
* There tend to be chances where a return value is returned without correctly init
|
||||
*/
|
||||
#ifndef LWP_DEBUG
|
||||
#define DEF_RETURN_CODE(name) rt_err_t name
|
||||
#define RETURN(name) return name
|
||||
#define LWP_DEF_RETURN_CODE(name) rt_err_t name;RT_UNUSED(name)
|
||||
#define LWP_RETURN(name) return name
|
||||
|
||||
#else
|
||||
#define _LWP_UNINITIALIZED_RC 0xbeefcafe
|
||||
#define DEF_RETURN_CODE(name) rt_err_t name = _LWP_UNINITIALIZED_RC
|
||||
#define RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;}
|
||||
#define LWP_DEF_RETURN_CODE(name) rt_err_t name = _LWP_UNINITIALIZED_RC
|
||||
#define LWP_RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;}
|
||||
#endif /* LWP_DEBUG */
|
||||
|
||||
#endif /* __LWP_INTERNAL_H__ */
|
||||
|
||||
+40
-41
@@ -8,7 +8,9 @@
|
||||
* 2019-10-12 Jesven first version
|
||||
* 2023-07-25 Shell Remove usage of rt_hw_interrupt API in the lwp
|
||||
* 2023-09-16 zmq810150896 Increased versatility of some features on dfs v2
|
||||
* 2024-01-25 Shell porting to susp_list API
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#define DBG_TAG "lwp.ipc"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
@@ -124,11 +126,9 @@ rt_inline rt_err_t rt_channel_list_resume(rt_list_t *list)
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* get the first thread entry waiting for sending */
|
||||
thread = rt_list_entry(list->next, struct rt_thread, tlist);
|
||||
thread = rt_susp_list_dequeue(list, RT_THREAD_RESUME_RES_THR_ERR);
|
||||
|
||||
rt_thread_resume(thread);
|
||||
|
||||
return RT_EOK;
|
||||
return thread ? RT_EOK : -RT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,15 +136,8 @@ rt_inline rt_err_t rt_channel_list_resume(rt_list_t *list)
|
||||
*/
|
||||
rt_inline rt_err_t _channel_list_resume_all_locked(rt_list_t *list)
|
||||
{
|
||||
struct rt_thread *thread;
|
||||
|
||||
/* wakeup all suspended threads for sending */
|
||||
while (!rt_list_isempty(list))
|
||||
{
|
||||
thread = rt_list_entry(list->next, struct rt_thread, tlist);
|
||||
thread->error = -RT_ERROR;
|
||||
rt_thread_resume(thread);
|
||||
}
|
||||
rt_susp_list_resume_all(list, RT_ERROR);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
@@ -155,12 +148,7 @@ rt_inline rt_err_t _channel_list_resume_all_locked(rt_list_t *list)
|
||||
rt_inline rt_err_t rt_channel_list_suspend(rt_list_t *list, struct rt_thread *thread)
|
||||
{
|
||||
/* suspend thread */
|
||||
rt_err_t ret = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
|
||||
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
rt_list_insert_before(list, &(thread->tlist)); /* list end */
|
||||
}
|
||||
rt_err_t ret = rt_thread_suspend_to_list(thread, list, RT_IPC_FLAG_FIFO, RT_INTERRUPTIBLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -372,10 +360,13 @@ static rt_err_t wakeup_sender_wait_reply(void *object, struct rt_thread *thread)
|
||||
|
||||
static void sender_timeout(void *parameter)
|
||||
{
|
||||
rt_sched_lock_level_t slvl;
|
||||
struct rt_thread *thread = (struct rt_thread *)parameter;
|
||||
rt_channel_t ch;
|
||||
|
||||
ch = (rt_channel_t)(thread->wakeup.user_data);
|
||||
rt_sched_lock(&slvl);
|
||||
|
||||
ch = (rt_channel_t)(thread->wakeup_handle.user_data);
|
||||
if (ch->stat == RT_IPC_STAT_ACTIVE && ch->reply == thread)
|
||||
{
|
||||
ch->stat = RT_IPC_STAT_IDLE;
|
||||
@@ -399,14 +390,14 @@ static void sender_timeout(void *parameter)
|
||||
l = l->next;
|
||||
}
|
||||
}
|
||||
thread->error = -RT_ETIMEOUT;
|
||||
thread->wakeup.func = RT_NULL;
|
||||
|
||||
rt_list_remove(&(thread->tlist));
|
||||
thread->wakeup_handle.func = RT_NULL;
|
||||
thread->error = RT_ETIMEOUT;
|
||||
|
||||
/* insert to schedule ready list */
|
||||
rt_schedule_insert_thread(thread);
|
||||
rt_sched_insert_thread(thread);
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
rt_sched_unlock_n_resched(slvl);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -522,7 +513,7 @@ static rt_err_t _send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, int n
|
||||
|
||||
static rt_err_t _do_send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, int need_reply, rt_channel_msg_t data_ret, rt_int32_t time, rt_ipc_msg_t msg)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
rt_thread_t thread_recv;
|
||||
rt_thread_t thread_send = 0;
|
||||
void (*old_timeout_func)(void *) = 0;
|
||||
@@ -627,9 +618,12 @@ static rt_err_t _do_send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, in
|
||||
|
||||
if (!need_reply || rc == RT_EOK)
|
||||
{
|
||||
thread_recv = rt_list_entry(ch->parent.suspend_thread.next, struct rt_thread, tlist);
|
||||
rt_sched_lock_level_t slvl;
|
||||
rt_sched_lock(&slvl);
|
||||
thread_recv = RT_THREAD_LIST_NODE_ENTRY(ch->parent.suspend_thread.next);
|
||||
thread_recv->msg_ret = msg; /* to the first suspended receiver */
|
||||
thread_recv->error = RT_EOK;
|
||||
rt_sched_unlock(slvl);
|
||||
rt_channel_list_resume(&ch->parent.suspend_thread);
|
||||
}
|
||||
break;
|
||||
@@ -706,7 +700,7 @@ rt_err_t rt_raw_channel_send_recv_timeout(rt_channel_t ch, rt_channel_msg_t data
|
||||
*/
|
||||
rt_err_t rt_raw_channel_reply(rt_channel_t ch, rt_channel_msg_t data)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
rt_ipc_msg_t msg;
|
||||
struct rt_thread *thread;
|
||||
rt_base_t level;
|
||||
@@ -758,7 +752,7 @@ rt_err_t rt_raw_channel_reply(rt_channel_t ch, rt_channel_msg_t data)
|
||||
rt_schedule();
|
||||
}
|
||||
|
||||
RETURN(rc);
|
||||
LWP_RETURN(rc);
|
||||
}
|
||||
|
||||
static rt_err_t wakeup_receiver(void *object, struct rt_thread *thread)
|
||||
@@ -783,24 +777,27 @@ static void receiver_timeout(void *parameter)
|
||||
{
|
||||
struct rt_thread *thread = (struct rt_thread *)parameter;
|
||||
rt_channel_t ch;
|
||||
rt_base_t level;
|
||||
rt_sched_lock_level_t slvl;
|
||||
|
||||
ch = (rt_channel_t)(thread->wakeup.user_data);
|
||||
rt_sched_lock(&slvl);
|
||||
|
||||
ch = (rt_channel_t)(thread->wakeup_handle.user_data);
|
||||
|
||||
level = rt_spin_lock_irqsave(&ch->slock);
|
||||
ch->stat = RT_IPC_STAT_IDLE;
|
||||
thread->error = -RT_ETIMEOUT;
|
||||
thread->wakeup.func = RT_NULL;
|
||||
thread->wakeup_handle.func = RT_NULL;
|
||||
|
||||
rt_list_remove(&(thread->tlist));
|
||||
rt_spin_lock(&ch->slock);
|
||||
ch->stat = RT_IPC_STAT_IDLE;
|
||||
|
||||
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
|
||||
/* insert to schedule ready list */
|
||||
rt_schedule_insert_thread(thread);
|
||||
rt_sched_insert_thread(thread);
|
||||
|
||||
_rt_channel_check_wq_wakup_locked(ch);
|
||||
rt_spin_unlock_irqrestore(&ch->slock, level);
|
||||
rt_spin_unlock(&ch->slock);
|
||||
|
||||
/* do schedule */
|
||||
rt_schedule();
|
||||
rt_sched_unlock_n_resched(slvl);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -808,7 +805,7 @@ static void receiver_timeout(void *parameter)
|
||||
*/
|
||||
static rt_err_t _rt_raw_channel_recv_timeout(rt_channel_t ch, rt_channel_msg_t data, rt_int32_t time)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
struct rt_thread *thread;
|
||||
rt_ipc_msg_t msg_ret;
|
||||
void (*old_timeout_func)(void *) = 0;
|
||||
@@ -839,10 +836,12 @@ static rt_err_t _rt_raw_channel_recv_timeout(rt_channel_t ch, rt_channel_msg_t d
|
||||
rt_list_remove(ch->wait_msg.next); /* remove the message from the channel */
|
||||
if (msg_ret->need_reply)
|
||||
{
|
||||
rt_sched_lock_level_t slvl;
|
||||
rt_sched_lock(&slvl);
|
||||
RT_ASSERT(ch->wait_thread.next != &ch->wait_thread);
|
||||
|
||||
thread = rt_list_entry(ch->wait_thread.next, struct rt_thread, tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(ch->wait_thread.next);
|
||||
rt_list_remove(ch->wait_thread.next);
|
||||
rt_sched_unlock(slvl);
|
||||
ch->reply = thread; /* record the waiting sender */
|
||||
ch->stat = RT_IPC_STAT_ACTIVE; /* no valid suspened receivers */
|
||||
}
|
||||
@@ -912,7 +911,7 @@ static rt_err_t _rt_raw_channel_recv_timeout(rt_channel_t ch, rt_channel_msg_t d
|
||||
|
||||
rt_spin_unlock_irqrestore(&ch->slock, level);
|
||||
|
||||
RETURN(rc);
|
||||
LWP_RETURN(rc);
|
||||
}
|
||||
|
||||
rt_err_t rt_raw_channel_recv(rt_channel_t ch, rt_channel_msg_t data)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-30 Shell Add itimer support
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/time.h>
|
||||
#undef _GNU_SOURCE
|
||||
|
||||
#define DBG_TAG "lwp.signal"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lwp_internal.h"
|
||||
#include "sys/signal.h"
|
||||
#include "syscall_generic.h"
|
||||
|
||||
rt_err_t lwp_signal_setitimer(rt_lwp_t lwp, int which, const struct itimerspec *restrict new, struct itimerspec *restrict old)
|
||||
{
|
||||
rt_err_t rc = RT_EOK;
|
||||
timer_t timerid = 0;
|
||||
int flags = 0;
|
||||
|
||||
if (lwp->signal.real_timer == LWP_SIG_INVALID_TIMER)
|
||||
{
|
||||
struct sigevent sevp = {
|
||||
.sigev_signo = SIGALRM,
|
||||
.sigev_notify = SIGEV_SIGNAL,
|
||||
};
|
||||
|
||||
rc = timer_create(CLOCK_REALTIME_ALARM, &sevp, &timerid);
|
||||
if (rc == RT_EOK)
|
||||
{
|
||||
RT_ASSERT(timerid != LWP_SIG_INVALID_TIMER);
|
||||
lwp->signal.real_timer = timerid;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* failed to create timer */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
timerid = lwp->signal.real_timer;
|
||||
}
|
||||
|
||||
if (rc == RT_EOK)
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case ITIMER_REAL:
|
||||
rc = timer_settime(timerid, flags, new, old);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
LOG_W("%s() unsupported timer", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
+39
-112
@@ -14,8 +14,12 @@
|
||||
* error
|
||||
* 2023-10-27 shell Format codes of sys_exit(). Fix the data racing where lock is missed
|
||||
* Add reference on pid/tid, so the resource is not freed while using.
|
||||
* 2024-01-25 shell porting to new sched API
|
||||
*/
|
||||
|
||||
/* includes scheduler related API */
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
@@ -59,7 +63,7 @@ int lwp_pid_init(void)
|
||||
|
||||
void lwp_pid_lock_take(void)
|
||||
{
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
|
||||
rc = lwp_mutex_take_safe(&pid_mtx, RT_WAITING_FOREVER, 0);
|
||||
/* should never failed */
|
||||
@@ -382,7 +386,7 @@ rt_lwp_t lwp_create(rt_base_t flags)
|
||||
}
|
||||
}
|
||||
|
||||
LOG_D("%s(pid=%d) => %p", __func__, new_lwp->pid, new_lwp);
|
||||
LOG_D("%s(pid=%d) => %p", __func__, new_lwp ? new_lwp->pid : -1, new_lwp);
|
||||
return new_lwp;
|
||||
}
|
||||
|
||||
@@ -699,6 +703,7 @@ pid_t lwp_name2pid(const char *name)
|
||||
pid_t pid = 0;
|
||||
rt_thread_t main_thread;
|
||||
char* process_name = RT_NULL;
|
||||
rt_sched_lock_level_t slvl;
|
||||
|
||||
lwp_pid_lock_take();
|
||||
for (idx = 0; idx < RT_LWP_MAX_NR; idx++)
|
||||
@@ -713,10 +718,12 @@ pid_t lwp_name2pid(const char *name)
|
||||
if (!rt_strncmp(name, process_name, RT_NAME_MAX))
|
||||
{
|
||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||
if (!(main_thread->stat & RT_THREAD_CLOSE))
|
||||
rt_sched_lock(&slvl);
|
||||
if (!(rt_sched_thread_get_stat(main_thread) == RT_THREAD_CLOSE))
|
||||
{
|
||||
pid = lwp->pid;
|
||||
}
|
||||
rt_sched_unlock(slvl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,7 +774,7 @@ static sysret_t _lwp_wait_and_recycle(struct rt_lwp *child, rt_thread_t cur_thr,
|
||||
error = rt_thread_suspend_with_flag(cur_thr, RT_INTERRUPTIBLE);
|
||||
if (error == 0)
|
||||
{
|
||||
rt_list_insert_before(&child->wait_list, &(cur_thr->tlist));
|
||||
rt_list_insert_before(&child->wait_list, &RT_THREAD_LIST_NODE(cur_thr));
|
||||
LWP_UNLOCK(child);
|
||||
|
||||
rt_set_errno(RT_EINTR);
|
||||
@@ -898,15 +905,15 @@ static void print_thread_info(struct rt_thread* thread, int maxlen)
|
||||
rt_uint8_t stat;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
if (thread->oncpu != RT_CPU_DETACHED)
|
||||
rt_kprintf("%-*.*s %3d %3d ", maxlen, RT_NAME_MAX, thread->parent.name, thread->oncpu, thread->current_priority);
|
||||
if (RT_SCHED_CTX(thread).oncpu != RT_CPU_DETACHED)
|
||||
rt_kprintf("%-*.*s %3d %3d ", maxlen, RT_NAME_MAX, thread->parent.name, RT_SCHED_CTX(thread).oncpu, RT_SCHED_PRIV(thread).current_priority);
|
||||
else
|
||||
rt_kprintf("%-*.*s N/A %3d ", maxlen, RT_NAME_MAX, thread->parent.name, thread->current_priority);
|
||||
rt_kprintf("%-*.*s N/A %3d ", maxlen, RT_NAME_MAX, thread->parent.name, RT_SCHED_PRIV(thread).current_priority);
|
||||
#else
|
||||
rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->parent.name, thread->current_priority);
|
||||
#endif /*RT_USING_SMP*/
|
||||
|
||||
stat = (thread->stat & RT_THREAD_STAT_MASK);
|
||||
stat = (RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK);
|
||||
if (stat == RT_THREAD_READY) rt_kprintf(" ready ");
|
||||
else if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) rt_kprintf(" suspend");
|
||||
else if (stat == RT_THREAD_INIT) rt_kprintf(" init ");
|
||||
@@ -932,7 +939,7 @@ static void print_thread_info(struct rt_thread* thread, int maxlen)
|
||||
thread->stack_size,
|
||||
(thread->stack_size + (rt_uint32_t)(rt_size_t)thread->stack_addr - (rt_uint32_t)(rt_size_t)ptr) * 100
|
||||
/ thread->stack_size,
|
||||
thread->remaining_tick,
|
||||
RT_SCHED_PRIV(thread).remaining_tick,
|
||||
thread->error);
|
||||
#endif
|
||||
}
|
||||
@@ -1066,99 +1073,15 @@ MSH_CMD_EXPORT_ALIAS(cmd_killall, killall, kill processes by name);
|
||||
int lwp_check_exit_request(void)
|
||||
{
|
||||
rt_thread_t thread = rt_thread_self();
|
||||
rt_base_t expected = LWP_EXIT_REQUEST_TRIGGERED;
|
||||
|
||||
if (!thread->lwp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (thread->exit_request == LWP_EXIT_REQUEST_TRIGGERED)
|
||||
{
|
||||
thread->exit_request = LWP_EXIT_REQUEST_IN_PROCESS;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int found_thread(struct rt_lwp* lwp, rt_thread_t thread)
|
||||
{
|
||||
int found = 0;
|
||||
rt_base_t level;
|
||||
rt_list_t *list;
|
||||
|
||||
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||
list = lwp->t_grp.next;
|
||||
while (list != &lwp->t_grp)
|
||||
{
|
||||
rt_thread_t iter_thread;
|
||||
|
||||
iter_thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||
if (thread == iter_thread)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||
return found;
|
||||
}
|
||||
|
||||
void lwp_request_thread_exit(rt_thread_t thread_to_exit)
|
||||
{
|
||||
rt_thread_t main_thread;
|
||||
rt_base_t level;
|
||||
rt_list_t *list;
|
||||
struct rt_lwp *lwp;
|
||||
|
||||
lwp = lwp_self();
|
||||
|
||||
if ((!thread_to_exit) || (!lwp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
level = rt_spin_lock_irqsave(&thread_to_exit->spinlock);
|
||||
|
||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||
if (thread_to_exit == main_thread)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
if ((struct rt_lwp *)thread_to_exit->lwp != lwp)
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||
if (thread != thread_to_exit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
|
||||
{
|
||||
thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
|
||||
}
|
||||
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
|
||||
{
|
||||
thread->error = -RT_EINTR;
|
||||
rt_hw_dsb();
|
||||
rt_thread_wakeup(thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
while (found_thread(lwp, thread_to_exit))
|
||||
{
|
||||
rt_thread_mdelay(10);
|
||||
}
|
||||
|
||||
finish:
|
||||
rt_spin_unlock_irqrestore(&thread_to_exit->spinlock, level);
|
||||
return;
|
||||
return rt_atomic_compare_exchange_strong(&thread->exit_request, &expected,
|
||||
LWP_EXIT_REQUEST_IN_PROCESS);
|
||||
}
|
||||
|
||||
static void _wait_sibling_exit(rt_lwp_t lwp, rt_thread_t curr_thread);
|
||||
@@ -1193,34 +1116,32 @@ void lwp_terminate(struct rt_lwp *lwp)
|
||||
|
||||
static void _wait_sibling_exit(rt_lwp_t lwp, rt_thread_t curr_thread)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_sched_lock_level_t slvl;
|
||||
rt_list_t *list;
|
||||
rt_thread_t thread;
|
||||
rt_base_t expected = LWP_EXIT_REQUEST_NONE;
|
||||
|
||||
/* broadcast exit request for sibling threads */
|
||||
LWP_LOCK(lwp);
|
||||
for (list = lwp->t_grp.next; list != &lwp->t_grp; list = list->next)
|
||||
{
|
||||
thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||
if (thread->exit_request == LWP_EXIT_REQUEST_NONE)
|
||||
{
|
||||
thread->exit_request = LWP_EXIT_REQUEST_TRIGGERED;
|
||||
}
|
||||
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||
|
||||
level = rt_spin_lock_irqsave(&thread->spinlock);
|
||||
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
|
||||
rt_atomic_compare_exchange_strong(&thread->exit_request, &expected,
|
||||
LWP_EXIT_REQUEST_TRIGGERED);
|
||||
|
||||
rt_sched_lock(&slvl);
|
||||
/* dont release, otherwise thread may have been freed */
|
||||
if (rt_sched_thread_is_suspended(thread))
|
||||
{
|
||||
thread->error = RT_EINTR;
|
||||
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||
rt_sched_unlock(slvl);
|
||||
|
||||
rt_hw_dsb();
|
||||
rt_thread_wakeup(thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&thread->spinlock, level);
|
||||
rt_sched_unlock(slvl);
|
||||
}
|
||||
}
|
||||
LWP_UNLOCK(lwp);
|
||||
@@ -1240,6 +1161,7 @@ static void _wait_sibling_exit(rt_lwp_t lwp, rt_thread_t curr_thread)
|
||||
subthread_is_terminated = (int)(curr_thread->sibling.prev == &lwp->t_grp);
|
||||
if (!subthread_is_terminated)
|
||||
{
|
||||
rt_sched_lock_level_t slvl;
|
||||
rt_thread_t sub_thread;
|
||||
rt_list_t *list;
|
||||
int all_subthread_in_init = 1;
|
||||
@@ -1247,13 +1169,18 @@ static void _wait_sibling_exit(rt_lwp_t lwp, rt_thread_t curr_thread)
|
||||
/* check all subthread is in init state */
|
||||
for (list = curr_thread->sibling.prev; list != &lwp->t_grp; list = list->prev)
|
||||
{
|
||||
|
||||
rt_sched_lock(&slvl);
|
||||
sub_thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||
if ((sub_thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
|
||||
if (rt_sched_thread_get_stat(sub_thread) != RT_THREAD_INIT)
|
||||
{
|
||||
rt_sched_unlock(slvl);
|
||||
all_subthread_in_init = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sched_unlock(slvl);
|
||||
}
|
||||
}
|
||||
if (all_subthread_in_init)
|
||||
{
|
||||
@@ -1344,7 +1271,7 @@ static void _resr_cleanup(struct rt_lwp *lwp)
|
||||
LWP_UNLOCK(lwp);
|
||||
if (!rt_list_isempty(&lwp->wait_list))
|
||||
{
|
||||
thread = rt_list_entry(lwp->wait_list.next, struct rt_thread, tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(lwp->wait_list.next);
|
||||
thread->error = RT_EOK;
|
||||
thread->msg_ret = (void*)(rt_size_t)lwp->lwp_ret;
|
||||
rt_thread_resume(thread);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* remove lwp_signal_backup/restore() to reduce architecture codes
|
||||
* update the generation, pending and delivery routines
|
||||
*/
|
||||
|
||||
#define __RT_IPC_SOURCE__
|
||||
#define DBG_TAG "lwp.signal"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
@@ -408,6 +408,8 @@ rt_err_t lwp_signal_init(struct lwp_signal *sig)
|
||||
{
|
||||
rt_err_t rc = RT_EOK;
|
||||
|
||||
sig->real_timer = LWP_SIG_INVALID_TIMER;
|
||||
|
||||
memset(&sig->sig_dispatch_thr, 0, sizeof(sig->sig_dispatch_thr));
|
||||
|
||||
memset(&sig->sig_action, 0, sizeof(sig->sig_action));
|
||||
@@ -423,6 +425,7 @@ rt_err_t lwp_signal_detach(struct lwp_signal *signal)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
timer_delete(signal->real_timer);
|
||||
lwp_sigqueue_clear(&signal->sig_queue);
|
||||
|
||||
return ret;
|
||||
@@ -561,27 +564,41 @@ void lwp_thread_signal_catch(void *exp_frame)
|
||||
static int _do_signal_wakeup(rt_thread_t thread, int sig)
|
||||
{
|
||||
int need_schedule;
|
||||
rt_sched_lock_level_t slvl;
|
||||
if (!_sigismember(&thread->signal.sigset_mask, sig))
|
||||
{
|
||||
if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
|
||||
rt_sched_lock(&slvl);
|
||||
int stat = rt_sched_thread_get_stat(thread);
|
||||
if ((stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
|
||||
{
|
||||
if ((thread->stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK)
|
||||
if ((stat & RT_SIGNAL_COMMON_WAKEUP_MASK) != RT_SIGNAL_COMMON_WAKEUP_MASK)
|
||||
{
|
||||
thread->error = RT_EINTR;
|
||||
rt_sched_unlock(slvl);
|
||||
|
||||
rt_thread_wakeup(thread);
|
||||
need_schedule = 1;
|
||||
}
|
||||
else if ((sig == SIGKILL) && ((thread->stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK))
|
||||
else if ((sig == SIGKILL || sig == SIGSTOP) &&
|
||||
((stat & RT_SIGNAL_KILL_WAKEUP_MASK) != RT_SIGNAL_KILL_WAKEUP_MASK))
|
||||
{
|
||||
thread->error = RT_EINTR;
|
||||
rt_sched_unlock(slvl);
|
||||
|
||||
rt_thread_wakeup(thread);
|
||||
need_schedule = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sched_unlock(slvl);
|
||||
need_schedule = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_sched_unlock(slvl);
|
||||
need_schedule = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
need_schedule = 0;
|
||||
@@ -838,7 +855,7 @@ rt_err_t lwp_thread_signal_kill(rt_thread_t thread, long signo, long code, long
|
||||
|
||||
LOG_D("%s(signo=%d)", __func__, signo);
|
||||
|
||||
if (!thread || signo < 0 || signo >= _LWP_NSIG)
|
||||
if (!thread || signo <= 0 || signo >= _LWP_NSIG)
|
||||
{
|
||||
ret = -RT_EINVAL;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include <rtthread.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
struct timespec;
|
||||
struct itimerspec;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -28,6 +31,7 @@ extern "C" {
|
||||
#define LWP_SIG_USER_SA_FLAGS \
|
||||
(SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | \
|
||||
SA_NODEFER | SA_RESETHAND | SA_EXPOSE_TAGBITS)
|
||||
#define LWP_SIG_INVALID_TIMER ((timer_t)-1)
|
||||
|
||||
typedef enum {
|
||||
LWP_SIG_MASK_CMD_BLOCK,
|
||||
@@ -40,6 +44,7 @@ typedef enum {
|
||||
* LwP implementation of POSIX signal
|
||||
*/
|
||||
struct lwp_signal {
|
||||
timer_t real_timer;
|
||||
struct lwp_sigqueue sig_queue;
|
||||
rt_thread_t sig_dispatch_thr[_LWP_NSIG];
|
||||
|
||||
@@ -167,6 +172,10 @@ rt_err_t lwp_thread_signal_timedwait(rt_thread_t thread, lwp_sigset_t *sigset,
|
||||
*/
|
||||
void lwp_thread_signal_pending(rt_thread_t thread, lwp_sigset_t *sigset);
|
||||
|
||||
rt_err_t lwp_signal_setitimer(struct rt_lwp *lwp, int which,
|
||||
const struct itimerspec *restrict new,
|
||||
struct itimerspec *restrict old);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* 2023-07-06 Shell adapt the signal API, and clone, fork to new implementation of lwp signal
|
||||
* 2023-07-27 Shell Move tid_put() from lwp_free() to sys_exit()
|
||||
*/
|
||||
|
||||
#define __RT_IPC_SOURCE__
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* RT-Thread System call */
|
||||
@@ -1120,7 +1120,7 @@ sysret_t sys_getpriority(int which, id_t who)
|
||||
if (lwp)
|
||||
{
|
||||
rt_thread_t thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||
prio = thread->current_priority;
|
||||
prio = RT_SCHED_PRIV(thread).current_priority;
|
||||
}
|
||||
|
||||
lwp_pid_lock_release();
|
||||
@@ -1808,7 +1808,7 @@ rt_thread_t sys_thread_create(void *arg[])
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
thread->bind_cpu = lwp->bind_cpu;
|
||||
RT_SCHED_CTX(thread).bind_cpu = lwp->bind_cpu;
|
||||
#endif
|
||||
thread->cleanup = lwp_cleanup;
|
||||
thread->user_entry = (void (*)(void *))arg[1];
|
||||
@@ -1935,15 +1935,15 @@ long _sys_clone(void *arg[])
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
self->stack_size,
|
||||
self->init_priority,
|
||||
self->init_tick);
|
||||
RT_SCHED_PRIV(self).init_priority,
|
||||
RT_SCHED_PRIV(self).init_tick);
|
||||
if (!thread)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
thread->bind_cpu = lwp->bind_cpu;
|
||||
RT_SCHED_CTX(self).bind_cpu = lwp->bind_cpu;
|
||||
#endif
|
||||
thread->cleanup = lwp_cleanup;
|
||||
thread->user_entry = RT_NULL;
|
||||
@@ -2120,8 +2120,8 @@ sysret_t _sys_fork(void)
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
self_thread->stack_size,
|
||||
self_thread->init_priority,
|
||||
self_thread->init_tick);
|
||||
RT_SCHED_PRIV(self_thread).init_priority,
|
||||
RT_SCHED_PRIV(self_thread).init_tick);
|
||||
if (!thread)
|
||||
{
|
||||
SET_ERRNO(ENOMEM);
|
||||
@@ -4231,6 +4231,9 @@ sysret_t sys_sigtimedwait(const sigset_t *sigset, siginfo_t *info, const struct
|
||||
struct timespec ktimeout;
|
||||
struct timespec *ptimeout;
|
||||
|
||||
/* for RT_ASSERT */
|
||||
RT_UNUSED(ret);
|
||||
|
||||
/* Fit sigset size to lwp set */
|
||||
if (sizeof(lwpset) < sigsize)
|
||||
{
|
||||
@@ -5505,7 +5508,7 @@ sysret_t sys_sched_setaffinity(pid_t pid, size_t size, void *set)
|
||||
sysret_t sys_sched_getaffinity(const pid_t pid, size_t size, void *set)
|
||||
{
|
||||
#ifdef ARCH_MM_MMU
|
||||
DEF_RETURN_CODE(rc);
|
||||
LWP_DEF_RETURN_CODE(rc);
|
||||
void *mask;
|
||||
struct rt_lwp *lwp;
|
||||
rt_bool_t need_release = RT_FALSE;
|
||||
@@ -5571,7 +5574,7 @@ sysret_t sys_sched_getaffinity(const pid_t pid, size_t size, void *set)
|
||||
|
||||
kmem_put(mask);
|
||||
|
||||
RETURN(rc);
|
||||
LWP_RETURN(rc);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
@@ -5679,13 +5682,11 @@ sysret_t sys_sched_yield(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sysret_t sys_sched_getparam(const pid_t pid, void *param)
|
||||
sysret_t sys_sched_getparam(const pid_t tid, void *param)
|
||||
{
|
||||
struct sched_param *sched_param = RT_NULL;
|
||||
struct rt_lwp *lwp = NULL;
|
||||
rt_thread_t main_thread;
|
||||
rt_thread_t thread;
|
||||
int ret = -1;
|
||||
rt_bool_t need_release = RT_FALSE;
|
||||
|
||||
if (!lwp_user_accessable(param, sizeof(struct sched_param)))
|
||||
{
|
||||
@@ -5698,27 +5699,16 @@ sysret_t sys_sched_getparam(const pid_t pid, void *param)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
need_release = RT_TRUE;
|
||||
lwp_pid_lock_take();
|
||||
lwp = lwp_from_pid_locked(pid);
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
lwp = lwp_self();
|
||||
}
|
||||
thread = lwp_tid_get_thread_and_inc_ref(tid);
|
||||
|
||||
if (lwp)
|
||||
if (thread)
|
||||
{
|
||||
main_thread = rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling);
|
||||
if (need_release)
|
||||
lwp_pid_lock_release();
|
||||
|
||||
sched_param->sched_priority = main_thread->current_priority;
|
||||
sched_param->sched_priority = RT_SCHED_PRIV(thread).current_priority;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
lwp_tid_dec_ref(thread);
|
||||
|
||||
lwp_put_to_user((void *)param, sched_param, sizeof(struct sched_param));
|
||||
kmem_put(sched_param);
|
||||
|
||||
@@ -5800,7 +5790,7 @@ sysret_t sys_sched_getscheduler(int tid, int *policy, void *param)
|
||||
}
|
||||
|
||||
thread = lwp_tid_get_thread_and_inc_ref(tid);
|
||||
sched_param->sched_priority = thread->current_priority;
|
||||
sched_param->sched_priority = RT_SCHED_PRIV(thread).current_priority;
|
||||
lwp_tid_dec_ref(thread);
|
||||
|
||||
lwp_put_to_user((void *)param, sched_param, sizeof(struct sched_param));
|
||||
@@ -6814,20 +6804,24 @@ sysret_t sys_memfd_create()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sysret_t sys_setitimer(int which, const struct itimerspec *restrict new, struct itimerspec *restrict old)
|
||||
{
|
||||
int ret = 0;
|
||||
timer_t timerid = 0;
|
||||
struct sigevent sevp_k = {0};
|
||||
sysret_t rc = 0;
|
||||
rt_lwp_t lwp = lwp_self();
|
||||
struct itimerspec new_value_k;
|
||||
struct itimerspec old_value_k;
|
||||
|
||||
sevp_k.sigev_notify = SIGEV_SIGNAL;
|
||||
sevp_k.sigev_signo = SIGALRM;
|
||||
ret = timer_create(CLOCK_REALTIME_ALARM, &sevp_k, &timerid);
|
||||
if (ret != 0)
|
||||
if (lwp_get_from_user(&new_value_k, (void *)new, sizeof(*new)) != sizeof(*new))
|
||||
{
|
||||
return GET_ERRNO();
|
||||
return -EFAULT;
|
||||
}
|
||||
return sys_timer_settime(timerid,0,new,old);
|
||||
|
||||
rc = lwp_signal_setitimer(lwp, which, &new_value_k, &old_value_k);
|
||||
if (old && lwp_put_to_user(old, (void *)&old_value_k, sizeof old_value_k) != sizeof old_value_k)
|
||||
return -EFAULT;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
const static struct rt_syscall_def func_table[] =
|
||||
|
||||
@@ -25,22 +25,12 @@
|
||||
#define MM_PA_TO_OFF(pa) ((uintptr_t)(pa) >> MM_PAGE_SHIFT)
|
||||
#define PV_OFFSET (rt_kmem_pvoff())
|
||||
|
||||
#ifndef RT_USING_SMP
|
||||
typedef rt_spinlock_t mm_spinlock;
|
||||
|
||||
#define MM_PGTBL_LOCK_INIT(aspace)
|
||||
#define MM_PGTBL_LOCK(aspace) (rt_hw_spin_lock(&((aspace)->pgtbl_lock)))
|
||||
#define MM_PGTBL_UNLOCK(aspace) (rt_hw_spin_unlock(&((aspace)->pgtbl_lock)))
|
||||
|
||||
#else
|
||||
typedef struct rt_spinlock mm_spinlock;
|
||||
typedef struct rt_spinlock mm_spinlock_t;
|
||||
|
||||
#define MM_PGTBL_LOCK_INIT(aspace) (rt_spin_lock_init(&((aspace)->pgtbl_lock)))
|
||||
#define MM_PGTBL_LOCK(aspace) (rt_spin_lock(&((aspace)->pgtbl_lock)))
|
||||
#define MM_PGTBL_UNLOCK(aspace) (rt_spin_unlock(&((aspace)->pgtbl_lock)))
|
||||
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
struct rt_aspace;
|
||||
struct rt_varea;
|
||||
struct rt_mem_obj;
|
||||
@@ -53,7 +43,7 @@ typedef struct rt_aspace
|
||||
rt_size_t size;
|
||||
|
||||
void *page_table;
|
||||
mm_spinlock pgtbl_lock;
|
||||
mm_spinlock_t pgtbl_lock;
|
||||
|
||||
struct _aspace_tree tree;
|
||||
struct rt_mutex bst_lock;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
group = []
|
||||
|
||||
group = DefineGroup('LIBADT', src, depend = [], CPPPATH = CPPPATH)
|
||||
Return('group')
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-01 Shell Init ver.
|
||||
*/
|
||||
|
||||
#ifndef __LIBADT_DICT_H__
|
||||
#define __LIBADT_DICT_H__
|
||||
|
||||
#include "rt_uthash.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-01 Shell Porting to RTT API
|
||||
*/
|
||||
#ifndef __LIBADT_RT_UTHASH_H__
|
||||
#define __LIBADT_RT_UTHASH_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define uthash_malloc(sz) rt_malloc(sz)
|
||||
#define uthash_free(ptr, sz) rt_free(ptr)
|
||||
|
||||
/**
|
||||
* for performance consideration, using libc implementations
|
||||
* as the default case. If you care about the compatibility
|
||||
* problem, define the RT_UTHASH_CONFIG_COMPATIBILITY_FIRST
|
||||
* before including the rt_uthash.h.
|
||||
*/
|
||||
#ifndef RT_UTHASH_CONFIG_COMPATIBILITY_FIRST
|
||||
#define uthash_bzero(a, n) memset(a, '\0', n)
|
||||
#define uthash_strlen(s) strlen(s)
|
||||
|
||||
#else
|
||||
#define uthash_bzero(a, n) rt_memset(a, '\0', n)
|
||||
#define uthash_strlen(s) rt_strlen(s)
|
||||
|
||||
#endif /* RT_UTHASH_CONFIG_COMPATIBILITY_FIRST */
|
||||
|
||||
/* if any fatal happen, throw an exception and return a failure */
|
||||
#define uthash_fatal(msg) \
|
||||
do \
|
||||
{ \
|
||||
LOG_E(msg); \
|
||||
return -RT_ENOMEM; \
|
||||
} while (0)
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
#define DEFINE_RT_UTHASH_TYPE(entry_name, key_type, key_name) \
|
||||
typedef struct entry_name \
|
||||
{ \
|
||||
key_type key_name; \
|
||||
UT_hash_handle hh; \
|
||||
} *entry_name##_t;
|
||||
|
||||
#define RT_UTHASH_ADD(head, key_member, keylen_in, value) \
|
||||
HASH_ADD(hh, head, key_member, keylen_in, value)
|
||||
#define RT_UTHASH_FIND(head, key_ptr, keylen_in, pval) \
|
||||
HASH_FIND(hh, head, key_ptr, keylen_in, pval)
|
||||
#define RT_UTHASH_DELETE(head, pobj) HASH_DELETE(hh, head, pobj)
|
||||
|
||||
#endif /* __LIBADT_RT_UTHASH_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -89,7 +89,7 @@ void rt_prio_queue_detach(struct rt_prio_queue *que)
|
||||
rt_base_t level = rt_hw_interrupt_disable();
|
||||
|
||||
/* get next suspend thread */
|
||||
thread = rt_list_entry(que->suspended_pop_list.next, struct rt_thread, tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(que->suspended_pop_list.next);
|
||||
/* set error code to -RT_ERROR */
|
||||
thread->error = -RT_ERROR;
|
||||
|
||||
@@ -160,9 +160,7 @@ rt_err_t rt_prio_queue_push(struct rt_prio_queue *que,
|
||||
rt_thread_t thread;
|
||||
|
||||
/* get thread entry */
|
||||
thread = rt_list_entry(que->suspended_pop_list.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(que->suspended_pop_list.next);
|
||||
/* resume it */
|
||||
rt_thread_resume(thread);
|
||||
rt_hw_interrupt_enable(level);
|
||||
@@ -207,7 +205,7 @@ rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que,
|
||||
thread->error = RT_EOK;
|
||||
rt_thread_suspend(thread);
|
||||
|
||||
rt_list_insert_before(&(que->suspended_pop_list), &(thread->tlist));
|
||||
rt_list_insert_before(&(que->suspended_pop_list), &RT_THREAD_LIST_NODE(thread));
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
|
||||
@@ -336,7 +336,7 @@ rt_err_t rt_vbus_post(rt_uint8_t id,
|
||||
rt_enter_critical();
|
||||
rt_thread_suspend(thread);
|
||||
|
||||
rt_list_insert_after(&_chn_suspended_threads[id], &thread->tlist);
|
||||
rt_list_insert_after(&_chn_suspended_threads[id], &RT_THREAD_LIST_NODE(thread));
|
||||
if (timeout > 0)
|
||||
{
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
@@ -443,9 +443,7 @@ static void rt_vbus_notify_chn(unsigned char chnr, rt_err_t err)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(_chn_suspended_threads[chnr].next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(_chn_suspended_threads[chnr].next);
|
||||
thread->error = err;
|
||||
rt_thread_resume(thread);
|
||||
}
|
||||
@@ -855,9 +853,7 @@ static int _chn0_actor(unsigned char *dp, size_t dsize)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(_chn_suspended_threads[chnr].next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(_chn_suspended_threads[chnr].next);
|
||||
rt_thread_resume(thread);
|
||||
}
|
||||
rt_exit_critical();
|
||||
|
||||
@@ -43,9 +43,7 @@ void rt_wm_que_dump(struct rt_watermark_queue *wg)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(wg->suspended_threads.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(wg->suspended_threads.next);
|
||||
rt_kprintf(" %.*s", RT_NAME_MAX, thread->parent.name);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
|
||||
@@ -64,7 +64,7 @@ rt_inline rt_err_t rt_wm_que_inc(struct rt_watermark_queue *wg,
|
||||
thread = rt_thread_self();
|
||||
thread->error = RT_EOK;
|
||||
rt_thread_suspend(thread);
|
||||
rt_list_insert_after(&wg->suspended_threads, &thread->tlist);
|
||||
rt_list_insert_after(&wg->suspended_threads, &RT_THREAD_LIST_NODE(thread));
|
||||
if (timeout > 0)
|
||||
{
|
||||
rt_timer_control(&(thread->thread_timer),
|
||||
@@ -116,9 +116,7 @@ rt_inline void rt_wm_que_dec(struct rt_watermark_queue *wg)
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
thread = rt_list_entry(wg->suspended_threads.next,
|
||||
struct rt_thread,
|
||||
tlist);
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(wg->suspended_threads.next);
|
||||
rt_thread_resume(thread);
|
||||
need_sched = 1;
|
||||
}
|
||||
|
||||
@@ -69,4 +69,8 @@ config UTEST_MTSAFE_KPRINT_TC
|
||||
bool "mtsafe kprint test"
|
||||
default n
|
||||
|
||||
config UTEST_SCHEDULER_TC
|
||||
bool "scheduler test"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -50,6 +50,13 @@ if GetDepend(['UTEST_HOOKLIST_TC']):
|
||||
if GetDepend(['UTEST_MTSAFE_KPRINT_TC']):
|
||||
src += ['mtsafe_kprint_tc.c']
|
||||
|
||||
# Stressful testcase for scheduler (MP/UP)
|
||||
if GetDepend(['UTEST_SCHEDULER_TC']):
|
||||
src += ['sched_timed_sem_tc.c']
|
||||
src += ['sched_timed_mtx_tc.c']
|
||||
src += ['sched_mtx_tc.c']
|
||||
src += ['sched_sem_tc.c', 'sched_thread_tc.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
@@ -8,15 +8,16 @@
|
||||
* 2021-09.01 luckyzjq the first version
|
||||
* 2023-09-15 xqyjlj change stack size in cpu64
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
#define THREAD_STACKSIZE 4096
|
||||
#define THREAD_STACKSIZE 8192
|
||||
#else
|
||||
#define THREAD_STACKSIZE 1024
|
||||
#define THREAD_STACKSIZE 4096
|
||||
#endif
|
||||
|
||||
static struct rt_mutex static_mutex;
|
||||
@@ -241,7 +242,7 @@ static void static_thread1_entry(void *param)
|
||||
|
||||
/* thread3 hode mutex thread2 take mutex */
|
||||
/* check thread2 and thread3 priority */
|
||||
if (tid2->current_priority != tid3->current_priority)
|
||||
if (RT_SCHED_PRIV(tid2).current_priority != RT_SCHED_PRIV(tid3).current_priority)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
@@ -550,7 +551,7 @@ static void dynamic_thread1_entry(void *param)
|
||||
|
||||
/* thread3 hode mutex thread2 take mutex */
|
||||
/* check thread2 and thread3 priority */
|
||||
if (tid2->current_priority != tid3->current_priority)
|
||||
if (RT_SCHED_PRIV(tid2).current_priority != RT_SCHED_PRIV(tid3).current_priority)
|
||||
{
|
||||
uassert_true(RT_FALSE);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-17 Shell the first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
/**
|
||||
* Stressful Test for Mutex
|
||||
*/
|
||||
|
||||
#define TEST_SECONDS 30
|
||||
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
|
||||
#define TEST_THREAD_COUNTS (RT_CPUS_NR)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS/TEST_PROGRESS_COUNTS)
|
||||
#define TEST_PRIORITY_HIGHEST (UTEST_THR_PRIORITY+1)
|
||||
#define TEST_RANDOM_LATENCY_MAX (1000 * 1000)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static rt_atomic_t _exit_flag;
|
||||
static struct rt_mutex _racing_lock;
|
||||
|
||||
static void test_thread_entry(void *param)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
rt_mutex_take(&_racing_lock, RT_WAITING_FOREVER);
|
||||
rt_mutex_release(&_racing_lock);
|
||||
|
||||
if (rt_atomic_load(&_exit_flag))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
}
|
||||
|
||||
static void mutex_stress_tc(void)
|
||||
{
|
||||
rt_err_t error;
|
||||
rt_thread_t tester;
|
||||
const rt_base_t priority_base = TEST_PRIORITY_HIGHEST;
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNTS; i++)
|
||||
{
|
||||
tester = rt_thread_create(
|
||||
"tester",
|
||||
test_thread_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
priority_base + (i % (RT_THREAD_PRIORITY_MAX - TEST_PRIORITY_HIGHEST)),
|
||||
1);
|
||||
|
||||
rt_thread_startup(tester);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
rt_thread_delay(1);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
/* trigger exit request for all sub-threads */
|
||||
rt_atomic_store(&_exit_flag, 1);
|
||||
|
||||
/* waiting for sub-threads to exit */
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNTS; i++)
|
||||
{
|
||||
error = rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
uassert_int_equal(error, RT_EOK);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
int *pseed = rt_malloc(sizeof(int));
|
||||
srand(*(int *)pseed);
|
||||
rt_free(pseed);
|
||||
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
rt_mutex_init(&_racing_lock, "ipc", RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
rt_mutex_detach(&_racing_lock);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(mutex_stress_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.mutex", utest_tc_init, utest_tc_cleanup, TEST_SECONDS);
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-17 Shell the first version
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "rthw.h"
|
||||
#include "utest.h"
|
||||
|
||||
#define KERN_TEST_CONFIG_LOOP_TIMES 160
|
||||
#define KERN_TEST_CONCURRENT_THREADS (RT_CPUS_NR * 2)
|
||||
#define KERN_TEST_CONFIG_HIGHEST_PRIO 3
|
||||
#define KERN_TEST_CONFIG_LOWEST_PRIO (RT_THREAD_PRIORITY_MAX - 2)
|
||||
|
||||
#define TEST_LEVEL_COUNTS (KERN_TEST_CONFIG_LOWEST_PRIO - KERN_TEST_CONFIG_HIGHEST_PRIO + 1)
|
||||
#if TEST_LEVEL_COUNTS <= RT_CPUS_NR
|
||||
#warning for the best of this test, TEST_LEVEL_COUNTS should greater than RT_CPUS_NR
|
||||
#endif
|
||||
#if KERN_TEST_CONCURRENT_THREADS < RT_CPUS_NR
|
||||
#warning for the best of this test, KERN_TEST_CONCURRENT_THREADS should greater than RT_CPUS_NR
|
||||
#endif
|
||||
#if KERN_TEST_CONFIG_LOWEST_PRIO >= RT_THREAD_PRIORITY_MAX - 1
|
||||
#error the thread priority should at least be greater than idle
|
||||
#endif
|
||||
|
||||
static rt_atomic_t _star_counter = 1;
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static struct rt_semaphore _level_waiting[TEST_LEVEL_COUNTS];
|
||||
static rt_thread_t _thread_matrix[TEST_LEVEL_COUNTS][KERN_TEST_CONCURRENT_THREADS];
|
||||
static rt_atomic_t _load_average[RT_CPUS_NR];
|
||||
|
||||
static void _print_char(rt_thread_t thr_self, int character)
|
||||
{
|
||||
rt_base_t current_counter;
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
rt_kprintf("%c%d", character, RT_SCHED_CTX(thr_self).oncpu);
|
||||
#else
|
||||
rt_kprintf("%c0", character);
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
current_counter = rt_atomic_add(&_star_counter, 1);
|
||||
if (current_counter % 30 == 0)
|
||||
{
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _stats_load_avg_inc(void)
|
||||
{
|
||||
int cpuid;
|
||||
|
||||
cpuid = rt_hw_cpu_id();
|
||||
rt_atomic_add(&_load_average[cpuid], 1);
|
||||
}
|
||||
|
||||
static void _stats_load_avg_print(void)
|
||||
{
|
||||
rt_base_t counts = 0;
|
||||
const rt_base_t total_test_counts = KERN_TEST_CONFIG_LOOP_TIMES * TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS;
|
||||
|
||||
for (size_t i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
rt_kprintf("%ld ", _load_average[i]);
|
||||
counts += _load_average[i];
|
||||
}
|
||||
|
||||
rt_kprintf("\n");
|
||||
uassert_int_equal(counts, total_test_counts);
|
||||
}
|
||||
|
||||
static void _thread_entry(void *param)
|
||||
{
|
||||
int level = (rt_ubase_t)param;
|
||||
rt_thread_t thr_self = rt_thread_self();
|
||||
|
||||
if (level == 0)
|
||||
{
|
||||
/* always the first to execute among other working threads */
|
||||
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
|
||||
{
|
||||
/* notify our consumer */
|
||||
rt_sem_release(&_level_waiting[level + 1]);
|
||||
|
||||
_stats_load_avg_inc();
|
||||
|
||||
/* waiting for resource of ours */
|
||||
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
else if (level == TEST_LEVEL_COUNTS - 1)
|
||||
{
|
||||
|
||||
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
|
||||
{
|
||||
/* waiting for our resource first */
|
||||
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
|
||||
|
||||
_stats_load_avg_inc();
|
||||
|
||||
_print_char(thr_self, '*');
|
||||
|
||||
rt_thread_delay(1);
|
||||
|
||||
/* produce for level 0 worker */
|
||||
rt_sem_release(&_level_waiting[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < KERN_TEST_CONFIG_LOOP_TIMES; i++)
|
||||
{
|
||||
/* waiting for resource of ours */
|
||||
rt_sem_take(&_level_waiting[level], RT_WAITING_FOREVER);
|
||||
|
||||
_stats_load_avg_inc();
|
||||
|
||||
/* notify our consumer */
|
||||
rt_sem_release(&_level_waiting[level + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
uassert_true(1);
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void scheduler_tc(void)
|
||||
{
|
||||
LOG_I("Test starts...");
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
|
||||
{
|
||||
for (size_t j = 0; j < KERN_TEST_CONCURRENT_THREADS; j++)
|
||||
{
|
||||
rt_thread_startup(_thread_matrix[i][j]);
|
||||
}
|
||||
}
|
||||
LOG_I("%d threads startup...", TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS);
|
||||
|
||||
/* waiting for sub-threads to exit */
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS * KERN_TEST_CONCURRENT_THREADS; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
/* print load average */
|
||||
_stats_load_avg_print();
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
LOG_I("Setup environment...");
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
|
||||
{
|
||||
rt_sem_init(&_level_waiting[i], "test", 0, RT_IPC_FLAG_PRIO);
|
||||
|
||||
for (size_t j = 0; j < KERN_TEST_CONCURRENT_THREADS; j++)
|
||||
{
|
||||
_thread_matrix[i][j] =
|
||||
rt_thread_create("test",
|
||||
_thread_entry,
|
||||
(void *)i,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
KERN_TEST_CONFIG_HIGHEST_PRIO+i,
|
||||
5);
|
||||
if (!_thread_matrix[i][j])
|
||||
uassert_not_null(_thread_matrix[i][j]);
|
||||
}
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
for (size_t i = 0; i < TEST_LEVEL_COUNTS; i++)
|
||||
{
|
||||
rt_sem_detach(&_level_waiting[i]);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(scheduler_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.sem", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-25 Shell init ver.
|
||||
*/
|
||||
#define __RT_KERNEL_SOURCE__
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_LOOP_TIMES (100 * 1000)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_THREAD_COUNT (RT_CPUS_NR * 1)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TIMES*TEST_THREAD_COUNT/TEST_PROGRESS_COUNTS)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static rt_atomic_t _progress_counter;
|
||||
|
||||
static volatile rt_thread_t threads_group[TEST_THREAD_COUNT][2];
|
||||
|
||||
static void _thread_entry1(void *param)
|
||||
{
|
||||
rt_base_t critical_level;
|
||||
size_t idx = (size_t)param;
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
critical_level = rt_enter_critical();
|
||||
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_thread_resume(threads_group[idx][1]);
|
||||
|
||||
rt_exit_critical_safe(critical_level);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _thread_entry2(void *param)
|
||||
{
|
||||
rt_base_t critical_level;
|
||||
size_t idx = (size_t)param;
|
||||
|
||||
for (size_t i = 0; i < TEST_LOOP_TIMES; i++)
|
||||
{
|
||||
critical_level = rt_enter_critical();
|
||||
|
||||
rt_thread_suspend(rt_thread_self());
|
||||
rt_thread_resume(threads_group[idx][0]);
|
||||
|
||||
rt_exit_critical_safe(critical_level);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void scheduler_tc(void)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_thread_t t1 =
|
||||
rt_thread_create(
|
||||
"t1",
|
||||
_thread_entry1,
|
||||
(void *)i,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
rt_thread_t t2 =
|
||||
rt_thread_create(
|
||||
"t2",
|
||||
_thread_entry2,
|
||||
(void *)i,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
|
||||
threads_group[i][0] = t1;
|
||||
threads_group[i][1] = t2;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_thread_startup(threads_group[i][0]);
|
||||
rt_thread_startup(threads_group[i][1]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < TEST_THREAD_COUNT; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(scheduler_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.thread", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-25 Shell init ver.
|
||||
*/
|
||||
#define __RT_KERNEL_SOURCE__
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_SECONDS 10
|
||||
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS*2/TEST_PROGRESS_COUNTS)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static struct rt_mutex _ipc_primitive;
|
||||
static struct rt_semaphore _cons_can_take_mtx;
|
||||
static struct rt_semaphore _prod_can_take_mtx;
|
||||
static rt_atomic_t _progress_counter;
|
||||
#define CONSUMER_MAGIC 0x11223344
|
||||
#define PRODUCER_MAGIC 0x44332211
|
||||
static rt_atomic_t _last_holder_flag = CONSUMER_MAGIC;
|
||||
static rt_base_t _timedout_failed_times = 0;
|
||||
|
||||
/**
|
||||
* Test on timedout IPC with racing condition where timedout routine and producer
|
||||
* thread may race to wakeup sleeper.
|
||||
*
|
||||
* This test will fork 2 thread, one producer and one consumer. The producer will
|
||||
* looping and trigger the IPC on the edge of new tick arrives. The consumer will
|
||||
* wait on IPC with a timedout of 1 tick.
|
||||
*/
|
||||
|
||||
static void _wait_until_edge(void)
|
||||
{
|
||||
rt_tick_t entry_level, current;
|
||||
rt_base_t random_latency;
|
||||
|
||||
entry_level = rt_tick_get();
|
||||
do
|
||||
{
|
||||
current = rt_tick_get();
|
||||
}
|
||||
while (current == entry_level);
|
||||
|
||||
/* give a random latency for test */
|
||||
random_latency = rand() % 1000 * 1000;
|
||||
entry_level = current;
|
||||
for (size_t i = 0; i < random_latency; i++)
|
||||
{
|
||||
current = rt_tick_get();
|
||||
if (current != entry_level)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _producer_entry(void *param)
|
||||
{
|
||||
rt_err_t error;
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
/**
|
||||
* only try to take mutex after consumer have taken it after last
|
||||
* release from us.
|
||||
*/
|
||||
error = rt_sem_take(&_prod_can_take_mtx, RT_WAITING_FOREVER);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
error = rt_mutex_take(&_ipc_primitive, RT_WAITING_FOREVER);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ensure that mutex should be held in round-robin method */
|
||||
if (rt_atomic_load(&_last_holder_flag) != CONSUMER_MAGIC)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_atomic_store(&_last_holder_flag, PRODUCER_MAGIC);
|
||||
rt_sem_release(&_cons_can_take_mtx);
|
||||
}
|
||||
|
||||
_wait_until_edge();
|
||||
|
||||
rt_mutex_release(&_ipc_primitive);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _consumer_entry(void *param)
|
||||
{
|
||||
rt_err_t error;
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
/**
|
||||
* only try to take mutex after producer have taken it after last
|
||||
* release from us.
|
||||
*/
|
||||
error = rt_sem_take(&_cons_can_take_mtx, RT_WAITING_FOREVER);
|
||||
if (error)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
error = rt_mutex_take_interruptible(&_ipc_primitive, 1);
|
||||
if (error == -RT_ETIMEOUT)
|
||||
{
|
||||
_timedout_failed_times++;
|
||||
if (rt_mutex_get_owner(&_ipc_primitive) == rt_thread_self())
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error != RT_EOK)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ensure that mutex should be held in round-robin method */
|
||||
if (rt_atomic_load(&_last_holder_flag) != PRODUCER_MAGIC)
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_atomic_store(&_last_holder_flag, CONSUMER_MAGIC);
|
||||
rt_sem_release(&_prod_can_take_mtx);
|
||||
}
|
||||
|
||||
rt_mutex_release(&_ipc_primitive);
|
||||
if (rt_mutex_get_owner(&_ipc_primitive) == rt_thread_self())
|
||||
{
|
||||
uassert_true(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void timed_mtx_tc(void)
|
||||
{
|
||||
rt_thread_t prod = rt_thread_create(
|
||||
"prod",
|
||||
_producer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
4);
|
||||
|
||||
rt_thread_t cons = rt_thread_create(
|
||||
"cons",
|
||||
_consumer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
|
||||
rt_thread_startup(prod);
|
||||
rt_thread_startup(cons);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
uassert_int_equal(
|
||||
rt_sem_take(&_thr_exit_sem, 2 * TEST_LOOP_TICKS),
|
||||
RT_EOK);
|
||||
}
|
||||
|
||||
/* Summary */
|
||||
LOG_I("Total failed times: %ld(in %d)\n", _timedout_failed_times, TEST_LOOP_TICKS);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
_timedout_failed_times = 0;
|
||||
|
||||
rt_mutex_init(&_ipc_primitive, "ipc", RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_cons_can_take_mtx, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_prod_can_take_mtx, "test", 1, RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_mutex_detach(&_ipc_primitive);
|
||||
rt_sem_detach(&_cons_can_take_mtx);
|
||||
rt_sem_detach(&_prod_can_take_mtx);
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(timed_mtx_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.timed_mtx", utest_tc_init, utest_tc_cleanup, TEST_SECONDS * 2);
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-25 Shell init ver.
|
||||
*/
|
||||
#define __RT_KERNEL_SOURCE__
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
|
||||
#define TEST_SECONDS 10
|
||||
#define TEST_LOOP_TICKS (TEST_SECONDS * RT_TICK_PER_SECOND)
|
||||
#define TEST_PROGRESS_COUNTS (36)
|
||||
#define TEST_PROGRESS_ON (TEST_LOOP_TICKS*2/TEST_PROGRESS_COUNTS)
|
||||
|
||||
static struct rt_semaphore _thr_exit_sem;
|
||||
static struct rt_semaphore _ipc_sem;
|
||||
static rt_atomic_t _progress_counter;
|
||||
static rt_base_t _timedout_failed_times = 0;
|
||||
|
||||
/**
|
||||
* Test on timedout IPC with racing condition where timedout routine and producer
|
||||
* thread may race to wakeup sleeper.
|
||||
*
|
||||
* This test will fork 2 thread, one producer and one consumer. The producer will
|
||||
* looping and trigger the IPC on the edge of new tick arrives. The consumer will
|
||||
* wait on IPC with a timedout of 1 tick.
|
||||
*/
|
||||
|
||||
static void _wait_until_edge(void)
|
||||
{
|
||||
rt_tick_t entry_level, current;
|
||||
rt_base_t random_latency;
|
||||
|
||||
entry_level = rt_tick_get();
|
||||
do
|
||||
{
|
||||
current = rt_tick_get();
|
||||
}
|
||||
while (current == entry_level);
|
||||
|
||||
/* give a random latency for test */
|
||||
random_latency = rand();
|
||||
entry_level = current;
|
||||
for (size_t i = 0; i < random_latency; i++)
|
||||
{
|
||||
current = rt_tick_get();
|
||||
if (current != entry_level)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _producer_entry(void *param)
|
||||
{
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
_wait_until_edge();
|
||||
|
||||
rt_sem_release(&_ipc_sem);
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void _consumer_entry(void *param)
|
||||
{
|
||||
int error;
|
||||
for (size_t i = 0; i < TEST_LOOP_TICKS; i++)
|
||||
{
|
||||
error = rt_sem_take_interruptible(&_ipc_sem, 1);
|
||||
if (error == -RT_ETIMEOUT)
|
||||
{
|
||||
_timedout_failed_times++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error != RT_EOK)
|
||||
uassert_true(0);
|
||||
}
|
||||
|
||||
if (rt_atomic_add(&_progress_counter, 1) % TEST_PROGRESS_ON == 0)
|
||||
uassert_true(1);
|
||||
}
|
||||
|
||||
rt_sem_release(&_thr_exit_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
static void timed_sem_tc(void)
|
||||
{
|
||||
rt_thread_t prod = rt_thread_create(
|
||||
"prod",
|
||||
_producer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
4);
|
||||
|
||||
rt_thread_t cons = rt_thread_create(
|
||||
"cons",
|
||||
_consumer_entry,
|
||||
(void *)0,
|
||||
UTEST_THR_STACK_SIZE,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
100);
|
||||
|
||||
rt_thread_startup(prod);
|
||||
rt_thread_startup(cons);
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
{
|
||||
rt_sem_take(&_thr_exit_sem, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
/* Summary */
|
||||
LOG_I("Total failed times: %ld(in %d)\n", _timedout_failed_times, TEST_LOOP_TICKS);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
int *pseed = rt_malloc(sizeof(int));
|
||||
srand(*(int *)pseed);
|
||||
rt_free(pseed);
|
||||
|
||||
rt_sem_init(&_ipc_sem, "ipc", 0, RT_IPC_FLAG_PRIO);
|
||||
rt_sem_init(&_thr_exit_sem, "test", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_ipc_sem);
|
||||
rt_sem_detach(&_thr_exit_sem);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void testcase(void)
|
||||
{
|
||||
UTEST_UNIT_RUN(timed_sem_tc);
|
||||
}
|
||||
UTEST_TC_EXPORT(testcase, "testcases.kernel.scheduler.timed_sem", utest_tc_init, utest_tc_cleanup, TEST_SECONDS * 2);
|
||||
@@ -22,7 +22,8 @@
|
||||
#include <rtthread.h>
|
||||
#include "utest.h"
|
||||
|
||||
int recive_sig = 0;
|
||||
static volatile int recive_sig = 0;
|
||||
static struct rt_semaphore _received_signal;
|
||||
|
||||
void sig_handle_default(int signo)
|
||||
{
|
||||
@@ -125,12 +126,15 @@ void rt_signal_wait_thread(void *parm)
|
||||
(void)sigaddset(&selectset, SIGUSR1);
|
||||
|
||||
/* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received. */
|
||||
if (rt_signal_wait(&selectset, &recive_si, RT_TICK_PER_SECOND) != RT_EOK)
|
||||
if (rt_signal_wait((void *)&selectset, &recive_si, RT_TICK_PER_SECOND) != RT_EOK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recive_sig = recive_si.si_signo;
|
||||
|
||||
LOG_I("received signal %d", recive_sig);
|
||||
rt_sem_release(&_received_signal);
|
||||
}
|
||||
|
||||
static void rt_signal_wait_test(void)
|
||||
@@ -147,7 +151,7 @@ static void rt_signal_wait_test(void)
|
||||
rt_thread_mdelay(1);
|
||||
/* case 5:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: kill, should received. */
|
||||
uassert_int_equal(rt_thread_kill(t1, SIGUSR1), RT_EOK);
|
||||
rt_thread_mdelay(1);
|
||||
rt_sem_take(&_received_signal, RT_WAITING_FOREVER);
|
||||
uassert_int_equal(recive_sig, SIGUSR1);
|
||||
|
||||
return;
|
||||
@@ -167,7 +171,9 @@ static void rt_signal_wait_test2(void)
|
||||
/* case 6:rt_signal_wait, two thread, thread1: install and unmask, then wait 1s; thread2: sleep 2s then kill, should can't received. */
|
||||
rt_thread_mdelay(2000);
|
||||
uassert_int_equal(rt_thread_kill(t1, SIGUSR1), RT_EOK);
|
||||
rt_thread_mdelay(1);
|
||||
uassert_int_not_equal(
|
||||
rt_sem_take(&_received_signal, 1),
|
||||
RT_EOK);
|
||||
uassert_int_not_equal(recive_sig, SIGUSR1);
|
||||
|
||||
return;
|
||||
@@ -175,11 +181,13 @@ static void rt_signal_wait_test2(void)
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
rt_sem_init(&_received_signal, "utest", 0, RT_IPC_FLAG_PRIO);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_sem_detach(&_received_signal);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
* 2021-10.11 mazhiyuan add idle, yield, suspend, control, priority, delay_until
|
||||
*/
|
||||
|
||||
#define __RT_IPC_SOURCE__ /* include internal API for utest */
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "utest.h"
|
||||
@@ -56,7 +58,7 @@ static void test_dynamic_thread(void)
|
||||
thread1_entry,
|
||||
(void *)1,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority + 1,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
THREAD_TIMESLICE - 5);
|
||||
if (tid1 == RT_NULL)
|
||||
{
|
||||
@@ -105,7 +107,7 @@ static void test_static_thread(void)
|
||||
(void *)2,
|
||||
&thread2_stack[0],
|
||||
sizeof(thread2_stack),
|
||||
__current_thread->current_priority + 1,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (ret_init != RT_EOK)
|
||||
{
|
||||
@@ -139,10 +141,11 @@ __exit:
|
||||
|
||||
static void thread3_entry(void *parameter)
|
||||
{
|
||||
rt_tick_t tick;
|
||||
rt_tick_t tick, latency_tick;
|
||||
tick = rt_tick_get();
|
||||
rt_thread_delay(15);
|
||||
if (rt_tick_get() - tick > 16)
|
||||
latency_tick = rt_tick_get() - tick;
|
||||
if (latency_tick > 16 || latency_tick < 15)
|
||||
{
|
||||
tid3_finish_flag = 1;
|
||||
tid3_delay_pass_flag = 0;
|
||||
@@ -160,7 +163,7 @@ static void test_thread_delay(void)
|
||||
thread3_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority - 1,
|
||||
UTEST_THR_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid3 == RT_NULL)
|
||||
{
|
||||
@@ -210,7 +213,7 @@ static void test_idle_hook(void)
|
||||
thread4_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority - 1,
|
||||
UTEST_THR_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid4 == RT_NULL)
|
||||
{
|
||||
@@ -264,7 +267,7 @@ static void test_thread_yield(void)
|
||||
thread5_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority - 1,
|
||||
UTEST_THR_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid5 == RT_NULL)
|
||||
{
|
||||
@@ -283,7 +286,7 @@ static void test_thread_yield(void)
|
||||
thread6_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority - 1,
|
||||
UTEST_THR_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid6 == RT_NULL)
|
||||
{
|
||||
@@ -319,12 +322,13 @@ static void test_thread_control(void)
|
||||
{
|
||||
rt_err_t ret_control = -RT_ERROR;
|
||||
rt_err_t rst_delete = -RT_ERROR;
|
||||
rt_sched_lock_level_t slvl;
|
||||
|
||||
tid7 = rt_thread_create("thread7",
|
||||
thread7_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority + 1,
|
||||
UTEST_THR_PRIORITY + 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid7 == RT_NULL)
|
||||
{
|
||||
@@ -342,12 +346,17 @@ static void test_thread_control(void)
|
||||
}
|
||||
rt_thread_mdelay(200);
|
||||
rt_thread_control(tid7, RT_THREAD_CTRL_CHANGE_PRIORITY, &change_priority);
|
||||
if (tid7->current_priority != change_priority)
|
||||
|
||||
rt_sched_lock(&slvl);
|
||||
if (rt_sched_thread_get_curr_prio(tid7) != change_priority)
|
||||
{
|
||||
LOG_E("rt_thread_control failed!");
|
||||
uassert_false(1);
|
||||
rt_sched_unlock(slvl);
|
||||
goto __exit;
|
||||
}
|
||||
rt_sched_unlock(slvl);
|
||||
|
||||
rst_delete = rt_thread_control(tid7, RT_THREAD_CTRL_CLOSE, RT_NULL);
|
||||
if (rst_delete != RT_EOK)
|
||||
{
|
||||
@@ -380,7 +389,7 @@ static void test_thread_priority(void)
|
||||
thread8_entry,
|
||||
RT_NULL,
|
||||
THREAD_STACK_SIZE,
|
||||
__current_thread->current_priority - 1,
|
||||
UTEST_THR_PRIORITY - 1,
|
||||
THREAD_TIMESLICE);
|
||||
if (tid8 == RT_NULL)
|
||||
{
|
||||
@@ -448,6 +457,10 @@ static void test_delay_until(void)
|
||||
rt_kprintf("delta[20] -> %d\n", delta);
|
||||
uassert_int_equal(delta, 20);
|
||||
|
||||
/**
|
||||
* the rt_kprints above can take few ticks to complete, maybe more than 10
|
||||
*/
|
||||
tick = rt_tick_get();
|
||||
check_tick = tick;
|
||||
rt_thread_delay(2);
|
||||
rt_thread_delay_until(&tick, 10);
|
||||
@@ -495,7 +508,7 @@ void test_timeslice(void)
|
||||
timeslice_cntB2 = 0;
|
||||
|
||||
tidA = rt_thread_create("timeslice", test_timeslice_threadA_entry, RT_NULL,
|
||||
2048, __current_thread->current_priority + 1, 10);
|
||||
2048, UTEST_THR_PRIORITY + 1, 10);
|
||||
if (!tidA)
|
||||
{
|
||||
LOG_E("rt_thread_create failed!");
|
||||
@@ -512,7 +525,7 @@ void test_timeslice(void)
|
||||
}
|
||||
|
||||
tidB1 = rt_thread_create("timeslice", test_timeslice_threadB1_entry, RT_NULL,
|
||||
2048, __current_thread->current_priority + 2, 2);
|
||||
2048, UTEST_THR_PRIORITY + 2, 2);
|
||||
if (!tidB1)
|
||||
{
|
||||
LOG_E("rt_thread_create failed!");
|
||||
@@ -529,7 +542,7 @@ void test_timeslice(void)
|
||||
}
|
||||
|
||||
tidB2 = rt_thread_create("timeslice", test_timeslice_threadB2_entry, RT_NULL,
|
||||
2048, __current_thread->current_priority + 2, 2);
|
||||
2048, UTEST_THR_PRIORITY + 2, 2);
|
||||
if (!tidB2)
|
||||
{
|
||||
LOG_E("rt_thread_create failed!");
|
||||
@@ -655,7 +668,7 @@ void test_thread_yield_nosmp(void)
|
||||
// thread9_entry,
|
||||
// RT_NULL,
|
||||
// THREAD_STACK_SIZE,
|
||||
// __current_thread->current_priority + 1,
|
||||
// UTEST_THR_PRIORITY + 1,
|
||||
// THREAD_TIMESLICE);
|
||||
// if (tid == RT_NULL)
|
||||
// {
|
||||
@@ -695,7 +708,7 @@ void test_thread_yield_nosmp(void)
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
__current_thread = rt_thread_self();
|
||||
change_priority = __current_thread->current_priority + 5;
|
||||
change_priority = UTEST_THR_PRIORITY + 5;
|
||||
tid3_delay_pass_flag = 0;
|
||||
tid3_finish_flag = 0;
|
||||
tid4_finish_flag = 0;
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-18 Shell Separate the compiler porting from rtdef.h
|
||||
*/
|
||||
#ifndef __RT_COMPILER_H__
|
||||
#define __RT_COMPILER_H__
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
#if defined(__ARMCC_VERSION) /* ARM Compiler */
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used))
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static __inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
|
||||
#define rt_section(x) @ x
|
||||
#define rt_used __root
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define rt_align(n) PRAGMA(data_alignment=n)
|
||||
#define rt_weak __weak
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__GNUC__) /* GNU GCC Compiler */
|
||||
#define __RT_STRINGIFY(x...) #x
|
||||
#define RT_STRINGIFY(x...) __RT_STRINGIFY(x)
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used))
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof __typeof__
|
||||
#define rt_noreturn __attribute__ ((noreturn))
|
||||
#define rt_inline static __inline
|
||||
#define rt_always_inline static inline __attribute__((always_inline))
|
||||
#elif defined (__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used))
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (_MSC_VER) /* for Visual Studio Compiler */
|
||||
#define rt_section(x)
|
||||
#define rt_used
|
||||
#define rt_align(n) __declspec(align(n))
|
||||
#define rt_weak
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static __inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__TI_COMPILER_VERSION__) /* for TI CCS Compiler */
|
||||
/**
|
||||
* The way that TI compiler set section is different from other(at least
|
||||
* GCC and MDK) compilers. See ARM Optimizing C/C++ Compiler 5.9.3 for more
|
||||
* details.
|
||||
*/
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#ifdef __TI_EABI__
|
||||
#define rt_used __attribute__((retain)) __attribute__((used))
|
||||
#else
|
||||
#define rt_used __attribute__((used))
|
||||
#endif
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#ifdef __TI_EABI__
|
||||
#define rt_weak __attribute__((weak))
|
||||
#else
|
||||
#define rt_weak
|
||||
#endif
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__TASKING__) /* for TASKING Compiler */
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used, protect))
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define rt_align(n) __attribute__((__align(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#else /* Unkown Compiler */
|
||||
#error not supported tool chain
|
||||
#endif /* __ARMCC_VERSION */
|
||||
|
||||
#endif /* __RT_COMPILER_H__ */
|
||||
+56
-240
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -55,6 +55,8 @@
|
||||
* 2023-11-21 Meco Man add RT_USING_NANO macro
|
||||
* 2023-12-18 xqyjlj add rt_always_inline
|
||||
* 2023-12-22 Shell Support hook list
|
||||
* 2024-01-18 Shell Seperate basical types to a rttypes.h
|
||||
* Seperate the compiler portings to rtcompiler.h
|
||||
*/
|
||||
|
||||
#ifndef __RT_DEF_H__
|
||||
@@ -96,71 +98,7 @@ extern "C" {
|
||||
|
||||
|
||||
/* RT-Thread basic data type definitions */
|
||||
typedef int rt_bool_t; /**< boolean type */
|
||||
typedef signed long rt_base_t; /**< Nbit CPU related date type */
|
||||
typedef unsigned long rt_ubase_t; /**< Nbit unsigned CPU related data type */
|
||||
|
||||
#ifndef RT_USING_ARCH_DATA_TYPE
|
||||
#ifdef RT_USING_LIBC
|
||||
typedef int8_t rt_int8_t; /**< 8bit integer type */
|
||||
typedef int16_t rt_int16_t; /**< 16bit integer type */
|
||||
typedef int32_t rt_int32_t; /**< 32bit integer type */
|
||||
typedef uint8_t rt_uint8_t; /**< 8bit unsigned integer type */
|
||||
typedef uint16_t rt_uint16_t; /**< 16bit unsigned integer type */
|
||||
typedef uint32_t rt_uint32_t; /**< 32bit unsigned integer type */
|
||||
typedef int64_t rt_int64_t; /**< 64bit integer type */
|
||||
typedef uint64_t rt_uint64_t; /**< 64bit unsigned integer type */
|
||||
#else
|
||||
typedef signed char rt_int8_t; /**< 8bit integer type */
|
||||
typedef signed short rt_int16_t; /**< 16bit integer type */
|
||||
typedef signed int rt_int32_t; /**< 32bit integer type */
|
||||
typedef unsigned char rt_uint8_t; /**< 8bit unsigned integer type */
|
||||
typedef unsigned short rt_uint16_t; /**< 16bit unsigned integer type */
|
||||
typedef unsigned int rt_uint32_t; /**< 32bit unsigned integer type */
|
||||
#ifdef ARCH_CPU_64BIT
|
||||
typedef signed long rt_int64_t; /**< 64bit integer type */
|
||||
typedef unsigned long rt_uint64_t; /**< 64bit unsigned integer type */
|
||||
#else
|
||||
typedef signed long long rt_int64_t; /**< 64bit integer type */
|
||||
typedef unsigned long long rt_uint64_t; /**< 64bit unsigned integer type */
|
||||
#endif /* ARCH_CPU_64BIT */
|
||||
#endif /* RT_USING_LIBC */
|
||||
#endif /* RT_USING_ARCH_DATA_TYPE */
|
||||
|
||||
#if defined(RT_USING_LIBC) && !defined(RT_USING_NANO)
|
||||
typedef size_t rt_size_t; /**< Type for size number */
|
||||
typedef ssize_t rt_ssize_t; /**< Used for a count of bytes or an error indication */
|
||||
#else
|
||||
typedef rt_ubase_t rt_size_t; /**< Type for size number */
|
||||
typedef rt_base_t rt_ssize_t; /**< Used for a count of bytes or an error indication */
|
||||
#endif /* defined(RT_USING_LIBC) && !defined(RT_USING_NANO) */
|
||||
|
||||
typedef rt_base_t rt_err_t; /**< Type for error number */
|
||||
typedef rt_uint32_t rt_time_t; /**< Type for time stamp */
|
||||
typedef rt_uint32_t rt_tick_t; /**< Type for tick count */
|
||||
typedef rt_base_t rt_flag_t; /**< Type for flags */
|
||||
typedef rt_ubase_t rt_dev_t; /**< Type for device */
|
||||
typedef rt_base_t rt_off_t; /**< Type for offset */
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef rt_base_t rt_atomic_t;
|
||||
#else
|
||||
#if defined(RT_USING_HW_ATOMIC)
|
||||
typedef rt_base_t rt_atomic_t;
|
||||
#elif defined(RT_USING_STDC_ATOMIC)
|
||||
#include <stdatomic.h>
|
||||
typedef atomic_size_t rt_atomic_t;
|
||||
#else
|
||||
typedef rt_base_t rt_atomic_t;
|
||||
#endif /* RT_USING_STDC_ATOMIC */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* boolean type definitions */
|
||||
#define RT_TRUE 1 /**< boolean true */
|
||||
#define RT_FALSE 0 /**< boolean fails */
|
||||
|
||||
/* null pointer definition */
|
||||
#define RT_NULL 0
|
||||
#include "rttypes.h"
|
||||
|
||||
/**@}*/
|
||||
|
||||
@@ -194,90 +132,7 @@ typedef rt_base_t rt_off_t; /**< Type for offset */
|
||||
#define RT_STATIC_ASSERT(name, expn) typedef char _static_assert_##name[(expn)?1:-1]
|
||||
|
||||
/* Compiler Related Definitions */
|
||||
#if defined(__ARMCC_VERSION) /* ARM Compiler */
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used))
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static __inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
|
||||
#define rt_section(x) @ x
|
||||
#define rt_used __root
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define rt_align(n) PRAGMA(data_alignment=n)
|
||||
#define rt_weak __weak
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__GNUC__) /* GNU GCC Compiler */
|
||||
#define __RT_STRINGIFY(x...) #x
|
||||
#define RT_STRINGIFY(x...) __RT_STRINGIFY(x)
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used))
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof __typeof__
|
||||
#define rt_noreturn __attribute__ ((noreturn))
|
||||
#define rt_inline static __inline
|
||||
#define rt_always_inline static inline __attribute__((always_inline))
|
||||
#elif defined (__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used))
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (_MSC_VER) /* for Visual Studio Compiler */
|
||||
#define rt_section(x)
|
||||
#define rt_used
|
||||
#define rt_align(n) __declspec(align(n))
|
||||
#define rt_weak
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static __inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__TI_COMPILER_VERSION__) /* for TI CCS Compiler */
|
||||
/**
|
||||
* The way that TI compiler set section is different from other(at least
|
||||
* GCC and MDK) compilers. See ARM Optimizing C/C++ Compiler 5.9.3 for more
|
||||
* details.
|
||||
*/
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#ifdef __TI_EABI__
|
||||
#define rt_used __attribute__((retain)) __attribute__((used))
|
||||
#else
|
||||
#define rt_used __attribute__((used))
|
||||
#endif
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define rt_align(n) __attribute__((aligned(n)))
|
||||
#ifdef __TI_EABI__
|
||||
#define rt_weak __attribute__((weak))
|
||||
#else
|
||||
#define rt_weak
|
||||
#endif
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#elif defined (__TASKING__) /* for TASKING Compiler */
|
||||
#define rt_section(x) __attribute__((section(x)))
|
||||
#define rt_used __attribute__((used, protect))
|
||||
#define PRAGMA(x) _Pragma(#x)
|
||||
#define rt_align(n) __attribute__((__align(n)))
|
||||
#define rt_weak __attribute__((weak))
|
||||
#define rt_typeof typeof
|
||||
#define rt_noreturn
|
||||
#define rt_inline static inline
|
||||
#define rt_always_inline rt_inline
|
||||
#else /* Unkown Compiler */
|
||||
#error not supported tool chain
|
||||
#endif /* __ARMCC_VERSION */
|
||||
#include "rtcompiler.h"
|
||||
|
||||
/* initialization export */
|
||||
#ifdef RT_USING_COMPONENTS_INIT
|
||||
@@ -417,6 +272,8 @@ typedef int (*init_fn_t)(void);
|
||||
#define RT_EPERM EPERM /**< Operation not permitted */
|
||||
#define RT_EFAULT EFAULT /**< Bad address */
|
||||
#define RT_ENOBUFS ENOBUFS /**< No buffer space is available */
|
||||
#define RT_ESCHEDISR 253 /**< scheduler failure in isr context */
|
||||
#define RT_ESCHEDLOCKED 252 /**< scheduler failure in critical region */
|
||||
#define RT_ETRAP 254 /**< Trap event */
|
||||
#else
|
||||
#define RT_EOK 0 /**< There is no error */
|
||||
@@ -436,6 +293,8 @@ typedef int (*init_fn_t)(void);
|
||||
#define RT_ETRAP 14 /**< Trap event */
|
||||
#define RT_EFAULT 15 /**< Bad address */
|
||||
#define RT_ENOBUFS 16 /**< No buffer space is available */
|
||||
#define RT_ESCHEDISR 17 /**< scheduler failure in isr context */
|
||||
#define RT_ESCHEDLOCKED 18 /**< scheduler failure in critical region */
|
||||
#endif /* defined(RT_USING_LIBC) && !defined(RT_USING_NANO) */
|
||||
|
||||
/**@}*/
|
||||
@@ -469,53 +328,6 @@ typedef int (*init_fn_t)(void);
|
||||
*/
|
||||
#define RT_ALIGN_DOWN(size, align) ((size) & ~((align) - 1))
|
||||
|
||||
/**
|
||||
* Double List structure
|
||||
*/
|
||||
struct rt_list_node
|
||||
{
|
||||
struct rt_list_node *next; /**< point to next node. */
|
||||
struct rt_list_node *prev; /**< point to prev node. */
|
||||
};
|
||||
typedef struct rt_list_node rt_list_t; /**< Type for lists. */
|
||||
|
||||
/**
|
||||
* Single List structure
|
||||
*/
|
||||
struct rt_slist_node
|
||||
{
|
||||
struct rt_slist_node *next; /**< point to next node. */
|
||||
};
|
||||
typedef struct rt_slist_node rt_slist_t; /**< Type for single list. */
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#include <cpuport.h> /* for spinlock from arch */
|
||||
|
||||
struct rt_spinlock
|
||||
{
|
||||
rt_hw_spinlock_t lock;
|
||||
#if defined(RT_DEBUGING_SPINLOCK)
|
||||
void *owner;
|
||||
void *pc;
|
||||
#endif /* RT_DEBUGING_SPINLOCK */
|
||||
};
|
||||
typedef struct rt_spinlock rt_spinlock_t;
|
||||
|
||||
#ifndef RT_SPINLOCK_INIT
|
||||
#define RT_SPINLOCK_INIT {{0}} // default
|
||||
#endif /* RT_SPINLOCK_INIT */
|
||||
|
||||
#else
|
||||
typedef rt_ubase_t rt_spinlock_t;
|
||||
struct rt_spinlock
|
||||
{
|
||||
rt_spinlock_t lock;
|
||||
};
|
||||
#define RT_SPINLOCK_INIT {0}
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
#define RT_DEFINE_SPINLOCK(x) struct rt_spinlock x = RT_SPINLOCK_INIT
|
||||
|
||||
/**
|
||||
* @addtogroup KernelObject
|
||||
*/
|
||||
@@ -770,6 +582,8 @@ struct rt_object_information
|
||||
|
||||
#define RT_TIMER_FLAG_HARD_TIMER 0x0 /**< hard timer,the timer's callback function will be called in tick isr. */
|
||||
#define RT_TIMER_FLAG_SOFT_TIMER 0x4 /**< soft timer,the timer's callback function will be called in timer thread. */
|
||||
#define RT_TIMER_FLAG_THREAD_TIMER \
|
||||
(0x8 | RT_TIMER_FLAG_HARD_TIMER) /**< thread timer that cooperates with scheduler directly */
|
||||
|
||||
#define RT_TIMER_CTRL_SET_TIME 0x0 /**< set timer control command */
|
||||
#define RT_TIMER_CTRL_GET_TIME 0x1 /**< get timer control command */
|
||||
@@ -791,6 +605,11 @@ struct rt_object_information
|
||||
#define RT_TIMER_SKIP_LIST_MASK 0x3 /**< Timer skips the list mask */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* timeout handler of rt_timer
|
||||
*/
|
||||
typedef void (*rt_timer_func_t)(void *parameter);
|
||||
|
||||
/**
|
||||
* timer structure
|
||||
*/
|
||||
@@ -800,8 +619,8 @@ struct rt_timer
|
||||
|
||||
rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL];
|
||||
|
||||
void (*timeout_func)(void *parameter); /**< timeout function */
|
||||
void *parameter; /**< timeout function's parameter */
|
||||
rt_timer_func_t timeout_func; /**< timeout function */
|
||||
void *parameter; /**< timeout function's parameter */
|
||||
|
||||
rt_tick_t init_tick; /**< timer timeout tick */
|
||||
rt_tick_t timeout_tick; /**< timeout tick */
|
||||
@@ -901,30 +720,43 @@ struct rt_cpu_usage_stats
|
||||
};
|
||||
typedef struct rt_cpu_usage_stats *rt_cpu_usage_stats_t;
|
||||
|
||||
#define _SCHEDULER_CONTEXT(fileds) fileds
|
||||
|
||||
/**
|
||||
* CPUs definitions
|
||||
*
|
||||
*/
|
||||
struct rt_cpu
|
||||
{
|
||||
struct rt_thread *current_thread;
|
||||
/**
|
||||
* protected by:
|
||||
* - other cores: accessing from other coress is undefined behaviour
|
||||
* - local core: rt_enter_critical()/rt_exit_critical()
|
||||
*/
|
||||
_SCHEDULER_CONTEXT(
|
||||
struct rt_thread *current_thread;
|
||||
|
||||
rt_uint8_t irq_switch_flag:1;
|
||||
rt_uint8_t critical_switch_flag:1;
|
||||
rt_uint8_t sched_lock_flag:1;
|
||||
|
||||
rt_uint8_t current_priority;
|
||||
rt_list_t priority_table[RT_THREAD_PRIORITY_MAX];
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_uint32_t priority_group;
|
||||
rt_uint8_t ready_table[32];
|
||||
#else
|
||||
rt_uint32_t priority_group;
|
||||
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
|
||||
|
||||
rt_atomic_t tick; /**< Passing tickes on this core */
|
||||
);
|
||||
|
||||
struct rt_thread *idle_thread;
|
||||
rt_atomic_t irq_nest;
|
||||
rt_uint8_t irq_switch_flag;
|
||||
|
||||
rt_uint8_t current_priority;
|
||||
rt_list_t priority_table[RT_THREAD_PRIORITY_MAX];
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_uint32_t priority_group;
|
||||
rt_uint8_t ready_table[32];
|
||||
#else
|
||||
rt_uint32_t priority_group;
|
||||
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
|
||||
|
||||
rt_atomic_t tick;
|
||||
|
||||
struct rt_spinlock spinlock;
|
||||
#ifdef RT_USING_SMART
|
||||
struct rt_spinlock spinlock;
|
||||
struct rt_cpu_usage_stats cpu_stat;
|
||||
#endif
|
||||
};
|
||||
@@ -1013,11 +845,12 @@ typedef void (*rt_thread_cleanup_t)(struct rt_thread *tid);
|
||||
/**
|
||||
* Thread structure
|
||||
*/
|
||||
|
||||
#include "rtsched.h" /* for struct rt_sched_thread_ctx */
|
||||
|
||||
struct rt_thread
|
||||
{
|
||||
struct rt_object parent;
|
||||
rt_list_t tlist; /**< the thread list */
|
||||
rt_list_t tlist_schedule; /**< the thread list */
|
||||
|
||||
/* stack point and entry */
|
||||
void *sp; /**< stack point */
|
||||
@@ -1029,24 +862,13 @@ struct rt_thread
|
||||
/* error code */
|
||||
rt_err_t error; /**< error code */
|
||||
|
||||
rt_uint8_t stat; /**< thread status */
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
rt_uint8_t bind_cpu; /**< thread is bind to cpu */
|
||||
rt_uint8_t oncpu; /**< process on cpu */
|
||||
|
||||
rt_atomic_t cpus_lock_nest; /**< cpus lock count */
|
||||
rt_atomic_t critical_lock_nest; /**< critical lock count */
|
||||
#endif /*RT_USING_SMP*/
|
||||
#endif
|
||||
|
||||
/* priority */
|
||||
rt_uint8_t current_priority; /**< current priority */
|
||||
rt_uint8_t init_priority; /**< initialized priority */
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_uint8_t number;
|
||||
rt_uint8_t high_mask;
|
||||
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
|
||||
rt_uint32_t number_mask; /**< priority number mask */
|
||||
RT_SCHED_THREAD_CTX;
|
||||
struct rt_timer thread_timer; /**< built-in thread timer */
|
||||
rt_thread_cleanup_t cleanup; /**< cleanup function when thread exit */
|
||||
|
||||
#ifdef RT_USING_MUTEX
|
||||
/* object for IPC */
|
||||
@@ -1071,9 +893,6 @@ struct rt_thread
|
||||
void *si_list; /**< the signal infor list */
|
||||
#endif /* RT_USING_SIGNALS */
|
||||
|
||||
rt_atomic_t init_tick; /**< thread's initialized tick */
|
||||
rt_atomic_t remaining_tick; /**< remaining tick */
|
||||
|
||||
#ifdef RT_USING_CPU_USAGE
|
||||
rt_uint64_t duration_tick; /**< cpu usage tick */
|
||||
#endif /* RT_USING_CPU_USAGE */
|
||||
@@ -1082,10 +901,6 @@ struct rt_thread
|
||||
void *pthread_data; /**< the handle of pthread data, adapt 32/64bit */
|
||||
#endif /* RT_USING_PTHREADS */
|
||||
|
||||
struct rt_timer thread_timer; /**< built-in thread timer */
|
||||
|
||||
rt_thread_cleanup_t cleanup; /**< cleanup function when thread exit */
|
||||
|
||||
/* light weight process if present */
|
||||
#ifdef RT_USING_SMART
|
||||
void *msg_ret; /**< the return msg */
|
||||
@@ -1100,11 +915,12 @@ struct rt_thread
|
||||
|
||||
struct lwp_thread_signal signal; /**< lwp signal for user-space thread */
|
||||
struct rt_user_context user_ctx; /**< user space context */
|
||||
struct rt_wakeup wakeup; /**< wakeup data */
|
||||
int exit_request; /**< pending exit request of thread */
|
||||
struct rt_wakeup wakeup_handle; /**< wakeup handle for IPC */
|
||||
rt_atomic_t exit_request; /**< pending exit request of thread */
|
||||
int tid; /**< thread ID used by process */
|
||||
int tid_ref_count; /**< reference of tid */
|
||||
void *susp_recycler; /**< suspended recycler on this thread */
|
||||
void *robust_list; /**< pi lock, very carefully, it's a userspace list!*/
|
||||
|
||||
rt_uint64_t user_time;
|
||||
rt_uint64_t system_time;
|
||||
@@ -1167,7 +983,7 @@ struct rt_ipc_object
|
||||
{
|
||||
struct rt_object parent; /**< inherit from rt_object */
|
||||
|
||||
rt_list_t suspend_thread; /**< threads pended on this resource */
|
||||
rt_list_t suspend_thread; /**< threads pended on this resource */
|
||||
};
|
||||
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-01-19 Shell Seperate schduling statements from rt_thread_t
|
||||
* to rt_sched_thread_ctx. Add definitions of scheduler.
|
||||
*/
|
||||
#ifndef __RT_SCHED_H__
|
||||
#define __RT_SCHED_H__
|
||||
|
||||
#include "rttypes.h"
|
||||
#include "rtcompiler.h"
|
||||
|
||||
struct rt_thread;
|
||||
|
||||
typedef rt_uint8_t rt_sched_thread_status_t;
|
||||
|
||||
#ifdef RT_USING_SCHED_THREAD_CTX
|
||||
|
||||
/**
|
||||
* Scheduler private status binding on thread. Caller should never accessing
|
||||
* these members.
|
||||
*/
|
||||
struct rt_sched_thread_priv
|
||||
{
|
||||
rt_tick_t init_tick; /**< thread's initialized tick */
|
||||
rt_tick_t remaining_tick; /**< remaining tick */
|
||||
|
||||
/* priority */
|
||||
rt_uint8_t current_priority; /**< current priority */
|
||||
rt_uint8_t init_priority; /**< initialized priority */
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
rt_uint8_t number; /**< priority low number */
|
||||
rt_uint8_t high_mask; /**< priority high mask */
|
||||
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
|
||||
rt_uint32_t number_mask; /**< priority number mask */
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Scheduler public status binding on thread. Caller must hold the scheduler
|
||||
* lock before access any one of its member.
|
||||
*/
|
||||
struct rt_sched_thread_ctx
|
||||
{
|
||||
rt_list_t thread_list_node; /**< node in thread list */
|
||||
|
||||
rt_uint8_t stat; /**< thread status */
|
||||
rt_uint8_t sched_flag_locked:1; /**< calling thread have the scheduler locked */
|
||||
rt_uint8_t sched_flag_ttmr_set:1; /**< thread timer is start */
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
rt_uint8_t bind_cpu; /**< thread is bind to cpu */
|
||||
rt_uint8_t oncpu; /**< process on cpu */
|
||||
|
||||
rt_base_t critical_lock_nest; /**< critical lock count */
|
||||
#endif
|
||||
|
||||
struct rt_sched_thread_priv sched_thread_priv; /**< private context of scheduler */
|
||||
};
|
||||
|
||||
#define RT_SCHED_THREAD_CTX struct rt_sched_thread_ctx sched_thread_ctx
|
||||
|
||||
#define RT_SCHED_PRIV(thread) ((thread)->sched_thread_ctx.sched_thread_priv)
|
||||
#define RT_SCHED_CTX(thread) ((thread)->sched_thread_ctx)
|
||||
|
||||
/**
|
||||
* Convert a list node in container RT_SCHED_CTX(thread)->thread_list_node
|
||||
* to a thread pointer.
|
||||
*/
|
||||
#define RT_THREAD_LIST_NODE_ENTRY(node) \
|
||||
rt_container_of( \
|
||||
rt_list_entry((node), struct rt_sched_thread_ctx, thread_list_node), \
|
||||
struct rt_thread, sched_thread_ctx)
|
||||
#define RT_THREAD_LIST_NODE(thread) (RT_SCHED_CTX(thread).thread_list_node)
|
||||
|
||||
#else /* !defined(RT_USING_SCHED_THREAD_CTX) */
|
||||
|
||||
#if RT_THREAD_PRIORITY_MAX > 32
|
||||
#define _RT_SCHED_THREAD_CTX_PRIO_EXT \
|
||||
rt_uint8_t number; /**< priority low number */ \
|
||||
rt_uint8_t high_mask; /**< priority high mask */
|
||||
|
||||
#else /* ! RT_THREAD_PRIORITY_MAX > 32 */
|
||||
|
||||
#define _RT_SCHED_THREAD_CTX_PRIO_EXT
|
||||
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
|
||||
|
||||
#define RT_SCHED_THREAD_CTX \
|
||||
rt_list_t tlist; /**< node in thread list */ \
|
||||
rt_uint8_t stat; /**< thread status */ \
|
||||
rt_uint8_t sched_flag_locked:1; \
|
||||
/**< calling thread have the scheduler locked */ \
|
||||
rt_uint8_t sched_flag_ttmr_set:1; /**< thread timer is start */ \
|
||||
rt_tick_t init_tick; /**< thread's initialized tick */ \
|
||||
rt_tick_t remaining_tick; /**< remaining tick */ \
|
||||
rt_uint8_t current_priority; /**< current priority */ \
|
||||
rt_uint8_t init_priority; /**< initialized priority */ \
|
||||
_RT_SCHED_THREAD_CTX_PRIO_EXT; \
|
||||
rt_uint32_t number_mask; /**< priority number mask */
|
||||
|
||||
#define RT_SCHED_PRIV(thread) (*thread)
|
||||
#define RT_SCHED_CTX(thread) (*thread)
|
||||
|
||||
/**
|
||||
* Convert a list node in container RT_SCHED_CTX(thread)->thread_list_node
|
||||
* to a thread pointer.
|
||||
*/
|
||||
#define RT_THREAD_LIST_NODE_ENTRY(node) rt_list_entry((node), struct rt_thread, tlist)
|
||||
#define RT_THREAD_LIST_NODE(thread) (RT_SCHED_CTX(thread).tlist)
|
||||
|
||||
#endif /* RT_USING_SCHED_THREAD_CTX */
|
||||
|
||||
/**
|
||||
* System Scheduler Locking
|
||||
*/
|
||||
|
||||
typedef rt_ubase_t rt_sched_lock_level_t;
|
||||
|
||||
rt_err_t rt_sched_lock(rt_sched_lock_level_t *plvl);
|
||||
rt_err_t rt_sched_unlock(rt_sched_lock_level_t level);
|
||||
rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t level);
|
||||
|
||||
rt_bool_t rt_sched_is_locked(void);
|
||||
|
||||
#ifdef RT_USING_SMP
|
||||
#define RT_SCHED_DEBUG_IS_LOCKED do { RT_ASSERT(rt_sched_is_locked()); } while (0)
|
||||
#define RT_SCHED_DEBUG_IS_UNLOCKED do { RT_ASSERT(!rt_sched_is_locked()); } while (0)
|
||||
|
||||
#else /* !RT_USING_SMP */
|
||||
|
||||
#define RT_SCHED_DEBUG_IS_LOCKED
|
||||
#define RT_SCHED_DEBUG_IS_UNLOCKED
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
/**
|
||||
* NOTE: user should NEVER use these APIs directly. See rt_thread_.* or IPC
|
||||
* methods instead.
|
||||
*/
|
||||
#if defined(__RT_KERNEL_SOURCE__) || defined(__RT_IPC_SOURCE__)
|
||||
|
||||
/* thread initialization and startup routine */
|
||||
void rt_sched_thread_init_ctx(struct rt_thread *thread, rt_uint32_t tick, rt_uint8_t priority);
|
||||
void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_uint8_t priority);
|
||||
void rt_sched_thread_startup(struct rt_thread *thread);
|
||||
|
||||
/* scheduler related routine */
|
||||
void rt_sched_post_ctx_switch(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_tick_increase(void);
|
||||
|
||||
/* thread status operation */
|
||||
rt_uint8_t rt_sched_thread_get_stat(struct rt_thread *thread);
|
||||
rt_uint8_t rt_sched_thread_get_curr_prio(struct rt_thread *thread);
|
||||
rt_uint8_t rt_sched_thread_get_init_prio(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_thread_yield(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_thread_close(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_thread_ready(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_thread_suspend(struct rt_thread *thread, rt_sched_lock_level_t level);
|
||||
rt_err_t rt_sched_thread_change_priority(struct rt_thread *thread, rt_uint8_t priority);
|
||||
rt_err_t rt_sched_thread_bind_cpu(struct rt_thread *thread, int cpu);
|
||||
rt_uint8_t rt_sched_thread_is_suspended(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_thread_timer_stop(struct rt_thread *thread);
|
||||
rt_err_t rt_sched_thread_timer_start(struct rt_thread *thread);
|
||||
void rt_sched_insert_thread(struct rt_thread *thread);
|
||||
void rt_sched_remove_thread(struct rt_thread *thread);
|
||||
|
||||
#endif /* defined(__RT_KERNEL_SOURCE__) || defined(__RT_IPC_SOURCE__) */
|
||||
|
||||
#endif /* __RT_SCHED_H__ */
|
||||
+26
-7
@@ -21,6 +21,7 @@
|
||||
* 2023-06-30 ChuShicheng move debug check from the rtdebug.h
|
||||
* 2023-10-16 Shell Support a new backtrace framework
|
||||
* 2023-12-10 xqyjlj fix spinlock in up
|
||||
* 2024-01-25 Shell Add rt_susp_list for IPC primitives
|
||||
*/
|
||||
|
||||
#ifndef __RT_THREAD_H__
|
||||
@@ -43,7 +44,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
int entry(void);
|
||||
int entry(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -173,7 +174,6 @@ rt_err_t rt_thread_resume(rt_thread_t thread);
|
||||
rt_err_t rt_thread_wakeup(rt_thread_t thread);
|
||||
void rt_thread_wakeup_set(struct rt_thread *thread, rt_wakeup_func_t func, void* user_data);
|
||||
#endif /* RT_USING_SMART */
|
||||
void rt_thread_timeout(void *parameter);
|
||||
rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size);
|
||||
#ifdef RT_USING_SIGNALS
|
||||
void rt_thread_alloc_sig(rt_thread_t tid);
|
||||
@@ -212,11 +212,10 @@ void rt_system_scheduler_start(void);
|
||||
|
||||
void rt_schedule(void);
|
||||
void rt_scheduler_do_irq_switch(void *context);
|
||||
void rt_schedule_insert_thread(struct rt_thread *thread);
|
||||
void rt_schedule_remove_thread(struct rt_thread *thread);
|
||||
|
||||
void rt_enter_critical(void);
|
||||
rt_base_t rt_enter_critical(void);
|
||||
void rt_exit_critical(void);
|
||||
void rt_exit_critical_safe(rt_base_t critical_level);
|
||||
rt_uint16_t rt_critical_level(void);
|
||||
|
||||
#ifdef RT_USING_HOOK
|
||||
@@ -368,6 +367,26 @@ void rt_slab_free(rt_slab_t m, void *ptr);
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Suspend list - A basic building block for IPC primitives which interacts with
|
||||
* scheduler directly. Its API is similar to a FIFO list.
|
||||
*
|
||||
* Note: don't use in application codes directly
|
||||
*/
|
||||
void rt_susp_list_print(rt_list_t *list);
|
||||
/* reserve thread error while resuming it */
|
||||
#define RT_THREAD_RESUME_RES_THR_ERR (-1)
|
||||
struct rt_thread *rt_susp_list_dequeue(rt_list_t *susp_list, rt_err_t thread_error);
|
||||
rt_err_t rt_susp_list_resume_all(rt_list_t *susp_list, rt_err_t thread_error);
|
||||
rt_err_t rt_susp_list_resume_all_irq(rt_list_t *susp_list,
|
||||
rt_err_t thread_error,
|
||||
struct rt_spinlock *lock);
|
||||
|
||||
/* suspend and enqueue */
|
||||
rt_err_t rt_thread_suspend_to_list(rt_thread_t thread, rt_list_t *susp_list, int ipc_flags, int suspend_flag);
|
||||
/* only for a suspended thread, and caller must hold the scheduler lock */
|
||||
rt_err_t rt_susp_list_enqueue(rt_list_t *susp_list, rt_thread_t thread, int ipc_flags);
|
||||
|
||||
#ifdef RT_USING_SEMAPHORE
|
||||
/*
|
||||
* semaphore interface
|
||||
@@ -725,11 +744,11 @@ int rt_snprintf(char *buf, rt_size_t size, const char *format, ...);
|
||||
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
|
||||
rt_device_t rt_console_set_device(const char *name);
|
||||
rt_device_t rt_console_get_device(void);
|
||||
#ifdef RT_USING_THREDSAFE_PRINTF
|
||||
#ifdef RT_USING_THREADSAFE_PRINTF
|
||||
rt_thread_t rt_console_current_user(void);
|
||||
#else
|
||||
rt_inline void *rt_console_current_user(void) { return RT_NULL; }
|
||||
#endif /* RT_USING_THREDSAFE_PRINTF */
|
||||
#endif /* RT_USING_THREADSAFE_PRINTF */
|
||||
#endif /* defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) */
|
||||
|
||||
rt_err_t rt_get_errno(void);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user