diff options
| author | HubretXie <[email protected]> | 2019-11-26 09:30:21 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2019-11-26 09:30:21 +0800 |
| commit | 17f7f1c7ca2581b2e308888f8acb99ca8a541422 (patch) | |
| tree | 5236e93ab1e4e24508d4ebf4540b6743dd7c9a41 /src | |
| parent | 9662e18c3688681cd95ebd65242773dbe7c1366b (diff) | |
| parent | e459084fe028c837762d40326a9be3dfdc179894 (diff) | |
Merge pull request #8 from RT-Thread/master
sync
Diffstat (limited to 'src')
| -rw-r--r-- | src/Kconfig | 12 | ||||
| -rw-r--r-- | src/SConscript | 6 | ||||
| -rw-r--r-- | src/clock.c | 2 | ||||
| -rw-r--r-- | src/components.c | 7 | ||||
| -rw-r--r-- | src/cpu.c | 99 | ||||
| -rw-r--r-- | src/idle.c | 12 | ||||
| -rw-r--r-- | src/ipc.c | 132 | ||||
| -rw-r--r-- | src/mempool.c | 14 | ||||
| -rw-r--r-- | src/scheduler.c | 47 | ||||
| -rw-r--r-- | src/thread.c | 13 |
10 files changed, 286 insertions, 58 deletions
diff --git a/src/Kconfig b/src/Kconfig index d301d25f55..22942a017e 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -20,7 +20,7 @@ config RT_USING_ARCH_DATA_TYPE config RT_USING_SMP bool "Enable SMP(Symmetric multiprocessing)" default n - help + 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 @@ -28,10 +28,10 @@ config RT_USING_SMP config RT_CPUS_NR int "Number of CPUs" - default 2 - depends on RT_USING_SMP + default 2 + depends on RT_USING_SMP help - Number of CPUs in the system + Number of CPUs in the system config RT_ALIGN_SIZE int "Alignment size for CPU architecture data access" @@ -86,8 +86,8 @@ config RT_USING_IDLE_HOOK default y if RT_USING_HOOK if RT_USING_IDLE_HOOK - config RT_IDEL_HOOK_LIST_SIZE - int "The max size of idel hook list" + config RT_IDLE_HOOK_LIST_SIZE + int "The max size of idle hook list" default 4 range 1 16 help diff --git a/src/SConscript b/src/SConscript index 7f448725a2..82c3b8aaf1 100644 --- a/src/SConscript +++ b/src/SConscript @@ -6,9 +6,6 @@ src = Glob('*.c') CPPPATH = [RTT_ROOT + '/include'] -if GetDepend('RT_USING_COMPONENTS_INIT') == False: - SrcRemove(src, ['components.c']) - if GetDepend('RT_USING_MODULE') == False: SrcRemove(src, ['module.c']) @@ -29,6 +26,9 @@ if GetDepend('RT_USING_MEMHEAP') == False: if GetDepend('RT_USING_DEVICE') == False: SrcRemove(src, ['device.c']) +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 a652282b6e..9b54101363 100644 --- a/src/clock.c +++ b/src/clock.c @@ -89,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(); } diff --git a/src/components.c b/src/components.c index b9fc4c178c..df3e0f0fb3 100644 --- a/src/components.c +++ b/src/components.c @@ -126,6 +126,7 @@ void rt_components_init(void) } #endif } +#endif /* RT_USING_COMPONENTS_INIT */ #ifdef RT_USING_USER_MAIN @@ -173,10 +174,11 @@ 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 @@ -254,4 +256,3 @@ int rtthread_startup(void) return 0; } #endif -#endif @@ -7,15 +7,106 @@ * Date Author Notes * 2018-10-30 Bernard The first version */ - -#include <rtthread.h> #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. */ @@ -42,7 +133,7 @@ rt_base_t rt_cpus_lock(void) pcpu = rt_cpu_self(); if (pcpu->current_thread != RT_NULL) { - register rt_uint16_t lock_nest = pcpu->current_thread->cpus_lock_nest; + register rt_ubase_t lock_nest = pcpu->current_thread->cpus_lock_nest; pcpu->current_thread->cpus_lock_nest++; if (lock_nest == 0) diff --git a/src/idle.c b/src/idle.c index 1108bc3367..99db64f571 100644 --- a/src/idle.c +++ b/src/idle.c @@ -51,11 +51,11 @@ ALIGN(RT_ALIGN_SIZE) static rt_uint8_t rt_thread_stack[_CPUS_NR][IDLE_THREAD_STACK_SIZE]; #ifdef RT_USING_IDLE_HOOK -#ifndef RT_IDEL_HOOK_LIST_SIZE -#define RT_IDEL_HOOK_LIST_SIZE 4 +#ifndef RT_IDLE_HOOK_LIST_SIZE +#define RT_IDLE_HOOK_LIST_SIZE 4 #endif -static void (*idle_hook_list[RT_IDEL_HOOK_LIST_SIZE])(void); +static void (*idle_hook_list[RT_IDLE_HOOK_LIST_SIZE])(void); /** * @ingroup Hook @@ -78,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) { @@ -110,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) { @@ -246,7 +246,7 @@ static void rt_thread_idle_entry(void *parameter) #ifdef RT_USING_IDLE_HOOK rt_size_t i; - 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) { @@ -33,6 +33,7 @@ * 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> @@ -1823,6 +1824,9 @@ rt_err_t rt_mq_init(rt_mq_t mq, /* the initial entry is zero */ mq->entry = 0; + /* init an additional list of sender suspend thread */ + rt_list_init(&(mq->suspend_sender_thread)); + return RT_EOK; } RTM_EXPORT(rt_mq_init); @@ -1843,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)); @@ -1894,7 +1900,7 @@ 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; } @@ -1916,6 +1922,9 @@ rt_mq_t rt_mq_create(const char *name, /* the initial entry is zero */ mq->entry = 0; + /* init an additional list of sender suspend thread */ + rt_list_init(&(mq->suspend_sender_thread)); + return mq; } RTM_EXPORT(rt_mq_create); @@ -1938,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); @@ -1951,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, const 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); @@ -1975,6 +1992,11 @@ rt_err_t rt_mq_send(rt_mq_t mq, const 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 */ @@ -1982,14 +2004,78 @@ rt_err_t rt_mq_send(rt_mq_t mq, const 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; @@ -2037,6 +2123,22 @@ rt_err_t rt_mq_send(rt_mq_t mq, const 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); /** @@ -2257,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); @@ -2292,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/mempool.c b/src/mempool.c index 6b1fc81231..00471efb35 100644 --- a/src/mempool.c +++ b/src/mempool.c @@ -106,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; @@ -160,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); } @@ -226,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; @@ -282,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); } @@ -344,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) { @@ -431,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, @@ -444,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/scheduler.c b/src/scheduler.c index b487bd4b60..6baaa9627a 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -83,7 +83,7 @@ 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)) != '#' || + if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' || #else if (*((rt_uint8_t *)thread->stack_addr) != '#' || #endif @@ -344,8 +344,13 @@ void rt_schedule(void) { 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); } } @@ -379,7 +384,12 @@ void rt_schedule(void) } } + /* 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); @@ -395,9 +405,6 @@ void rt_schedule(void) { rt_hw_interrupt_enable(level); } -#else - /* enable interrupt */ - rt_hw_interrupt_enable(level); #endif __exit: @@ -435,8 +442,13 @@ void rt_schedule(void) { 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; } } @@ -477,7 +489,13 @@ void rt_schedule(void) rt_hw_context_switch((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp); + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + #ifdef RT_USING_SIGNALS + /* check stat of thread for signal */ + level = rt_hw_interrupt_disable(); if (rt_current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING) { extern void rt_thread_handle_sig(rt_bool_t clean_state); @@ -493,9 +511,6 @@ void rt_schedule(void) { rt_hw_interrupt_enable(level); } -#else - /* enable interrupt */ - rt_hw_interrupt_enable(level); #endif goto __exit; } @@ -578,8 +593,13 @@ void rt_scheduler_do_irq_switch(void *context) { 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); } } @@ -840,11 +860,14 @@ void rt_enter_critical(void) */ /* lock scheduler for all cpus */ - if (current_thread->scheduler_lock_nest == !!current_thread->cpus_lock_nest) + 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 ++; @@ -892,7 +915,9 @@ void rt_exit_critical(void) current_thread->scheduler_lock_nest --; - if (current_thread->scheduler_lock_nest == !!current_thread->cpus_lock_nest) + current_thread->critical_lock_nest --; + + if (current_thread->critical_lock_nest == 0) { rt_hw_spin_unlock(&_rt_critical_lock); } @@ -951,9 +976,9 @@ rt_uint16_t rt_critical_level(void) #ifdef RT_USING_SMP struct rt_thread *current_thread = rt_cpu_self()->current_thread; - return current_thread->scheduler_lock_nest; + return current_thread->critical_lock_nest; #else - return rt_scheduler_lock_nest; + return rt_scheduler_lock_nest; #endif /*RT_USING_SMP*/ } RTM_EXPORT(rt_critical_level); diff --git a/src/thread.c b/src/thread.c index ab203b1d49..c5f75a1176 100644 --- a/src/thread.c +++ b/src/thread.c @@ -107,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, @@ -172,6 +172,7 @@ static rt_err_t _rt_thread_init(struct rt_thread *thread, /* 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 */ @@ -445,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)); |
