1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2006-03-28 Bernard first version
9 * 2006-04-29 Bernard implement thread timer
10 * 2006-04-30 Bernard added THREAD_DEBUG
11 * 2006-05-27 Bernard fixed the rt_thread_yield bug
12 * 2006-06-03 Bernard fixed the thread timer init bug
13 * 2006-08-10 Bernard fixed the timer bug in thread_sleep
14 * 2006-09-03 Bernard changed rt_timer_delete to rt_timer_detach
15 * 2006-09-03 Bernard implement rt_thread_detach
16 * 2008-02-16 Bernard fixed the rt_thread_timeout bug
17 * 2010-03-21 Bernard change the errno of rt_thread_delay/sleep to
18 * RT_EOK.
19 * 2010-11-10 Bernard add cleanup callback function in thread exit.
20 * 2011-09-01 Bernard fixed rt_thread_exit issue when the current
21 * thread preempted, which reported by Jiaxing Lee.
22 * 2011-09-08 Bernard fixed the scheduling issue in rt_thread_startup.
23 * 2012-12-29 Bernard fixed compiling warning.
24 * 2016-08-09 ArdaFu add thread suspend and resume hook.
25 * 2017-04-10 armink fixed the rt_thread_delete and rt_thread_detach
26 * bug when thread has not startup.
27 * 2018-11-22 Jesven yield is same to rt_schedule
28 * add support for tasks bound to cpu
29 * 2021-02-24 Meco Man rearrange rt_thread_control() - schedule the thread when close it
30 * 2021-11-15 THEWON Remove duplicate work between idle and _thread_exit
31 * 2021-12-27 Meco Man remove .init_priority
32 * 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to thread.c
33 * 2022-01-24 THEWON let _thread_sleep return thread->error when using signal
34 * 2022-10-15 Bernard add nested mutex feature
35 * 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
36 * 2023-12-10 xqyjlj fix thread_exit/detach/delete
37 * fix rt_thread_delay
38 */
39
40 #include <rthw.h>
41 #include <rtthread.h>
42 #include <stddef.h>
43
44 #define DBG_TAG "kernel.thread"
45 #define DBG_LVL DBG_INFO
46 #include <rtdbg.h>
47
48 #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
49 static void (*rt_thread_suspend_hook)(rt_thread_t thread);
50 static void (*rt_thread_resume_hook) (rt_thread_t thread);
51
52 /**
53 * @brief This function sets a hook function when the system suspend a thread.
54 *
55 * @note The hook function must be simple and never be blocked or suspend.
56 *
57 * @param hook is the specified hook function.
58 */
rt_thread_suspend_sethook(void (* hook)(rt_thread_t thread))59 void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread))
60 {
61 rt_thread_suspend_hook = hook;
62 }
63
64 /**
65 * @brief This function sets a hook function when the system resume a thread.
66 *
67 * @note The hook function must be simple and never be blocked or suspend.
68 *
69 * @param hook is the specified hook function.
70 */
rt_thread_resume_sethook(void (* hook)(rt_thread_t thread))71 void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread))
72 {
73 rt_thread_resume_hook = hook;
74 }
75
76 RT_OBJECT_HOOKLIST_DEFINE(rt_thread_inited);
77 #endif /* defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR) */
78
79 #ifdef RT_USING_MUTEX
_thread_detach_from_mutex(rt_thread_t thread)80 static void _thread_detach_from_mutex(rt_thread_t thread)
81 {
82 rt_list_t *node;
83 rt_list_t *tmp_list;
84 struct rt_mutex *mutex;
85 rt_base_t level;
86
87 level = rt_spin_lock_irqsave(&thread->spinlock);
88
89 /* check if thread is waiting on a mutex */
90 if ((thread->pending_object) &&
91 (rt_object_get_type(thread->pending_object) == RT_Object_Class_Mutex))
92 {
93 /* remove it from its waiting list */
94 struct rt_mutex *mutex = (struct rt_mutex*)thread->pending_object;
95 rt_mutex_drop_thread(mutex, thread);
96 thread->pending_object = RT_NULL;
97 }
98
99 /* free taken mutex after detaching from waiting, so we don't lost mutex just got */
100 rt_list_for_each_safe(node, tmp_list, &(thread->taken_object_list))
101 {
102 mutex = rt_list_entry(node, struct rt_mutex, taken_list);
103 LOG_D("Thread [%s] exits while holding mutex [%s].\n", thread->parent.name, mutex->parent.parent.name);
104 /* recursively take */
105 mutex->hold = 1;
106 rt_mutex_release(mutex);
107 }
108
109 rt_spin_unlock_irqrestore(&thread->spinlock, level);
110 }
111
112 #else
113
_thread_detach_from_mutex(rt_thread_t thread)114 static void _thread_detach_from_mutex(rt_thread_t thread) {}
115 #endif
116
_thread_exit(void)117 static void _thread_exit(void)
118 {
119 struct rt_thread *thread;
120 rt_base_t critical_level;
121
122 /* get current thread */
123 thread = rt_thread_self();
124
125 critical_level = rt_enter_critical();
126
127 rt_thread_close(thread);
128
129 _thread_detach_from_mutex(thread);
130
131 /* insert to defunct thread list */
132 rt_thread_defunct_enqueue(thread);
133
134 rt_exit_critical_safe(critical_level);
135
136 /* switch to next task */
137 rt_schedule();
138 }
139
140 /**
141 * @brief This function is the timeout function for thread, normally which is invoked
142 * when thread is timeout to wait some resource.
143 *
144 * @param parameter is the parameter of thread timeout function
145 */
_thread_timeout(void * parameter)146 static void _thread_timeout(void *parameter)
147 {
148 struct rt_thread *thread;
149 rt_sched_lock_level_t slvl;
150
151 thread = (struct rt_thread *)parameter;
152
153 /* parameter check */
154 RT_ASSERT(thread != RT_NULL);
155 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
156
157 rt_sched_lock(&slvl);
158
159 /**
160 * resume of the thread and stop of the thread timer should be an atomic
161 * operation. So we don't expected that thread had resumed.
162 */
163 RT_ASSERT(rt_sched_thread_is_suspended(thread));
164
165 /* set error number */
166 thread->error = -RT_ETIMEOUT;
167
168 /* remove from suspend list */
169 rt_list_remove(&RT_THREAD_LIST_NODE(thread));
170 /* insert to schedule ready list */
171 rt_sched_insert_thread(thread);
172 /* do schedule and release the scheduler lock */
173 rt_sched_unlock_n_resched(slvl);
174 }
175
_thread_init(struct rt_thread * thread,const char * name,void (* entry)(void * parameter),void * parameter,void * stack_start,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick)176 static rt_err_t _thread_init(struct rt_thread *thread,
177 const char *name,
178 void (*entry)(void *parameter),
179 void *parameter,
180 void *stack_start,
181 rt_uint32_t stack_size,
182 rt_uint8_t priority,
183 rt_uint32_t tick)
184 {
185 RT_UNUSED(name);
186
187 rt_sched_thread_init_ctx(thread, tick, priority);
188
189 #ifdef RT_USING_MEM_PROTECTION
190 thread->mem_regions = RT_NULL;
191 #endif
192
193 #ifdef RT_USING_SMART
194 thread->wakeup_handle.func = RT_NULL;
195 #endif
196
197 thread->entry = (void *)entry;
198 thread->parameter = parameter;
199
200 /* stack init */
201 thread->stack_addr = stack_start;
202 thread->stack_size = stack_size;
203
204 /* init thread stack */
205 rt_memset(thread->stack_addr, '#', thread->stack_size);
206 #ifdef RT_USING_HW_STACK_GUARD
207 rt_hw_stack_guard_init(thread);
208 #endif
209 #ifdef ARCH_CPU_STACK_GROWS_UPWARD
210 thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
211 (void *)((char *)thread->stack_addr),
212 (void *)_thread_exit);
213 #else
214 thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
215 (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
216 (void *)_thread_exit);
217 #endif /* ARCH_CPU_STACK_GROWS_UPWARD */
218
219 #ifdef RT_USING_MUTEX
220 rt_list_init(&thread->taken_object_list);
221 thread->pending_object = RT_NULL;
222 #endif
223
224 #ifdef RT_USING_EVENT
225 thread->event_set = 0;
226 thread->event_info = 0;
227 #endif /* RT_USING_EVENT */
228
229 /* error and flags */
230 thread->error = RT_EOK;
231
232 /* lock init */
233 #ifdef RT_USING_SMP
234 rt_atomic_store(&thread->cpus_lock_nest, 0);
235 #endif
236
237 /* initialize cleanup function and user data */
238 thread->cleanup = 0;
239 thread->user_data = 0;
240
241 /* initialize thread timer */
242 rt_timer_init(&(thread->thread_timer),
243 thread->parent.name,
244 _thread_timeout,
245 thread,
246 0,
247 RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_THREAD_TIMER);
248
249 /* initialize signal */
250 #ifdef RT_USING_SIGNALS
251 thread->sig_mask = 0x00;
252 thread->sig_pending = 0x00;
253
254 #ifndef RT_USING_SMP
255 thread->sig_ret = RT_NULL;
256 #endif /* RT_USING_SMP */
257 thread->sig_vectors = RT_NULL;
258 thread->si_list = RT_NULL;
259 #endif /* RT_USING_SIGNALS */
260
261 #ifdef RT_USING_SMART
262 thread->tid_ref_count = 0;
263 thread->lwp = RT_NULL;
264 thread->susp_recycler = RT_NULL;
265 thread->robust_list = RT_NULL;
266 rt_list_init(&(thread->sibling));
267
268 /* lwp thread-signal init */
269 rt_memset(&thread->signal.sigset_mask, 0, sizeof(lwp_sigset_t));
270 rt_memset(&thread->signal.sig_queue.sigset_pending, 0, sizeof(lwp_sigset_t));
271 rt_list_init(&thread->signal.sig_queue.siginfo_list);
272
273 rt_memset(&thread->user_ctx, 0, sizeof thread->user_ctx);
274
275 /* initialize user_time and system_time */
276 thread->user_time = 0;
277 thread->system_time = 0;
278 #endif
279
280 #ifdef RT_USING_CPU_USAGE
281 thread->duration_tick = 0;
282 #endif /* RT_USING_CPU_USAGE */
283
284 #ifdef RT_USING_PTHREADS
285 thread->pthread_data = RT_NULL;
286 #endif /* RT_USING_PTHREADS */
287
288 #ifdef RT_USING_MODULE
289 thread->parent.module_id = 0;
290 #endif /* RT_USING_MODULE */
291
292 rt_spin_lock_init(&thread->spinlock);
293
294 RT_OBJECT_HOOKLIST_CALL(rt_thread_inited, (thread));
295
296 return RT_EOK;
297 }
298
299 /**
300 * @addtogroup group_thread_management
301 */
302
303 /**@{*/
304
305 /**
306 * @brief This function will initialize a thread. It's used to initialize a
307 * static thread object.
308 *
309 * @param thread is the static thread object.
310 *
311 * @param name is the name of thread, which shall be unique.
312 *
313 * @param entry is the entry function of thread.
314 *
315 * @param parameter is the parameter of thread enter function.
316 *
317 * @param stack_start is the start address of thread stack.
318 *
319 * @param stack_size is the size of thread stack.
320 *
321 * @param priority is the priority of thread.
322 *
323 * @param tick is the time slice if there are same priority thread.
324 *
325 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
326 * If the return value is any other values, it means this operation failed.
327 */
rt_thread_init(struct rt_thread * thread,const char * name,void (* entry)(void * parameter),void * parameter,void * stack_start,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick)328 rt_err_t rt_thread_init(struct rt_thread *thread,
329 const char *name,
330 void (*entry)(void *parameter),
331 void *parameter,
332 void *stack_start,
333 rt_uint32_t stack_size,
334 rt_uint8_t priority,
335 rt_uint32_t tick)
336 {
337 /* parameter check */
338 RT_ASSERT(thread != RT_NULL);
339 RT_ASSERT(stack_start != RT_NULL);
340 RT_ASSERT(tick != 0);
341
342 /* clean memory data of thread */
343 rt_memset(thread, 0x0, sizeof(struct rt_thread));
344
345 /* initialize thread object */
346 rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
347
348 return _thread_init(thread,
349 name,
350 entry,
351 parameter,
352 stack_start,
353 stack_size,
354 priority,
355 tick);
356 }
357 RTM_EXPORT(rt_thread_init);
358
359 /**
360 * @brief This function will return self thread object.
361 *
362 * @return The self thread object.
363 */
rt_thread_self(void)364 rt_thread_t rt_thread_self(void)
365 {
366 #ifndef RT_USING_SMP
367 return rt_cpu_self()->current_thread;
368
369 #elif defined (ARCH_USING_HW_THREAD_SELF)
370 return rt_hw_thread_self();
371
372 #else /* !ARCH_USING_HW_THREAD_SELF */
373 rt_thread_t self;
374 rt_base_t lock;
375
376 lock = rt_hw_local_irq_disable();
377 self = rt_cpu_self()->current_thread;
378 rt_hw_local_irq_enable(lock);
379
380 return self;
381 #endif /* ARCH_USING_HW_THREAD_SELF */
382 }
383 RTM_EXPORT(rt_thread_self);
384
385 /**
386 * @brief This function will start a thread and put it to system ready queue.
387 *
388 * @param thread is the thread to be started.
389 *
390 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
391 * If the return value is any other values, it means this operation failed.
392 */
rt_thread_startup(rt_thread_t thread)393 rt_err_t rt_thread_startup(rt_thread_t thread)
394 {
395 /* parameter check */
396 RT_ASSERT(thread != RT_NULL);
397 RT_ASSERT((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
398 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
399
400 LOG_D("startup a thread:%s with priority:%d",
401 thread->parent.name, RT_SCHED_PRIV(thread).current_priority);
402
403 /* calculate priority attribute and reset thread stat to suspend */
404 rt_sched_thread_startup(thread);
405
406 /* resume and do a schedule if scheduler is available */
407 rt_thread_resume(thread);
408
409 return RT_EOK;
410 }
411 RTM_EXPORT(rt_thread_startup);
412
413 /**
414 * @brief This function will close a thread. The thread object will be removed from
415 * thread queue and detached/deleted from the system object management.
416 * It's different from rt_thread_delete or rt_thread_detach that this will not enqueue
417 * the closing thread to cleanup queue.
418 *
419 * @param thread is the thread to be closed.
420 *
421 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
422 * If the return value is any other values, it means this operation failed.
423 */
rt_thread_close(rt_thread_t thread)424 rt_err_t rt_thread_close(rt_thread_t thread)
425 {
426 rt_sched_lock_level_t slvl;
427 rt_uint8_t thread_status;
428
429 /* forbid scheduling on current core if closing current thread */
430 RT_ASSERT(thread != rt_thread_self() || rt_critical_level());
431
432 /* before checking status of scheduler */
433 rt_sched_lock(&slvl);
434
435 /* check if thread is already closed */
436 thread_status = rt_sched_thread_get_stat(thread);
437 if (thread_status != RT_THREAD_CLOSE)
438 {
439 if (thread_status != RT_THREAD_INIT)
440 {
441 /* remove from schedule */
442 rt_sched_remove_thread(thread);
443 }
444
445 /* release thread timer */
446 rt_timer_detach(&(thread->thread_timer));
447
448 /* change stat */
449 rt_sched_thread_close(thread);
450 }
451
452 /* scheduler works are done */
453 rt_sched_unlock(slvl);
454
455 return RT_EOK;
456 }
457 RTM_EXPORT(rt_thread_close);
458
459 static rt_err_t _thread_detach(rt_thread_t thread);
460
461 /**
462 * @brief This function will detach a thread. The thread object will be removed from
463 * thread queue and detached/deleted from the system object management.
464 *
465 * @param thread is the thread to be deleted.
466 *
467 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
468 * If the return value is any other values, it means this operation failed.
469 */
rt_thread_detach(rt_thread_t thread)470 rt_err_t rt_thread_detach(rt_thread_t thread)
471 {
472 /* parameter check */
473 RT_ASSERT(thread != RT_NULL);
474 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
475 RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));
476
477 return _thread_detach(thread);
478 }
479 RTM_EXPORT(rt_thread_detach);
480
_thread_detach(rt_thread_t thread)481 static rt_err_t _thread_detach(rt_thread_t thread)
482 {
483 rt_err_t error;
484 rt_base_t critical_level;
485
486 /**
487 * forbid scheduling on current core before returning since current thread
488 * may be detached from scheduler.
489 */
490 critical_level = rt_enter_critical();
491
492 error = rt_thread_close(thread);
493
494 _thread_detach_from_mutex(thread);
495
496 /* insert to defunct thread list */
497 rt_thread_defunct_enqueue(thread);
498
499 rt_exit_critical_safe(critical_level);
500 return error;
501 }
502
503 #ifdef RT_USING_HEAP
504 /**
505 * @brief This function will create a thread object and allocate thread object memory.
506 * and stack.
507 *
508 * @param name is the name of thread, which shall be unique.
509 *
510 * @param entry is the entry function of thread.
511 *
512 * @param parameter is the parameter of thread enter function.
513 *
514 * @param stack_size is the size of thread stack.
515 *
516 * @param priority is the priority of thread.
517 *
518 * @param tick is the time slice if there are same priority thread.
519 *
520 * @return If the return value is a rt_thread structure pointer, the function is successfully executed.
521 * If the return value is RT_NULL, it means this operation failed.
522 */
rt_thread_create(const char * name,void (* entry)(void * parameter),void * parameter,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick)523 rt_thread_t rt_thread_create(const char *name,
524 void (*entry)(void *parameter),
525 void *parameter,
526 rt_uint32_t stack_size,
527 rt_uint8_t priority,
528 rt_uint32_t tick)
529 {
530 /* parameter check */
531 RT_ASSERT(tick != 0);
532
533 struct rt_thread *thread;
534 void *stack_start;
535
536 thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
537 name);
538 if (thread == RT_NULL)
539 return RT_NULL;
540
541 stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
542 if (stack_start == RT_NULL)
543 {
544 /* allocate stack failure */
545 rt_object_delete((rt_object_t)thread);
546
547 return RT_NULL;
548 }
549
550 _thread_init(thread,
551 name,
552 entry,
553 parameter,
554 stack_start,
555 stack_size,
556 priority,
557 tick);
558
559 return thread;
560 }
561 RTM_EXPORT(rt_thread_create);
562
563 /**
564 * @brief This function will delete a thread. The thread object will be removed from
565 * thread queue and deleted from system object management in the idle thread.
566 *
567 * @param thread is the thread to be deleted.
568 *
569 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
570 * If the return value is any other values, it means this operation failed.
571 */
rt_thread_delete(rt_thread_t thread)572 rt_err_t rt_thread_delete(rt_thread_t thread)
573 {
574 /* parameter check */
575 RT_ASSERT(thread != RT_NULL);
576 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
577 RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);
578
579 return _thread_detach(thread);
580 }
581 RTM_EXPORT(rt_thread_delete);
582 #endif /* RT_USING_HEAP */
583
584 /**
585 * @brief This function will let current thread yield processor, and scheduler will
586 * choose the highest thread to run. After yield processor, the current thread
587 * is still in READY state.
588 *
589 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
590 * If the return value is any other values, it means this operation failed.
591 */
rt_thread_yield(void)592 rt_err_t rt_thread_yield(void)
593 {
594 rt_sched_lock_level_t slvl;
595 rt_sched_lock(&slvl);
596
597 rt_sched_thread_yield(rt_thread_self());
598
599 rt_sched_unlock_n_resched(slvl);
600
601 return RT_EOK;
602 }
603 RTM_EXPORT(rt_thread_yield);
604
605 /**
606 * @brief This function will let current thread sleep for some ticks. Change current thread state to suspend,
607 * when the thread timer reaches the tick value, scheduler will awaken this thread.
608 *
609 * @param tick is the sleep ticks.
610 *
611 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
612 * If the return value is any other values, it means this operation failed.
613 */
_thread_sleep(rt_tick_t tick)614 static rt_err_t _thread_sleep(rt_tick_t tick)
615 {
616 struct rt_thread *thread;
617 rt_base_t critical_level;
618 int err;
619
620 if (tick == 0)
621 {
622 return -RT_EINVAL;
623 }
624
625 /* set to current thread */
626 thread = rt_thread_self();
627 RT_ASSERT(thread != RT_NULL);
628 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
629
630 /* current context checking */
631 RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
632
633 /* reset thread error */
634 thread->error = RT_EOK;
635
636 /* lock scheduler since current thread may be suspended */
637 critical_level = rt_enter_critical();
638
639 /* suspend thread */
640 err = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
641
642 /* reset the timeout of thread timer and start it */
643 if (err == RT_EOK)
644 {
645 rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
646 rt_timer_start(&(thread->thread_timer));
647
648 thread->error = -RT_EINTR;
649
650 /* notify a pending rescheduling */
651 rt_schedule();
652
653 /* exit critical and do a rescheduling */
654 rt_exit_critical_safe(critical_level);
655
656 /* clear error number of this thread to RT_EOK */
657 if (thread->error == -RT_ETIMEOUT)
658 thread->error = RT_EOK;
659 }
660 else
661 {
662 rt_exit_critical_safe(critical_level);
663 }
664
665 return err;
666 }
667
668 /**
669 * @brief This function will let current thread delay for some ticks.
670 *
671 * @param tick is the delay ticks.
672 *
673 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
674 * If the return value is any other values, it means this operation failed.
675 */
rt_thread_delay(rt_tick_t tick)676 rt_err_t rt_thread_delay(rt_tick_t tick)
677 {
678 return _thread_sleep(tick);
679 }
680 RTM_EXPORT(rt_thread_delay);
681
682 /**
683 * @brief This function will let current thread delay until (*tick + inc_tick).
684 *
685 * @param tick is the tick of last wakeup.
686 *
687 * @param inc_tick is the increment tick.
688 *
689 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
690 * If the return value is any other values, it means this operation failed.
691 */
rt_thread_delay_until(rt_tick_t * tick,rt_tick_t inc_tick)692 rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
693 {
694 struct rt_thread *thread;
695 rt_tick_t cur_tick;
696 rt_base_t critical_level;
697
698 RT_ASSERT(tick != RT_NULL);
699
700 /* set to current thread */
701 thread = rt_thread_self();
702 RT_ASSERT(thread != RT_NULL);
703 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
704
705 /* reset thread error */
706 thread->error = RT_EOK;
707
708 /* disable interrupt */
709 critical_level = rt_enter_critical();
710
711 cur_tick = rt_tick_get();
712 if (cur_tick - *tick < inc_tick)
713 {
714 rt_tick_t left_tick;
715
716 *tick += inc_tick;
717 left_tick = *tick - cur_tick;
718
719 /* suspend thread */
720 rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
721
722 /* reset the timeout of thread timer and start it */
723 rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &left_tick);
724 rt_timer_start(&(thread->thread_timer));
725
726 rt_exit_critical_safe(critical_level);
727
728 rt_schedule();
729
730 /* clear error number of this thread to RT_EOK */
731 if (thread->error == -RT_ETIMEOUT)
732 {
733 thread->error = RT_EOK;
734 }
735 }
736 else
737 {
738 *tick = cur_tick;
739 rt_exit_critical_safe(critical_level);
740 }
741
742 return thread->error;
743 }
744 RTM_EXPORT(rt_thread_delay_until);
745
746 /**
747 * @brief This function will let current thread delay for some milliseconds.
748 *
749 * @param ms is the delay ms time.
750 *
751 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
752 * If the return value is any other values, it means this operation failed.
753 */
rt_thread_mdelay(rt_int32_t ms)754 rt_err_t rt_thread_mdelay(rt_int32_t ms)
755 {
756 rt_tick_t tick;
757
758 tick = rt_tick_from_millisecond(ms);
759
760 return _thread_sleep(tick);
761 }
762 RTM_EXPORT(rt_thread_mdelay);
763
764 #ifdef RT_USING_SMP
765 #endif
766
767 /**
768 * @brief This function will control thread behaviors according to control command.
769 *
770 * @param thread is the specified thread to be controlled.
771 *
772 * @param cmd is the control command, which includes.
773 *
774 * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread.
775 *
776 * RT_THREAD_CTRL_STARTUP for starting a thread.
777 *
778 * RT_THREAD_CTRL_CLOSE for delete a thread.
779 *
780 * RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.
781 *
782 * RT_THREAD_CTRL_RESET_PRIORITY for reset priority level of thread.
783 *
784 * @param arg is the argument of control command.
785 *
786 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
787 * If the return value is any other values, it means this operation failed.
788 */
rt_thread_control(rt_thread_t thread,int cmd,void * arg)789 rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
790 {
791 /* parameter check */
792 RT_ASSERT(thread != RT_NULL);
793 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
794
795 switch (cmd)
796 {
797 case RT_THREAD_CTRL_CHANGE_PRIORITY:
798 {
799 rt_err_t error;
800 rt_sched_lock_level_t slvl;
801 rt_sched_lock(&slvl);
802 error = rt_sched_thread_change_priority(thread, *(rt_uint8_t *)arg);
803 rt_sched_unlock(slvl);
804 return error;
805 }
806
807 case RT_THREAD_CTRL_RESET_PRIORITY:
808 {
809 rt_err_t error;
810 rt_sched_lock_level_t slvl;
811 rt_sched_lock(&slvl);
812 error = rt_sched_thread_reset_priority(thread, *(rt_uint8_t *)arg);
813 rt_sched_unlock(slvl);
814 return error;
815 }
816
817 case RT_THREAD_CTRL_STARTUP:
818 {
819 return rt_thread_startup(thread);
820 }
821
822 case RT_THREAD_CTRL_CLOSE:
823 {
824 rt_err_t rt_err = -RT_EINVAL;
825
826 if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
827 {
828 rt_err = rt_thread_detach(thread);
829 }
830 #ifdef RT_USING_HEAP
831 else
832 {
833 rt_err = rt_thread_delete(thread);
834 }
835 #endif /* RT_USING_HEAP */
836 rt_schedule();
837 return rt_err;
838 }
839
840 case RT_THREAD_CTRL_BIND_CPU:
841 {
842 rt_uint8_t cpu;
843
844 cpu = (rt_uint8_t)(rt_size_t)arg;
845 return rt_sched_thread_bind_cpu(thread, cpu);
846 }
847
848 default:
849 break;
850 }
851
852 return RT_EOK;
853 }
854 RTM_EXPORT(rt_thread_control);
855
856 #ifdef RT_USING_SMART
857 #include <lwp_signal.h>
858 #endif
859
_thread_set_suspend_state(struct rt_thread * thread,int suspend_flag)860 static void _thread_set_suspend_state(struct rt_thread *thread, int suspend_flag)
861 {
862 rt_uint8_t stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
863
864 RT_ASSERT(thread != RT_NULL);
865 switch (suspend_flag)
866 {
867 case RT_INTERRUPTIBLE:
868 stat = RT_THREAD_SUSPEND_INTERRUPTIBLE;
869 break;
870 case RT_KILLABLE:
871 stat = RT_THREAD_SUSPEND_KILLABLE;
872 break;
873 case RT_UNINTERRUPTIBLE:
874 stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
875 break;
876 default:
877 RT_ASSERT(0);
878 break;
879 }
880 RT_SCHED_CTX(thread).stat = stat | (RT_SCHED_CTX(thread).stat & ~RT_THREAD_STAT_MASK);
881 }
882
883 /**
884 * @brief This function will suspend the specified thread and change it to suspend state.
885 *
886 * @note This function ONLY can suspend current thread itself.
887 * rt_thread_suspend(rt_thread_self());
888 *
889 * Do not use the rt_thread_suspend to suspend other threads. You have no way of knowing what code a
890 * thread is executing when you suspend it. If you suspend a thread while sharing a resouce with
891 * other threads and occupying this resouce, starvation can occur very easily.
892 *
893 * @param thread the thread to be suspended.
894 * @param susp_list the list thread enqueued to. RT_NULL if no list.
895 * @param ipc_flags is a flag for the thread object to be suspended. It determines how the thread is suspended.
896 * The flag can be ONE of the following values:
897 * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
898 * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
899 * (also known as first-come-first-served (FCFS) scheduling strategy).
900 * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to use
901 * RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
902 * the first-in-first-out principle, and you clearly understand that all threads involved in
903 * this semaphore will become non-real-time threads.
904 * @param suspend_flag status flag of the thread to be suspended.
905 *
906 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
907 * If the return value is any other values, it means this operation failed.
908 */
rt_thread_suspend_to_list(rt_thread_t thread,rt_list_t * susp_list,int ipc_flags,int suspend_flag)909 rt_err_t rt_thread_suspend_to_list(rt_thread_t thread, rt_list_t *susp_list, int ipc_flags, int suspend_flag)
910 {
911 rt_base_t stat;
912 rt_sched_lock_level_t slvl;
913
914 /* parameter check */
915 RT_ASSERT(thread != RT_NULL);
916 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
917 RT_ASSERT(thread == rt_thread_self());
918
919 LOG_D("thread suspend: %s", thread->parent.name);
920
921 rt_sched_lock(&slvl);
922
923 stat = rt_sched_thread_get_stat(thread);
924 if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
925 {
926 LOG_D("thread suspend: thread disorder, 0x%2x", RT_SCHED_CTX(thread).stat);
927 rt_sched_unlock(slvl);
928 return -RT_ERROR;
929 }
930
931 if (stat == RT_THREAD_RUNNING)
932 {
933 /* not suspend running status thread on other core */
934 RT_ASSERT(thread == rt_thread_self());
935 }
936
937 #ifdef RT_USING_SMART
938 if (thread->lwp)
939 {
940 rt_sched_unlock(slvl);
941
942 /* check pending signals for thread before suspend */
943 if (lwp_thread_signal_suspend_check(thread, suspend_flag) == 0)
944 {
945 /* not to suspend */
946 return -RT_EINTR;
947 }
948
949 rt_sched_lock(&slvl);
950 if (stat == RT_THREAD_READY)
951 {
952 stat = rt_sched_thread_get_stat(thread);
953
954 if (stat != RT_THREAD_READY)
955 {
956 /* status updated while we check for signal */
957 rt_sched_unlock(slvl);
958 return -RT_ERROR;
959 }
960 }
961 }
962 #endif
963
964 /* change thread stat */
965 rt_sched_remove_thread(thread);
966 _thread_set_suspend_state(thread, suspend_flag);
967
968 if (susp_list)
969 {
970 /**
971 * enqueue thread on the push list before leaving critical region of
972 * scheduler, so we won't miss notification of async events.
973 */
974 rt_susp_list_enqueue(susp_list, thread, ipc_flags);
975 }
976
977 /* stop thread timer anyway */
978 rt_sched_thread_timer_stop(thread);
979
980 rt_sched_unlock(slvl);
981
982 RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
983 return RT_EOK;
984 }
985 RTM_EXPORT(rt_thread_suspend_to_list);
986
987 /**
988 * @brief This function will suspend the specified thread and change it to suspend state.
989 *
990 * @note This function ONLY can suspend current thread itself.
991 * rt_thread_suspend(rt_thread_self());
992 *
993 * Do not use the rt_thread_suspend to suspend other threads. You have no way of knowing what code a
994 * thread is executing when you suspend it. If you suspend a thread while sharing a resouce with
995 * other threads and occupying this resouce, starvation can occur very easily.
996 *
997 * @param thread the thread to be suspended.
998 * @param suspend_flag status flag of the thread to be suspended.
999 *
1000 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
1001 * If the return value is any other values, it means this operation failed.
1002 */
rt_thread_suspend_with_flag(rt_thread_t thread,int suspend_flag)1003 rt_err_t rt_thread_suspend_with_flag(rt_thread_t thread, int suspend_flag)
1004 {
1005 return rt_thread_suspend_to_list(thread, RT_NULL, 0, suspend_flag);
1006 }
1007 RTM_EXPORT(rt_thread_suspend_with_flag);
1008
rt_thread_suspend(rt_thread_t thread)1009 rt_err_t rt_thread_suspend(rt_thread_t thread)
1010 {
1011 return rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
1012 }
1013 RTM_EXPORT(rt_thread_suspend);
1014
1015 /**
1016 * @brief This function will resume a thread and put it to system ready queue.
1017 *
1018 * @param thread is the thread to be resumed.
1019 *
1020 * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed.
1021 * If the return value is any other values, it means this operation failed.
1022 */
rt_thread_resume(rt_thread_t thread)1023 rt_err_t rt_thread_resume(rt_thread_t thread)
1024 {
1025 rt_sched_lock_level_t slvl;
1026 rt_err_t error;
1027
1028 /* parameter check */
1029 RT_ASSERT(thread != RT_NULL);
1030 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
1031
1032 LOG_D("thread resume: %s", thread->parent.name);
1033
1034 rt_sched_lock(&slvl);
1035
1036 error = rt_sched_thread_ready(thread);
1037
1038 if (!error)
1039 {
1040 error = rt_sched_unlock_n_resched(slvl);
1041
1042 /**
1043 * RT_ESCHEDLOCKED indicates that the current thread is in a critical section,
1044 * rather than 'thread' can't be resumed. Therefore, we can ignore this error.
1045 */
1046 if (error == -RT_ESCHEDLOCKED)
1047 {
1048 error = RT_EOK;
1049 }
1050 }
1051 else
1052 {
1053 rt_sched_unlock(slvl);
1054 }
1055
1056 RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
1057
1058 return error;
1059 }
1060 RTM_EXPORT(rt_thread_resume);
1061
1062 #ifdef RT_USING_SMART
1063 /**
1064 * This function will wakeup a thread with customized operation.
1065 *
1066 * @param thread the thread to be resumed
1067 *
1068 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
1069 */
rt_thread_wakeup(rt_thread_t thread)1070 rt_err_t rt_thread_wakeup(rt_thread_t thread)
1071 {
1072 rt_sched_lock_level_t slvl;
1073 rt_err_t ret;
1074 rt_wakeup_func_t func = RT_NULL;
1075
1076 RT_ASSERT(thread != RT_NULL);
1077 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
1078
1079 rt_sched_lock(&slvl);
1080 func = thread->wakeup_handle.func;
1081 thread->wakeup_handle.func = RT_NULL;
1082 rt_sched_unlock(slvl);
1083
1084 if (func)
1085 {
1086 ret = func(thread->wakeup_handle.user_data, thread);
1087 }
1088 else
1089 {
1090 ret = rt_thread_resume(thread);
1091 }
1092 return ret;
1093 }
1094 RTM_EXPORT(rt_thread_wakeup);
1095
rt_thread_wakeup_set(struct rt_thread * thread,rt_wakeup_func_t func,void * user_data)1096 void rt_thread_wakeup_set(struct rt_thread *thread, rt_wakeup_func_t func, void* user_data)
1097 {
1098 rt_sched_lock_level_t slvl;
1099
1100 RT_ASSERT(thread != RT_NULL);
1101 RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
1102
1103 rt_sched_lock(&slvl);
1104 thread->wakeup_handle.func = func;
1105 thread->wakeup_handle.user_data = user_data;
1106 rt_sched_unlock(slvl);
1107 }
1108 RTM_EXPORT(rt_thread_wakeup_set);
1109 #endif
1110 /**
1111 * @brief This function will find the specified thread.
1112 *
1113 * @note Please don't invoke this function in interrupt status.
1114 *
1115 * @param name is the name of thread finding.
1116 *
1117 * @return If the return value is a rt_thread structure pointer, the function is successfully executed.
1118 * If the return value is RT_NULL, it means this operation failed.
1119 */
rt_thread_find(char * name)1120 rt_thread_t rt_thread_find(char *name)
1121 {
1122 return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
1123 }
1124
1125 RTM_EXPORT(rt_thread_find);
1126
1127 /**
1128 * @brief This function will return the name of the specified thread
1129 *
1130 * @note Please don't invoke this function in interrupt status
1131 *
1132 * @param thread the thread to retrieve thread name
1133 * @param name buffer to store the thread name string
1134 * @param name_size maximum size of the buffer to store the thread name
1135 *
1136 * @return If the return value is RT_EOK, the function is successfully executed
1137 * If the return value is -RT_EINVAL, it means this operation failed
1138 */
rt_thread_get_name(rt_thread_t thread,char * name,rt_uint8_t name_size)1139 rt_err_t rt_thread_get_name(rt_thread_t thread, char *name, rt_uint8_t name_size)
1140 {
1141 return (thread == RT_NULL) ? -RT_EINVAL : rt_object_get_name(&thread->parent, name, name_size);
1142 }
1143 RTM_EXPORT(rt_thread_get_name);
1144
1145 /**@}*/
1146