summaryrefslogtreecommitdiff
path: root/src/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread.c')
-rw-r--r--src/thread.c234
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.
*