diff options
Diffstat (limited to 'src/thread.c')
| -rw-r--r-- | src/thread.c | 234 |
1 files changed, 202 insertions, 32 deletions
diff --git a/src/thread.c b/src/thread.c index 9d37861c5a..1bc4169d30 100644 --- a/src/thread.c +++ b/src/thread.c @@ -133,7 +133,7 @@ static void _thread_timeout(void *parameter) /* parameter check */ RT_ASSERT(thread != RT_NULL); - RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND); + RT_ASSERT((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK); RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); /* disable interrupt */ @@ -167,6 +167,10 @@ static rt_err_t _thread_init(struct rt_thread *thread, /* init thread list */ rt_list_init(&(thread->tlist)); +#ifdef RT_USING_LWP + thread->wakeup.func = RT_NULL; +#endif + thread->entry = (void *)entry; thread->parameter = parameter; @@ -253,7 +257,13 @@ static rt_err_t _thread_init(struct rt_thread *thread, #ifdef RT_USING_LWP thread->lwp = RT_NULL; -#endif /* RT_USING_LWP */ + rt_list_init(&(thread->sibling)); + rt_memset(&thread->signal, 0, sizeof(lwp_sigset_t)); + rt_memset(&thread->signal_mask, 0, sizeof(lwp_sigset_t)); + thread->signal_mask_bak = 0; + thread->signal_in_process = 0; + rt_memset(&thread->user_ctx, 0, sizeof thread->user_ctx); +#endif #ifdef RT_USING_CPU_USAGE thread->duration_tick = 0; @@ -598,6 +608,7 @@ rt_err_t rt_thread_sleep(rt_tick_t tick) { rt_base_t level; struct rt_thread *thread; + int err; if (tick == 0) { @@ -619,22 +630,31 @@ rt_err_t rt_thread_sleep(rt_tick_t tick) thread->error = RT_EOK; /* suspend thread */ - rt_thread_suspend(thread); + err = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE); /* 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)); + if (err == RT_EOK) + { + 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); + /* enable interrupt */ + rt_hw_interrupt_enable(level); - rt_schedule(); + thread->error = -RT_EINTR; + + rt_schedule(); - /* clear error number of this thread to RT_EOK */ - if (thread->error == -RT_ETIMEOUT) - thread->error = RT_EOK; + /* clear error number of this thread to RT_EOK */ + if (thread->error == -RT_ETIMEOUT) + thread->error = RT_EOK; + } + else + { + rt_hw_interrupt_enable(level); + } - return thread->error; + return err; } /** @@ -689,7 +709,7 @@ rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick) left_tick = *tick - cur_tick; /* suspend thread */ - rt_thread_suspend(thread); + rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &left_tick); @@ -734,6 +754,66 @@ rt_err_t rt_thread_mdelay(rt_int32_t ms) } RTM_EXPORT(rt_thread_mdelay); +#ifdef RT_USING_SMP +static void rt_thread_cpu_bind(rt_thread_t thread, int cpu) +{ + rt_base_t level; + + if (cpu >= RT_CPUS_NR) + { + cpu = RT_CPUS_NR; + } + + level = rt_hw_interrupt_disable(); + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) + { + /* unbind */ + /* remove from old ready queue */ + rt_schedule_remove_thread(thread); + /* change thread bind cpu */ + thread->bind_cpu = cpu; + /* add to new ready queue */ + rt_schedule_insert_thread(thread); + if (rt_thread_self() != RT_NULL) + { + rt_schedule(); + } + } + else + { + thread->bind_cpu = cpu; + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) + { + /* thread is running on a cpu */ + int current_cpu = rt_hw_cpu_id(); + + if (cpu != RT_CPUS_NR) + { + if (thread->oncpu == current_cpu) + { + /* current thread on current cpu */ + if (cpu != current_cpu) + { + /* bind to other cpu */ + rt_hw_ipi_send(RT_SCHEDULE_IPI, 1U << cpu); + /* self cpu need reschedule */ + rt_schedule(); + } + /* else do nothing */ + } + else + { + /* no running on self cpu, but dest cpu can be itself */ + rt_hw_ipi_send(RT_SCHEDULE_IPI, 1U << thread->oncpu); + } + } + /* else do nothing */ + } + } + rt_hw_interrupt_enable(level); +} +#endif + /** * @brief This function will control thread behaviors according to control command. * @@ -837,26 +917,46 @@ rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg) { 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)(rt_size_t)arg; - thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu; - break; - } - #endif /* RT_USING_SMP */ - - default: - break; + cpu = (rt_uint8_t)(size_t)arg; + rt_thread_cpu_bind(thread, cpu); + break; + } +#endif /*RT_USING_SMP*/ + default: + break; } return RT_EOK; } RTM_EXPORT(rt_thread_control); +#ifdef RT_USING_LWP +int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag); +#endif + +static void rt_thread_set_suspend_state(struct rt_thread *thread, int suspend_flag) +{ + rt_uint8_t stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE; + + RT_ASSERT(thread != RT_NULL); + switch (suspend_flag) + { + case RT_INTERRUPTIBLE: + stat = RT_THREAD_SUSPEND_INTERRUPTIBLE; + break; + case RT_KILLABLE: + stat = RT_THREAD_SUSPEND_KILLABLE; + break; + case RT_UNINTERRUPTIBLE: + stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE; + break; + default: + RT_ASSERT(0); + break; + } + thread->stat = stat | (thread->stat & ~RT_THREAD_STAT_MASK); +} + /** * @brief This function will suspend the specified thread and change it to suspend state. * @@ -872,7 +972,7 @@ RTM_EXPORT(rt_thread_control); * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed. * If the return value is any other values, it means this operation failed. */ -rt_err_t rt_thread_suspend(rt_thread_t thread) +rt_err_t rt_thread_suspend_with_flag(rt_thread_t thread, int suspend_flag) { rt_base_t stat; rt_base_t level; @@ -893,10 +993,24 @@ rt_err_t rt_thread_suspend(rt_thread_t thread) /* disable interrupt */ level = rt_hw_interrupt_disable(); + if (stat == RT_THREAD_RUNNING) + { + /* not suspend running status thread on other core */ + RT_ASSERT(thread == rt_thread_self()); + } +#ifdef RT_USING_LWP + if (lwp_suspend_sigcheck(thread, suspend_flag) == 0) + { + /* not to suspend */ + rt_hw_interrupt_enable(level); + rt_kprintf("-RT_EINTR\r\n"); + return -RT_EINTR; + } +#endif /* change thread stat */ rt_schedule_remove_thread(thread); - thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK); + rt_thread_set_suspend_state(thread, suspend_flag); /* stop thread timer anyway */ rt_timer_stop(&(thread->thread_timer)); @@ -907,6 +1021,12 @@ rt_err_t rt_thread_suspend(rt_thread_t thread) RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread)); return RT_EOK; } +RTM_EXPORT(rt_thread_suspend_with_flag); + +rt_err_t rt_thread_suspend(rt_thread_t thread) +{ + return rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_thread_suspend); /** @@ -927,7 +1047,7 @@ rt_err_t rt_thread_resume(rt_thread_t thread) RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name)); - if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND) + if ((thread->stat & RT_THREAD_SUSPEND_MASK) != RT_THREAD_SUSPEND_MASK) { RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n", thread->stat)); @@ -943,17 +1063,67 @@ rt_err_t rt_thread_resume(rt_thread_t thread) rt_timer_stop(&thread->thread_timer); - /* insert to schedule ready list */ - rt_schedule_insert_thread(thread); +#ifdef RT_USING_LWP + thread->wakeup.func = RT_NULL; +#endif /* enable interrupt */ rt_hw_interrupt_enable(level); + /* insert to schedule ready list */ + rt_schedule_insert_thread(thread); + RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread)); return RT_EOK; } RTM_EXPORT(rt_thread_resume); +#ifdef RT_USING_LWP +/** + * This function will wakeup a thread with customized operation. + * + * @param thread the thread to be resumed + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_wakeup(rt_thread_t thread) +{ + register rt_base_t temp; + rt_err_t ret; + + 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(); + if (thread->wakeup.func) + { + ret = thread->wakeup.func(thread->wakeup.user_data, thread); + thread->wakeup.func = RT_NULL; + } + else + { + ret = rt_thread_resume(thread); + } + + rt_hw_interrupt_enable(temp); + return ret; +} +RTM_EXPORT(rt_thread_wakeup); + +void rt_thread_wakeup_set(struct rt_thread *thread, rt_wakeup_func_t func, void* user_data) +{ + register rt_base_t temp; + + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + temp = rt_hw_interrupt_disable(); + thread->wakeup.func = func; + thread->wakeup.user_data = user_data; + rt_hw_interrupt_enable(temp); +} +RTM_EXPORT(rt_thread_wakeup_set); +#endif /** * @brief This function will find the specified thread. * |
