🎯 Sync smart & scheduler codes (#8537)

Signed-off-by: Shell <smokewood@qq.com>
Co-authored-by: xqyjlj <xqyjlj@126.com>
This commit is contained in:
Shell
2024-02-23 17:49:15 +08:00
committed by GitHub
co-authored by xqyjlj
parent 6fe69d7431
commit 71560bafb5
71 changed files with 6218 additions and 2329 deletions
+11 -1
View File
@@ -35,6 +35,7 @@ config RT_USING_SMART
select RT_USING_POSIX_FS
select RT_USING_POSIX_TERMIOS
select RT_USING_KTIME
select RT_USING_STDC_ATOMIC
depends on ARCH_ARM_CORTEX_M || ARCH_ARM_ARM9 || ARCH_ARM_CORTEX_A || ARCH_ARMV8 || ARCH_RISCV64
depends on !RT_USING_NANO
help
@@ -66,6 +67,7 @@ config RT_USING_AMP
config RT_USING_SMP
bool "Enable SMP (Symmetric multiprocessing)"
default n
select RT_USING_SCHED_THREAD_CTX
help
This option should be selected by machines which have an SMP-
capable CPU.
@@ -417,10 +419,18 @@ config RT_USING_INTERRUPT_INFO
help
Add name and counter information for interrupt trace.
config RT_USING_THREDSAFE_PRINTF
config RT_USING_THREADSAFE_PRINTF
bool "Enable thread safe kernel print service"
default y if RT_USING_SMP && RT_USING_SMART
config RT_USING_SCHED_THREAD_CTX
bool "Using the scheduler thread context"
help
Using the scheduler thread context embedded in the thread object.
This options is only for backward compatible codes. Maybe use as a
mandatory option in the future.
default y if RT_USING_SMP
config RT_USING_CONSOLE
bool "Using console for rt_kprintf"
default y
+2 -3
View File
@@ -26,8 +26,7 @@ if GetDepend('RT_USING_DEVICE') == False:
if GetDepend('RT_USING_SMP') == False:
SrcRemove(src, ['cpu.c', 'scheduler_mp.c'])
if GetDepend('RT_USING_SMP') == True:
else:
SrcRemove(src, ['scheduler_up.c'])
LOCAL_CFLAGS = ''
@@ -43,6 +42,6 @@ if rtconfig.PLATFORM in GetGCCLikePLATFORM():
LOCAL_CFLAGS += ' -Wimplicit-fallthrough' # implicit fallthrough warning
LOCAL_CFLAGS += ' -Wduplicated-cond -Wduplicated-branches' # duplicated condition warning
group = DefineGroup('Kernel', src, depend=[''], CPPPATH=inc, CPPDEFINES=['__RTTHREAD__'], LOCAL_CFLAGS=LOCAL_CFLAGS)
group = DefineGroup('Kernel', src, depend=[''], CPPPATH=inc, CPPDEFINES=['__RTTHREAD__'], LOCAL_CFLAGS=LOCAL_CFLAGS, LOCAL_CPPDEFINES=['__RT_KERNEL_SOURCE__'])
Return('group')
+2 -17
View File
@@ -85,34 +85,19 @@ void rt_tick_set(rt_tick_t tick)
*/
void rt_tick_increase(void)
{
struct rt_thread *thread;
rt_base_t level;
rt_atomic_t oldval = 0;
RT_ASSERT(rt_interrupt_get_nest() > 0);
RT_OBJECT_HOOK_CALL(rt_tick_hook, ());
/* increase the global tick */
#ifdef RT_USING_SMP
/* get percpu and increase the tick */
rt_atomic_add(&(rt_cpu_self()->tick), 1);
#else
rt_atomic_add(&(rt_tick), 1);
#endif /* RT_USING_SMP */
/* check time slice */
thread = rt_thread_self();
level = rt_spin_lock_irqsave(&(thread->spinlock));
rt_atomic_sub(&(thread->remaining_tick), 1);
if (rt_atomic_compare_exchange_strong(&(thread->remaining_tick), &oldval, thread->init_tick))
{
thread->stat |= RT_THREAD_STAT_YIELD;
rt_spin_unlock_irqrestore(&(thread->spinlock), level);
rt_schedule();
}
else
{
rt_spin_unlock_irqrestore(&(thread->spinlock), level);
}
rt_sched_tick_increase();
/* check timer */
#ifdef RT_USING_SMP
+29 -48
View File
@@ -8,6 +8,7 @@
* 2018-10-30 Bernard The first version
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
* 2023-12-10 xqyjlj spinlock should lock sched
* 2024-01-25 Shell Using rt_exit_critical_safe
*/
#include <rthw.h>
#include <rtthread.h>
@@ -16,6 +17,10 @@
#include <lwp.h>
#endif
#ifdef RT_USING_DEBUG
rt_base_t _cpus_critical_level;
#endif /* RT_USING_DEBUG */
#ifdef RT_USING_SMP
static struct rt_cpu _cpus[RT_CPUS_NR];
rt_hw_spinlock_t _cpus_lock;
@@ -23,14 +28,6 @@ rt_hw_spinlock_t _cpus_lock;
void *_cpus_lock_owner = 0;
void *_cpus_lock_pc = 0;
#define __OWNER_MAGIC ((void *)0xdeadbeaf)
#if defined (__GNUC__)
#define __GET_RETURN_ADDRESS __builtin_return_address(0)
#else
#define __GET_RETURN_ADDRESS RT_NULL
#endif
#endif /* RT_DEBUGING_SPINLOCK */
/**
@@ -56,13 +53,7 @@ void rt_spin_lock(struct rt_spinlock *lock)
{
rt_enter_critical();
rt_hw_spin_lock(&lock->lock);
#if defined(RT_DEBUGING_SPINLOCK)
if (rt_cpu_self() != RT_NULL)
{
lock->owner = rt_cpu_self()->current_thread;
}
lock->pc = __GET_RETURN_ADDRESS;
#endif /* RT_DEBUGING_SPINLOCK */
RT_SPIN_LOCK_DEBUG(lock);
}
RTM_EXPORT(rt_spin_lock)
@@ -73,12 +64,10 @@ RTM_EXPORT(rt_spin_lock)
*/
void rt_spin_unlock(struct rt_spinlock *lock)
{
rt_base_t critical_level;
RT_SPIN_UNLOCK_DEBUG(lock, critical_level);
rt_hw_spin_unlock(&lock->lock);
#if defined(RT_DEBUGING_SPINLOCK)
lock->owner = __OWNER_MAGIC;
lock->pc = RT_NULL;
#endif /* RT_DEBUGING_SPINLOCK */
rt_exit_critical();
rt_exit_critical_safe(critical_level);
}
RTM_EXPORT(rt_spin_unlock)
@@ -99,13 +88,7 @@ rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock)
level = rt_hw_local_irq_disable();
rt_enter_critical();
rt_hw_spin_lock(&lock->lock);
#if defined(RT_DEBUGING_SPINLOCK)
if (rt_cpu_self() != RT_NULL)
{
lock->owner = rt_cpu_self()->current_thread;
lock->pc = __GET_RETURN_ADDRESS;
}
#endif /* RT_DEBUGING_SPINLOCK */
RT_SPIN_LOCK_DEBUG(lock);
return level;
}
RTM_EXPORT(rt_spin_lock_irqsave)
@@ -119,13 +102,12 @@ RTM_EXPORT(rt_spin_lock_irqsave)
*/
void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
{
#if defined(RT_DEBUGING_SPINLOCK)
lock->owner = __OWNER_MAGIC;
lock->pc = RT_NULL;
#endif /* RT_DEBUGING_SPINLOCK */
rt_base_t critical_level;
RT_SPIN_UNLOCK_DEBUG(lock, critical_level);
rt_hw_spin_unlock(&lock->lock);
rt_hw_local_irq_enable(level);
rt_exit_critical();
rt_exit_critical_safe(critical_level);
}
RTM_EXPORT(rt_spin_unlock_irqrestore)
@@ -162,7 +144,6 @@ rt_base_t rt_cpus_lock(void)
struct rt_cpu* pcpu;
level = rt_hw_local_irq_disable();
rt_enter_critical();
pcpu = rt_cpu_self();
if (pcpu->current_thread != RT_NULL)
{
@@ -171,11 +152,16 @@ rt_base_t rt_cpus_lock(void)
rt_atomic_add(&(pcpu->current_thread->cpus_lock_nest), 1);
if (lock_nest == 0)
{
rt_enter_critical();
rt_hw_spin_lock(&_cpus_lock);
#if defined(RT_DEBUGING_SPINLOCK)
#ifdef RT_USING_DEBUG
_cpus_critical_level = rt_critical_level();
#endif /* RT_USING_DEBUG */
#ifdef RT_DEBUGING_SPINLOCK
_cpus_lock_owner = pcpu->current_thread;
_cpus_lock_pc = __GET_RETURN_ADDRESS;
#endif
#endif /* RT_DEBUGING_SPINLOCK */
}
}
@@ -194,6 +180,7 @@ void rt_cpus_unlock(rt_base_t level)
if (pcpu->current_thread != RT_NULL)
{
rt_base_t critical_level = 0;
RT_ASSERT(rt_atomic_load(&(pcpu->current_thread->cpus_lock_nest)) > 0);
rt_atomic_sub(&(pcpu->current_thread->cpus_lock_nest), 1);
@@ -202,12 +189,16 @@ void rt_cpus_unlock(rt_base_t level)
#if defined(RT_DEBUGING_SPINLOCK)
_cpus_lock_owner = __OWNER_MAGIC;
_cpus_lock_pc = RT_NULL;
#endif
#endif /* RT_DEBUGING_SPINLOCK */
#ifdef RT_USING_DEBUG
critical_level = _cpus_critical_level;
_cpus_critical_level = 0;
#endif /* RT_USING_DEBUG */
rt_hw_spin_unlock(&_cpus_lock);
rt_exit_critical_safe(critical_level);
}
}
rt_hw_local_irq_enable(level);
rt_exit_critical();
}
RTM_EXPORT(rt_cpus_unlock);
@@ -220,20 +211,10 @@ RTM_EXPORT(rt_cpus_unlock);
*/
void rt_cpus_lock_status_restore(struct rt_thread *thread)
{
struct rt_cpu* pcpu = rt_cpu_self();
#if defined(ARCH_MM_MMU) && defined(RT_USING_SMART)
lwp_aspace_switch(thread);
#endif
if (pcpu->current_thread != RT_NULL )
{
rt_hw_spin_unlock(&(pcpu->current_thread->spinlock.lock));
if ((pcpu->current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
{
rt_schedule_insert_thread(pcpu->current_thread);
}
}
pcpu->current_thread = thread;
rt_sched_post_ctx_switch(thread);
}
RTM_EXPORT(rt_cpus_lock_status_restore);
#endif /* RT_USING_SMP */
+7 -10
View File
@@ -146,7 +146,7 @@ void rt_thread_defunct_enqueue(rt_thread_t thread)
{
rt_base_t level;
level = rt_spin_lock_irqsave(&_defunct_spinlock);
rt_list_insert_after(&_rt_thread_defunct, &thread->tlist);
rt_list_insert_after(&_rt_thread_defunct, &RT_THREAD_LIST_NODE(thread));
rt_spin_unlock_irqrestore(&_defunct_spinlock, level);
#ifdef RT_USING_SMP
rt_sem_release(&system_sem);
@@ -166,20 +166,16 @@ rt_thread_t rt_thread_defunct_dequeue(void)
level = rt_spin_lock_irqsave(&_defunct_spinlock);
if (l->next != l)
{
thread = rt_list_entry(l->next,
struct rt_thread,
tlist);
rt_list_remove(&(thread->tlist));
thread = RT_THREAD_LIST_NODE_ENTRY(l->next);
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
}
rt_spin_unlock_irqrestore(&_defunct_spinlock, level);
#else
if (l->next != l)
{
thread = rt_list_entry(l->next,
struct rt_thread,
tlist);
thread = RT_THREAD_LIST_NODE_ENTRY(l->next);
level = rt_hw_interrupt_disable();
rt_list_remove(&(thread->tlist));
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
rt_hw_interrupt_enable(level);
}
#endif
@@ -308,9 +304,10 @@ static void rt_thread_system_entry(void *parameter)
while (1)
{
int ret= rt_sem_take(&system_sem, RT_WAITING_FOREVER);
int ret = rt_sem_take(&system_sem, RT_WAITING_FOREVER);
if (ret != RT_EOK)
{
rt_kprintf("failed to sem_take() error %d\n", ret);
RT_ASSERT(0);
}
rt_defunct_execute();
+424 -301
View File
File diff suppressed because it is too large Load Diff
+34 -14
View File
@@ -1500,14 +1500,21 @@ rt_weak void rt_hw_console_output(const char *str)
}
RTM_EXPORT(rt_hw_console_output);
#ifdef RT_USING_THREDSAFE_PRINTF
#ifdef RT_USING_THREADSAFE_PRINTF
static struct rt_spinlock _pr_lock = RT_SPINLOCK_INIT;
static struct rt_spinlock _prf_lock = RT_SPINLOCK_INIT;
/* system console lock */
static struct rt_spinlock _syscon_lock = RT_SPINLOCK_INIT;
/* lock of kprintf buffer */
static struct rt_spinlock _prbuf_lock = RT_SPINLOCK_INIT;
/* current user of system console */
static rt_thread_t _pr_curr_user;
#ifdef RT_USING_DEBUG
static rt_base_t _pr_critical_level;
#endif /* RT_USING_DEBUG */
/* nested level of current user */
static int _pr_curr_user_nested;
static volatile int _pr_curr_user_nested;
rt_thread_t rt_console_current_user(void)
{
@@ -1516,35 +1523,42 @@ rt_thread_t rt_console_current_user(void)
static void _console_take(void)
{
rt_ubase_t level = rt_spin_lock_irqsave(&_pr_lock);
rt_ubase_t level = rt_spin_lock_irqsave(&_syscon_lock);
rt_thread_t self_thread = rt_thread_self();
rt_base_t critical_level;
RT_UNUSED(critical_level);
while (_pr_curr_user != self_thread)
{
if (_pr_curr_user == RT_NULL)
{
/* no preemption is allowed to avoid dead lock */
rt_enter_critical();
critical_level = rt_enter_critical();
#ifdef RT_USING_DEBUG
_pr_critical_level = _syscon_lock.critical_level;
_syscon_lock.critical_level = critical_level;
#endif
_pr_curr_user = self_thread;
break;
}
else
{
rt_spin_unlock_irqrestore(&_pr_lock, level);
rt_spin_unlock_irqrestore(&_syscon_lock, level);
rt_thread_yield();
level = rt_spin_lock_irqsave(&_pr_lock);
level = rt_spin_lock_irqsave(&_syscon_lock);
}
}
_pr_curr_user_nested++;
rt_spin_unlock_irqrestore(&_pr_lock, level);
rt_spin_unlock_irqrestore(&_syscon_lock, level);
}
static void _console_release(void)
{
rt_ubase_t level = rt_spin_lock_irqsave(&_pr_lock);
rt_ubase_t level = rt_spin_lock_irqsave(&_syscon_lock);
rt_thread_t self_thread = rt_thread_self();
RT_UNUSED(self_thread);
RT_ASSERT(_pr_curr_user == self_thread);
@@ -1552,22 +1566,28 @@ static void _console_release(void)
if (!_pr_curr_user_nested)
{
_pr_curr_user = RT_NULL;
#ifdef RT_USING_DEBUG
rt_exit_critical_safe(_syscon_lock.critical_level);
_syscon_lock.critical_level = _pr_critical_level;
#else
rt_exit_critical();
#endif
}
rt_spin_unlock_irqrestore(&_pr_lock, level);
rt_spin_unlock_irqrestore(&_syscon_lock, level);
}
#define CONSOLE_TAKE _console_take()
#define CONSOLE_RELEASE _console_release()
#define PRINTF_BUFFER_TAKE rt_ubase_t level = rt_spin_lock_irqsave(&_prf_lock)
#define PRINTF_BUFFER_RELEASE rt_spin_unlock_irqrestore(&_prf_lock, level)
#define PRINTF_BUFFER_TAKE rt_ubase_t level = rt_spin_lock_irqsave(&_prbuf_lock)
#define PRINTF_BUFFER_RELEASE rt_spin_unlock_irqrestore(&_prbuf_lock, level)
#else
#define CONSOLE_TAKE
#define CONSOLE_RELEASE
#define PRINTF_BUFFER_TAKE
#define PRINTF_BUFFER_RELEASE
#endif /* RT_USING_THREDSAFE_PRINTF */
#endif /* RT_USING_THREADSAFE_PRINTF */
/**
* @brief This function will put string to the console.
+4 -46
View File
@@ -141,7 +141,6 @@ RTM_EXPORT(rt_mp_init);
*/
rt_err_t rt_mp_detach(struct rt_mempool *mp)
{
struct rt_thread *thread;
rt_base_t level;
/* parameter check */
@@ -151,21 +150,7 @@ rt_err_t rt_mp_detach(struct rt_mempool *mp)
level = rt_spin_lock_irqsave(&(mp->spinlock));
/* wake up all suspended threads */
while (!rt_list_isempty(&(mp->suspend_thread)))
{
/* get next suspend thread */
thread = rt_list_entry(mp->suspend_thread.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);
}
rt_susp_list_resume_all(&mp->suspend_thread, RT_ERROR);
/* detach object */
rt_object_detach(&(mp->parent));
@@ -257,7 +242,6 @@ RTM_EXPORT(rt_mp_create);
*/
rt_err_t rt_mp_delete(rt_mp_t mp)
{
struct rt_thread *thread;
rt_base_t level;
RT_DEBUG_NOT_IN_INTERRUPT;
@@ -269,20 +253,7 @@ rt_err_t rt_mp_delete(rt_mp_t mp)
level = rt_spin_lock_irqsave(&(mp->spinlock));
/* wake up all suspended threads */
while (!rt_list_isempty(&(mp->suspend_thread)))
{
/* get next suspend thread */
thread = rt_list_entry(mp->suspend_thread.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);
}
rt_susp_list_resume_all(&mp->suspend_thread, RT_ERROR);
rt_spin_unlock_irqrestore(&(mp->spinlock), level);
@@ -339,8 +310,7 @@ void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
thread->error = RT_EOK;
/* need suspend thread */
rt_thread_suspend(thread);
rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
rt_thread_suspend_to_list(thread, &mp->suspend_thread, RT_IPC_FLAG_FIFO, RT_UNINTERRUPTIBLE);
if (time > 0)
{
@@ -403,7 +373,6 @@ void rt_mp_free(void *block)
{
rt_uint8_t **block_ptr;
struct rt_mempool *mp;
struct rt_thread *thread;
rt_base_t level;
/* parameter check */
@@ -424,19 +393,8 @@ void rt_mp_free(void *block)
*block_ptr = mp->block_list;
mp->block_list = (rt_uint8_t *)block_ptr;
if (!rt_list_isempty(&(mp->suspend_thread)))
if (rt_susp_list_dequeue(&mp->suspend_thread, RT_EOK))
{
/* get the suspended thread */
thread = rt_list_entry(mp->suspend_thread.next,
struct rt_thread,
tlist);
/* set error */
thread->error = RT_EOK;
/* resume thread */
rt_thread_resume(thread);
rt_spin_unlock_irqrestore(&(mp->spinlock), level);
/* do a schedule */
+1 -1
View File
@@ -70,7 +70,7 @@ enum rt_object_info_type
RT_Object_Info_Module, /**< The object is a module. */
#endif
#ifdef RT_USING_HEAP
RT_Object_Info_Memory, /**< The object is a memory. */
RT_Object_Info_Memory, /**< The object is a memory. */
#endif
#ifdef RT_USING_SMART
RT_Object_Info_Channel, /**< The object is a IPC channel */
+217
View File
@@ -0,0 +1,217 @@
/*
* Copyright (c) 2006-2024, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* (scheduler_comm.c) Common API of scheduling routines.
*
* Change Logs:
* Date Author Notes
* 2024-01-18 Shell Separate scheduling related codes from thread.c, scheduler_.*
*/
#define DBG_TAG "kernel.sched"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include <rtthread.h>
void rt_sched_thread_init_ctx(struct rt_thread *thread, rt_uint32_t tick, rt_uint8_t priority)
{
/* setup thread status */
RT_SCHED_CTX(thread).stat = RT_THREAD_INIT;
#ifdef RT_USING_SMP
/* not bind on any cpu */
RT_SCHED_CTX(thread).bind_cpu = RT_CPUS_NR;
RT_SCHED_CTX(thread).oncpu = RT_CPU_DETACHED;
#endif /* RT_USING_SMP */
rt_sched_thread_init_priv(thread, tick, priority);
}
rt_err_t rt_sched_thread_timer_start(struct rt_thread *thread)
{
RT_SCHED_DEBUG_IS_LOCKED;
RT_SCHED_CTX(thread).sched_flag_ttmr_set = 1;
return RT_EOK;
}
rt_err_t rt_sched_thread_timer_stop(struct rt_thread *thread)
{
rt_err_t error;
RT_SCHED_DEBUG_IS_LOCKED;
if (RT_SCHED_CTX(thread).sched_flag_ttmr_set)
{
error = rt_timer_stop(&thread->thread_timer);
/* mask out timer flag no matter stop success or not */
RT_SCHED_CTX(thread).sched_flag_ttmr_set = 0;
}
else
{
error = RT_EOK;
}
return error;
}
rt_uint8_t rt_sched_thread_get_stat(struct rt_thread *thread)
{
RT_SCHED_DEBUG_IS_LOCKED;
return RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK;
}
rt_uint8_t rt_sched_thread_get_curr_prio(struct rt_thread *thread)
{
RT_SCHED_DEBUG_IS_LOCKED;
return RT_SCHED_PRIV(thread).current_priority;
}
rt_uint8_t rt_sched_thread_get_init_prio(struct rt_thread *thread)
{
/* read only fields, so lock is unecessary */
return RT_SCHED_PRIV(thread).init_priority;
}
/**
* @note Caller must hold the scheduler lock
*/
rt_uint8_t rt_sched_thread_is_suspended(struct rt_thread *thread)
{
RT_SCHED_DEBUG_IS_LOCKED;
return (RT_SCHED_CTX(thread).stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK;
}
rt_err_t rt_sched_thread_close(struct rt_thread *thread)
{
RT_SCHED_DEBUG_IS_LOCKED;
RT_SCHED_CTX(thread).stat = RT_THREAD_CLOSE;
return RT_EOK;
}
rt_err_t rt_sched_thread_yield(struct rt_thread *thread)
{
RT_SCHED_DEBUG_IS_LOCKED;
RT_SCHED_PRIV(thread).remaining_tick = RT_SCHED_PRIV(thread).init_tick;
RT_SCHED_CTX(thread).stat |= RT_THREAD_STAT_YIELD;
return RT_EOK;
}
rt_err_t rt_sched_thread_ready(struct rt_thread *thread)
{
rt_err_t error;
RT_SCHED_DEBUG_IS_LOCKED;
if (!rt_sched_thread_is_suspended(thread))
{
/* failed to proceed, and that's possibly due to a racing condition */
error = -RT_EINVAL;
}
else
{
if (RT_SCHED_CTX(thread).sched_flag_ttmr_set)
{
/**
* Quiet timeout timer first if set. and don't continue if we
* failed, because it probably means that a timeout ISR racing to
* resume thread before us.
*/
error = rt_sched_thread_timer_stop(thread);
}
else
{
error = RT_EOK;
}
if (!error)
{
/* remove from suspend list */
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
#ifdef RT_USING_SMART
thread->wakeup_handle.func = RT_NULL;
#endif
/* insert to schedule ready list and remove from susp list */
rt_sched_insert_thread(thread);
}
}
return error;
}
rt_err_t rt_sched_tick_increase(void)
{
struct rt_thread *thread;
rt_sched_lock_level_t slvl;
thread = rt_thread_self();
rt_sched_lock(&slvl);
RT_SCHED_PRIV(thread).remaining_tick--;
if (RT_SCHED_PRIV(thread).remaining_tick)
{
rt_sched_unlock(slvl);
}
else
{
rt_sched_thread_yield(thread);
/* request a rescheduling even though we are probably in an ISR */
rt_sched_unlock_n_resched(slvl);
}
return RT_EOK;
}
/**
* @brief Update priority of the target thread
*/
rt_err_t rt_sched_thread_change_priority(struct rt_thread *thread, rt_uint8_t priority)
{
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
RT_SCHED_DEBUG_IS_LOCKED;
/* for ready thread, change queue; otherwise simply update the priority */
if ((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
{
/* remove thread from schedule queue first */
rt_sched_remove_thread(thread);
/* change thread priority */
RT_SCHED_PRIV(thread).current_priority = priority;
/* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
RT_SCHED_PRIV(thread).number = RT_SCHED_PRIV(thread).current_priority >> 3; /* 5bit */
RT_SCHED_PRIV(thread).number_mask = 1 << RT_SCHED_PRIV(thread).number;
RT_SCHED_PRIV(thread).high_mask = 1 << (RT_SCHED_PRIV(thread).current_priority & 0x07); /* 3bit */
#else
RT_SCHED_PRIV(thread).number_mask = 1 << RT_SCHED_PRIV(thread).current_priority;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
RT_SCHED_CTX(thread).stat = RT_THREAD_INIT;
/* insert thread to schedule queue again */
rt_sched_insert_thread(thread);
}
else
{
RT_SCHED_PRIV(thread).current_priority = priority;
/* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
RT_SCHED_PRIV(thread).number = RT_SCHED_PRIV(thread).current_priority >> 3; /* 5bit */
RT_SCHED_PRIV(thread).number_mask = 1 << RT_SCHED_PRIV(thread).number;
RT_SCHED_PRIV(thread).high_mask = 1 << (RT_SCHED_PRIV(thread).current_priority & 0x07); /* 3bit */
#else
RT_SCHED_PRIV(thread).number_mask = 1 << RT_SCHED_PRIV(thread).current_priority;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
}
return RT_EOK;
}
+934 -454
View File
File diff suppressed because it is too large Load Diff
+152 -37
View File
@@ -161,15 +161,44 @@ static struct rt_thread* _scheduler_get_highest_priority_thread(rt_ubase_t *high
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
/* get highest ready priority thread */
highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
struct rt_thread,
tlist);
highest_priority_thread = RT_THREAD_LIST_NODE_ENTRY(rt_thread_priority_table[highest_ready_priority].next);
*highest_prio = highest_ready_priority;
return highest_priority_thread;
}
rt_err_t rt_sched_lock(rt_sched_lock_level_t *plvl)
{
rt_base_t level;
if (!plvl)
return -RT_EINVAL;
level = rt_hw_interrupt_disable();
*plvl = level;
return RT_EOK;
}
rt_err_t rt_sched_unlock(rt_sched_lock_level_t level)
{
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t level)
{
if (rt_thread_self())
{
/* if scheduler is available */
rt_schedule();
}
rt_hw_interrupt_enable(level);
return RT_EOK;
}
/**
* @brief This function will initialize the system scheduler.
*/
@@ -208,8 +237,8 @@ void rt_system_scheduler_start(void)
rt_current_thread = to_thread;
rt_schedule_remove_thread(to_thread);
to_thread->stat = RT_THREAD_RUNNING;
rt_sched_remove_thread(to_thread);
RT_SCHED_CTX(to_thread).stat = RT_THREAD_RUNNING;
/* switch to new thread */
@@ -250,13 +279,13 @@ void rt_schedule(void)
to_thread = _scheduler_get_highest_priority_thread(&highest_ready_priority);
if ((rt_current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
if ((RT_SCHED_CTX(rt_current_thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
{
if (rt_current_thread->current_priority < highest_ready_priority)
if (RT_SCHED_PRIV(rt_current_thread).current_priority < highest_ready_priority)
{
to_thread = rt_current_thread;
}
else if (rt_current_thread->current_priority == highest_ready_priority && (rt_current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
else if (RT_SCHED_PRIV(rt_current_thread).current_priority == highest_ready_priority && (RT_SCHED_CTX(rt_current_thread).stat & RT_THREAD_STAT_YIELD_MASK) == 0)
{
to_thread = rt_current_thread;
}
@@ -277,16 +306,16 @@ void rt_schedule(void)
if (need_insert_from_thread)
{
rt_schedule_insert_thread(from_thread);
rt_sched_insert_thread(from_thread);
}
if ((from_thread->stat & RT_THREAD_STAT_YIELD_MASK) != 0)
if ((RT_SCHED_CTX(from_thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0)
{
from_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
RT_SCHED_CTX(from_thread).stat &= ~RT_THREAD_STAT_YIELD_MASK;
}
rt_schedule_remove_thread(to_thread);
to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
rt_sched_remove_thread(to_thread);
RT_SCHED_CTX(to_thread).stat = RT_THREAD_RUNNING | (RT_SCHED_CTX(to_thread).stat & ~RT_THREAD_STAT_MASK);
/* switch to new thread */
LOG_D("[%d]switch to priority#%d "
@@ -315,11 +344,11 @@ void rt_schedule(void)
#ifdef RT_USING_SIGNALS
/* check stat of thread for signal */
level = rt_hw_interrupt_disable();
if (rt_current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
if (RT_SCHED_CTX(rt_current_thread).stat & RT_THREAD_STAT_SIGNAL_PENDING)
{
extern void rt_thread_handle_sig(rt_bool_t clean_state);
rt_current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
RT_SCHED_CTX(rt_current_thread).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
rt_hw_interrupt_enable(level);
@@ -343,8 +372,8 @@ void rt_schedule(void)
}
else
{
rt_schedule_remove_thread(rt_current_thread);
rt_current_thread->stat = RT_THREAD_RUNNING | (rt_current_thread->stat & ~RT_THREAD_STAT_MASK);
rt_sched_remove_thread(rt_current_thread);
RT_SCHED_CTX(rt_current_thread).stat = RT_THREAD_RUNNING | (RT_SCHED_CTX(rt_current_thread).stat & ~RT_THREAD_STAT_MASK);
}
}
}
@@ -356,6 +385,42 @@ __exit:
return;
}
/* Normally, there isn't anyone racing with us so this operation is lockless */
void rt_sched_thread_startup(struct rt_thread *thread)
{
#if RT_THREAD_PRIORITY_MAX > 32
RT_SCHED_PRIV(thread).number = RT_SCHED_PRIV(thread).current_priority >> 3; /* 5bit */
RT_SCHED_PRIV(thread).number_mask = 1L << RT_SCHED_PRIV(thread).number;
RT_SCHED_PRIV(thread).high_mask = 1L << (RT_SCHED_PRIV(thread).current_priority & 0x07); /* 3bit */
#else
RT_SCHED_PRIV(thread).number_mask = 1L << RT_SCHED_PRIV(thread).current_priority;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
/* change thread stat, so we can resume it */
RT_SCHED_CTX(thread).stat = RT_THREAD_SUSPEND;
}
void rt_sched_thread_init_priv(struct rt_thread *thread, rt_uint32_t tick, rt_uint8_t priority)
{
rt_list_init(&RT_THREAD_LIST_NODE(thread));
/* priority init */
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
RT_SCHED_PRIV(thread).init_priority = priority;
RT_SCHED_PRIV(thread).current_priority = priority;
/* don't add to scheduler queue as init thread */
RT_SCHED_PRIV(thread).number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32
RT_SCHED_PRIV(thread).number = 0;
RT_SCHED_PRIV(thread).high_mask = 0;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
/* tick init */
RT_SCHED_PRIV(thread).init_tick = tick;
RT_SCHED_PRIV(thread).remaining_tick = tick;
}
/**
* @brief This function will insert a thread to the system ready queue. The state of
* thread will be set as READY and the thread will be removed from suspend queue.
@@ -364,7 +429,7 @@ __exit:
*
* @note Please do not invoke this function in user application.
*/
void rt_schedule_insert_thread(struct rt_thread *thread)
void rt_sched_insert_thread(struct rt_thread *thread)
{
rt_base_t level;
@@ -376,33 +441,33 @@ void rt_schedule_insert_thread(struct rt_thread *thread)
/* it's current thread, it should be RUNNING thread */
if (thread == rt_current_thread)
{
thread->stat = RT_THREAD_RUNNING | (thread->stat & ~RT_THREAD_STAT_MASK);
RT_SCHED_CTX(thread).stat = RT_THREAD_RUNNING | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK);
goto __exit;
}
/* READY thread, insert to ready queue */
thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
RT_SCHED_CTX(thread).stat = RT_THREAD_READY | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK);
/* there is no time slices left(YIELD), inserting thread before ready list*/
if((thread->stat & RT_THREAD_STAT_YIELD_MASK) != 0)
if((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_YIELD_MASK) != 0)
{
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
&(thread->tlist));
rt_list_insert_before(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
}
/* there are some time slices left, inserting thread after ready list to schedule it firstly at next time*/
else
{
rt_list_insert_after(&(rt_thread_priority_table[thread->current_priority]),
&(thread->tlist));
rt_list_insert_after(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority]),
&RT_THREAD_LIST_NODE(thread));
}
LOG_D("insert thread[%.*s], the priority: %d",
RT_NAME_MAX, thread->parent.name, thread->current_priority);
RT_NAME_MAX, thread->parent.name, RT_SCHED_PRIV(rt_current_thread).current_priority);
/* set priority mask */
#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] |= thread->high_mask;
rt_thread_ready_table[RT_SCHED_PRIV(thread).number] |= RT_SCHED_PRIV(thread).high_mask;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
rt_thread_ready_priority_group |= thread->number_mask;
rt_thread_ready_priority_group |= RT_SCHED_PRIV(thread).number_mask;
__exit:
/* enable interrupt */
@@ -416,7 +481,7 @@ __exit:
*
* @note Please do not invoke this function in user application.
*/
void rt_schedule_remove_thread(struct rt_thread *thread)
void rt_sched_remove_thread(struct rt_thread *thread)
{
rt_base_t level;
@@ -427,20 +492,20 @@ void rt_schedule_remove_thread(struct rt_thread *thread)
LOG_D("remove thread[%.*s], the priority: %d",
RT_NAME_MAX, thread->parent.name,
thread->current_priority);
RT_SCHED_PRIV(rt_current_thread).current_priority);
/* remove thread from ready list */
rt_list_remove(&(thread->tlist));
if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
rt_list_remove(&RT_THREAD_LIST_NODE(thread));
if (rt_list_isempty(&(rt_thread_priority_table[RT_SCHED_PRIV(thread).current_priority])))
{
#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] &= ~thread->high_mask;
if (rt_thread_ready_table[thread->number] == 0)
rt_thread_ready_table[RT_SCHED_PRIV(thread).number] &= ~RT_SCHED_PRIV(thread).high_mask;
if (rt_thread_ready_table[RT_SCHED_PRIV(thread).number] == 0)
{
rt_thread_ready_priority_group &= ~thread->number_mask;
rt_thread_ready_priority_group &= ~RT_SCHED_PRIV(thread).number_mask;
}
#else
rt_thread_ready_priority_group &= ~thread->number_mask;
rt_thread_ready_priority_group &= ~RT_SCHED_PRIV(thread).number_mask;
#endif /* RT_THREAD_PRIORITY_MAX > 32 */
}
@@ -448,12 +513,54 @@ void rt_schedule_remove_thread(struct rt_thread *thread)
rt_hw_interrupt_enable(level);
}
#ifdef RT_USING_DEBUG
static volatile int _critical_error_occurred = 0;
void rt_exit_critical_safe(rt_base_t critical_level)
{
rt_base_t level;
/* disable interrupt */
level = rt_hw_interrupt_disable();
if (!_critical_error_occurred)
{
if (critical_level != rt_scheduler_lock_nest)
{
int dummy = 1;
_critical_error_occurred = 1;
rt_kprintf("%s: un-compatible critical level\n" \
"\tCurrent %d\n\tCaller %d\n",
__func__, rt_scheduler_lock_nest,
critical_level);
rt_backtrace();
while (dummy) ;
}
}
rt_hw_interrupt_enable(level);
rt_exit_critical();
}
#else
void rt_exit_critical_safe(rt_base_t critical_level)
{
return rt_exit_critical();
}
#endif
RTM_EXPORT(rt_exit_critical_safe);
/**
* @brief This function will lock the thread scheduler.
*/
void rt_enter_critical(void)
rt_base_t rt_enter_critical(void)
{
rt_base_t level;
rt_base_t critical_level;
/* disable interrupt */
level = rt_hw_interrupt_disable();
@@ -463,9 +570,12 @@ void rt_enter_critical(void)
* enough and does not check here
*/
rt_scheduler_lock_nest ++;
critical_level = rt_scheduler_lock_nest;
/* enable interrupt */
rt_hw_interrupt_enable(level);
return critical_level;
}
RTM_EXPORT(rt_enter_critical);
@@ -511,5 +621,10 @@ rt_uint16_t rt_critical_level(void)
}
RTM_EXPORT(rt_critical_level);
rt_err_t rt_sched_thread_bind_cpu(struct rt_thread *thread, int cpu)
{
return -RT_EINVAL;
}
/**@}*/
/**@endcond*/
+73 -51
View File
@@ -29,6 +29,8 @@
#define sig_mask(sig_no) (1u << sig_no)
#define sig_valid(sig_no) (sig_no >= 0 && sig_no < RT_SIG_MAX)
static struct rt_spinlock _thread_signal_lock = RT_SPINLOCK_INIT;
struct siginfo_node
{
siginfo_t si;
@@ -63,7 +65,7 @@ static void _signal_entry(void *parameter)
#endif /* RT_USING_SMP */
LOG_D("switch back to: 0x%08x\n", tid->sp);
tid->stat &= ~RT_THREAD_STAT_SIGNAL;
RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL;
#ifdef RT_USING_SMP
rt_hw_context_switch_to((rt_base_t)&parameter, tid);
@@ -86,16 +88,16 @@ static void _signal_deliver(rt_thread_t tid)
{
rt_base_t level;
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
/* thread is not interested in pended signals */
if (!(tid->sig_pending & tid->sig_mask))
{
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
return;
}
if ((tid->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
if ((RT_SCHED_CTX(tid).stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
{
/* resume thread to handle signal */
#ifdef RT_USING_SMART
@@ -104,9 +106,9 @@ static void _signal_deliver(rt_thread_t tid)
rt_thread_resume(tid);
#endif
/* add signal state */
tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
RT_SCHED_CTX(tid).stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
/* re-schedule */
rt_schedule();
@@ -116,9 +118,9 @@ static void _signal_deliver(rt_thread_t tid)
if (tid == rt_thread_self())
{
/* add signal state */
tid->stat |= RT_THREAD_STAT_SIGNAL;
RT_SCHED_CTX(tid).stat |= RT_THREAD_STAT_SIGNAL;
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
/* do signal action in self thread context */
if (rt_interrupt_get_nest() == 0)
@@ -126,16 +128,16 @@ static void _signal_deliver(rt_thread_t tid)
rt_thread_handle_sig(RT_TRUE);
}
}
else if (!((tid->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL))
else if (!((RT_SCHED_CTX(tid).stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL))
{
/* add signal state */
tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
RT_SCHED_CTX(tid).stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
#ifdef RT_USING_SMP
{
int cpu_id;
cpu_id = tid->oncpu;
cpu_id = RT_SCHED_CTX(tid).oncpu;
if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_hw_cpu_id()))
{
rt_uint32_t cpu_mask;
@@ -146,13 +148,13 @@ static void _signal_deliver(rt_thread_t tid)
}
#else
/* point to the signal handle entry */
tid->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
tid->sig_ret = tid->sp;
tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL,
(void *)((char *)tid->sig_ret - 32), RT_NULL);
#endif /* RT_USING_SMP */
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
LOG_D("signal stack pointer @ 0x%08x", tid->sp);
/* re-schedule */
@@ -160,7 +162,7 @@ static void _signal_deliver(rt_thread_t tid)
}
else
{
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
}
}
}
@@ -168,37 +170,38 @@ static void _signal_deliver(rt_thread_t tid)
#ifdef RT_USING_SMP
void *rt_signal_check(void* context)
{
rt_base_t level;
rt_sched_lock_level_t level;
int cpu_id;
struct rt_cpu* pcpu;
struct rt_thread *current_thread;
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
cpu_id = rt_hw_cpu_id();
pcpu = rt_cpu_index(cpu_id);
current_thread = pcpu->current_thread;
if (pcpu->irq_nest)
{
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
return context;
}
if (current_thread->cpus_lock_nest == 1)
{
if (current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
if (RT_SCHED_CTX(current_thread).stat & RT_THREAD_STAT_SIGNAL_PENDING)
{
void *sig_context;
current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
RT_SCHED_CTX(current_thread).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
sig_context = rt_hw_stack_init((void *)_signal_entry, context,
(void*)((char*)context - 32), RT_NULL);
return sig_context;
}
}
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
return context;
}
#endif /* RT_USING_SMP */
@@ -227,10 +230,14 @@ rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
if (!sig_valid(signo)) return SIG_ERR;
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
if (tid->sig_vectors == RT_NULL)
{
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
rt_thread_alloc_sig(tid);
level = rt_spin_lock_irqsave(&_thread_signal_lock);
}
if (tid->sig_vectors)
@@ -241,7 +248,7 @@ rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
else if (handler == SIG_DFL) tid->sig_vectors[signo] = _signal_default_handler;
else tid->sig_vectors[signo] = handler;
}
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
return old;
}
@@ -262,11 +269,11 @@ void rt_signal_mask(int signo)
rt_base_t level;
rt_thread_t tid = rt_thread_self();
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
tid->sig_mask &= ~sig_mask(signo);
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
}
/**
@@ -285,19 +292,19 @@ void rt_signal_unmask(int signo)
rt_base_t level;
rt_thread_t tid = rt_thread_self();
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
tid->sig_mask |= sig_mask(signo);
/* let thread handle pended signals */
if (tid->sig_mask & tid->sig_pending)
{
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
_signal_deliver(tid);
}
else
{
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
}
}
@@ -335,7 +342,7 @@ int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
/* clear siginfo to avoid unknown value */
memset(si, 0x0, sizeof(rt_siginfo_t));
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
/* already pending */
if (tid->sig_pending & *set) goto __done;
@@ -349,7 +356,7 @@ int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
/* suspend self thread */
rt_thread_suspend_with_flag(tid, RT_UNINTERRUPTIBLE);
/* set thread stat as waiting for signal */
tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT;
RT_SCHED_CTX(tid).stat |= RT_THREAD_STAT_SIGNAL_WAIT;
/* start timeout timer */
if (timeout != RT_WAITING_FOREVER)
@@ -360,21 +367,21 @@ int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
&timeout);
rt_timer_start(&(tid->thread_timer));
}
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
/* do thread scheduling */
rt_schedule();
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
/* remove signal waiting flag */
tid->stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;
RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;
/* check errno of thread */
if (tid->error == -RT_ETIMEOUT)
{
tid->error = RT_EOK;
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
/* timer timeout */
ret = -RT_ETIMEOUT;
@@ -428,7 +435,7 @@ __done:
}
__done_int:
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
__done_return:
return ret;
@@ -441,11 +448,11 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
rt_thread_t tid = rt_thread_self();
struct siginfo_node *si_node;
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
if (tid->sig_pending & tid->sig_mask)
{
/* if thread is not waiting for signal */
if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT))
if (!(RT_SCHED_CTX(tid).stat & RT_THREAD_STAT_SIGNAL_WAIT))
{
while (tid->sig_pending & tid->sig_mask)
{
@@ -464,12 +471,12 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
signo = si_node->si.si_signo;
handler = tid->sig_vectors[signo];
tid->sig_pending &= ~sig_mask(signo);
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
LOG_D("handle signal: %d, handler 0x%08x", signo, handler);
if (handler) handler(signo);
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
error = -RT_EINTR;
rt_mp_free(si_node); /* release this siginfo node */
@@ -480,7 +487,7 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
/* whether clean signal status */
if (clean_state == RT_TRUE)
{
tid->stat &= ~RT_THREAD_STAT_SIGNAL;
RT_SCHED_CTX(tid).stat &= ~RT_THREAD_STAT_SIGNAL;
}
else
{
@@ -488,12 +495,13 @@ void rt_thread_handle_sig(rt_bool_t clean_state)
}
}
}
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
}
void rt_thread_alloc_sig(rt_thread_t tid)
{
int index;
rt_bool_t need_free = RT_FALSE;
rt_base_t level;
rt_sighandler_t *vectors;
@@ -505,9 +513,23 @@ void rt_thread_alloc_sig(rt_thread_t tid)
vectors[index] = _signal_default_handler;
}
level = rt_hw_interrupt_disable();
tid->sig_vectors = vectors;
rt_hw_interrupt_enable(level);
level = rt_spin_lock_irqsave(&_thread_signal_lock);
if (tid->sig_vectors == RT_NULL)
{
tid->sig_vectors = vectors;
}
else
{
need_free = RT_TRUE;
}
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
if (need_free)
{
rt_free(vectors);
}
}
void rt_thread_free_sig(rt_thread_t tid)
@@ -516,13 +538,13 @@ void rt_thread_free_sig(rt_thread_t tid)
struct siginfo_node *si_node;
rt_sighandler_t *sig_vectors;
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
si_node = (struct siginfo_node *)tid->si_list;
tid->si_list = RT_NULL;
sig_vectors = tid->sig_vectors;
tid->sig_vectors = RT_NULL;
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
if (si_node)
{
@@ -570,7 +592,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
si.si_code = SI_USER;
si.si_value.sival_ptr = RT_NULL;
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
if (tid->sig_pending & sig_mask(sig))
{
/* whether already emits this signal? */
@@ -590,12 +612,12 @@ int rt_thread_kill(rt_thread_t tid, int sig)
if (entry->si.si_signo == sig)
{
memcpy(&(entry->si), &si, sizeof(siginfo_t));
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
return 0;
}
}
}
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
si_node = (struct siginfo_node *) rt_mp_alloc(_siginfo_pool, 0);
if (si_node)
@@ -603,7 +625,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
rt_slist_init(&(si_node->list));
memcpy(&(si_node->si), &si, sizeof(siginfo_t));
level = rt_hw_interrupt_disable();
level = rt_spin_lock_irqsave(&_thread_signal_lock);
if (tid->si_list)
{
@@ -620,7 +642,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
/* a new signal */
tid->sig_pending |= sig_mask(sig);
rt_hw_interrupt_enable(level);
rt_spin_unlock_irqrestore(&_thread_signal_lock, level);
}
else
{
+273 -356
View File
File diff suppressed because it is too large Load Diff
+88 -59
View File
@@ -20,6 +20,7 @@
* 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to timer.c
* 2022-04-19 Stanley Correct descriptions
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
* 2024-01-25 Shell add RT_TIMER_FLAG_THREAD_TIMER for timer to sync with sched
*/
#include <rtthread.h>
@@ -31,7 +32,7 @@
/* hard timer list */
static rt_list_t _timer_list[RT_TIMER_SKIP_LIST_LEVEL];
static struct rt_spinlock _hard_spinlock;
static struct rt_spinlock _htimer_lock;
#ifdef RT_USING_TIMER_SOFT
@@ -50,7 +51,7 @@ static struct rt_spinlock _hard_spinlock;
static rt_uint8_t _soft_timer_status = RT_SOFT_TIMER_IDLE;
/* soft timer list */
static rt_list_t _soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
static struct rt_spinlock _soft_spinlock;
static struct rt_spinlock _stimer_lock;
static struct rt_thread _timer_thread;
static struct rt_semaphore _soft_timer_sem;
rt_align(RT_ALIGN_SIZE)
@@ -94,6 +95,35 @@ void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer))
/**@}*/
#endif /* RT_USING_HOOK */
rt_inline struct rt_spinlock* _timerlock_idx(struct rt_timer *timer)
{
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
return &_stimer_lock;
}
else
#endif /* RT_USING_TIMER_SOFT */
{
return &_htimer_lock;
}
}
rt_inline rt_list_t* _timerhead_idx(struct rt_timer *timer)
{
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
/* insert timer to soft timer list */
return _soft_timer_list;
}
else
#endif /* RT_USING_TIMER_SOFT */
{
/* insert timer to system timer list */
return _timer_list;
}
}
/**
* @brief [internal] The init funtion of timer
@@ -280,17 +310,7 @@ rt_err_t rt_timer_detach(rt_timer_t timer)
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
RT_ASSERT(rt_object_is_systemobject(&timer->parent));
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
spinlock = &_soft_spinlock;
}
else
#endif /* RT_USING_TIMER_SOFT */
{
spinlock = &_hard_spinlock;
}
spinlock = _timerlock_idx(timer);
level = rt_spin_lock_irqsave(spinlock);
_timer_remove(timer);
@@ -325,6 +345,7 @@ RTM_EXPORT(rt_timer_detach);
*
* RT_TIMER_FLAG_HARD_TIMER Hardware timer
* RT_TIMER_FLAG_SOFT_TIMER Software timer
* RT_TIMER_FLAG_THREAD_TIMER Thread timer
*
* NOTE:
* You can use multiple values with "|" logical operator. By default, system will use the RT_TIME_FLAG_HARD_TIMER.
@@ -373,16 +394,7 @@ rt_err_t rt_timer_delete(rt_timer_t timer)
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
spinlock = &_soft_spinlock;
}
else
#endif /* RT_USING_TIMER_SOFT */
{
spinlock = &_hard_spinlock;
}
spinlock = _timerlock_idx(timer);
level = rt_spin_lock_irqsave(spinlock);
@@ -485,6 +497,8 @@ static rt_err_t _timer_start(rt_list_t *timer_list, rt_timer_t timer)
*/
rt_err_t rt_timer_start(rt_timer_t timer)
{
rt_sched_lock_level_t slvl;
int is_thread_timer = 0;
struct rt_spinlock *spinlock;
rt_list_t *timer_list;
rt_base_t level;
@@ -498,13 +512,24 @@ rt_err_t rt_timer_start(rt_timer_t timer)
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
timer_list = _soft_timer_list;
spinlock = &_soft_spinlock;
spinlock = &_stimer_lock;
}
else
#endif /* RT_USING_TIMER_SOFT */
{
timer_list = _timer_list;
spinlock = &_hard_spinlock;
spinlock = &_htimer_lock;
}
if (timer->parent.flag & RT_TIMER_FLAG_THREAD_TIMER)
{
rt_thread_t thread;
is_thread_timer = 1;
rt_sched_lock(&slvl);
thread = rt_container_of(timer, struct rt_thread, thread_timer);
RT_ASSERT(rt_object_get_type(&thread->parent) == RT_Object_Class_Thread);
rt_sched_thread_timer_start(thread);
}
level = rt_spin_lock_irqsave(spinlock);
@@ -512,17 +537,19 @@ rt_err_t rt_timer_start(rt_timer_t timer)
err = _timer_start(timer_list, timer);
#ifdef RT_USING_TIMER_SOFT
if (err == RT_EOK)
if (err == RT_EOK && (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER))
{
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
rt_sem_release(&_soft_timer_sem);
}
rt_sem_release(&_soft_timer_sem);
}
#endif /* RT_USING_TIMER_SOFT */
rt_spin_unlock_irqrestore(spinlock, level);
if (is_thread_timer)
{
rt_sched_unlock(slvl);
}
return err;
}
RTM_EXPORT(rt_timer_start);
@@ -543,16 +570,8 @@ rt_err_t rt_timer_stop(rt_timer_t timer)
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
spinlock = &_soft_spinlock;
}
else
#endif /* RT_USING_TIMER_SOFT */
{
spinlock = &_hard_spinlock;
}
spinlock = _timerlock_idx(timer);
level = rt_spin_lock_irqsave(spinlock);
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
@@ -565,6 +584,7 @@ rt_err_t rt_timer_stop(rt_timer_t timer)
_timer_remove(timer);
/* change status */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
rt_spin_unlock_irqrestore(spinlock, level);
return RT_EOK;
@@ -582,10 +602,16 @@ RTM_EXPORT(rt_timer_stop);
*/
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
{
struct rt_spinlock *spinlock;
rt_base_t level;
/* parameter check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
spinlock = _timerlock_idx(timer);
level = rt_spin_lock_irqsave(spinlock);
switch (cmd)
{
case RT_TIMER_CTRL_GET_TIME:
@@ -640,6 +666,7 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
default:
break;
}
rt_spin_unlock_irqrestore(spinlock, level);
return RT_EOK;
}
@@ -660,21 +687,23 @@ void rt_timer_check(void)
RT_ASSERT(rt_interrupt_get_nest() > 0);
LOG_D("timer check enter");
level = rt_spin_lock_irqsave(&_htimer_lock);
current_tick = rt_tick_get();
#ifdef RT_USING_SMP
/* Running on core 0 only */
if (rt_hw_cpu_id() != 0)
{
rt_spin_unlock_irqrestore(&_htimer_lock, level);
return;
}
#endif
rt_list_init(&list);
LOG_D("timer check enter");
current_tick = rt_tick_get();
level = rt_spin_lock_irqsave(&_hard_spinlock);
while (!rt_list_isempty(&_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
{
t = rt_list_entry(_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
@@ -696,7 +725,7 @@ void rt_timer_check(void)
}
/* add timer to temporary list */
rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
rt_spin_unlock_irqrestore(&_hard_spinlock, level);
rt_spin_unlock_irqrestore(&_htimer_lock, level);
/* call timeout function */
t->timeout_func(t->parameter);
@@ -705,7 +734,7 @@ void rt_timer_check(void)
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
LOG_D("current tick: %d", current_tick);
level = rt_spin_lock_irqsave(&_hard_spinlock);
level = rt_spin_lock_irqsave(&_htimer_lock);
/* Check whether the timer object is detached or started again */
if (rt_list_isempty(&list))
{
@@ -722,7 +751,7 @@ void rt_timer_check(void)
}
else break;
}
rt_spin_unlock_irqrestore(&_hard_spinlock, level);
rt_spin_unlock_irqrestore(&_htimer_lock, level);
LOG_D("timer check leave");
}
@@ -736,9 +765,9 @@ rt_tick_t rt_timer_next_timeout_tick(void)
rt_base_t level;
rt_tick_t next_timeout = RT_TICK_MAX;
level = rt_spin_lock_irqsave(&_hard_spinlock);
level = rt_spin_lock_irqsave(&_htimer_lock);
_timer_list_next_timeout(_timer_list, &next_timeout);
rt_spin_unlock_irqrestore(&_hard_spinlock, level);
rt_spin_unlock_irqrestore(&_htimer_lock, level);
return next_timeout;
}
@@ -757,7 +786,7 @@ static void _soft_timer_check(void)
rt_list_init(&list);
LOG_D("software timer check enter");
level = rt_spin_lock_irqsave(&_soft_spinlock);
level = rt_spin_lock_irqsave(&_stimer_lock);
while (!rt_list_isempty(&_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
{
@@ -785,7 +814,7 @@ static void _soft_timer_check(void)
_soft_timer_status = RT_SOFT_TIMER_BUSY;
rt_spin_unlock_irqrestore(&_soft_spinlock, level);
rt_spin_unlock_irqrestore(&_stimer_lock, level);
/* call timeout function */
t->timeout_func(t->parameter);
@@ -793,7 +822,7 @@ static void _soft_timer_check(void)
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
LOG_D("current tick: %d", current_tick);
level = rt_spin_lock_irqsave(&_soft_spinlock);
level = rt_spin_lock_irqsave(&_stimer_lock);
_soft_timer_status = RT_SOFT_TIMER_IDLE;
/* Check whether the timer object is detached or started again */
@@ -813,7 +842,7 @@ static void _soft_timer_check(void)
else break; /* not check anymore */
}
rt_spin_unlock_irqrestore(&_soft_spinlock, level);
rt_spin_unlock_irqrestore(&_stimer_lock, level);
LOG_D("software timer check leave");
}
@@ -836,9 +865,9 @@ static void _timer_thread_entry(void *parameter)
while (1)
{
/* get the next timeout tick */
level = rt_spin_lock_irqsave(&_soft_spinlock);
level = rt_spin_lock_irqsave(&_stimer_lock);
ret = _timer_list_next_timeout(_soft_timer_list, &next_timeout);
rt_spin_unlock_irqrestore(&_soft_spinlock, level);
rt_spin_unlock_irqrestore(&_stimer_lock, level);
if (ret != RT_EOK)
{
@@ -878,7 +907,7 @@ void rt_system_timer_init(void)
{
rt_list_init(_timer_list + i);
}
rt_spin_lock_init(&_hard_spinlock);
rt_spin_lock_init(&_htimer_lock);
}
/**
@@ -897,7 +926,7 @@ void rt_system_timer_thread_init(void)
{
rt_list_init(_soft_timer_list + i);
}
rt_spin_lock_init(&_soft_spinlock);
rt_spin_lock_init(&_stimer_lock);
rt_sem_init(&_soft_timer_sem, "stimer", 0, RT_IPC_FLAG_PRIO);
/* start software timer thread */
rt_thread_init(&_timer_thread,