summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShell <[email protected]>2024-05-28 14:27:55 +0800
committerGitHub <[email protected]>2024-05-28 14:27:55 +0800
commitf17f994f8c85a0ca58d42c81a14f1134af6ada91 (patch)
tree49cb8514b38fc30884553e6b572c873a09f6935c /src
parentb45fb59df2a7d938965c241431436adf77769b5b (diff)
[arm64] add hw thread self (#8942)
* [libcpu] arm64: Add hardware thread_self support This patch introduces hardware-based thread self-identification for the AArch64 architecture. It optimizes thread management by using hardware registers to store and access the current thread's pointer, reducing overhead and improving overall performance. Changes include: - Added `ARCH_USING_HW_THREAD_SELF` configuration option. - Modified `rtdef.h`, `rtsched.h` to conditionally include `critical_switch_flag` based on the new config. - Updated context management in `context_gcc.S`, `cpuport.h` to support hardware-based thread self. - Enhanced `scheduler_mp.c` and `thread.c` to leverage the new hardware thread self feature. These modifications ensure better scheduling and thread handling, particularly in multi-core environments, by minimizing the software overhead associated with thread management. Signed-off-by: Shell <[email protected]> * fixup: address suggestion * fixup: rt_current_thread as global * scheduler: add cpu object for UP scheduler Also, maintain the rt_current_thread in cpu object on UP scheduler. --------- Signed-off-by: Shell <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/cpu_up.c26
-rw-r--r--src/scheduler_mp.c77
-rw-r--r--src/scheduler_up.c30
-rw-r--r--src/thread.c18
4 files changed, 111 insertions, 40 deletions
diff --git a/src/cpu_up.c b/src/cpu_up.c
index 8a1804cf55..32825461b0 100644
--- a/src/cpu_up.c
+++ b/src/cpu_up.c
@@ -6,10 +6,14 @@
* Change Logs:
* Date Author Notes
* 2024-04-19 Shell Fixup UP irq spinlock
+ * 2024-05-22 Shell Add UP cpu object and
+ * maintain the rt_current_thread inside it
*/
#include <rthw.h>
#include <rtthread.h>
+static struct rt_cpu _cpu;
+
/**
* @brief Initialize a static spinlock object.
*
@@ -80,3 +84,25 @@ void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
rt_exit_critical_safe(critical_level);
rt_hw_interrupt_enable(level);
}
+
+/**
+ * @brief This fucntion will return current cpu object.
+ *
+ * @return Return a pointer to the current cpu object.
+ */
+struct rt_cpu *rt_cpu_self(void)
+{
+ return &_cpu;
+}
+
+/**
+ * @brief This fucntion will return the cpu object corresponding to index.
+ *
+ * @param index is the index of target cpu object.
+ *
+ * @return Return a pointer to the cpu object corresponding to index.
+ */
+struct rt_cpu *rt_cpu_index(int index)
+{
+ return index == 0 ? &_cpu : RT_NULL;
+}
diff --git a/src/scheduler_mp.c b/src/scheduler_mp.c
index c1626c5f99..7a7bd61e00 100644
--- a/src/scheduler_mp.c
+++ b/src/scheduler_mp.c
@@ -33,6 +33,7 @@
* 2023-12-10 xqyjlj use rt_hw_spinlock
* 2024-01-05 Shell Fixup of data racing in rt_critical_level
* 2024-01-18 Shell support rt_sched_thread of scheduling status for better mt protection
+ * 2024-01-18 Shell support rt_hw_thread_self to improve overall performance
*/
#include <rtthread.h>
@@ -99,6 +100,18 @@ static struct rt_spinlock _mp_scheduler_lock;
rt_hw_local_irq_enable(level); \
} while (0)
+#ifdef ARCH_USING_HW_THREAD_SELF
+#define IS_CRITICAL_SWITCH_PEND(pcpu, curthr) (RT_SCHED_CTX(curthr).critical_switch_flag)
+#define SET_CRITICAL_SWITCH_FLAG(pcpu, curthr) (RT_SCHED_CTX(curthr).critical_switch_flag = 1)
+#define CLR_CRITICAL_SWITCH_FLAG(pcpu, curthr) (RT_SCHED_CTX(curthr).critical_switch_flag = 0)
+
+#else /* !ARCH_USING_HW_THREAD_SELF */
+#define IS_CRITICAL_SWITCH_PEND(pcpu, curthr) ((pcpu)->critical_switch_flag)
+#define SET_CRITICAL_SWITCH_FLAG(pcpu, curthr) ((pcpu)->critical_switch_flag = 1)
+#define CLR_CRITICAL_SWITCH_FLAG(pcpu, curthr) ((pcpu)->critical_switch_flag = 0)
+
+#endif /* ARCH_USING_HW_THREAD_SELF */
+
static rt_uint32_t rt_thread_ready_priority_group;
#if RT_THREAD_PRIORITY_MAX > 32
/* Maximum priority level, 256 */
@@ -749,7 +762,7 @@ rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t level)
/* leaving critical region of global context since we can't schedule */
SCHEDULER_CONTEXT_UNLOCK(pcpu);
- pcpu->critical_switch_flag = 1;
+ SET_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
error = -RT_ESCHEDLOCKED;
SCHEDULER_EXIT_CRITICAL(current_thread);
@@ -757,7 +770,7 @@ rt_err_t rt_sched_unlock_n_resched(rt_sched_lock_level_t level)
else
{
/* flush critical switch flag since a scheduling is done */
- pcpu->critical_switch_flag = 0;
+ CLR_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
/* pick the highest runnable thread, and pass the control to it */
to_thread = _prepare_context_switch_locked(cpu_id, pcpu, current_thread);
@@ -828,7 +841,7 @@ void rt_schedule(void)
/* whether caller had locked the local scheduler already */
if (RT_SCHED_CTX(current_thread).critical_lock_nest > 1)
{
- pcpu->critical_switch_flag = 1;
+ SET_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
SCHEDULER_EXIT_CRITICAL(current_thread);
@@ -837,7 +850,7 @@ void rt_schedule(void)
else
{
/* flush critical switch flag since a scheduling is done */
- pcpu->critical_switch_flag = 0;
+ CLR_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
pcpu->irq_switch_flag = 0;
/**
@@ -912,13 +925,13 @@ void rt_scheduler_do_irq_switch(void *context)
/* whether caller had locked the local scheduler already */
if (RT_SCHED_CTX(current_thread).critical_lock_nest > 1)
{
- pcpu->critical_switch_flag = 1;
+ SET_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
SCHEDULER_EXIT_CRITICAL(current_thread);
}
else if (rt_atomic_load(&(pcpu->irq_nest)) == 0)
{
/* flush critical & irq switch flag since a scheduling is done */
- pcpu->critical_switch_flag = 0;
+ CLR_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
pcpu->irq_switch_flag = 0;
SCHEDULER_CONTEXT_LOCK(pcpu);
@@ -1056,6 +1069,9 @@ void rt_sched_post_ctx_switch(struct rt_thread *thread)
}
/* safe to access since irq is masked out */
pcpu->current_thread = thread;
+#ifdef ARCH_USING_HW_THREAD_SELF
+ rt_hw_thread_set_self(thread);
+#endif /* ARCH_USING_HW_THREAD_SELF */
}
#ifdef RT_DEBUGING_CRITICAL
@@ -1096,14 +1112,28 @@ void rt_exit_critical_safe(rt_base_t critical_level)
#endif /* RT_DEBUGING_CRITICAL */
RTM_EXPORT(rt_exit_critical_safe);
+#ifdef ARCH_USING_HW_THREAD_SELF
+#define FREE_THREAD_SELF(lvl)
+
+#else /* !ARCH_USING_HW_THREAD_SELF */
+#define FREE_THREAD_SELF(lvl) \
+ do \
+ { \
+ rt_hw_local_irq_enable(lvl); \
+ } while (0)
+
+#endif /* ARCH_USING_HW_THREAD_SELF */
+
/**
* @brief This function will lock the thread scheduler.
*/
rt_base_t rt_enter_critical(void)
{
- rt_base_t level;
rt_base_t critical_level;
struct rt_thread *current_thread;
+
+#ifndef ARCH_USING_HW_THREAD_SELF
+ rt_base_t level;
struct rt_cpu *pcpu;
/* disable interrupt */
@@ -1111,9 +1141,15 @@ rt_base_t rt_enter_critical(void)
pcpu = rt_cpu_self();
current_thread = pcpu->current_thread;
+
+#else /* !ARCH_USING_HW_THREAD_SELF */
+ current_thread = rt_hw_thread_self();
+
+#endif /* ARCH_USING_HW_THREAD_SELF */
+
if (!current_thread)
{
- rt_hw_local_irq_enable(level);
+ FREE_THREAD_SELF(level);
/* scheduler unavailable */
return -RT_EINVAL;
}
@@ -1122,8 +1158,7 @@ rt_base_t rt_enter_critical(void)
RT_SCHED_CTX(current_thread).critical_lock_nest++;
critical_level = RT_SCHED_CTX(current_thread).critical_lock_nest;
- /* enable interrupt */
- rt_hw_local_irq_enable(level);
+ FREE_THREAD_SELF(level);
return critical_level;
}
@@ -1134,9 +1169,11 @@ RTM_EXPORT(rt_enter_critical);
*/
void rt_exit_critical(void)
{
- rt_base_t level;
struct rt_thread *current_thread;
rt_bool_t need_resched;
+
+#ifndef ARCH_USING_HW_THREAD_SELF
+ rt_base_t level;
struct rt_cpu *pcpu;
/* disable interrupt */
@@ -1144,9 +1181,15 @@ void rt_exit_critical(void)
pcpu = rt_cpu_self();
current_thread = pcpu->current_thread;
+
+#else /* !ARCH_USING_HW_THREAD_SELF */
+ current_thread = rt_hw_thread_self();
+
+#endif /* ARCH_USING_HW_THREAD_SELF */
+
if (!current_thread)
{
- rt_hw_local_irq_enable(level);
+ FREE_THREAD_SELF(level);
return;
}
@@ -1157,11 +1200,10 @@ void rt_exit_critical(void)
if (RT_SCHED_CTX(current_thread).critical_lock_nest == 0)
{
/* is there any scheduling request unfinished? */
- need_resched = pcpu->critical_switch_flag;
- pcpu->critical_switch_flag = 0;
+ need_resched = IS_CRITICAL_SWITCH_PEND(pcpu, current_thread);
+ CLR_CRITICAL_SWITCH_FLAG(pcpu, current_thread);
- /* enable interrupt */
- rt_hw_local_irq_enable(level);
+ FREE_THREAD_SELF(level);
if (need_resched)
rt_schedule();
@@ -1171,8 +1213,7 @@ void rt_exit_critical(void)
/* each exit_critical is strictly corresponding to an enter_critical */
RT_ASSERT(RT_SCHED_CTX(current_thread).critical_lock_nest > 0);
- /* enable interrupt */
- rt_hw_local_irq_enable(level);
+ FREE_THREAD_SELF(level);
}
}
RTM_EXPORT(rt_exit_critical);
diff --git a/src/scheduler_up.c b/src/scheduler_up.c
index 822d4a8046..acc8ee8c95 100644
--- a/src/scheduler_up.c
+++ b/src/scheduler_up.c
@@ -48,7 +48,6 @@ rt_uint8_t rt_thread_ready_table[32];
extern volatile rt_uint8_t rt_interrupt_nest;
static rt_int16_t rt_scheduler_lock_nest;
-struct rt_thread *rt_current_thread = RT_NULL;
rt_uint8_t rt_current_priority;
#if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
@@ -175,7 +174,7 @@ void rt_system_scheduler_start(void)
to_thread = _scheduler_get_highest_priority_thread(&highest_ready_priority);
- rt_current_thread = to_thread;
+ rt_cpu_self()->current_thread = to_thread;
rt_sched_remove_thread(to_thread);
RT_SCHED_CTX(to_thread).stat = RT_THREAD_RUNNING;
@@ -203,6 +202,8 @@ void rt_schedule(void)
rt_base_t level;
struct rt_thread *to_thread;
struct rt_thread *from_thread;
+ /* using local variable to avoid unecessary function call */
+ struct rt_thread *curr_thread = rt_thread_self();
/* disable interrupt */
level = rt_hw_interrupt_disable();
@@ -219,15 +220,16 @@ void rt_schedule(void)
to_thread = _scheduler_get_highest_priority_thread(&highest_ready_priority);
- if ((RT_SCHED_CTX(rt_current_thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
+ if ((RT_SCHED_CTX(curr_thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
{
- if (RT_SCHED_PRIV(rt_current_thread).current_priority < highest_ready_priority)
+ if (RT_SCHED_PRIV(curr_thread).current_priority < highest_ready_priority)
{
- to_thread = rt_current_thread;
+ to_thread = curr_thread;
}
- 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)
+ else if (RT_SCHED_PRIV(curr_thread).current_priority == highest_ready_priority
+ && (RT_SCHED_CTX(curr_thread).stat & RT_THREAD_STAT_YIELD_MASK) == 0)
{
- to_thread = rt_current_thread;
+ to_thread = curr_thread;
}
else
{
@@ -235,12 +237,12 @@ void rt_schedule(void)
}
}
- if (to_thread != rt_current_thread)
+ if (to_thread != curr_thread)
{
/* if the destination thread is not the same as current thread */
rt_current_priority = (rt_uint8_t)highest_ready_priority;
- from_thread = rt_current_thread;
- rt_current_thread = to_thread;
+ from_thread = curr_thread;
+ rt_cpu_self()->current_thread = to_thread;
RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));
@@ -282,11 +284,11 @@ void rt_schedule(void)
#ifdef RT_USING_SIGNALS
/* check stat of thread for signal */
level = rt_hw_interrupt_disable();
- if (RT_SCHED_CTX(rt_current_thread).stat & RT_THREAD_STAT_SIGNAL_PENDING)
+ if (RT_SCHED_CTX(curr_thread).stat & RT_THREAD_STAT_SIGNAL_PENDING)
{
extern void rt_thread_handle_sig(rt_bool_t clean_state);
- RT_SCHED_CTX(rt_current_thread).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
+ RT_SCHED_CTX(curr_thread).stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
rt_hw_interrupt_enable(level);
@@ -310,8 +312,8 @@ void rt_schedule(void)
}
else
{
- 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);
+ rt_sched_remove_thread(curr_thread);
+ RT_SCHED_CTX(curr_thread).stat = RT_THREAD_RUNNING | (RT_SCHED_CTX(curr_thread).stat & ~RT_THREAD_STAT_MASK);
}
}
}
diff --git a/src/thread.c b/src/thread.c
index 8d4752409d..1369b7560a 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -355,20 +355,22 @@ RTM_EXPORT(rt_thread_init);
*/
rt_thread_t rt_thread_self(void)
{
-#ifdef RT_USING_SMP
- rt_base_t lock;
+#ifndef RT_USING_SMP
+ return rt_cpu_self()->current_thread;
+
+#elif defined (ARCH_USING_HW_THREAD_SELF)
+ return rt_hw_thread_self();
+
+#else /* !ARCH_USING_HW_THREAD_SELF */
rt_thread_t self;
+ rt_base_t lock;
lock = rt_hw_local_irq_disable();
self = rt_cpu_self()->current_thread;
rt_hw_local_irq_enable(lock);
- return self;
-
-#else /* !RT_USING_SMP */
- extern rt_thread_t rt_current_thread;
- return rt_current_thread;
-#endif /* RT_USING_SMP */
+ return self;
+#endif /* ARCH_USING_HW_THREAD_SELF */
}
RTM_EXPORT(rt_thread_self);