summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxph <[email protected]>2020-04-09 16:35:28 +0800
committerGitHub <[email protected]>2020-04-09 16:35:28 +0800
commitca7f01d79b3e0a997c771cec298e4ebd65b75809 (patch)
tree3d2c48aae7203b14038ba7b98b500b5343ed7f2a /src
parentf763f8e7284b0492c5a65ad0abf94ee1963d7dcc (diff)
parentbaa3145bfe61b3330b6a160523cc5470fa5db3a7 (diff)
Merge pull request #1 from RT-Thread/master
sync rtt
Diffstat (limited to 'src')
-rw-r--r--src/Kconfig48
-rw-r--r--src/SConscript17
-rw-r--r--src/clock.c30
-rw-r--r--src/components.c29
-rw-r--r--src/cpu.c188
-rw-r--r--src/device.c16
-rw-r--r--src/idle.c84
-rw-r--r--src/ipc.c253
-rw-r--r--src/irq.c17
-rw-r--r--src/kservice.c180
-rw-r--r--src/mem.c62
-rw-r--r--src/memheap.c6
-rw-r--r--src/mempool.c27
-rw-r--r--src/object.c23
-rw-r--r--src/scheduler.c778
-rw-r--r--src/signal.c211
-rw-r--r--src/slab.c44
-rw-r--r--src/thread.c203
-rw-r--r--src/timer.c62
19 files changed, 1777 insertions, 501 deletions
diff --git a/src/Kconfig b/src/Kconfig
index d3889f4211..63a7a67887 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -8,6 +8,31 @@ config RT_NAME_MAX
Each kernel object, such as thread, timer, semaphore etc, has a name,
the RT_NAME_MAX is the maximal size of this object name.
+config RT_USING_ARCH_DATA_TYPE
+ bool "Use the data types defined in ARCH_CPU"
+ default n
+ help
+ For the data type like, `rt_uint8/int8_t, rt_uint16/int16_t, rt_uint32/int32_t`,
+ BSP can define these basic data types in ARCH_CPU level.
+
+ Please re-define these data types in rtconfig_project.h file.
+
+config RT_USING_SMP
+ bool "Enable SMP(Symmetric multiprocessing)"
+ default n
+ help
+ This option should be selected by machines which have an SMP-
+ capable CPU.
+ The only effect of this option is to make the SMP-related
+ options available to the user for configuration.
+
+config RT_CPUS_NR
+ int "Number of CPUs"
+ default 2
+ depends on RT_USING_SMP
+ help
+ Number of CPUs in the system
+
config RT_ALIGN_SIZE
int "Alignment size for CPU architecture data access"
default 4
@@ -51,13 +76,18 @@ config RT_USING_OVERFLOW_CHECK
config RT_USING_HOOK
bool "Enable system hook"
default y
+ select RT_USING_IDLE_HOOK
help
Enable the hook function when system running, such as idle thread hook,
thread context switch etc.
- if RT_USING_HOOK
- config RT_IDEL_HOOK_LIST_SIZE
- int "The max size of idel hook list"
+config RT_USING_IDLE_HOOK
+ bool "Enable IDLE Task hook"
+ default y if RT_USING_HOOK
+
+ if RT_USING_IDLE_HOOK
+ config RT_IDLE_HOOK_LIST_SIZE
+ int "The max size of idle hook list"
default 4
range 1 16
help
@@ -70,7 +100,7 @@ config IDLE_THREAD_STACK_SIZE
config RT_USING_TIMER_SOFT
bool "Enable software timer with a timer thread"
- default n
+ default y
help
the timeout function context of soft-timer is under a high priority timer
thread.
@@ -92,6 +122,10 @@ menuconfig RT_DEBUG
if RT_DEBUG
+config RT_DEBUG_COLOR
+ bool "Enable color debugging log"
+ default n
+
config RT_DEBUG_INIT_CONFIG
bool "Enable debugging of components initialization"
default n
@@ -295,4 +329,10 @@ menu "Kernel Device Object"
endmenu
+config RT_VER_NUM
+ hex
+ default 0x40003
+ help
+ RT-Thread version number
+
endmenu
diff --git a/src/SConscript b/src/SConscript
index bb38baa6bd..82c3b8aaf1 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -5,18 +5,6 @@ from building import *
src = Glob('*.c')
CPPPATH = [RTT_ROOT + '/include']
-if rtconfig.CROSS_TOOL == 'keil':
- # add more link flags for module and components_init.
- LINKFLAGS = ''
- if GetDepend('RT_USING_MODULE'):
- LINKFLAGS += ' --keep *.o(RTMSymTab) '
- if GetDepend('RT_USING_COMPONENTS_INIT'):
- LINKFLAGS += ' --keep *.o(.rti_fn.*) '
-else:
- LINKFLAGS = ''
-
-if GetDepend('RT_USING_COMPONENTS_INIT') == False:
- SrcRemove(src, ['components.c'])
if GetDepend('RT_USING_MODULE') == False:
SrcRemove(src, ['module.c'])
@@ -38,6 +26,9 @@ if GetDepend('RT_USING_MEMHEAP') == False:
if GetDepend('RT_USING_DEVICE') == False:
SrcRemove(src, ['device.c'])
-group = DefineGroup('Kernel', src, depend = [''], CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS)
+if GetDepend('RT_USING_SMP') == False:
+ SrcRemove(src, ['cpu.c'])
+
+group = DefineGroup('Kernel', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/src/clock.c b/src/clock.c
index 651465e0a8..97a09ddeaf 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -12,17 +12,20 @@
* 2010-05-20 Bernard fix the tick exceeds the maximum limits
* 2010-07-13 Bernard fix rt_tick_from_millisecond issue found by kuronca
* 2011-06-26 Bernard add rt_tick_set function.
+ * 2018-11-22 Jesven add per cpu tick
*/
#include <rthw.h>
#include <rtthread.h>
+#ifdef RT_USING_SMP
+#define rt_tick rt_cpu_index(0)->tick
+#else
static rt_tick_t rt_tick = 0;
-
-extern void rt_timer_check(void);
+#endif
/**
- * This function will init system tick and set it to zero.
+ * This function will initialize system tick and set it to zero.
* @ingroup SystemInit
*
* @deprecated since 1.1.0, this function does not need to be invoked
@@ -71,7 +74,11 @@ void rt_tick_increase(void)
struct rt_thread *thread;
/* increase the global tick */
+#ifdef RT_USING_SMP
+ rt_cpu_self()->tick ++;
+#else
++ rt_tick;
+#endif
/* check time slice */
thread = rt_thread_self();
@@ -82,6 +89,8 @@ void rt_tick_increase(void)
/* change to initialized tick */
thread->remaining_tick = thread->init_tick;
+ thread->stat |= RT_THREAD_STAT_YIELD;
+
/* yield */
rt_thread_yield();
}
@@ -100,15 +109,20 @@ void rt_tick_increase(void)
*
* @return the calculated tick
*/
-int rt_tick_from_millisecond(rt_int32_t ms)
+rt_tick_t rt_tick_from_millisecond(rt_int32_t ms)
{
- int tick;
+ rt_tick_t tick;
if (ms < 0)
- tick = RT_WAITING_FOREVER;
+ {
+ tick = (rt_tick_t)RT_WAITING_FOREVER;
+ }
else
- tick = (RT_TICK_PER_SECOND * ms + 999) / 1000;
-
+ {
+ tick = RT_TICK_PER_SECOND * (ms / 1000);
+ tick += (RT_TICK_PER_SECOND * (ms % 1000) + 999) / 1000;
+ }
+
/* return the calculated tick */
return tick;
}
diff --git a/src/components.c b/src/components.c
index 679a88ef11..e7824b65ef 100644
--- a/src/components.c
+++ b/src/components.c
@@ -14,6 +14,7 @@
* 2015-05-04 Bernard Rename it to components.c because compiling issue
* in some IDEs.
* 2015-07-29 Arda.Fu Add support to use RT_USING_USER_MAIN with IAR
+ * 2018-11-22 Jesven Add secondary cpu boot up
*/
#include <rthw.h>
@@ -44,7 +45,7 @@
*
* rti_end --> 6.end
*
- * These automatically initializaiton, the driver or component initial function must
+ * These automatically initialization, the driver or component initial function must
* be defined with:
* INIT_BOARD_EXPORT(fn);
* INIT_DEVICE_EXPORT(fn);
@@ -91,7 +92,7 @@ void rt_components_board_init(void)
rt_kprintf(":%d done\n", result);
}
#else
- const init_fn_t *fn_ptr;
+ volatile const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++)
{
@@ -109,7 +110,7 @@ void rt_components_init(void)
int result;
const struct rt_init_desc *desc;
- rt_kprintf("do components intialization.\n");
+ rt_kprintf("do components initialization.\n");
for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++)
{
rt_kprintf("initialize %s", desc->fn_name);
@@ -117,7 +118,7 @@ void rt_components_init(void)
rt_kprintf(":%d done\n", result);
}
#else
- const init_fn_t *fn_ptr;
+ volatile const init_fn_t *fn_ptr;
for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++)
{
@@ -125,6 +126,7 @@ void rt_components_init(void)
}
#endif
}
+#endif /* RT_USING_COMPONENTS_INIT */
#ifdef RT_USING_USER_MAIN
@@ -137,7 +139,6 @@ extern int $Super$$main(void);
/* re-define main function */
int $Sub$$main(void)
{
- rt_hw_interrupt_disable();
rtthread_startup();
return 0;
}
@@ -149,16 +150,13 @@ int __low_level_init(void)
{
// call IAR table copy function.
__iar_data_init3();
- rt_hw_interrupt_disable();
rtthread_startup();
return 0;
}
#elif defined(__GNUC__)
-extern int main(void);
/* Add -eentry to arm-none-eabi-gcc argument */
int entry(void)
{
- rt_hw_interrupt_disable();
rtthread_startup();
return 0;
}
@@ -177,9 +175,13 @@ void main_thread_entry(void *parameter)
extern int main(void);
extern int $Super$$main(void);
+#ifdef RT_USING_COMPONENTS_INIT
/* RT-Thread components initialization */
rt_components_init();
-
+#endif
+#ifdef RT_USING_SMP
+ rt_hw_secondary_cpu_up();
+#endif
/* invoke system main function */
#if defined(__CC_ARM) || defined(__CLANG_ARM)
$Super$$main(); /* for ARMCC. */
@@ -203,7 +205,7 @@ void rt_application_init(void)
result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,
main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);
RT_ASSERT(result == RT_EOK);
-
+
/* if not define RT_USING_HEAP, using to eliminate the warning */
(void)result;
#endif
@@ -215,7 +217,7 @@ int rtthread_startup(void)
{
rt_hw_interrupt_disable();
- /* board level initalization
+ /* board level initialization
* NOTE: please initialize heap inside board initialization.
*/
rt_hw_board_init();
@@ -243,6 +245,10 @@ int rtthread_startup(void)
/* idle thread initialization */
rt_thread_idle_init();
+#ifdef RT_USING_SMP
+ rt_hw_spin_lock(&_cpus_lock);
+#endif /*RT_USING_SMP*/
+
/* start scheduler */
rt_system_scheduler_start();
@@ -250,4 +256,3 @@ int rtthread_startup(void)
return 0;
}
#endif
-#endif
diff --git a/src/cpu.c b/src/cpu.c
new file mode 100644
index 0000000000..96e585713b
--- /dev/null
+++ b/src/cpu.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2018-10-30 Bernard The first version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+
+#ifdef RT_USING_SMP
+static struct rt_cpu rt_cpus[RT_CPUS_NR];
+rt_hw_spinlock_t _cpus_lock;
+
+/*
+ * disable scheduler
+ */
+static void rt_preempt_disable(void)
+{
+ register rt_base_t level;
+ struct rt_thread *current_thread;
+
+ /* disable interrupt */
+ level = rt_hw_local_irq_disable();
+
+ current_thread = rt_thread_self();
+ if (!current_thread)
+ {
+ rt_hw_local_irq_enable(level);
+ return;
+ }
+
+ /* lock scheduler for local cpu */
+ current_thread->scheduler_lock_nest ++;
+
+ /* enable interrupt */
+ rt_hw_local_irq_enable(level);
+}
+
+/*
+ * enable scheduler
+ */
+static void rt_preempt_enable(void)
+{
+ register rt_base_t level;
+ struct rt_thread *current_thread;
+
+ /* disable interrupt */
+ level = rt_hw_local_irq_disable();
+
+ current_thread = rt_thread_self();
+ if (!current_thread)
+ {
+ rt_hw_local_irq_enable(level);
+ return;
+ }
+
+ /* unlock scheduler for local cpu */
+ current_thread->scheduler_lock_nest --;
+
+ rt_schedule();
+ /* enable interrupt */
+ rt_hw_local_irq_enable(level);
+}
+
+void rt_spin_lock_init(struct rt_spinlock *lock)
+{
+ rt_hw_spin_lock_init(&lock->lock);
+}
+RTM_EXPORT(rt_spin_lock_init)
+
+void rt_spin_lock(struct rt_spinlock *lock)
+{
+ rt_preempt_disable();
+ rt_hw_spin_lock(&lock->lock);
+}
+RTM_EXPORT(rt_spin_lock)
+
+void rt_spin_unlock(struct rt_spinlock *lock)
+{
+ rt_hw_spin_unlock(&lock->lock);
+ rt_preempt_enable();
+}
+RTM_EXPORT(rt_spin_unlock)
+
+rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock)
+{
+ unsigned long level;
+
+ rt_preempt_disable();
+
+ level = rt_hw_local_irq_disable();
+ rt_hw_spin_lock(&lock->lock);
+
+ return level;
+}
+RTM_EXPORT(rt_spin_lock_irqsave)
+
+void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
+{
+ rt_hw_spin_unlock(&lock->lock);
+ rt_hw_local_irq_enable(level);
+
+ rt_preempt_enable();
+}
+RTM_EXPORT(rt_spin_unlock_irqrestore)
+
+/**
+ * This fucntion will return current cpu.
+ */
+struct rt_cpu *rt_cpu_self(void)
+{
+ return &rt_cpus[rt_hw_cpu_id()];
+}
+
+struct rt_cpu *rt_cpu_index(int index)
+{
+ return &rt_cpus[index];
+}
+
+/**
+ * This function will lock all cpus's scheduler and disable local irq.
+ */
+rt_base_t rt_cpus_lock(void)
+{
+ rt_base_t level;
+ struct rt_cpu* pcpu;
+
+ level = rt_hw_local_irq_disable();
+
+ pcpu = rt_cpu_self();
+ if (pcpu->current_thread != RT_NULL)
+ {
+ register rt_ubase_t lock_nest = pcpu->current_thread->cpus_lock_nest;
+
+ pcpu->current_thread->cpus_lock_nest++;
+ if (lock_nest == 0)
+ {
+ pcpu->current_thread->scheduler_lock_nest++;
+ rt_hw_spin_lock(&_cpus_lock);
+ }
+ }
+
+ return level;
+}
+RTM_EXPORT(rt_cpus_lock);
+
+/**
+ * This function will restore all cpus's scheduler and restore local irq.
+ */
+void rt_cpus_unlock(rt_base_t level)
+{
+ struct rt_cpu* pcpu = rt_cpu_self();
+
+ if (pcpu->current_thread != RT_NULL)
+ {
+ pcpu->current_thread->cpus_lock_nest--;
+
+ if (pcpu->current_thread->cpus_lock_nest == 0)
+ {
+ pcpu->current_thread->scheduler_lock_nest--;
+ rt_hw_spin_unlock(&_cpus_lock);
+ }
+ }
+ rt_hw_local_irq_enable(level);
+}
+RTM_EXPORT(rt_cpus_unlock);
+
+/**
+ * This function is invoked by scheduler.
+ * It will restore the lock state to whatever the thread's counter expects.
+ * If target thread not locked the cpus then unlock the cpus lock.
+ */
+void rt_cpus_lock_status_restore(struct rt_thread *thread)
+{
+ struct rt_cpu* pcpu = rt_cpu_self();
+
+ pcpu->current_thread = thread;
+ if (!thread->cpus_lock_nest)
+ {
+ rt_hw_spin_unlock(&_cpus_lock);
+ }
+}
+RTM_EXPORT(rt_cpus_lock_status_restore);
+
+#endif
diff --git a/src/device.c b/src/device.c
index 51fc6176a6..32c06b380c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -95,7 +95,7 @@ RTM_EXPORT(rt_device_unregister);
* @return the error code, RT_EOK on successfully.
*
* @deprecated since 1.2.x, this function is not needed because the initialization
- * of a device is performed when applicaiton opens it.
+ * of a device is performed when application opens it.
*/
rt_err_t rt_device_init_all(void)
{
@@ -162,7 +162,7 @@ rt_device_t rt_device_create(int type, int attach_size)
size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE);
attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE);
- /* use the totoal size */
+ /* use the total size */
size += attach_size;
device = (rt_device_t)rt_malloc(size);
@@ -208,7 +208,7 @@ rt_err_t rt_device_init(rt_device_t dev)
RT_ASSERT(dev != RT_NULL);
- /* get device init handler */
+ /* get device_init handler */
if (device_init != RT_NULL)
{
if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
@@ -269,7 +269,7 @@ rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
return -RT_EBUSY;
}
- /* call device open interface */
+ /* call device_open interface */
if (device_open != RT_NULL)
{
result = device_open(dev, oflag);
@@ -317,7 +317,7 @@ rt_err_t rt_device_close(rt_device_t dev)
if (dev->ref_count != 0)
return RT_EOK;
- /* call device close interface */
+ /* call device_close interface */
if (device_close != RT_NULL)
{
result = device_close(dev);
@@ -357,7 +357,7 @@ rt_size_t rt_device_read(rt_device_t dev,
return 0;
}
- /* call device read interface */
+ /* call device_read interface */
if (device_read != RT_NULL)
{
return device_read(dev, pos, buffer, size);
@@ -396,7 +396,7 @@ rt_size_t rt_device_write(rt_device_t dev,
return 0;
}
- /* call device write interface */
+ /* call device_write interface */
if (device_write != RT_NULL)
{
return device_write(dev, pos, buffer, size);
@@ -423,7 +423,7 @@ rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
- /* call device write interface */
+ /* call device_write interface */
if (device_control != RT_NULL)
{
return device_control(dev, cmd, arg);
diff --git a/src/idle.c b/src/idle.c
index ec7d6bea6e..99db64f571 100644
--- a/src/idle.c
+++ b/src/idle.c
@@ -13,6 +13,8 @@
* 2016-08-09 ArdaFu add method to get the handler of the idle thread.
* 2018-02-07 Bernard lock scheduler to protect tid->cleanup.
* 2018-07-14 armink add idle hook list
+ * 2018-11-22 Jesven add per cpu idle task
+ * combine the code of primary and secondary cpu
*/
#include <rthw.h>
@@ -36,19 +38,24 @@
#endif
#endif
-static struct rt_thread idle;
-ALIGN(RT_ALIGN_SIZE)
-static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE];
+#ifdef RT_USING_SMP
+#define _CPUS_NR RT_CPUS_NR
+#else
+#define _CPUS_NR 1
+#endif
extern rt_list_t rt_thread_defunct;
-#ifdef RT_USING_IDLE_HOOK
+static struct rt_thread idle[_CPUS_NR];
+ALIGN(RT_ALIGN_SIZE)
+static rt_uint8_t rt_thread_stack[_CPUS_NR][IDLE_THREAD_STACK_SIZE];
-#ifndef RT_IDEL_HOOK_LIST_SIZE
-#define RT_IDEL_HOOK_LIST_SIZE 4
+#ifdef RT_USING_IDLE_HOOK
+#ifndef RT_IDLE_HOOK_LIST_SIZE
+#define RT_IDLE_HOOK_LIST_SIZE 4
#endif
-static void (*idle_hook_list[RT_IDEL_HOOK_LIST_SIZE])();
+static void (*idle_hook_list[RT_IDLE_HOOK_LIST_SIZE])(void);
/**
* @ingroup Hook
@@ -71,7 +78,7 @@ rt_err_t rt_thread_idle_sethook(void (*hook)(void))
/* disable interrupt */
level = rt_hw_interrupt_disable();
- for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
+ for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] == RT_NULL)
{
@@ -103,7 +110,7 @@ rt_err_t rt_thread_idle_delhook(void (*hook)(void))
/* disable interrupt */
level = rt_hw_interrupt_disable();
- for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
+ for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] == hook)
{
@@ -186,6 +193,8 @@ void rt_thread_idle_excute(void)
/* if it's a system object, not delete it */
if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
{
+ /* detach this object */
+ rt_object_detach((rt_object_t)thread);
/* unlock scheduler */
rt_exit_critical();
@@ -219,17 +228,25 @@ void rt_thread_idle_excute(void)
}
}
+extern void rt_system_power_manager(void);
static void rt_thread_idle_entry(void *parameter)
{
-#ifdef RT_USING_IDLE_HOOK
- rt_size_t i;
+#ifdef RT_USING_SMP
+ if (rt_hw_cpu_id() != 0)
+ {
+ while (1)
+ {
+ rt_hw_secondary_cpu_idle_exec();
+ }
+ }
#endif
while (1)
{
-
#ifdef RT_USING_IDLE_HOOK
- for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++)
+ rt_size_t i;
+
+ for (i = 0; i < RT_IDLE_HOOK_LIST_SIZE; i++)
{
if (idle_hook_list[i] != RT_NULL)
{
@@ -239,6 +256,9 @@ static void rt_thread_idle_entry(void *parameter)
#endif
rt_thread_idle_excute();
+#ifdef RT_USING_PM
+ rt_system_power_manager();
+#endif
}
}
@@ -251,18 +271,26 @@ static void rt_thread_idle_entry(void *parameter)
*/
void rt_thread_idle_init(void)
{
- /* initialize thread */
- rt_thread_init(&idle,
- "tidle",
- rt_thread_idle_entry,
- RT_NULL,
- &rt_thread_stack[0],
- sizeof(rt_thread_stack),
- RT_THREAD_PRIORITY_MAX - 1,
- 32);
+ rt_ubase_t i;
+ char tidle_name[RT_NAME_MAX];
- /* startup */
- rt_thread_startup(&idle);
+ for (i = 0; i < _CPUS_NR; i++)
+ {
+ rt_sprintf(tidle_name, "tidle%d", i);
+ rt_thread_init(&idle[i],
+ tidle_name,
+ rt_thread_idle_entry,
+ RT_NULL,
+ &rt_thread_stack[i][0],
+ sizeof(rt_thread_stack[i]),
+ RT_THREAD_PRIORITY_MAX - 1,
+ 32);
+#ifdef RT_USING_SMP
+ rt_thread_control(&idle[i], RT_THREAD_CTRL_BIND_CPU, (void*)i);
+#endif
+ /* startup */
+ rt_thread_startup(&idle[i]);
+ }
}
/**
@@ -273,5 +301,11 @@ void rt_thread_idle_init(void)
*/
rt_thread_t rt_thread_idle_gethandler(void)
{
- return (rt_thread_t)(&idle);
+#ifdef RT_USING_SMP
+ register int id = rt_hw_cpu_id();
+#else
+ register int id = 0;
+#endif
+
+ return (rt_thread_t)(&idle[id]);
}
diff --git a/src/ipc.c b/src/ipc.c
index 56045911a8..e6955bae37 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -32,6 +32,8 @@
* 2010-11-10 Bernard add IPC reset command implementation.
* 2011-12-18 Bernard add more parameter checking in message queue
* 2013-09-14 Grissiom add an option check in rt_event_recv
+ * 2018-10-02 Bernard add 64bit support for mailbox
+ * 2019-09-16 tyx add send wait support for message queue
*/
#include <rtthread.h>
@@ -58,7 +60,7 @@ extern void (*rt_object_put_hook)(struct rt_object *object);
*/
rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
{
- /* init ipc object */
+ /* initialize ipc object */
rt_list_init(&(ipc->suspend_thread));
return RT_EOK;
@@ -157,13 +159,13 @@ rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
struct rt_thread *thread;
register rt_ubase_t temp;
- /* wakeup all suspend threads */
+ /* wakeup all suspended threads */
while (!rt_list_isempty(list))
{
/* disable interrupt */
temp = rt_hw_interrupt_disable();
- /* get next suspend thread */
+ /* get next suspended thread */
thread = rt_list_entry(list->next, struct rt_thread, tlist);
/* set error code to RT_ERROR */
thread->error = -RT_ERROR;
@@ -171,7 +173,7 @@ rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
/*
* resume thread
* In rt_thread_resume function, it will remove current thread from
- * suspend list
+ * suspended list
*/
rt_thread_resume(thread);
@@ -189,7 +191,7 @@ rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list)
*
* @param sem the semaphore object
* @param name the name of semaphore
- * @param value the init value of semaphore
+ * @param value the initial value of semaphore
* @param flag the flag of semaphore
*
* @return the operation status, RT_EOK on successful
@@ -200,15 +202,16 @@ rt_err_t rt_sem_init(rt_sem_t sem,
rt_uint8_t flag)
{
RT_ASSERT(sem != RT_NULL);
+ RT_ASSERT(value < 0x10000U);
- /* init object */
+ /* initialize object */
rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(sem->parent));
- /* set init value */
- sem->value = value;
+ /* set initial value */
+ sem->value = (rt_uint16_t)value;
/* set parent */
sem->parent.parent.flag = flag;
@@ -233,7 +236,7 @@ rt_err_t rt_sem_detach(rt_sem_t sem)
RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent));
- /* wakeup all suspend threads */
+ /* wakeup all suspended threads */
rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
/* detach semaphore object */
@@ -248,7 +251,7 @@ RTM_EXPORT(rt_sem_detach);
* This function will create a semaphore from system resource
*
* @param name the name of semaphore
- * @param value the init value of semaphore
+ * @param value the initial value of semaphore
* @param flag the flag of semaphore
*
* @return the created semaphore, RT_NULL on error happen
@@ -260,16 +263,17 @@ rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
rt_sem_t sem;
RT_DEBUG_NOT_IN_INTERRUPT;
+ RT_ASSERT(value < 0x10000U);
/* allocate object */
sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
if (sem == RT_NULL)
return sem;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(sem->parent));
- /* set init value */
+ /* set initial value */
sem->value = value;
/* set parent */
@@ -297,7 +301,7 @@ rt_err_t rt_sem_delete(rt_sem_t sem)
RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent) == RT_FALSE);
- /* wakeup all suspend threads */
+ /* wakeup all suspended threads */
rt_ipc_list_resume_all(&(sem->parent.suspend_thread));
/* delete semaphore object */
@@ -486,10 +490,10 @@ rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg)
if (cmd == RT_IPC_CMD_RESET)
{
- rt_uint32_t value;
+ rt_ubase_t value;
/* get value */
- value = (rt_uint32_t)arg;
+ value = (rt_ubase_t)arg;
/* disable interrupt */
level = rt_hw_interrupt_disable();
@@ -528,10 +532,10 @@ rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)
/* parameter check */
RT_ASSERT(mutex != RT_NULL);
- /* init object */
+ /* initialize object */
rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name);
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(mutex->parent));
mutex->value = 1;
@@ -562,7 +566,7 @@ rt_err_t rt_mutex_detach(rt_mutex_t mutex)
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent));
- /* wakeup all suspend threads */
+ /* wakeup all suspended threads */
rt_ipc_list_resume_all(&(mutex->parent.suspend_thread));
/* detach semaphore object */
@@ -594,7 +598,7 @@ rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
if (mutex == RT_NULL)
return mutex;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(mutex->parent));
mutex->value = 1;
@@ -627,10 +631,10 @@ rt_err_t rt_mutex_delete(rt_mutex_t mutex)
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent) == RT_FALSE);
- /* wakeup all suspend threads */
+ /* wakeup all suspended threads */
rt_ipc_list_resume_all(&(mutex->parent.suspend_thread));
- /* delete semaphore object */
+ /* delete mutex object */
rt_object_delete(&(mutex->parent.parent));
return RT_EOK;
@@ -750,8 +754,8 @@ __again:
if (thread->error != RT_EOK)
{
- /* interrupt by signal, try it again */
- if (thread->error == -RT_EINTR) goto __again;
+ /* interrupt by signal, try it again */
+ if (thread->error == -RT_EINTR) goto __again;
/* return error */
return thread->error;
@@ -913,16 +917,16 @@ rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)
/* parameter check */
RT_ASSERT(event != RT_NULL);
- /* init object */
+ /* initialize object */
rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);
/* set parent flag */
event->parent.parent.flag = flag;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(event->parent));
- /* init event */
+ /* initialize event */
event->set = 0;
return RT_EOK;
@@ -976,10 +980,10 @@ rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
/* set parent */
event->parent.parent.flag = flag;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(event->parent));
- /* init event */
+ /* initialize event */
event->set = 0;
return event;
@@ -1046,7 +1050,7 @@ rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
event->set |= set;
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(event->parent.parent)));
-
+
if (!rt_list_isempty(&event->parent.suspend_thread))
{
/* search thread list to resume thread */
@@ -1069,7 +1073,7 @@ rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
{
if (thread->event_set & event->set)
{
- /* save recieved event set */
+ /* save the received event set */
thread->event_set = thread->event_set & event->set;
/* received an OR event */
@@ -1139,7 +1143,7 @@ rt_err_t rt_event_recv(rt_event_t event,
if (set == 0)
return -RT_ERROR;
- /* init status */
+ /* initialize status */
status = -RT_ERROR;
/* get current thread */
thread = rt_thread_self();
@@ -1249,7 +1253,7 @@ rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg)
/* parameter check */
RT_ASSERT(event != RT_NULL);
RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
-
+
if (cmd == RT_IPC_CMD_RESET)
{
/* disable interrupt */
@@ -1258,7 +1262,7 @@ rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg)
/* resume all waiting thread */
rt_ipc_list_resume_all(&event->parent.suspend_thread);
- /* init event set */
+ /* initialize event set */
event->set = 0;
/* enable interrupt */
@@ -1295,23 +1299,23 @@ rt_err_t rt_mb_init(rt_mailbox_t mb,
{
RT_ASSERT(mb != RT_NULL);
- /* init object */
+ /* initialize object */
rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name);
/* set parent flag */
mb->parent.parent.flag = flag;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(mb->parent));
- /* init mailbox */
- mb->msg_pool = msgpool;
+ /* initialize mailbox */
+ mb->msg_pool = (rt_ubase_t *)msgpool;
mb->size = size;
mb->entry = 0;
mb->in_offset = 0;
mb->out_offset = 0;
- /* init an additional list of sender suspend thread */
+ /* initialize an additional list of sender suspend thread */
rt_list_init(&(mb->suspend_sender_thread));
return RT_EOK;
@@ -1368,12 +1372,12 @@ rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
/* set parent */
mb->parent.parent.flag = flag;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(mb->parent));
- /* init mailbox */
+ /* initialize mailbox */
mb->size = size;
- mb->msg_pool = RT_KERNEL_MALLOC(mb->size * sizeof(rt_uint32_t));
+ mb->msg_pool = (rt_ubase_t *)RT_KERNEL_MALLOC(mb->size * sizeof(rt_ubase_t));
if (mb->msg_pool == RT_NULL)
{
/* delete mailbox object */
@@ -1385,7 +1389,7 @@ rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
mb->in_offset = 0;
mb->out_offset = 0;
- /* init an additional list of sender suspend thread */
+ /* initialize an additional list of sender suspend thread */
rt_list_init(&(mb->suspend_sender_thread));
return mb;
@@ -1436,7 +1440,7 @@ RTM_EXPORT(rt_mb_delete);
* @return the error code
*/
rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
- rt_uint32_t value,
+ rt_ubase_t value,
rt_int32_t timeout)
{
struct rt_thread *thread;
@@ -1567,7 +1571,7 @@ RTM_EXPORT(rt_mb_send_wait);
*
* @return the error code
*/
-rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value)
+rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value)
{
return rt_mb_send_wait(mb, value, 0);
}
@@ -1583,7 +1587,7 @@ RTM_EXPORT(rt_mb_send);
*
* @return the error code
*/
-rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_uint32_t *value, rt_int32_t timeout)
+rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
{
struct rt_thread *thread;
register rt_ubase_t temp;
@@ -1787,39 +1791,42 @@ rt_err_t rt_mq_init(rt_mq_t mq,
/* parameter check */
RT_ASSERT(mq != RT_NULL);
- /* init object */
+ /* initialize object */
rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name);
/* set parent flag */
mq->parent.parent.flag = flag;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(mq->parent));
- /* set messasge pool */
+ /* set message pool */
mq->msg_pool = msgpool;
/* get correct message size */
mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message));
- /* init message list */
+ /* initialize message list */
mq->msg_queue_head = RT_NULL;
mq->msg_queue_tail = RT_NULL;
- /* init message empty list */
+ /* initialize message empty list */
mq->msg_queue_free = RT_NULL;
for (temp = 0; temp < mq->max_msgs; temp ++)
{
head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
temp * (mq->msg_size + sizeof(struct rt_mq_message)));
- head->next = mq->msg_queue_free;
+ head->next = (struct rt_mq_message *)mq->msg_queue_free;
mq->msg_queue_free = head;
}
/* the initial entry is zero */
mq->entry = 0;
+ /* initialize an additional list of sender suspend thread */
+ rt_list_init(&(mq->suspend_sender_thread));
+
return RT_EOK;
}
RTM_EXPORT(rt_mq_init);
@@ -1840,6 +1847,8 @@ rt_err_t rt_mq_detach(rt_mq_t mq)
/* resume all suspended thread */
rt_ipc_list_resume_all(&mq->parent.suspend_thread);
+ /* also resume all message queue private suspended thread */
+ rt_ipc_list_resume_all(&(mq->suspend_sender_thread));
/* detach message queue object */
rt_object_detach(&(mq->parent.parent));
@@ -1878,10 +1887,10 @@ rt_mq_t rt_mq_create(const char *name,
/* set parent */
mq->parent.parent.flag = flag;
- /* init ipc object */
+ /* initialize ipc object */
rt_ipc_object_init(&(mq->parent));
- /* init message queue */
+ /* initialize message queue */
/* get correct message size */
mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
@@ -1891,28 +1900,31 @@ rt_mq_t rt_mq_create(const char *name,
mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs);
if (mq->msg_pool == RT_NULL)
{
- rt_mq_delete(mq);
+ rt_object_delete(&(mq->parent.parent));
return RT_NULL;
}
- /* init message list */
+ /* initialize message list */
mq->msg_queue_head = RT_NULL;
mq->msg_queue_tail = RT_NULL;
- /* init message empty list */
+ /* initialize message empty list */
mq->msg_queue_free = RT_NULL;
for (temp = 0; temp < mq->max_msgs; temp ++)
{
head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
temp * (mq->msg_size + sizeof(struct rt_mq_message)));
- head->next = mq->msg_queue_free;
+ head->next = (struct rt_mq_message *)mq->msg_queue_free;
mq->msg_queue_free = head;
}
/* the initial entry is zero */
mq->entry = 0;
+ /* initialize an additional list of sender suspend thread */
+ rt_list_init(&(mq->suspend_sender_thread));
+
return mq;
}
RTM_EXPORT(rt_mq_create);
@@ -1935,6 +1947,8 @@ rt_err_t rt_mq_delete(rt_mq_t mq)
/* resume all suspended thread */
rt_ipc_list_resume_all(&(mq->parent.suspend_thread));
+ /* also resume all message queue private suspended thread */
+ rt_ipc_list_resume_all(&(mq->suspend_sender_thread));
/* free message queue pool */
RT_KERNEL_FREE(mq->msg_pool);
@@ -1948,19 +1962,25 @@ RTM_EXPORT(rt_mq_delete);
#endif
/**
- * This function will send a message to message queue object, if there are
- * threads suspended on message queue object, it will be waked up.
+ * This function will send a message to message queue object. If the message queue is full,
+ * current thread will be suspended until timeout.
*
* @param mq the message queue object
* @param buffer the message
* @param size the size of buffer
+ * @param timeout the waiting time
*
* @return the error code
*/
-rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
+rt_err_t rt_mq_send_wait(rt_mq_t mq,
+ const void *buffer,
+ rt_size_t size,
+ rt_int32_t timeout)
{
register rt_ubase_t temp;
struct rt_mq_message *msg;
+ rt_uint32_t tick_delta;
+ struct rt_thread *thread;
/* parameter check */
RT_ASSERT(mq != RT_NULL);
@@ -1972,6 +1992,11 @@ rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
if (size > mq->msg_size)
return -RT_ERROR;
+ /* initialize delta tick */
+ tick_delta = 0;
+ /* get current thread */
+ thread = rt_thread_self();
+
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent)));
/* disable interrupt */
@@ -1979,14 +2004,78 @@ rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
/* get a free list, there must be an empty item */
msg = (struct rt_mq_message *)mq->msg_queue_free;
- /* message queue is full */
- if (msg == RT_NULL)
+ /* for non-blocking call */
+ if (msg == RT_NULL && timeout == 0)
{
/* enable interrupt */
rt_hw_interrupt_enable(temp);
return -RT_EFULL;
}
+
+ /* message queue is full */
+ while ((msg = mq->msg_queue_free) == RT_NULL)
+ {
+ /* reset error number in thread */
+ thread->error = RT_EOK;
+
+ /* no waiting, return timeout */
+ if (timeout == 0)
+ {
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ return -RT_EFULL;
+ }
+
+ RT_DEBUG_IN_THREAD_CONTEXT;
+ /* suspend current thread */
+ rt_ipc_list_suspend(&(mq->suspend_sender_thread),
+ thread,
+ mq->parent.parent.flag);
+
+ /* has waiting time, start thread timer */
+ if (timeout > 0)
+ {
+ /* get the start tick of timer */
+ tick_delta = rt_tick_get();
+
+ RT_DEBUG_LOG(RT_DEBUG_IPC, ("mq_send_wait: start timer of thread:%s\n",
+ thread->name));
+
+ /* 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_hw_interrupt_enable(temp);
+
+ /* re-schedule */
+ rt_schedule();
+
+ /* resume from suspend state */
+ if (thread->error != RT_EOK)
+ {
+ /* return error */
+ return thread->error;
+ }
+
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
+ /* if it's not waiting forever and then re-calculate timeout tick */
+ if (timeout > 0)
+ {
+ tick_delta = rt_tick_get() - tick_delta;
+ timeout -= tick_delta;
+ if (timeout < 0)
+ timeout = 0;
+ }
+ }
+
/* move free list pointer */
mq->msg_queue_free = msg->next;
@@ -2034,6 +2123,22 @@ rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size)
return RT_EOK;
}
+RTM_EXPORT(rt_mq_send_wait)
+
+/**
+ * This function will send a message to message queue object, if there are
+ * threads suspended on message queue object, it will be waked up.
+ *
+ * @param mq the message queue object
+ * @param buffer the message
+ * @param size the size of buffer
+ *
+ * @return the error code
+ */
+rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size)
+{
+ return rt_mq_send_wait(mq, buffer, size, 0);
+}
RTM_EXPORT(rt_mq_send);
/**
@@ -2047,7 +2152,7 @@ RTM_EXPORT(rt_mq_send);
*
* @return the error code
*/
-rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size)
+rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size)
{
register rt_ubase_t temp;
struct rt_mq_message *msg;
@@ -2090,7 +2195,7 @@ rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size)
temp = rt_hw_interrupt_disable();
/* link msg to the beginning of message queue */
- msg->next = mq->msg_queue_head;
+ msg->next = (struct rt_mq_message *)mq->msg_queue_head;
mq->msg_queue_head = msg;
/* if there is no tail */
@@ -2254,6 +2359,22 @@ rt_err_t rt_mq_recv(rt_mq_t mq,
/* put message to free list */
msg->next = (struct rt_mq_message *)mq->msg_queue_free;
mq->msg_queue_free = msg;
+
+ /* resume suspended thread */
+ if (!rt_list_isempty(&(mq->suspend_sender_thread)))
+ {
+ rt_ipc_list_resume(&(mq->suspend_sender_thread));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(temp);
+
+ RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent)));
+
+ rt_schedule();
+
+ return RT_EOK;
+ }
+
/* enable interrupt */
rt_hw_interrupt_enable(temp);
@@ -2289,6 +2410,8 @@ rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg)
/* resume all waiting thread */
rt_ipc_list_resume_all(&mq->parent.suspend_thread);
+ /* also resume all message queue private suspended thread */
+ rt_ipc_list_resume_all(&(mq->suspend_sender_thread));
/* release all message in the queue */
while (mq->msg_queue_head != RT_NULL)
diff --git a/src/irq.c b/src/irq.c
index 72d220bd92..311d297bfe 100644
--- a/src/irq.c
+++ b/src/irq.c
@@ -8,6 +8,7 @@
* 2006-02-24 Bernard first version
* 2006-05-03 Bernard add IRQ_DEBUG
* 2016-08-09 ArdaFu add interrupt enter and leave hook.
+ * 2018-11-22 Jesven rt_interrupt_get_nest function add disable irq
*/
#include <rthw.h>
@@ -48,7 +49,11 @@ void rt_interrupt_leave_sethook(void (*hook)(void))
/**@{*/
-volatile rt_uint8_t rt_interrupt_nest;
+#ifdef RT_USING_SMP
+#define rt_interrupt_nest rt_cpu_self()->irq_nest
+#else
+volatile rt_uint8_t rt_interrupt_nest = 0;
+#endif
/**
* This function will be invoked by BSP, when enter interrupt service routine
@@ -100,9 +105,15 @@ RTM_EXPORT(rt_interrupt_leave);
*
* @return the number of nested interrupts.
*/
-rt_uint8_t rt_interrupt_get_nest(void)
+RT_WEAK rt_uint8_t rt_interrupt_get_nest(void)
{
- return rt_interrupt_nest;
+ rt_uint8_t ret;
+ rt_base_t level;
+
+ level = rt_hw_interrupt_disable();
+ ret = rt_interrupt_nest;
+ rt_hw_interrupt_enable(level);
+ return ret;
}
RTM_EXPORT(rt_interrupt_get_nest);
diff --git a/src/kservice.c b/src/kservice.c
index dbc4a2fb0e..1705ce5283 100644
--- a/src/kservice.c
+++ b/src/kservice.c
@@ -133,20 +133,21 @@ void *rt_memset(void *s, int c, rt_ubase_t count)
return s;
#else
-#define LBLOCKSIZE (sizeof(rt_int32_t))
-#define UNALIGNED(X) ((rt_int32_t)X & (LBLOCKSIZE - 1))
+#define LBLOCKSIZE (sizeof(long))
+#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1))
#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
- int i;
+ unsigned int i;
char *m = (char *)s;
- rt_uint32_t buffer;
- rt_uint32_t *aligned_addr;
- rt_uint32_t d = c & 0xff;
+ unsigned long buffer;
+ unsigned long *aligned_addr;
+ unsigned int d = c & 0xff; /* To avoid sign extension, copy C to an
+ unsigned variable. */
if (!TOO_SMALL(count) && !UNALIGNED(s))
{
/* If we get this far, we know that n is large and m is word-aligned. */
- aligned_addr = (rt_uint32_t *)s;
+ aligned_addr = (unsigned long *)s;
/* Store D into each char sized location in BUFFER so that
* we can set large blocks quickly.
@@ -226,25 +227,24 @@ void *rt_memcpy(void *dst, const void *src, rt_ubase_t count)
return dst;
#else
-#define UNALIGNED(X, Y) \
- (((rt_int32_t)X & (sizeof(rt_int32_t) - 1)) | \
- ((rt_int32_t)Y & (sizeof(rt_int32_t) - 1)))
-#define BIGBLOCKSIZE (sizeof(rt_int32_t) << 2)
-#define LITTLEBLOCKSIZE (sizeof(rt_int32_t))
+#define UNALIGNED(X, Y) \
+ (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+#define BIGBLOCKSIZE (sizeof (long) << 2)
+#define LITTLEBLOCKSIZE (sizeof (long))
#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
char *dst_ptr = (char *)dst;
char *src_ptr = (char *)src;
- rt_int32_t *aligned_dst;
- rt_int32_t *aligned_src;
+ long *aligned_dst;
+ long *aligned_src;
int len = count;
/* If the size is small, or either SRC or DST is unaligned,
then punt into the byte copy loop. This should be rare. */
if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr))
{
- aligned_dst = (rt_int32_t *)dst_ptr;
- aligned_src = (rt_int32_t *)src_ptr;
+ aligned_dst = (long *)dst_ptr;
+ aligned_src = (long *)src_ptr;
/* Copy 4X long words at a time if possible. */
while (len >= BIGBLOCKSIZE)
@@ -316,7 +316,7 @@ RTM_EXPORT(rt_memmove);
* This function will compare two areas of memory
*
* @param cs one area of memory
- * @param ct znother area of memory
+ * @param ct another area of memory
* @param count the size of the area
*
* @return the result
@@ -326,7 +326,7 @@ rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count)
const unsigned char *su1, *su2;
int res = 0;
- for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ for (su1 = (const unsigned char *)cs, su2 = (const unsigned char *)ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
@@ -370,7 +370,7 @@ RTM_EXPORT(rt_strstr);
*
* @return the result
*/
-rt_uint32_t rt_strcasecmp(const char *a, const char *b)
+rt_int32_t rt_strcasecmp(const char *a, const char *b)
{
int ca, cb;
@@ -461,6 +461,7 @@ rt_int32_t rt_strcmp(const char *cs, const char *ct)
return (*cs - *ct);
}
RTM_EXPORT(rt_strcmp);
+
/**
* The strnlen() function returns the number of characters in the
* string pointed to by s, excluding the terminating null byte ('\0'),
@@ -476,11 +477,13 @@ rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen)
{
const char *sc;
- for (sc = s; *sc != '\0' && sc - s < maxlen; ++sc) /* nothing */
+ for (sc = s; *sc != '\0' && (rt_ubase_t)(sc - s) < maxlen; ++sc) /* nothing */
;
return sc - s;
}
+RTM_EXPORT(rt_strnlen);
+
/**
* This function will return the length of a string, which terminate will
* null character.
@@ -535,31 +538,52 @@ void rt_show_version(void)
rt_kprintf("- RT - Thread Operating System\n");
rt_kprintf(" / | \\ %d.%d.%d build %s\n",
RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__);
- rt_kprintf(" 2006 - 2018 Copyright by rt-thread team\n");
+ rt_kprintf(" 2006 - 2020 Copyright by rt-thread team\n");
}
RTM_EXPORT(rt_show_version);
/* private function */
#define isdigit(c) ((unsigned)((c) - '0') < 10)
-rt_inline rt_int32_t divide(rt_int32_t *n, rt_int32_t base)
+#ifdef RT_PRINTF_LONGLONG
+rt_inline int divide(long long *n, int base)
{
- rt_int32_t res;
+ int res;
/* optimized for processor which does not support divide instructions. */
if (base == 10)
{
- res = ((rt_uint32_t) * n) % 10U;
- *n = ((rt_uint32_t) * n) / 10U;
+ res = (int)(((unsigned long long)*n) % 10U);
+ *n = (long long)(((unsigned long long)*n) / 10U);
}
else
{
- res = ((rt_uint32_t) * n) % 16U;
- *n = ((rt_uint32_t) * n) / 16U;
+ res = (int)(((unsigned long long)*n) % 16U);
+ *n = (long long)(((unsigned long long)*n) / 16U);
}
return res;
}
+#else
+rt_inline int divide(long *n, int base)
+{
+ int res;
+
+ /* optimized for processor which does not support divide instructions. */
+ if (base == 10)
+ {
+ res = (int)(((unsigned long)*n) % 10U);
+ *n = (long)(((unsigned long)*n) / 10U);
+ }
+ else
+ {
+ res = (int)(((unsigned long)*n) % 16U);
+ *n = (long)(((unsigned long)*n) / 16U);
+ }
+
+ return res;
+}
+#endif
rt_inline int skip_atoi(const char **s)
{
@@ -581,7 +605,11 @@ rt_inline int skip_atoi(const char **s)
#ifdef RT_PRINTF_PRECISION
static char *print_number(char *buf,
char *end,
+#ifdef RT_PRINTF_LONGLONG
+ long long num,
+#else
long num,
+#endif
int base,
int s,
int precision,
@@ -589,7 +617,11 @@ static char *print_number(char *buf,
#else
static char *print_number(char *buf,
char *end,
+#ifdef RT_PRINTF_LONGLONG
+ long long num,
+#else
long num,
+#endif
int base,
int s,
int type)
@@ -601,6 +633,7 @@ static char *print_number(char *buf,
#else
char tmp[16];
#endif
+ int precision_bak = precision;
const char *digits;
static const char small_digits[] = "0123456789abcdef";
static const char large_digits[] = "0123456789ABCDEF";
@@ -664,7 +697,7 @@ static char *print_number(char *buf,
while (size-- > 0)
{
- if (buf <= end)
+ if (buf < end)
*buf = ' ';
++ buf;
}
@@ -672,11 +705,11 @@ static char *print_number(char *buf,
if (sign)
{
- if (buf <= end)
+ if (buf < end)
{
*buf = sign;
- -- size;
}
+ -- size;
++ buf;
}
@@ -685,16 +718,16 @@ static char *print_number(char *buf,
{
if (base == 8)
{
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++ buf;
}
else if (base == 16)
{
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++ buf;
- if (buf <= end)
+ if (buf < end)
{
*buf = type & LARGE ? 'X' : 'x';
}
@@ -708,7 +741,7 @@ static char *print_number(char *buf,
{
while (size-- > 0)
{
- if (buf <= end)
+ if (buf < end)
*buf = c;
++ buf;
}
@@ -717,23 +750,23 @@ static char *print_number(char *buf,
#ifdef RT_PRINTF_PRECISION
while (i < precision--)
{
- if (buf <= end)
+ if (buf < end)
*buf = '0';
++ buf;
}
#endif
/* put number in the temporary buffer */
- while (i-- > 0)
+ while (i-- > 0 && (precision_bak != 0))
{
- if (buf <= end)
+ if (buf < end)
*buf = tmp[i];
++ buf;
}
while (size-- > 0)
{
- if (buf <= end)
+ if (buf < end)
*buf = ' ';
++ buf;
}
@@ -765,7 +798,7 @@ rt_int32_t rt_vsnprintf(char *buf,
#endif
str = buf;
- end = buf + size - 1;
+ end = buf + size;
/* Make sure end is always >= buf */
if (end < buf)
@@ -778,7 +811,7 @@ rt_int32_t rt_vsnprintf(char *buf,
{
if (*fmt != '%')
{
- if (str <= end)
+ if (str < end)
*str = *fmt;
++ str;
continue;
@@ -859,20 +892,20 @@ rt_int32_t rt_vsnprintf(char *buf,
{
while (--field_width > 0)
{
- if (str <= end) *str = ' ';
+ if (str < end) *str = ' ';
++ str;
}
}
/* get character */
c = (rt_uint8_t)va_arg(args, int);
- if (str <= end) *str = c;
+ if (str < end) *str = c;
++ str;
/* put width */
while (--field_width > 0)
{
- if (str <= end) *str = ' ';
+ if (str < end) *str = ' ';
++ str;
}
continue;
@@ -890,21 +923,21 @@ rt_int32_t rt_vsnprintf(char *buf,
{
while (len < field_width--)
{
- if (str <= end) *str = ' ';
+ if (str < end) *str = ' ';
++ str;
}
}
for (i = 0; i < len; ++i)
{
- if (str <= end) *str = *s;
+ if (str < end) *str = *s;
++ str;
++ s;
}
while (len < field_width--)
{
- if (str <= end) *str = ' ';
+ if (str < end) *str = ' ';
++ str;
}
continue;
@@ -927,7 +960,7 @@ rt_int32_t rt_vsnprintf(char *buf,
continue;
case '%':
- if (str <= end) *str = '%';
+ if (str < end) *str = '%';
++ str;
continue;
@@ -949,12 +982,12 @@ rt_int32_t rt_vsnprintf(char *buf,
break;
default:
- if (str <= end) *str = '%';
+ if (str < end) *str = '%';
++ str;
if (*fmt)
{
- if (str <= end) *str = *fmt;
+ if (str < end) *str = *fmt;
++ str;
}
else
@@ -991,8 +1024,14 @@ rt_int32_t rt_vsnprintf(char *buf,
#endif
}
- if (str <= end) *str = '\0';
- else *end = '\0';
+ if (size > 0)
+ {
+ if (str < end) *str = '\0';
+ else
+ {
+ end[-1] = '\0';
+ }
+ }
/* the trailing null byte doesn't count towards the total
* ++str;
@@ -1078,14 +1117,14 @@ RTM_EXPORT(rt_console_get_device);
*/
rt_device_t rt_console_set_device(const char *name)
{
- rt_device_t new, old;
+ rt_device_t new_device, old_device;
/* save old device */
- old = _console_device;
+ old_device = _console_device;
/* find new console device */
- new = rt_device_find(name);
- if (new != RT_NULL)
+ new_device = rt_device_find(name);
+ if (new_device != RT_NULL)
{
if (_console_device != RT_NULL)
{
@@ -1094,11 +1133,11 @@ rt_device_t rt_console_set_device(const char *name)
}
/* set new console device */
- rt_device_open(new, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM);
- _console_device = new;
+ rt_device_open(new_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM);
+ _console_device = new_device;
}
- return old;
+ return old_device;
}
RTM_EXPORT(rt_console_set_device);
#endif
@@ -1189,31 +1228,36 @@ RTM_EXPORT(rt_kprintf);
*/
void *rt_malloc_align(rt_size_t size, rt_size_t align)
{
- void *align_ptr;
void *ptr;
+ void *align_ptr;
+ int uintptr_size;
rt_size_t align_size;
- /* align the alignment size to 4 byte */
- align = ((align + 0x03) & ~0x03);
+ /* sizeof pointer */
+ uintptr_size = sizeof(void*);
+ uintptr_size -= 1;
+
+ /* align the alignment size to uintptr size byte */
+ align = ((align + uintptr_size) & ~uintptr_size);
/* get total aligned size */
- align_size = ((size + 0x03) & ~0x03) + align;
+ align_size = ((size + uintptr_size) & ~uintptr_size) + align;
/* allocate memory block from heap */
ptr = rt_malloc(align_size);
if (ptr != RT_NULL)
{
/* the allocated memory block is aligned */
- if (((rt_uint32_t)ptr & (align - 1)) == 0)
+ if (((rt_ubase_t)ptr & (align - 1)) == 0)
{
- align_ptr = (void *)((rt_uint32_t)ptr + align);
+ align_ptr = (void *)((rt_ubase_t)ptr + align);
}
else
{
- align_ptr = (void *)(((rt_uint32_t)ptr + (align - 1)) & ~(align - 1));
+ align_ptr = (void *)(((rt_ubase_t)ptr + (align - 1)) & ~(align - 1));
}
/* set the pointer before alignment pointer to the real pointer */
- *((rt_uint32_t *)((rt_uint32_t)align_ptr - sizeof(void *))) = (rt_uint32_t)ptr;
+ *((rt_ubase_t *)((rt_ubase_t)align_ptr - sizeof(void *))) = (rt_ubase_t)ptr;
ptr = align_ptr;
}
@@ -1232,7 +1276,7 @@ void rt_free_align(void *ptr)
{
void *real_ptr;
- real_ptr = (void *) * (rt_uint32_t *)((rt_uint32_t)ptr - sizeof(void *));
+ real_ptr = (void *) * (rt_ubase_t *)((rt_ubase_t)ptr - sizeof(void *));
rt_free(real_ptr);
}
RTM_EXPORT(rt_free_align);
@@ -1288,7 +1332,9 @@ int __rt_ffs(int value)
#ifdef RT_DEBUG
/* RT_ASSERT(EX)'s hook */
+
void (*rt_assert_hook)(const char *ex, const char *func, rt_size_t line);
+
/**
* This function will set a hook function to RT_ASSERT(EX). It will run when the expression is false.
*
diff --git a/src/mem.c b/src/mem.c
index cb96ab9ee0..c03c8b3452 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -11,6 +11,7 @@
* 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca
* 2010-10-14 Bernard fix rt_realloc issue when realloc a NULL pointer.
* 2017-07-14 armink fix rt_realloc issue when new size is 0
+ * 2018-10-02 Bernard Add 64bit support
*/
/*
@@ -97,12 +98,19 @@ struct heap_mem
/* magic and used flag */
rt_uint16_t magic;
rt_uint16_t used;
+#ifdef ARCH_CPU_64BIT
+ rt_uint32_t resv;
+#endif
rt_size_t next, prev;
#ifdef RT_USING_MEMTRACE
+#ifdef ARCH_CPU_64BIT
+ rt_uint8_t thread[8];
+#else
rt_uint8_t thread[4]; /* thread name */
#endif
+#endif
};
/** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */
@@ -111,7 +119,12 @@ static rt_uint8_t *heap_ptr;
/** the last entry, always unused! */
static struct heap_mem *heap_end;
+#ifdef ARCH_CPU_64BIT
+#define MIN_SIZE 24
+#else
#define MIN_SIZE 12
+#endif
+
#define MIN_SIZE_ALIGNED RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE)
#define SIZEOF_STRUCT_MEM RT_ALIGN(sizeof(struct heap_mem), RT_ALIGN_SIZE)
@@ -191,8 +204,8 @@ static void plug_holes(struct heap_mem *mem)
void rt_system_heap_init(void *begin_addr, void *end_addr)
{
struct heap_mem *mem;
- rt_uint32_t begin_align = RT_ALIGN((rt_uint32_t)begin_addr, RT_ALIGN_SIZE);
- rt_uint32_t end_align = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_ALIGN_SIZE);
+ rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE);
+ rt_ubase_t end_align = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE);
RT_DEBUG_NOT_IN_INTERRUPT;
@@ -206,7 +219,7 @@ void rt_system_heap_init(void *begin_addr, void *end_addr)
else
{
rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n",
- (rt_uint32_t)begin_addr, (rt_uint32_t)end_addr);
+ (rt_ubase_t)begin_addr, (rt_ubase_t)end_addr);
return;
}
@@ -215,7 +228,7 @@ void rt_system_heap_init(void *begin_addr, void *end_addr)
heap_ptr = (rt_uint8_t *)begin_align;
RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n",
- (rt_uint32_t)heap_ptr, mem_size_aligned));
+ (rt_ubase_t)heap_ptr, mem_size_aligned));
/* initialize the start of the heap */
mem = (struct heap_mem *)heap_ptr;
@@ -261,11 +274,11 @@ void *rt_malloc(rt_size_t size)
rt_size_t ptr, ptr2;
struct heap_mem *mem, *mem2;
- RT_DEBUG_NOT_IN_INTERRUPT;
-
if (size == 0)
return RT_NULL;
+ RT_DEBUG_NOT_IN_INTERRUPT;
+
if (size != RT_ALIGN(size, RT_ALIGN_SIZE))
RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n",
size, RT_ALIGN(size, RT_ALIGN_SIZE)));
@@ -374,14 +387,14 @@ void *rt_malloc(rt_size_t size)
}
rt_sem_release(&heap_sem);
- RT_ASSERT((rt_uint32_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_uint32_t)heap_end);
- RT_ASSERT((rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);
- RT_ASSERT((((rt_uint32_t)mem) & (RT_ALIGN_SIZE - 1)) == 0);
+ RT_ASSERT((rt_ubase_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_ubase_t)heap_end);
+ RT_ASSERT((rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);
+ RT_ASSERT((((rt_ubase_t)mem) & (RT_ALIGN_SIZE - 1)) == 0);
RT_DEBUG_LOG(RT_DEBUG_MEM,
("allocate memory at 0x%x, size: %d\n",
- (rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM),
- (rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
+ (rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM),
+ (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
RT_OBJECT_HOOK_CALL(rt_malloc_hook,
(((void *)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM)), size));
@@ -476,6 +489,12 @@ void *rt_realloc(void *rmem, rt_size_t newsize)
{
((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
}
+
+ if (mem2 < lfree)
+ {
+ /* the splited struct is now the lowest */
+ lfree = mem2;
+ }
plug_holes(mem2);
@@ -513,8 +532,6 @@ void *rt_calloc(rt_size_t count, rt_size_t size)
{
void *p;
- RT_DEBUG_NOT_IN_INTERRUPT;
-
/* allocate 'count' objects of size 'size' */
p = rt_malloc(count * size);
@@ -536,11 +553,12 @@ void rt_free(void *rmem)
{
struct heap_mem *mem;
- RT_DEBUG_NOT_IN_INTERRUPT;
-
if (rmem == RT_NULL)
return;
- RT_ASSERT((((rt_uint32_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0);
+
+ RT_DEBUG_NOT_IN_INTERRUPT;
+
+ RT_ASSERT((((rt_ubase_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0);
RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr &&
(rt_uint8_t *)rmem < (rt_uint8_t *)heap_end);
@@ -559,8 +577,8 @@ void rt_free(void *rmem)
RT_DEBUG_LOG(RT_DEBUG_MEM,
("release memory 0x%x, size: %d\n",
- (rt_uint32_t)rmem,
- (rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
+ (rt_ubase_t)rmem,
+ (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
/* protect the heap from concurrent access */
@@ -625,14 +643,14 @@ FINSH_FUNCTION_EXPORT(list_mem, list memory usage information)
int memcheck(void)
{
int position;
- rt_uint32_t level;
+ rt_ubase_t level;
struct heap_mem *mem;
level = rt_hw_interrupt_disable();
for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next])
{
- position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr;
+ position = (rt_ubase_t)mem - (rt_ubase_t)heap_ptr;
if (position < 0) goto __exit;
- if (position > mem_size_aligned) goto __exit;
+ if (position > (int)mem_size_aligned) goto __exit;
if (mem->magic != HEAP_MAGIC) goto __exit;
if (mem->used != 0 && mem->used != 1) goto __exit;
}
@@ -665,7 +683,7 @@ int memtrace(int argc, char **argv)
rt_kprintf("\n--memory item information --\n");
for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next])
{
- int position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr;
+ int position = (rt_ubase_t)mem - (rt_ubase_t)heap_ptr;
int size;
rt_kprintf("[0x%08x - ", mem);
diff --git a/src/memheap.c b/src/memheap.c
index 946f163b64..aef56e1a74 100644
--- a/src/memheap.c
+++ b/src/memheap.c
@@ -34,7 +34,7 @@
#define RT_MEMHEAP_MINIALLOC 12
#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
-#define MEMITEM_SIZE(item) ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE)
+#define MEMITEM_SIZE(item) ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE)
/*
* The initialized memory pool will be:
@@ -50,7 +50,7 @@
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
const char *name,
void *start_addr,
- rt_uint32_t size)
+ rt_size_t size)
{
struct rt_memheap_item *item;
@@ -135,7 +135,7 @@ rt_err_t rt_memheap_detach(struct rt_memheap *heap)
}
RTM_EXPORT(rt_memheap_detach);
-void *rt_memheap_alloc(struct rt_memheap *heap, rt_uint32_t size)
+void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
{
rt_err_t result;
rt_uint32_t free_size;
diff --git a/src/mempool.c b/src/mempool.c
index 2184586aba..00471efb35 100644
--- a/src/mempool.c
+++ b/src/mempool.c
@@ -85,6 +85,9 @@ rt_err_t rt_mp_init(struct rt_mempool *mp,
/* parameter check */
RT_ASSERT(mp != RT_NULL);
+ RT_ASSERT(name != RT_NULL);
+ RT_ASSERT(start != RT_NULL);
+ RT_ASSERT(size > 0 && block_size > 0);
/* initialize object */
rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name);
@@ -103,7 +106,6 @@ rt_err_t rt_mp_init(struct rt_mempool *mp,
/* initialize suspended thread list */
rt_list_init(&(mp->suspend_thread));
- mp->suspend_thread_count = 0;
/* initialize free block list */
block_ptr = (rt_uint8_t *)mp->start_address;
@@ -157,9 +159,6 @@ rt_err_t rt_mp_detach(struct rt_mempool *mp)
*/
rt_thread_resume(thread);
- /* decrease suspended thread count */
- mp->suspend_thread_count --;
-
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
@@ -192,6 +191,10 @@ rt_mp_t rt_mp_create(const char *name,
RT_DEBUG_NOT_IN_INTERRUPT;
+ /* parameter check */
+ RT_ASSERT(name != RT_NULL);
+ RT_ASSERT(block_count > 0 && block_size > 0);
+
/* allocate object */
mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name);
/* allocate object failed */
@@ -219,7 +222,6 @@ rt_mp_t rt_mp_create(const char *name,
/* initialize suspended thread list */
rt_list_init(&(mp->suspend_thread));
- mp->suspend_thread_count = 0;
/* initialize free block list */
block_ptr = (rt_uint8_t *)mp->start_address;
@@ -275,9 +277,6 @@ rt_err_t rt_mp_delete(rt_mp_t mp)
*/
rt_thread_resume(thread);
- /* decrease suspended thread count */
- mp->suspend_thread_count --;
-
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
@@ -308,6 +307,9 @@ void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
struct rt_thread *thread;
rt_uint32_t before_sleep = 0;
+ /* parameter check */
+ RT_ASSERT(mp != RT_NULL);
+
/* get current thread */
thread = rt_thread_self();
@@ -334,7 +336,6 @@ void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
/* need suspend thread */
rt_thread_suspend(thread);
rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist));
- mp->suspend_thread_count++;
if (time > 0)
{
@@ -402,6 +403,9 @@ void rt_mp_free(void *block)
struct rt_thread *thread;
register rt_base_t level;
+ /* parameter check */
+ if (block == RT_NULL) return;
+
/* get the control block of pool which the block belongs to */
block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *));
mp = (struct rt_mempool *)*block_ptr;
@@ -418,7 +422,7 @@ void rt_mp_free(void *block)
*block_ptr = mp->block_list;
mp->block_list = (rt_uint8_t *)block_ptr;
- if (mp->suspend_thread_count > 0)
+ if (!rt_list_isempty(&(mp->suspend_thread)))
{
/* get the suspended thread */
thread = rt_list_entry(mp->suspend_thread.next,
@@ -431,9 +435,6 @@ void rt_mp_free(void *block)
/* resume thread */
rt_thread_resume(thread);
- /* decrease suspended thread count */
- mp->suspend_thread_count --;
-
/* enable interrupt */
rt_hw_interrupt_enable(level);
diff --git a/src/object.c b/src/object.c
index 70b9a5c04e..4ee2f6a1a1 100644
--- a/src/object.c
+++ b/src/object.c
@@ -240,6 +240,7 @@ void rt_object_init(struct rt_object *object,
const char *name)
{
register rt_base_t temp;
+ struct rt_list_node *node = RT_NULL;
struct rt_object_information *information;
#ifdef RT_USING_MODULE
struct rt_dlmodule *module = dlmodule_self();
@@ -249,11 +250,29 @@ void rt_object_init(struct rt_object *object,
information = rt_object_get_information(type);
RT_ASSERT(information != RT_NULL);
- /* initialize object's parameters */
+ /* check object type to avoid re-initialization */
+
+ /* enter critical */
+ rt_enter_critical();
+ /* try to find object */
+ for (node = information->object_list.next;
+ node != &(information->object_list);
+ node = node->next)
+ {
+ struct rt_object *obj;
+ obj = rt_list_entry(node, struct rt_object, list);
+ if (obj) /* skip warning when disable debug */
+ {
+ RT_ASSERT(obj != object);
+ }
+ }
+ /* leave critical */
+ rt_exit_critical();
+
+ /* initialize object's parameters */
/* set object type to static */
object->type = type | RT_Object_Class_Static;
-
/* copy name */
rt_strncpy(object->name, name, RT_NAME_MAX);
diff --git a/src/scheduler.c b/src/scheduler.c
index 95b5d487df..6baaa9627a 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -21,28 +21,36 @@
* 2010-12-13 Bernard add defunct list initialization even if not use heap.
* 2011-05-10 Bernard clean scheduler debug log.
* 2013-12-21 Grissiom add rt_critical_level
+ * 2018-11-22 Jesven remove the current task from ready queue
+ * add per cpu ready queue
+ * add _get_highest_priority_thread to find highest priority task
+ * rt_schedule_insert_thread won't insert current task to ready queue
+ * in smp version, rt_hw_context_switch_interrupt maybe switch to
+ * new task directly
+ *
*/
#include <rtthread.h>
#include <rthw.h>
-static rt_int16_t rt_scheduler_lock_nest;
-extern volatile rt_uint8_t rt_interrupt_nest;
+#ifdef RT_USING_SMP
+rt_hw_spinlock_t _rt_critical_lock;
+#endif /*RT_USING_SMP*/
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
-struct rt_thread *rt_current_thread;
-
-rt_uint8_t rt_current_priority;
-
+rt_uint32_t rt_thread_ready_priority_group;
#if RT_THREAD_PRIORITY_MAX > 32
/* Maximum priority level, 256 */
-rt_uint32_t rt_thread_ready_priority_group;
rt_uint8_t rt_thread_ready_table[32];
-#else
-/* Maximum priority level, 32 */
-rt_uint32_t rt_thread_ready_priority_group;
#endif
+#ifndef RT_USING_SMP
+extern volatile rt_uint8_t rt_interrupt_nest;
+static rt_int16_t rt_scheduler_lock_nest;
+struct rt_thread *rt_current_thread;
+rt_uint8_t rt_current_priority;
+#endif /*RT_USING_SMP*/
+
rt_list_t rt_thread_defunct;
#ifdef RT_USING_HOOK
@@ -74,12 +82,16 @@ static void _rt_scheduler_stack_check(struct rt_thread *thread)
{
RT_ASSERT(thread != RT_NULL);
+#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
+ if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
+#else
if (*((rt_uint8_t *)thread->stack_addr) != '#' ||
- (rt_uint32_t)thread->sp <= (rt_uint32_t)thread->stack_addr ||
- (rt_uint32_t)thread->sp >
- (rt_uint32_t)thread->stack_addr + (rt_uint32_t)thread->stack_size)
+#endif
+ (rt_ubase_t)thread->sp <= (rt_ubase_t)thread->stack_addr ||
+ (rt_ubase_t)thread->sp >
+ (rt_ubase_t)thread->stack_addr + (rt_ubase_t)thread->stack_size)
{
- rt_uint32_t level;
+ rt_ubase_t level;
rt_kprintf("thread:%s stack overflow\n", thread->name);
#ifdef RT_USING_FINSH
@@ -91,11 +103,84 @@ static void _rt_scheduler_stack_check(struct rt_thread *thread)
level = rt_hw_interrupt_disable();
while (level);
}
- else if ((rt_uint32_t)thread->sp <= ((rt_uint32_t)thread->stack_addr + 32))
+#if defined(ARCH_CPU_STACK_GROWS_UPWARD)
+ else if ((rt_ubase_t)thread->sp > ((rt_ubase_t)thread->stack_addr + thread->stack_size))
+ {
+ rt_kprintf("warning: %s stack is close to the top of stack address.\n",
+ thread->name);
+ }
+#else
+ else if ((rt_ubase_t)thread->sp <= ((rt_ubase_t)thread->stack_addr + 32))
{
rt_kprintf("warning: %s stack is close to end of stack address.\n",
thread->name);
}
+#endif
+}
+#endif
+
+/*
+ * get the highest priority thread in ready queue
+ */
+#ifdef RT_USING_SMP
+static struct rt_thread* _get_highest_priority_thread(rt_ubase_t *highest_prio)
+{
+ register struct rt_thread *highest_priority_thread;
+ register rt_ubase_t highest_ready_priority, local_highest_ready_priority;
+ struct rt_cpu* pcpu = rt_cpu_self();
+#if RT_THREAD_PRIORITY_MAX > 32
+ register rt_ubase_t number;
+
+ number = __rt_ffs(rt_thread_ready_priority_group) - 1;
+ highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
+ number = __rt_ffs(pcpu->priority_group) - 1;
+ local_highest_ready_priority = (number << 3) + __rt_ffs(pcpu->ready_table[number]) - 1;
+#else
+ highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
+ local_highest_ready_priority = __rt_ffs(pcpu->priority_group) - 1;
+#endif
+
+ /* get highest ready priority thread */
+ if (highest_ready_priority < local_highest_ready_priority)
+ {
+ *highest_prio = highest_ready_priority;
+ highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
+ struct rt_thread,
+ tlist);
+ }
+ else
+ {
+ *highest_prio = local_highest_ready_priority;
+ highest_priority_thread = rt_list_entry(pcpu->priority_table[local_highest_ready_priority].next,
+ struct rt_thread,
+ tlist);
+ }
+
+ return highest_priority_thread;
+}
+#else
+static struct rt_thread* _get_highest_priority_thread(rt_ubase_t *highest_prio)
+{
+ register struct rt_thread *highest_priority_thread;
+ register rt_ubase_t highest_ready_priority;
+
+#if RT_THREAD_PRIORITY_MAX > 32
+ register rt_ubase_t number;
+
+ number = __rt_ffs(rt_thread_ready_priority_group) - 1;
+ highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
+#else
+ highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
+#endif
+
+ /* get highest ready priority thread */
+ highest_priority_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
+ struct rt_thread,
+ tlist);
+
+ *highest_prio = highest_ready_priority;
+
+ return highest_priority_thread;
}
#endif
@@ -105,9 +190,14 @@ static void _rt_scheduler_stack_check(struct rt_thread *thread)
*/
void rt_system_scheduler_init(void)
{
+#ifdef RT_USING_SMP
+ int cpu;
+#endif /*RT_USING_SMP*/
register rt_base_t offset;
+#ifndef RT_USING_SMP
rt_scheduler_lock_nest = 0;
+#endif /*RT_USING_SMP*/
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n",
RT_THREAD_PRIORITY_MAX));
@@ -116,9 +206,25 @@ void rt_system_scheduler_init(void)
{
rt_list_init(&rt_thread_priority_table[offset]);
}
+#ifdef RT_USING_SMP
+ for (cpu = 0; cpu < RT_CPUS_NR; cpu++)
+ {
+ struct rt_cpu *pcpu = rt_cpu_index(cpu);
+ for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
+ {
+ rt_list_init(&pcpu->priority_table[offset]);
+ }
+
+ pcpu->irq_switch_flag = 0;
+ pcpu->current_priority = RT_THREAD_PRIORITY_MAX - 1;
+ pcpu->current_thread = RT_NULL;
+ pcpu->priority_group = 0;
- rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
- rt_current_thread = RT_NULL;
+#if RT_THREAD_PRIORITY_MAX > 32
+ rt_memset(pcpu->ready_table, 0, sizeof(pcpu->ready_table));
+#endif
+ }
+#endif /*RT_USING_SMP*/
/* initialize ready priority group */
rt_thread_ready_priority_group = 0;
@@ -140,26 +246,25 @@ void rt_system_scheduler_init(void)
void rt_system_scheduler_start(void)
{
register struct rt_thread *to_thread;
- register rt_ubase_t highest_ready_priority;
+ rt_ubase_t highest_ready_priority;
-#if RT_THREAD_PRIORITY_MAX > 32
- register rt_ubase_t number;
+ to_thread = _get_highest_priority_thread(&highest_ready_priority);
- number = __rt_ffs(rt_thread_ready_priority_group) - 1;
- highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
+#ifdef RT_USING_SMP
+ to_thread->oncpu = rt_hw_cpu_id();
#else
- highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
-#endif
-
- /* get switch to thread */
- to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
- struct rt_thread,
- tlist);
-
rt_current_thread = to_thread;
+#endif /*RT_USING_SMP*/
+
+ rt_schedule_remove_thread(to_thread);
+ to_thread->stat = RT_THREAD_RUNNING;
/* switch to new thread */
- rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
+#ifdef RT_USING_SMP
+ rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp, to_thread);
+#else
+ rt_hw_context_switch_to((rt_ubase_t)&to_thread->sp);
+#endif /*RT_USING_SMP*/
/* never come back */
}
@@ -170,6 +275,142 @@ void rt_system_scheduler_start(void)
/**@{*/
+
+#ifdef RT_USING_SMP
+/**
+ * This function will handle IPI interrupt and do a scheduling in system;
+ *
+ * @param vector, the number of IPI interrupt for system scheduling
+ * @param param, use RT_NULL
+ *
+ * NOTE: this function should be invoke or register as ISR in BSP.
+ */
+void rt_scheduler_ipi_handler(int vector, void *param)
+{
+ rt_schedule();
+}
+
+/**
+ * This function will perform one scheduling. It will select one thread
+ * with the highest priority level in global ready queue or local ready queue,
+ * then switch to it.
+ */
+void rt_schedule(void)
+{
+ rt_base_t level;
+ struct rt_thread *to_thread;
+ struct rt_thread *current_thread;
+ struct rt_cpu *pcpu;
+ int cpu_id;
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ cpu_id = rt_hw_cpu_id();
+ pcpu = rt_cpu_index(cpu_id);
+ current_thread = pcpu->current_thread;
+
+ /* whether do switch in interrupt */
+ if (pcpu->irq_nest)
+ {
+ pcpu->irq_switch_flag = 1;
+ rt_hw_interrupt_enable(level);
+ goto __exit;
+ }
+
+#ifdef RT_USING_SIGNALS
+ if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
+ {
+ /* if current_thread signal is in pending */
+
+ if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING)
+ {
+ rt_thread_resume(current_thread);
+ }
+ }
+#endif
+
+ if (current_thread->scheduler_lock_nest == 1) /* whether lock scheduler */
+ {
+ rt_ubase_t highest_ready_priority;
+
+ if (rt_thread_ready_priority_group != 0 || pcpu->priority_group != 0)
+ {
+ to_thread = _get_highest_priority_thread(&highest_ready_priority);
+ current_thread->oncpu = RT_CPU_DETACHED;
+ if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
+ {
+ if (current_thread->current_priority < highest_ready_priority)
+ {
+ to_thread = current_thread;
+ }
+ else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
+ {
+ to_thread = current_thread;
+ }
+ else
+ {
+ current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
+ rt_schedule_insert_thread(current_thread);
+ }
+ }
+ to_thread->oncpu = cpu_id;
+ if (to_thread != current_thread)
+ {
+ /* if the destination thread is not the same as current thread */
+ pcpu->current_priority = (rt_uint8_t)highest_ready_priority;
+
+ RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (current_thread, to_thread));
+
+ rt_schedule_remove_thread(to_thread);
+ to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
+
+ /* switch to new thread */
+ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
+ ("[%d]switch to priority#%d "
+ "thread:%.*s(sp:0x%08x), "
+ "from thread:%.*s(sp: 0x%08x)\n",
+ pcpu->irq_nest, highest_ready_priority,
+ RT_NAME_MAX, to_thread->name, to_thread->sp,
+ RT_NAME_MAX, current_thread->name, current_thread->sp));
+
+#ifdef RT_USING_OVERFLOW_CHECK
+ _rt_scheduler_stack_check(to_thread);
+#endif
+
+ rt_hw_context_switch((rt_ubase_t)&current_thread->sp,
+ (rt_ubase_t)&to_thread->sp, to_thread);
+ }
+ }
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+#ifdef RT_USING_SIGNALS
+ /* check stat of thread for signal */
+ level = rt_hw_interrupt_disable();
+ if (current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
+ {
+ extern void rt_thread_handle_sig(rt_bool_t clean_state);
+
+ current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
+
+ rt_hw_interrupt_enable(level);
+
+ /* check signal status */
+ rt_thread_handle_sig(RT_TRUE);
+ }
+ else
+ {
+ rt_hw_interrupt_enable(level);
+ }
+#endif
+
+__exit:
+ return ;
+}
+#else
/**
* This function will perform one schedule. It will select one thread
* with the highest priority level, then switch to it.
@@ -186,81 +427,210 @@ void rt_schedule(void)
/* check the scheduler is enabled or not */
if (rt_scheduler_lock_nest == 0)
{
- register rt_ubase_t highest_ready_priority;
+ rt_ubase_t highest_ready_priority;
-#if RT_THREAD_PRIORITY_MAX <= 32
- highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
-#else
- register rt_ubase_t number;
+ if (rt_thread_ready_priority_group != 0)
+ {
+ /* need_insert_from_thread: need to insert from_thread to ready queue */
+ int need_insert_from_thread = 0;
- number = __rt_ffs(rt_thread_ready_priority_group) - 1;
- highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
-#endif
+ to_thread = _get_highest_priority_thread(&highest_ready_priority);
- /* get switch to thread */
- to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
- struct rt_thread,
- tlist);
+ if ((rt_current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
+ {
+ if (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)
+ {
+ to_thread = rt_current_thread;
+ }
+ else
+ {
+ rt_current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
+ need_insert_from_thread = 1;
+ }
+ }
- /* if the destination thread is not the same as current thread */
- if (to_thread != rt_current_thread)
- {
- rt_current_priority = (rt_uint8_t)highest_ready_priority;
- from_thread = rt_current_thread;
- rt_current_thread = to_thread;
+ if (to_thread != rt_current_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;
+
+ RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));
+
+ if (need_insert_from_thread)
+ {
+ rt_schedule_insert_thread(from_thread);
+ }
- RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));
+ rt_schedule_remove_thread(to_thread);
+ to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
- /* switch to new thread */
- RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
- ("[%d]switch to priority#%d "
- "thread:%.*s(sp:0x%p), "
- "from thread:%.*s(sp: 0x%p)\n",
- rt_interrupt_nest, highest_ready_priority,
- RT_NAME_MAX, to_thread->name, to_thread->sp,
- RT_NAME_MAX, from_thread->name, from_thread->sp));
+ /* switch to new thread */
+ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
+ ("[%d]switch to priority#%d "
+ "thread:%.*s(sp:0x%08x), "
+ "from thread:%.*s(sp: 0x%08x)\n",
+ rt_interrupt_nest, highest_ready_priority,
+ RT_NAME_MAX, to_thread->name, to_thread->sp,
+ RT_NAME_MAX, from_thread->name, from_thread->sp));
#ifdef RT_USING_OVERFLOW_CHECK
- _rt_scheduler_stack_check(to_thread);
+ _rt_scheduler_stack_check(to_thread);
#endif
- if (rt_interrupt_nest == 0)
- {
- extern void rt_thread_handle_sig(rt_bool_t clean_state);
+ if (rt_interrupt_nest == 0)
+ {
+ extern void rt_thread_handle_sig(rt_bool_t clean_state);
- rt_hw_context_switch((rt_uint32_t)&from_thread->sp,
- (rt_uint32_t)&to_thread->sp);
+ rt_hw_context_switch((rt_ubase_t)&from_thread->sp,
+ (rt_ubase_t)&to_thread->sp);
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
#ifdef RT_USING_SIGNALS
- /* check signal status */
- rt_thread_handle_sig(RT_TRUE);
+ /* check stat of thread for signal */
+ level = rt_hw_interrupt_disable();
+ if (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_hw_interrupt_enable(level);
+
+ /* check signal status */
+ rt_thread_handle_sig(RT_TRUE);
+ }
+ else
+ {
+ rt_hw_interrupt_enable(level);
+ }
#endif
+ goto __exit;
+ }
+ else
+ {
+ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));
+
+ rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,
+ (rt_ubase_t)&to_thread->sp);
+ }
}
else
{
- RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));
-
- rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp,
- (rt_uint32_t)&to_thread->sp);
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
+ rt_schedule_remove_thread(rt_current_thread);
+ rt_current_thread->stat = RT_THREAD_RUNNING | (rt_current_thread->stat & ~RT_THREAD_STAT_MASK);
}
}
- else
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+__exit:
+ return;
+}
+#endif /*RT_USING_SMP*/
+
+/**
+ * This function checks if a scheduling is needed after IRQ context. If yes,
+ * it will select one thread with the highest priority level, and then switch
+ * to it.
+ */
+#ifdef RT_USING_SMP
+void rt_scheduler_do_irq_switch(void *context)
+{
+ int cpu_id;
+ rt_base_t level;
+ struct rt_cpu* pcpu;
+ struct rt_thread *to_thread;
+ struct rt_thread *current_thread;
+
+ level = rt_hw_interrupt_disable();
+
+ cpu_id = rt_hw_cpu_id();
+ pcpu = rt_cpu_index(cpu_id);
+ current_thread = pcpu->current_thread;
+
+#ifdef RT_USING_SIGNALS
+ if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
+ {
+ /* if current_thread signal is in pending */
+
+ if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING)
{
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
+ rt_thread_resume(current_thread);
}
}
- else
+#endif
+
+ if (pcpu->irq_switch_flag == 0)
{
- /* enable interrupt */
rt_hw_interrupt_enable(level);
+ return;
}
+
+ if (current_thread->scheduler_lock_nest == 1 && pcpu->irq_nest == 0)
+ {
+ rt_ubase_t highest_ready_priority;
+
+ /* clear irq switch flag */
+ pcpu->irq_switch_flag = 0;
+
+ if (rt_thread_ready_priority_group != 0 || pcpu->priority_group != 0)
+ {
+ to_thread = _get_highest_priority_thread(&highest_ready_priority);
+ current_thread->oncpu = RT_CPU_DETACHED;
+ if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING)
+ {
+ if (current_thread->current_priority < highest_ready_priority)
+ {
+ to_thread = current_thread;
+ }
+ else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0)
+ {
+ to_thread = current_thread;
+ }
+ else
+ {
+ current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK;
+ rt_schedule_insert_thread(current_thread);
+ }
+ }
+ to_thread->oncpu = cpu_id;
+ if (to_thread != current_thread)
+ {
+ /* if the destination thread is not the same as current thread */
+
+ pcpu->current_priority = (rt_uint8_t)highest_ready_priority;
+
+ RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (current_thread, to_thread));
+
+ rt_schedule_remove_thread(to_thread);
+ to_thread->stat = RT_THREAD_RUNNING | (to_thread->stat & ~RT_THREAD_STAT_MASK);
+
+#ifdef RT_USING_OVERFLOW_CHECK
+ _rt_scheduler_stack_check(to_thread);
+#endif
+ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));
+
+ current_thread->cpus_lock_nest--;
+ current_thread->scheduler_lock_nest--;
+
+ rt_hw_context_switch_interrupt(context, (rt_ubase_t)&current_thread->sp,
+ (rt_ubase_t)&to_thread->sp, to_thread);
+ }
+ }
+ }
+ rt_hw_interrupt_enable(level);
}
+#endif /*RT_USING_SMP*/
/*
* This function will insert a thread to system ready queue. The state of
@@ -269,6 +639,72 @@ void rt_schedule(void)
* @param thread the thread to be inserted
* @note Please do not invoke this function in user application.
*/
+#ifdef RT_USING_SMP
+void rt_schedule_insert_thread(struct rt_thread *thread)
+{
+ int cpu_id;
+ int bind_cpu;
+ rt_uint32_t cpu_mask;
+ register rt_base_t level;
+
+ RT_ASSERT(thread != RT_NULL);
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ /* it should be RUNNING thread */
+ if (thread->oncpu != RT_CPU_DETACHED)
+ {
+ thread->stat = RT_THREAD_RUNNING | (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);
+
+ cpu_id = rt_hw_cpu_id();
+ bind_cpu = thread->bind_cpu ;
+
+ /* insert thread to ready list */
+ if (bind_cpu == RT_CPUS_NR)
+ {
+#if RT_THREAD_PRIORITY_MAX > 32
+ rt_thread_ready_table[thread->number] |= thread->high_mask;
+#endif
+ rt_thread_ready_priority_group |= thread->number_mask;
+
+ rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
+ &(thread->tlist));
+ cpu_mask = RT_CPU_MASK ^ (1 << cpu_id);
+ rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
+ }
+ else
+ {
+ struct rt_cpu *pcpu = rt_cpu_index(bind_cpu);
+
+#if RT_THREAD_PRIORITY_MAX > 32
+ pcpu->ready_table[thread->number] |= thread->high_mask;
+#endif
+ pcpu->priority_group |= thread->number_mask;
+
+ rt_list_insert_before(&(rt_cpu_index(bind_cpu)->priority_table[thread->current_priority]),
+ &(thread->tlist));
+
+ if (cpu_id != bind_cpu)
+ {
+ cpu_mask = 1 << bind_cpu;
+ rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
+ }
+ }
+
+ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n",
+ RT_NAME_MAX, thread->name, thread->current_priority));
+
+__exit:
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+}
+#else
void rt_schedule_insert_thread(struct rt_thread *thread)
{
register rt_base_t temp;
@@ -278,35 +714,33 @@ void rt_schedule_insert_thread(struct rt_thread *thread)
/* disable interrupt */
temp = rt_hw_interrupt_disable();
- /* change stat */
- thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
+ /* 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);
+ goto __exit;
+ }
+ /* READY thread, insert to ready queue */
+ thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);
/* insert thread to ready list */
rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
&(thread->tlist));
- /* set priority mask */
-#if RT_THREAD_PRIORITY_MAX <= 32
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n",
RT_NAME_MAX, thread->name, thread->current_priority));
-#else
- RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
- ("insert thread[%.*s], the priority: %d 0x%x %d\n",
- RT_NAME_MAX,
- thread->name,
- thread->number,
- thread->number_mask,
- thread->high_mask));
-#endif
+ /* set priority mask */
#if RT_THREAD_PRIORITY_MAX > 32
rt_thread_ready_table[thread->number] |= thread->high_mask;
#endif
rt_thread_ready_priority_group |= thread->number_mask;
+__exit:
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
+#endif /*RT_USING_SMP*/
/*
* This function will remove a thread from system ready queue.
@@ -315,28 +749,71 @@ void rt_schedule_insert_thread(struct rt_thread *thread)
*
* @note Please do not invoke this function in user application.
*/
+#ifdef RT_USING_SMP
void rt_schedule_remove_thread(struct rt_thread *thread)
{
- register rt_base_t temp;
+ register rt_base_t level;
RT_ASSERT(thread != RT_NULL);
/* disable interrupt */
- temp = rt_hw_interrupt_disable();
+ level = rt_hw_interrupt_disable();
-#if RT_THREAD_PRIORITY_MAX <= 32
RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n",
RT_NAME_MAX, thread->name,
thread->current_priority));
+
+ /* remove thread from ready list */
+ rt_list_remove(&(thread->tlist));
+ if (thread->bind_cpu == RT_CPUS_NR)
+ {
+ if (rt_list_isempty(&(rt_thread_priority_table[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_priority_group &= ~thread->number_mask;
+ }
#else
- RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
- ("remove thread[%.*s], the priority: %d 0x%x %d\n",
- RT_NAME_MAX,
- thread->name,
- thread->number,
- thread->number_mask,
- thread->high_mask));
+ rt_thread_ready_priority_group &= ~thread->number_mask;
#endif
+ }
+ }
+ else
+ {
+ struct rt_cpu *pcpu = rt_cpu_index(thread->bind_cpu);
+
+ if (rt_list_isempty(&(pcpu->priority_table[thread->current_priority])))
+ {
+#if RT_THREAD_PRIORITY_MAX > 32
+ pcpu->ready_table[thread->number] &= ~thread->high_mask;
+ if (rt_thread_ready_table[thread->number] == 0)
+ {
+ pcpu->priority_group &= ~thread->number_mask;
+ }
+#else
+ pcpu->priority_group &= ~thread->number_mask;
+#endif
+ }
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+}
+#else
+void rt_schedule_remove_thread(struct rt_thread *thread)
+{
+ register rt_base_t level;
+
+ RT_ASSERT(thread != RT_NULL);
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n",
+ RT_NAME_MAX, thread->name,
+ thread->current_priority));
/* remove thread from ready list */
rt_list_remove(&(thread->tlist));
@@ -354,12 +831,50 @@ void rt_schedule_remove_thread(struct rt_thread *thread)
}
/* enable interrupt */
- rt_hw_interrupt_enable(temp);
+ rt_hw_interrupt_enable(level);
}
+#endif /*RT_USING_SMP*/
/**
* This function will lock the thread scheduler.
*/
+#ifdef RT_USING_SMP
+void rt_enter_critical(void)
+{
+ register rt_base_t level;
+ struct rt_thread *current_thread;
+
+ /* disable interrupt */
+ level = rt_hw_local_irq_disable();
+
+ current_thread = rt_cpu_self()->current_thread;
+ if (!current_thread)
+ {
+ rt_hw_local_irq_enable(level);
+ return ;
+ }
+
+ /*
+ * the maximal number of nest is RT_UINT16_MAX, which is big
+ * enough and does not check here
+ */
+
+ /* lock scheduler for all cpus */
+ if (current_thread->critical_lock_nest == 0)
+ {
+ rt_hw_spin_lock(&_rt_critical_lock);
+ }
+
+ /* critical for local cpu */
+ current_thread->critical_lock_nest ++;
+
+ /* lock scheduler for local cpu */
+ current_thread->scheduler_lock_nest ++;
+
+ /* enable interrupt */
+ rt_hw_local_irq_enable(level);
+}
+#else
void rt_enter_critical(void)
{
register rt_base_t level;
@@ -376,11 +891,52 @@ void rt_enter_critical(void)
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
+#endif /*RT_USING_SMP*/
RTM_EXPORT(rt_enter_critical);
/**
* This function will unlock the thread scheduler.
*/
+#ifdef RT_USING_SMP
+void rt_exit_critical(void)
+{
+ register rt_base_t level;
+ struct rt_thread *current_thread;
+
+ /* disable interrupt */
+ level = rt_hw_local_irq_disable();
+
+ current_thread = rt_cpu_self()->current_thread;
+ if (!current_thread)
+ {
+ rt_hw_local_irq_enable(level);
+ return ;
+ }
+
+ current_thread->scheduler_lock_nest --;
+
+ current_thread->critical_lock_nest --;
+
+ if (current_thread->critical_lock_nest == 0)
+ {
+ rt_hw_spin_unlock(&_rt_critical_lock);
+ }
+
+ if (current_thread->scheduler_lock_nest <= 0)
+ {
+ current_thread->scheduler_lock_nest = 0;
+ /* enable interrupt */
+ rt_hw_local_irq_enable(level);
+
+ rt_schedule();
+ }
+ else
+ {
+ /* enable interrupt */
+ rt_hw_local_irq_enable(level);
+ }
+}
+#else
void rt_exit_critical(void)
{
register rt_base_t level;
@@ -389,14 +945,17 @@ void rt_exit_critical(void)
level = rt_hw_interrupt_disable();
rt_scheduler_lock_nest --;
-
if (rt_scheduler_lock_nest <= 0)
{
rt_scheduler_lock_nest = 0;
/* enable interrupt */
rt_hw_interrupt_enable(level);
- rt_schedule();
+ if (rt_current_thread)
+ {
+ /* if scheduler is started, do a schedule */
+ rt_schedule();
+ }
}
else
{
@@ -404,6 +963,7 @@ void rt_exit_critical(void)
rt_hw_interrupt_enable(level);
}
}
+#endif /*RT_USING_SMP*/
RTM_EXPORT(rt_exit_critical);
/**
@@ -413,8 +973,14 @@ RTM_EXPORT(rt_exit_critical);
*/
rt_uint16_t rt_critical_level(void)
{
+#ifdef RT_USING_SMP
+ struct rt_thread *current_thread = rt_cpu_self()->current_thread;
+
+ return current_thread->critical_lock_nest;
+#else
return rt_scheduler_lock_nest;
+#endif /*RT_USING_SMP*/
}
RTM_EXPORT(rt_critical_level);
-/**@}*/
+/**@}*/
diff --git a/src/signal.c b/src/signal.c
index c783420514..bb9339ab6c 100644
--- a/src/signal.c
+++ b/src/signal.c
@@ -6,6 +6,8 @@
* Change Logs:
* Date Author Notes
* 2017/10/5 Bernard the first version
+ * 2018/09/17 Jesven fix: in _signal_deliver RT_THREAD_STAT_MASK to RT_THREAD_STAT_SIGNAL_MASK
+ * 2018/11/22 Jesven in smp version rt_hw_context_switch_to add a param
*/
#include <stdint.h>
@@ -20,10 +22,8 @@
#define RT_SIG_INFO_MAX 32
#endif
-// #define DBG_ENABLE
-#define DBG_SECTION_NAME "SIGN"
-#define DBG_COLOR
-#define DBG_LEVEL DBG_LOG
+#define DBG_TAG "SIGN"
+#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
#define sig_mask(sig_no) (1u << sig_no)
@@ -41,7 +41,7 @@ void rt_thread_handle_sig(rt_bool_t clean_state);
static void _signal_default_handler(int signo)
{
- dbg_log(DBG_INFO, "handled signo[%d] with default action.\n", signo);
+ LOG_I("handled signo[%d] with default action.", signo);
return ;
}
@@ -49,21 +49,34 @@ static void _signal_entry(void *parameter)
{
rt_thread_t tid = rt_thread_self();
- dbg_enter;
-
/* handle signal */
rt_thread_handle_sig(RT_FALSE);
- /* never come back... */
- rt_hw_interrupt_disable();
+#ifdef RT_USING_SMP
+ {
+ struct rt_cpu* pcpu = rt_cpu_self();
+
+ pcpu->current_thread->cpus_lock_nest--;
+ if (pcpu->current_thread->cpus_lock_nest == 0)
+ {
+ pcpu->current_thread->scheduler_lock_nest--;
+ }
+
+ }
+#else
/* return to thread */
tid->sp = tid->sig_ret;
tid->sig_ret = RT_NULL;
+#endif
- dbg_log(DBG_LOG, "switch back to: 0x%08x\n", tid->sp);
+ LOG_D("switch back to: 0x%08x\n", tid->sp);
tid->stat &= ~RT_THREAD_STAT_SIGNAL;
- rt_hw_context_switch_to((rt_uint32_t) & (tid->sp));
+#ifdef RT_USING_SMP
+ rt_hw_context_switch_to((rt_base_t)&parameter, tid);
+#else
+ rt_hw_context_switch_to((rt_ubase_t)&(tid->sp));
+#endif /*RT_USING_SMP*/
}
/*
@@ -80,16 +93,21 @@ static void _signal_deliver(rt_thread_t tid)
{
rt_ubase_t level;
+ level = rt_hw_interrupt_disable();
+
/* thread is not interested in pended signals */
- if (!(tid->sig_pending & tid->sig_mask)) return;
+ if (!(tid->sig_pending & tid->sig_mask))
+ {
+ rt_hw_interrupt_enable(level);
+ return;
+ }
- level = rt_hw_interrupt_disable();
if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
{
/* resume thread to handle signal */
rt_thread_resume(tid);
/* add signal state */
- tid->stat |= RT_THREAD_STAT_SIGNAL;
+ tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
rt_hw_interrupt_enable(level);
@@ -106,20 +124,39 @@ static void _signal_deliver(rt_thread_t tid)
rt_hw_interrupt_enable(level);
/* do signal action in self thread context */
- rt_thread_handle_sig(RT_TRUE);
+ if (rt_interrupt_get_nest() == 0)
+ {
+ rt_thread_handle_sig(RT_TRUE);
+ }
}
- else if (!((tid->stat & RT_THREAD_STAT_MASK) & RT_THREAD_STAT_SIGNAL))
+ else if (!((tid->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL))
{
/* add signal state */
- tid->stat |= RT_THREAD_STAT_SIGNAL;
+ tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);
+#ifdef RT_USING_SMP
+ {
+ int cpu_id;
+
+ cpu_id = tid->oncpu;
+ if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_hw_cpu_id()))
+ {
+ rt_uint32_t cpu_mask;
+
+ cpu_mask = RT_CPU_MASK ^ (1 << cpu_id);
+ rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
+ }
+ }
+#else
/* point to the signal handle entry */
+ 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_hw_interrupt_enable(level);
- dbg_log(DBG_LOG, "signal stack pointer @ 0x%08x\n", tid->sp);
+ LOG_D("signal stack pointer @ 0x%08x", tid->sp);
/* re-schedule */
rt_schedule();
@@ -131,14 +168,53 @@ static void _signal_deliver(rt_thread_t tid)
}
}
+#ifdef RT_USING_SMP
+void *rt_signal_check(void* context)
+{
+ rt_base_t level;
+ int cpu_id;
+ struct rt_cpu* pcpu;
+ struct rt_thread *current_thread;
+
+ level = rt_hw_interrupt_disable();
+ 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);
+ return context;
+ }
+
+ if (current_thread->cpus_lock_nest == 1)
+ {
+ if (current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
+ {
+ void *sig_context;
+
+ current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
+
+ rt_hw_interrupt_enable(level);
+ sig_context = rt_hw_stack_init((void *)_signal_entry, context,
+ (void *)(context - 32), RT_NULL);
+ return sig_context;
+ }
+ }
+ rt_hw_interrupt_enable(level);
+ return context;
+}
+#endif
+
rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
{
+ rt_base_t level;
rt_sighandler_t old = RT_NULL;
rt_thread_t tid = rt_thread_self();
if (!sig_valid(signo)) return SIG_ERR;
- rt_enter_critical();
+ level = rt_hw_interrupt_disable();
if (tid->sig_vectors == RT_NULL)
{
rt_thread_alloc_sig(tid);
@@ -152,7 +228,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_exit_critical();
+ rt_hw_interrupt_enable(level);
return old;
}
@@ -268,9 +344,22 @@ __done:
{
*si = si_node->si;
- dbg_log(DBG_LOG, "sigwait: %d sig raised!\n", signo);
+ LOG_D("sigwait: %d sig raised!", signo);
if (si_prev) si_prev->list.next = si_node->list.next;
- else tid->si_list = si_node->list.next;
+ else
+ {
+ struct siginfo_node *node_next;
+
+ if (si_node->list.next)
+ {
+ node_next = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
+ tid->si_list = node_next;
+ }
+ else
+ {
+ tid->si_list = RT_NULL;
+ }
+ }
/* clear pending */
tid->sig_pending &= ~sig_mask(signo);
@@ -279,7 +368,14 @@ __done:
}
si_prev = si_node;
- si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
+ if (si_node->list.next)
+ {
+ si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
+ }
+ else
+ {
+ si_node = RT_NULL;
+ }
}
__done_int:
@@ -318,13 +414,13 @@ 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);
- dbg_log(DBG_LOG, "handle signal: %d, handler 0x%08x\n", signo, handler);
+ LOG_D("handle signal: %d, handler 0x%08x", signo, handler);
if (handler) handler(signo);
level = rt_hw_interrupt_disable();
- tid->sig_pending &= ~sig_mask(signo);
error = -RT_EINTR;
rt_mp_free(si_node); /* release this siginfo node */
@@ -333,10 +429,16 @@ 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;
+ if (clean_state == RT_TRUE)
+ {
+ tid->stat &= ~RT_THREAD_STAT_SIGNAL;
+ }
+ else
+ {
+ return;
+ }
}
}
-
rt_hw_interrupt_enable(level);
}
@@ -362,30 +464,30 @@ void rt_thread_alloc_sig(rt_thread_t tid)
void rt_thread_free_sig(rt_thread_t tid)
{
rt_base_t level;
- struct siginfo_node *si_list;
+ struct siginfo_node *si_node;
rt_sighandler_t *sig_vectors;
level = rt_hw_interrupt_disable();
- si_list = (struct siginfo_node *)tid->si_list;
+ 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);
- if (si_list)
+ if (si_node)
{
struct rt_slist_node *node;
- struct siginfo_node *si_node;
+ struct rt_slist_node *node_to_free;
- dbg_log(DBG_LOG, "free signal info list\n");
- node = &(si_list->list);
+ LOG_D("free signal info list");
+ node = &(si_node->list);
do
{
- si_node = rt_slist_entry(node, struct siginfo_node, list);
- rt_mp_free(si_node);
-
+ node_to_free = node;
node = node->next;
+ si_node = rt_slist_entry(node_to_free, struct siginfo_node, list);
+ rt_mp_free(si_node);
} while (node);
}
@@ -404,7 +506,7 @@ int rt_thread_kill(rt_thread_t tid, int sig)
RT_ASSERT(tid != RT_NULL);
if (!sig_valid(sig)) return -RT_EINVAL;
- dbg_log(DBG_INFO, "send signal: %d\n", sig);
+ LOG_I("send signal: %d", sig);
si.si_signo = sig;
si.si_code = SI_USER;
si.si_value.sival_ptr = RT_NULL;
@@ -416,30 +518,23 @@ int rt_thread_kill(rt_thread_t tid, int sig)
struct rt_slist_node *node;
struct siginfo_node *entry;
- node = (struct rt_slist_node *)tid->si_list;
- rt_hw_interrupt_enable(level);
+ si_node = (struct siginfo_node *)tid->si_list;
+ if (si_node)
+ node = (struct rt_slist_node *)&si_node->list;
+ else
+ node = RT_NULL;
/* update sig info */
- rt_enter_critical();
for (; (node) != RT_NULL; node = node->next)
{
entry = rt_slist_entry(node, struct siginfo_node, list);
if (entry->si.si_signo == sig)
{
memcpy(&(entry->si), &si, sizeof(siginfo_t));
- rt_exit_critical();
+ rt_hw_interrupt_enable(level);
return 0;
}
}
- rt_exit_critical();
-
- /* disable interrupt to protect tcb */
- level = rt_hw_interrupt_disable();
- }
- else
- {
- /* a new signal */
- tid->sig_pending |= sig_mask(sig);
}
rt_hw_interrupt_enable(level);
@@ -450,19 +545,27 @@ int rt_thread_kill(rt_thread_t tid, int sig)
memcpy(&(si_node->si), &si, sizeof(siginfo_t));
level = rt_hw_interrupt_disable();
- if (!tid->si_list) tid->si_list = si_node;
- else
+
+ if (tid->si_list)
{
struct siginfo_node *si_list;
si_list = (struct siginfo_node *)tid->si_list;
rt_slist_append(&(si_list->list), &(si_node->list));
}
+ else
+ {
+ tid->si_list = si_node;
+ }
+
+ /* a new signal */
+ tid->sig_pending |= sig_mask(sig);
+
rt_hw_interrupt_enable(level);
}
else
{
- dbg_log(DBG_ERROR, "The allocation of signal info node failed.\n");
+ LOG_E("The allocation of signal info node failed.");
}
/* deliver signal to this thread */
@@ -476,7 +579,7 @@ int rt_system_signal_init(void)
_rt_siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node));
if (_rt_siginfo_pool == RT_NULL)
{
- dbg_log(DBG_ERROR, "create memory pool for signal info failed.\n");
+ LOG_E("create memory pool for signal info failed.");
RT_ASSERT(0);
}
diff --git a/src/slab.c b/src/slab.c
index bf26c84cca..0872ecf092 100644
--- a/src/slab.c
+++ b/src/slab.c
@@ -217,9 +217,9 @@ struct memusage
};
static struct memusage *memusage = RT_NULL;
#define btokup(addr) \
- (&memusage[((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS])
+ (&memusage[((rt_ubase_t)(addr) - heap_start) >> RT_MM_PAGE_BITS])
-static rt_uint32_t heap_start, heap_end;
+static rt_ubase_t heap_start, heap_end;
/* page allocator */
struct rt_page_head
@@ -275,7 +275,7 @@ void rt_page_free(void *addr, rt_size_t npages)
struct rt_page_head **prev;
RT_ASSERT(addr != RT_NULL);
- RT_ASSERT((rt_uint32_t)addr % RT_MM_PAGE_SIZE == 0);
+ RT_ASSERT((rt_ubase_t)addr % RT_MM_PAGE_SIZE == 0);
RT_ASSERT(npages != 0);
n = (struct rt_page_head *)addr;
@@ -348,13 +348,13 @@ void rt_system_heap_init(void *begin_addr, void *end_addr)
RT_DEBUG_NOT_IN_INTERRUPT;
/* align begin and end addr to page */
- heap_start = RT_ALIGN((rt_uint32_t)begin_addr, RT_MM_PAGE_SIZE);
- heap_end = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_MM_PAGE_SIZE);
+ heap_start = RT_ALIGN((rt_ubase_t)begin_addr, RT_MM_PAGE_SIZE);
+ heap_end = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_MM_PAGE_SIZE);
if (heap_start >= heap_end)
{
rt_kprintf("rt_system_heap_init, wrong address[0x%x - 0x%x]\n",
- (rt_uint32_t)begin_addr, (rt_uint32_t)end_addr);
+ (rt_ubase_t)begin_addr, (rt_ubase_t)end_addr);
return;
}
@@ -391,17 +391,17 @@ void rt_system_heap_init(void *begin_addr, void *end_addr)
memusage = rt_page_alloc(limsize / RT_MM_PAGE_SIZE);
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("memusage 0x%x, size 0x%x\n",
- (rt_uint32_t)memusage, limsize));
+ (rt_ubase_t)memusage, limsize));
}
/*
* Calculate the zone index for the allocation request size and set the
* allocation request size to that particular zone's chunk size.
*/
-rt_inline int zoneindex(rt_uint32_t *bytes)
+rt_inline int zoneindex(rt_size_t *bytes)
{
/* unsigned for shift opt */
- rt_uint32_t n = (rt_uint32_t) * bytes;
+ rt_ubase_t n = (rt_ubase_t)(*bytes);
if (n < 128)
{
@@ -507,7 +507,7 @@ void *rt_malloc(rt_size_t size)
("malloc a large memory 0x%x, page cnt %d, kup %d\n",
size,
size >> RT_MM_PAGE_BITS,
- ((rt_uint32_t)chunk - heap_start) >> RT_MM_PAGE_BITS));
+ ((rt_ubase_t)chunk - heap_start) >> RT_MM_PAGE_BITS));
/* lock heap */
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
@@ -610,7 +610,7 @@ void *rt_malloc(rt_size_t size)
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("alloc a new zone: 0x%x\n",
- (rt_uint32_t)z));
+ (rt_ubase_t)z));
/* set message usage */
for (off = 0, kup = btokup(z); off < zone_page_cnt; off ++)
@@ -694,7 +694,7 @@ void *rt_realloc(void *ptr, rt_size_t size)
* Get the original allocation's zone. If the new request winds up
* using the same chunk size we do not have to do anything.
*/
- kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
+ kup = btokup((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK);
if (kup->type == PAGE_TYPE_LARGE)
{
rt_size_t osize;
@@ -709,7 +709,7 @@ void *rt_realloc(void *ptr, rt_size_t size)
}
else if (kup->type == PAGE_TYPE_SMALL)
{
- z = (slab_zone *)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) -
+ z = (slab_zone *)(((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK) -
kup->size * RT_MM_PAGE_SIZE);
RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC);
@@ -783,20 +783,20 @@ void rt_free(void *ptr)
/* get memory usage */
#if RT_DEBUG_SLAB
{
- rt_uint32_t addr = ((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
+ rt_ubase_t addr = ((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK);
RT_DEBUG_LOG(RT_DEBUG_SLAB,
("free a memory 0x%x and align to 0x%x, kup index %d\n",
- (rt_uint32_t)ptr,
- (rt_uint32_t)addr,
- ((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS));
+ (rt_ubase_t)ptr,
+ (rt_ubase_t)addr,
+ ((rt_ubase_t)(addr) - heap_start) >> RT_MM_PAGE_BITS));
}
#endif
- kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK);
+ kup = btokup((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK);
/* release large allocation */
if (kup->type == PAGE_TYPE_LARGE)
{
- rt_uint32_t size;
+ rt_ubase_t size;
/* lock heap */
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
@@ -811,7 +811,7 @@ void rt_free(void *ptr)
RT_DEBUG_LOG(RT_DEBUG_SLAB,
("free large memory block 0x%x, page count %d\n",
- (rt_uint32_t)ptr, size));
+ (rt_ubase_t)ptr, size));
/* free this page */
rt_page_free(ptr, size);
@@ -823,7 +823,7 @@ void rt_free(void *ptr)
rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
/* zone case. get out zone. */
- z = (slab_zone *)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) -
+ z = (slab_zone *)(((rt_ubase_t)ptr & ~RT_MM_PAGE_MASK) -
kup->size * RT_MM_PAGE_SIZE);
RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC);
@@ -857,7 +857,7 @@ void rt_free(void *ptr)
slab_zone **pz;
RT_DEBUG_LOG(RT_DEBUG_SLAB, ("free zone 0x%x\n",
- (rt_uint32_t)z, z->z_zoneindex));
+ (rt_ubase_t)z, z->z_zoneindex));
/* remove zone from zone array list */
for (pz = &zone_array[z->z_zoneindex]; z != *pz; pz = &(*pz)->z_next)
diff --git a/src/thread.c b/src/thread.c
index 6d79ece54b..19ab5549c8 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -23,18 +23,17 @@
* 2012-12-29 Bernard fixed compiling warning.
* 2016-08-09 ArdaFu add thread suspend and resume hook.
* 2017-04-10 armink fixed the rt_thread_delete and rt_thread_detach
- bug when thread has not startup.
+ * bug when thread has not startup.
+ * 2018-11-22 Jesven yield is same to rt_schedule
+ * add support for tasks bound to cpu
*/
-#include <rtthread.h>
#include <rthw.h>
+#include <rtthread.h>
-extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
-extern struct rt_thread *rt_current_thread;
extern rt_list_t rt_thread_defunct;
#ifdef RT_USING_HOOK
-
static void (*rt_thread_suspend_hook)(rt_thread_t thread);
static void (*rt_thread_resume_hook) (rt_thread_t thread);
static void (*rt_thread_inited_hook) (rt_thread_t thread);
@@ -84,7 +83,7 @@ void rt_thread_exit(void)
register rt_base_t level;
/* get current thread */
- thread = rt_current_thread;
+ thread = rt_thread_self();
/* disable interrupt */
level = rt_hw_interrupt_disable();
@@ -108,11 +107,11 @@ void rt_thread_exit(void)
rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
}
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
-
/* switch to next task */
rt_schedule();
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
}
static rt_err_t _rt_thread_init(struct rt_thread *thread,
@@ -136,9 +135,15 @@ static rt_err_t _rt_thread_init(struct rt_thread *thread,
/* init thread stack */
rt_memset(thread->stack_addr, '#', thread->stack_size);
+#ifdef ARCH_CPU_STACK_GROWS_UPWARD
+ thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
+ (void *)((char *)thread->stack_addr),
+ (void *)rt_thread_exit);
+#else
thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
- (void *)((char *)thread->stack_addr + thread->stack_size - 4),
+ (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
(void *)rt_thread_exit);
+#endif
/* priority init */
RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
@@ -159,11 +164,22 @@ static rt_err_t _rt_thread_init(struct rt_thread *thread,
thread->error = RT_EOK;
thread->stat = RT_THREAD_INIT;
+#ifdef RT_USING_SMP
+ /* not bind on any cpu */
+ thread->bind_cpu = RT_CPUS_NR;
+ thread->oncpu = RT_CPU_DETACHED;
+
+ /* lock init */
+ thread->scheduler_lock_nest = 0;
+ thread->cpus_lock_nest = 0;
+ thread->critical_lock_nest = 0;
+#endif /*RT_USING_SMP*/
+
/* initialize cleanup function and user data */
thread->cleanup = 0;
thread->user_data = 0;
- /* init thread timer */
+ /* initialize thread timer */
rt_timer_init(&(thread->thread_timer),
thread->name,
rt_thread_timeout,
@@ -176,7 +192,9 @@ static rt_err_t _rt_thread_init(struct rt_thread *thread,
thread->sig_mask = 0x00;
thread->sig_pending = 0x00;
+#ifndef RT_USING_SMP
thread->sig_ret = RT_NULL;
+#endif
thread->sig_vectors = RT_NULL;
thread->si_list = RT_NULL;
#endif
@@ -224,7 +242,7 @@ rt_err_t rt_thread_init(struct rt_thread *thread,
RT_ASSERT(thread != RT_NULL);
RT_ASSERT(stack_start != RT_NULL);
- /* init thread object */
+ /* initialize thread object */
rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
return _rt_thread_init(thread,
@@ -245,7 +263,19 @@ RTM_EXPORT(rt_thread_init);
*/
rt_thread_t rt_thread_self(void)
{
+#ifdef RT_USING_SMP
+ rt_base_t lock;
+ rt_thread_t self;
+
+ lock = rt_hw_local_irq_disable();
+ self = rt_cpu_self()->current_thread;
+ rt_hw_local_irq_enable(lock);
+ return self;
+#else
+ extern rt_thread_t rt_current_thread;
+
return rt_current_thread;
+#endif
}
RTM_EXPORT(rt_thread_self);
@@ -263,7 +293,7 @@ rt_err_t rt_thread_startup(rt_thread_t thread)
RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
- /* set current priority to init priority */
+ /* set current priority to initialize priority */
thread->current_priority = thread->init_priority;
/* calculate priority attribute */
@@ -320,17 +350,17 @@ rt_err_t rt_thread_detach(rt_thread_t thread)
/* change stat */
thread->stat = RT_THREAD_CLOSE;
- /* detach object */
- rt_object_detach((rt_object_t)thread);
-
- if (thread->cleanup != RT_NULL)
+ if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
+ thread->cleanup == RT_NULL)
+ {
+ rt_object_detach((rt_object_t)thread);
+ }
+ else
{
/* disable interrupt */
lock = rt_hw_interrupt_disable();
-
/* insert to defunct thread list */
rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
-
/* enable interrupt */
rt_hw_interrupt_enable(lock);
}
@@ -339,7 +369,6 @@ rt_err_t rt_thread_detach(rt_thread_t thread)
}
RTM_EXPORT(rt_thread_detach);
-
#ifdef RT_USING_HEAP
/**
* This function will create a thread object and allocate thread object memory
@@ -417,12 +446,12 @@ rt_err_t rt_thread_delete(rt_thread_t thread)
/* release thread timer */
rt_timer_detach(&(thread->thread_timer));
- /* change stat */
- thread->stat = RT_THREAD_CLOSE;
-
/* disable interrupt */
lock = rt_hw_interrupt_disable();
+ /* change stat */
+ thread->stat = RT_THREAD_CLOSE;
+
/* insert to defunct thread list */
rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
@@ -443,36 +472,7 @@ RTM_EXPORT(rt_thread_delete);
*/
rt_err_t rt_thread_yield(void)
{
- register rt_base_t level;
- struct rt_thread *thread;
-
- /* disable interrupt */
- level = rt_hw_interrupt_disable();
-
- /* set to current thread */
- thread = rt_current_thread;
-
- /* if the thread stat is READY and on ready queue list */
- if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&
- thread->tlist.next != thread->tlist.prev)
- {
- /* remove thread from thread list */
- rt_list_remove(&(thread->tlist));
-
- /* put thread to end of ready queue */
- rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
- &(thread->tlist));
-
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
-
- rt_schedule();
-
- return RT_EOK;
- }
-
- /* enable interrupt */
- rt_hw_interrupt_enable(level);
+ rt_schedule();
return RT_EOK;
}
@@ -490,13 +490,14 @@ rt_err_t rt_thread_sleep(rt_tick_t tick)
register rt_base_t temp;
struct rt_thread *thread;
- /* disable interrupt */
- temp = rt_hw_interrupt_disable();
/* set to current thread */
- thread = rt_current_thread;
+ thread = rt_thread_self();
RT_ASSERT(thread != RT_NULL);
RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
+ /* disable interrupt */
+ temp = rt_hw_interrupt_disable();
+
/* suspend thread */
rt_thread_suspend(thread);
@@ -530,9 +531,66 @@ rt_err_t rt_thread_delay(rt_tick_t tick)
RTM_EXPORT(rt_thread_delay);
/**
+ * This function will let current thread delay until (*tick + inc_tick).
+ *
+ * @param tick the tick of last wakeup.
+ * @param inc_tick the increment tick
+ *
+ * @return RT_EOK
+ */
+rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
+{
+ register rt_base_t level;
+ struct rt_thread *thread;
+
+ RT_ASSERT(tick != RT_NULL);
+
+ /* set to current thread */
+ thread = rt_thread_self();
+ RT_ASSERT(thread != RT_NULL);
+ RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
+
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
+
+ if (rt_tick_get() - *tick < inc_tick)
+ {
+ *tick = rt_tick_get() - *tick + inc_tick;
+
+ /* suspend thread */
+ rt_thread_suspend(thread);
+
+ /* reset the timeout of thread timer and start it */
+ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, tick);
+ rt_timer_start(&(thread->thread_timer));
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
+
+ rt_schedule();
+
+ /* clear error number of this thread to RT_EOK */
+ if (thread->error == -RT_ETIMEOUT)
+ {
+ thread->error = RT_EOK;
+ }
+ }
+ else
+ {
+ rt_hw_interrupt_enable(level);
+ }
+
+ /* get the wakeup tick */
+ *tick = rt_tick_get();
+
+ return RT_EOK;
+}
+RTM_EXPORT(rt_thread_delay_until);
+
+/**
* This function will let current thread delay for some milliseconds.
*
- * @param tick the delay time
+ * @param ms the delay ms time
*
* @return RT_EOK
*/
@@ -553,7 +611,8 @@ RTM_EXPORT(rt_thread_mdelay);
* @param cmd the control command, which includes
* RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
* RT_THREAD_CTRL_STARTUP for starting a thread;
- * RT_THREAD_CTRL_CLOSE for delete a thread.
+ * RT_THREAD_CTRL_CLOSE for delete a thread;
+ * RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.
* @param arg the argument of control command
*
* @return RT_EOK
@@ -619,6 +678,22 @@ rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
return rt_thread_delete(thread);
#endif
+#ifdef RT_USING_SMP
+ case RT_THREAD_CTRL_BIND_CPU:
+ {
+ rt_uint8_t cpu;
+
+ if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
+ {
+ /* we only support bind cpu before started phase. */
+ return RT_ERROR;
+ }
+
+ cpu = (rt_uint8_t)(size_t)arg;
+ thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu;
+ break;
+ }
+#endif /*RT_USING_SMP*/
default:
break;
}
@@ -639,6 +714,7 @@ RTM_EXPORT(rt_thread_control);
*/
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
+ register rt_base_t stat;
register rt_base_t temp;
/* thread check */
@@ -647,20 +723,25 @@ rt_err_t rt_thread_suspend(rt_thread_t thread)
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
- if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
+ stat = thread->stat & RT_THREAD_STAT_MASK;
+ if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
{
RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
thread->stat));
-
return -RT_ERROR;
}
/* disable interrupt */
temp = rt_hw_interrupt_disable();
+ if (stat == RT_THREAD_RUNNING)
+ {
+ /* not suspend running status thread on other core */
+ RT_ASSERT(thread == rt_thread_self());
+ }
/* change thread stat */
- thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
rt_schedule_remove_thread(thread);
+ thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);
/* stop thread timer anyway */
rt_timer_stop(&(thread->thread_timer));
diff --git a/src/timer.c b/src/timer.c
index dc489a2d0d..0034f0246c 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -43,7 +43,8 @@ static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
#ifdef RT_USING_HOOK
extern void (*rt_object_take_hook)(struct rt_object *object);
extern void (*rt_object_put_hook)(struct rt_object *object);
-static void (*rt_timer_timeout_hook)(struct rt_timer *timer);
+static void (*rt_timer_enter_hook)(struct rt_timer *timer);
+static void (*rt_timer_exit_hook)(struct rt_timer *timer);
/**
* @addtogroup Hook
@@ -52,14 +53,25 @@ static void (*rt_timer_timeout_hook)(struct rt_timer *timer);
/**@{*/
/**
- * This function will set a hook function, which will be invoked when timer
- * is timeout.
+ * This function will set a hook function, which will be invoked when enter
+ * timer timeout callback function.
*
* @param hook the hook function
*/
-void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer))
+void rt_timer_enter_sethook(void (*hook)(struct rt_timer *timer))
{
- rt_timer_timeout_hook = hook;
+ rt_timer_enter_hook = hook;
+}
+
+/**
+ * This function will set a hook function, which will be invoked when exit
+ * timer timeout callback function.
+ *
+ * @param hook the hook function
+ */
+void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer))
+{
+ rt_timer_exit_hook = hook;
}
/**@}*/
@@ -96,14 +108,23 @@ static void _rt_timer_init(rt_timer_t timer,
static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[])
{
struct rt_timer *timer;
+ register rt_base_t level;
+ rt_tick_t timeout_tick = RT_TICK_MAX;
- if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
- return RT_TICK_MAX;
+ /* disable interrupt */
+ level = rt_hw_interrupt_disable();
- timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
- struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
+ if (!rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
+ {
+ timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
+ struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
+ timeout_tick = timer->timeout_tick;
+ }
+
+ /* enable interrupt */
+ rt_hw_interrupt_enable(level);
- return timer->timeout_tick;
+ return timeout_tick;
}
rt_inline void _rt_timer_remove(rt_timer_t timer)
@@ -387,7 +408,7 @@ rt_err_t rt_timer_start(rt_timer_t timer)
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
/* check whether timer thread is ready */
- if ((timer_thread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
+ if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
{
/* resume timer thread to check soft timer */
rt_thread_resume(&timer_thread);
@@ -467,6 +488,19 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
case RT_TIMER_CTRL_SET_PERIODIC:
timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
break;
+ /* zhaoshimin 20191204 add query the timer state */
+ case RT_TIMER_CTRL_GET_STATE:
+ if(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
+ {
+ /*timer is start and run*/
+ *(rt_tick_t *)arg = RT_TIMER_FLAG_ACTIVATED;
+ }
+ else
+ {
+ /*timer is stop*/
+ *(rt_tick_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
+ }
+ break;
}
return RT_EOK;
@@ -503,7 +537,7 @@ void rt_timer_check(void)
*/
if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
{
- RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
+ RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
/* remove timer from timer list firstly */
_rt_timer_remove(t);
@@ -514,6 +548,7 @@ void rt_timer_check(void)
/* re-get tick */
current_tick = rt_tick_get();
+ RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
@@ -578,7 +613,7 @@ void rt_soft_timer_check(void)
*/
if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
{
- RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
+ RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
/* move node to the next */
n = n->next;
@@ -594,6 +629,7 @@ void rt_soft_timer_check(void)
/* re-get tick */
current_tick = rt_tick_get();
+ RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
/* lock scheduler */