thread.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /*
  2. * Copyright (c) 2006-2018, 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. */
  30. #include <rthw.h>
  31. #include <rtthread.h>
  32. extern rt_list_t rt_thread_defunct;
  33. #ifdef RT_USING_HOOK
  34. static void (*rt_thread_suspend_hook)(rt_thread_t thread);
  35. static void (*rt_thread_resume_hook) (rt_thread_t thread);
  36. static void (*rt_thread_inited_hook) (rt_thread_t thread);
  37. /**
  38. * @ingroup Hook
  39. * This function sets a hook function when the system suspend a thread.
  40. *
  41. * @param hook the specified hook function
  42. *
  43. * @note the hook function must be simple and never be blocked or suspend.
  44. */
  45. void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread))
  46. {
  47. rt_thread_suspend_hook = hook;
  48. }
  49. /**
  50. * @ingroup Hook
  51. * This function sets a hook function when the system resume a thread.
  52. *
  53. * @param hook the specified hook function
  54. *
  55. * @note the hook function must be simple and never be blocked or suspend.
  56. */
  57. void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread))
  58. {
  59. rt_thread_resume_hook = hook;
  60. }
  61. /**
  62. * @ingroup Hook
  63. * This function sets a hook function when a thread is initialized.
  64. *
  65. * @param hook the specified hook function
  66. */
  67. void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread))
  68. {
  69. rt_thread_inited_hook = hook;
  70. }
  71. #endif
  72. void rt_thread_exit(void)
  73. {
  74. struct rt_thread *thread;
  75. register rt_base_t level;
  76. /* get current thread */
  77. thread = rt_thread_self();
  78. /* disable interrupt */
  79. level = rt_hw_interrupt_disable();
  80. /* remove from schedule */
  81. rt_schedule_remove_thread(thread);
  82. /* change stat */
  83. thread->stat = RT_THREAD_CLOSE;
  84. /* remove it from timer list */
  85. rt_timer_detach(&thread->thread_timer);
  86. if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
  87. thread->cleanup == RT_NULL)
  88. {
  89. rt_object_detach((rt_object_t)thread);
  90. }
  91. else
  92. {
  93. /* insert to defunct thread list */
  94. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  95. }
  96. /* switch to next task */
  97. rt_schedule();
  98. /* enable interrupt */
  99. rt_hw_interrupt_enable(level);
  100. }
  101. static rt_err_t _rt_thread_init(struct rt_thread *thread,
  102. const char *name,
  103. void (*entry)(void *parameter),
  104. void *parameter,
  105. void *stack_start,
  106. rt_uint32_t stack_size,
  107. rt_uint8_t priority,
  108. rt_uint32_t tick)
  109. {
  110. /* init thread list */
  111. rt_list_init(&(thread->tlist));
  112. #ifdef RT_USING_LWP
  113. thread->wakeup.func = RT_NULL;
  114. #endif
  115. thread->entry = (void *)entry;
  116. thread->parameter = parameter;
  117. /* stack init */
  118. thread->stack_addr = stack_start;
  119. thread->stack_size = stack_size;
  120. /* init thread stack */
  121. rt_memset(thread->stack_addr, '#', thread->stack_size);
  122. #ifdef ARCH_CPU_STACK_GROWS_UPWARD
  123. thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
  124. (void *)((char *)thread->stack_addr),
  125. (void *)rt_thread_exit);
  126. #else
  127. thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
  128. (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
  129. (void *)rt_thread_exit);
  130. #endif
  131. /* priority init */
  132. RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
  133. thread->init_priority = priority;
  134. thread->current_priority = priority;
  135. thread->number_mask = 0;
  136. #if RT_THREAD_PRIORITY_MAX > 32
  137. thread->number = 0;
  138. thread->high_mask = 0;
  139. #endif
  140. /* tick init */
  141. thread->init_tick = tick;
  142. thread->remaining_tick = tick;
  143. /* error and flags */
  144. thread->error = RT_EOK;
  145. thread->stat = RT_THREAD_INIT;
  146. #ifdef RT_USING_SMP
  147. /* not bind on any cpu */
  148. thread->bind_cpu = RT_CPUS_NR;
  149. thread->oncpu = RT_CPU_DETACHED;
  150. /* lock init */
  151. thread->scheduler_lock_nest = 0;
  152. thread->cpus_lock_nest = 0;
  153. thread->critical_lock_nest = 0;
  154. #endif /*RT_USING_SMP*/
  155. /* initialize cleanup function and user data */
  156. thread->cleanup = 0;
  157. thread->user_data = 0;
  158. /* initialize thread timer */
  159. rt_timer_init(&(thread->thread_timer),
  160. thread->name,
  161. rt_thread_timeout,
  162. thread,
  163. 0,
  164. RT_TIMER_FLAG_ONE_SHOT);
  165. /* initialize signal */
  166. #ifdef RT_USING_SIGNALS
  167. thread->sig_mask = 0x00;
  168. thread->sig_pending = 0x00;
  169. #ifndef RT_USING_SMP
  170. thread->sig_ret = RT_NULL;
  171. #endif
  172. thread->sig_vectors = RT_NULL;
  173. thread->si_list = RT_NULL;
  174. #endif
  175. #ifdef RT_USING_LWP
  176. thread->lwp = RT_NULL;
  177. rt_list_init(&(thread->sibling));
  178. rt_memset(&thread->signal, 0, sizeof(lwp_sigset_t));
  179. rt_memset(&thread->signal_mask, 0, sizeof(lwp_sigset_t));
  180. thread->signal_mask_bak = 0;
  181. thread->signal_in_process = 0;
  182. rt_memset(thread->signal_handler, 0, sizeof thread->signal_handler);
  183. rt_memset(&thread->user_ctx, 0, sizeof thread->user_ctx);
  184. #endif
  185. RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));
  186. return RT_EOK;
  187. }
  188. /**
  189. * @addtogroup Thread
  190. */
  191. /**@{*/
  192. /**
  193. * This function will initialize a thread, normally it's used to initialize a
  194. * static thread object.
  195. *
  196. * @param thread the static thread object
  197. * @param name the name of thread, which shall be unique
  198. * @param entry the entry function of thread
  199. * @param parameter the parameter of thread enter function
  200. * @param stack_start the start address of thread stack
  201. * @param stack_size the size of thread stack
  202. * @param priority the priority of thread
  203. * @param tick the time slice if there are same priority thread
  204. *
  205. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  206. */
  207. rt_err_t rt_thread_init(struct rt_thread *thread,
  208. const char *name,
  209. void (*entry)(void *parameter),
  210. void *parameter,
  211. void *stack_start,
  212. rt_uint32_t stack_size,
  213. rt_uint8_t priority,
  214. rt_uint32_t tick)
  215. {
  216. /* thread check */
  217. RT_ASSERT(thread != RT_NULL);
  218. RT_ASSERT(stack_start != RT_NULL);
  219. /* initialize thread object */
  220. rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
  221. return _rt_thread_init(thread,
  222. name,
  223. entry,
  224. parameter,
  225. stack_start,
  226. stack_size,
  227. priority,
  228. tick);
  229. }
  230. RTM_EXPORT(rt_thread_init);
  231. /**
  232. * This function will return self thread object
  233. *
  234. * @return the self thread object
  235. */
  236. rt_thread_t rt_thread_self(void)
  237. {
  238. #ifdef RT_USING_SMP
  239. rt_base_t lock;
  240. rt_thread_t self;
  241. lock = rt_hw_local_irq_disable();
  242. self = rt_cpu_self()->current_thread;
  243. rt_hw_local_irq_enable(lock);
  244. return self;
  245. #else
  246. extern rt_thread_t rt_current_thread;
  247. return rt_current_thread;
  248. #endif
  249. }
  250. RTM_EXPORT(rt_thread_self);
  251. /**
  252. * This function will start a thread and put it to system ready queue
  253. *
  254. * @param thread the thread to be started
  255. *
  256. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  257. */
  258. rt_err_t rt_thread_startup(rt_thread_t thread)
  259. {
  260. /* thread check */
  261. RT_ASSERT(thread != RT_NULL);
  262. RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
  263. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  264. /* set current priority to initialize priority */
  265. thread->current_priority = thread->init_priority;
  266. /* calculate priority attribute */
  267. #if RT_THREAD_PRIORITY_MAX > 32
  268. thread->number = thread->current_priority >> 3; /* 5bit */
  269. thread->number_mask = 1L << thread->number;
  270. thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
  271. #else
  272. thread->number_mask = 1L << thread->current_priority;
  273. #endif
  274. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
  275. thread->name, thread->init_priority));
  276. /* change thread stat */
  277. thread->stat = RT_THREAD_SUSPEND;
  278. /* then resume it */
  279. rt_thread_resume(thread);
  280. if (rt_thread_self() != RT_NULL)
  281. {
  282. /* do a scheduling */
  283. rt_schedule();
  284. }
  285. return RT_EOK;
  286. }
  287. RTM_EXPORT(rt_thread_startup);
  288. /**
  289. * This function will detach a thread. The thread object will be removed from
  290. * thread queue and detached/deleted from system object management.
  291. *
  292. * @param thread the thread to be deleted
  293. *
  294. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  295. */
  296. rt_err_t rt_thread_detach(rt_thread_t thread)
  297. {
  298. rt_base_t lock;
  299. /* thread check */
  300. RT_ASSERT(thread != RT_NULL);
  301. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  302. RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));
  303. if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
  304. return RT_EOK;
  305. if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
  306. {
  307. /* remove from schedule */
  308. rt_schedule_remove_thread(thread);
  309. }
  310. /* release thread timer */
  311. rt_timer_detach(&(thread->thread_timer));
  312. /* change stat */
  313. thread->stat = RT_THREAD_CLOSE;
  314. if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) &&
  315. thread->cleanup == RT_NULL)
  316. {
  317. rt_object_detach((rt_object_t)thread);
  318. }
  319. else
  320. {
  321. /* disable interrupt */
  322. lock = rt_hw_interrupt_disable();
  323. /* insert to defunct thread list */
  324. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  325. /* enable interrupt */
  326. rt_hw_interrupt_enable(lock);
  327. }
  328. return RT_EOK;
  329. }
  330. RTM_EXPORT(rt_thread_detach);
  331. #ifdef RT_USING_HEAP
  332. /**
  333. * This function will create a thread object and allocate thread object memory
  334. * and stack.
  335. *
  336. * @param name the name of thread, which shall be unique
  337. * @param entry the entry function of thread
  338. * @param parameter the parameter of thread enter function
  339. * @param stack_size the size of thread stack
  340. * @param priority the priority of thread
  341. * @param tick the time slice if there are same priority thread
  342. *
  343. * @return the created thread object
  344. */
  345. rt_thread_t rt_thread_create(const char *name,
  346. void (*entry)(void *parameter),
  347. void *parameter,
  348. rt_uint32_t stack_size,
  349. rt_uint8_t priority,
  350. rt_uint32_t tick)
  351. {
  352. struct rt_thread *thread;
  353. void *stack_start;
  354. thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
  355. name);
  356. if (thread == RT_NULL)
  357. return RT_NULL;
  358. stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
  359. if (stack_start == RT_NULL)
  360. {
  361. /* allocate stack failure */
  362. rt_object_delete((rt_object_t)thread);
  363. return RT_NULL;
  364. }
  365. _rt_thread_init(thread,
  366. name,
  367. entry,
  368. parameter,
  369. stack_start,
  370. stack_size,
  371. priority,
  372. tick);
  373. return thread;
  374. }
  375. RTM_EXPORT(rt_thread_create);
  376. /**
  377. * This function will delete a thread. The thread object will be removed from
  378. * thread queue and deleted from system object management in the idle thread.
  379. *
  380. * @param thread the thread to be deleted
  381. *
  382. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  383. */
  384. rt_err_t rt_thread_delete(rt_thread_t thread)
  385. {
  386. rt_base_t lock;
  387. /* thread check */
  388. RT_ASSERT(thread != RT_NULL);
  389. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  390. RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);
  391. if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
  392. return RT_EOK;
  393. if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
  394. {
  395. /* remove from schedule */
  396. rt_schedule_remove_thread(thread);
  397. }
  398. /* release thread timer */
  399. rt_timer_detach(&(thread->thread_timer));
  400. /* disable interrupt */
  401. lock = rt_hw_interrupt_disable();
  402. /* change stat */
  403. thread->stat = RT_THREAD_CLOSE;
  404. /* insert to defunct thread list */
  405. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  406. /* enable interrupt */
  407. rt_hw_interrupt_enable(lock);
  408. return RT_EOK;
  409. }
  410. RTM_EXPORT(rt_thread_delete);
  411. #endif
  412. /**
  413. * This function will let current thread yield processor, and scheduler will
  414. * choose a highest thread to run. After yield processor, the current thread
  415. * is still in READY state.
  416. *
  417. * @return RT_EOK
  418. */
  419. rt_err_t rt_thread_yield(void)
  420. {
  421. rt_base_t level;
  422. struct rt_thread *thread;
  423. thread = rt_thread_self();
  424. level = rt_hw_interrupt_disable();
  425. thread->remaining_tick = thread->init_tick;
  426. thread->stat |= RT_THREAD_STAT_YIELD;
  427. rt_schedule();
  428. rt_hw_interrupt_enable(level);
  429. return RT_EOK;
  430. }
  431. RTM_EXPORT(rt_thread_yield);
  432. /**
  433. * This function will set a thread's suspend status
  434. *
  435. * @param thread the thread to be suspend
  436. * @param status flag of the thread, must be one of RT_INTERRUPTIBLE RT_KILLABLE RT_UNINTERRUPTIBLE
  437. */
  438. void rt_thread_set_suspend_state(struct rt_thread *thread, int suspend_flag)
  439. {
  440. rt_uint8_t stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
  441. RT_ASSERT(thread != RT_NULL);
  442. switch (suspend_flag)
  443. {
  444. case RT_INTERRUPTIBLE:
  445. stat = RT_THREAD_SUSPEND_INTERRUPTIBLE;
  446. break;
  447. case RT_KILLABLE:
  448. stat = RT_THREAD_SUSPEND_KILLABLE;
  449. break;
  450. case RT_UNINTERRUPTIBLE:
  451. stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE;
  452. break;
  453. default:
  454. RT_ASSERT(0);
  455. break;
  456. }
  457. thread->stat = stat | (thread->stat & ~RT_THREAD_STAT_MASK);
  458. }
  459. /**
  460. * This function will let current thread sleep for some ticks.
  461. *
  462. * @param tick the sleep ticks
  463. *
  464. * @return RT_EOK
  465. */
  466. rt_err_t rt_thread_sleep(rt_tick_t tick)
  467. {
  468. register rt_base_t temp;
  469. struct rt_thread *thread;
  470. /* set to current thread */
  471. thread = rt_thread_self();
  472. RT_ASSERT(thread != RT_NULL);
  473. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  474. /* disable interrupt */
  475. temp = rt_hw_interrupt_disable();
  476. /* suspend thread */
  477. rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE);
  478. /* reset the timeout of thread timer and start it */
  479. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
  480. rt_timer_start(&(thread->thread_timer));
  481. /* enable interrupt */
  482. rt_hw_interrupt_enable(temp);
  483. rt_schedule();
  484. /* clear error number of this thread to RT_EOK */
  485. if (thread->error == -RT_ETIMEOUT)
  486. thread->error = RT_EOK;
  487. return RT_EOK;
  488. }
  489. /**
  490. * This function will let current thread delay for some ticks.
  491. *
  492. * @param tick the delay ticks
  493. *
  494. * @return RT_EOK
  495. */
  496. rt_err_t rt_thread_delay(rt_tick_t tick)
  497. {
  498. return rt_thread_sleep(tick);
  499. }
  500. RTM_EXPORT(rt_thread_delay);
  501. /**
  502. * This function will let current thread delay until (*tick + inc_tick).
  503. *
  504. * @param tick the tick of last wakeup.
  505. * @param inc_tick the increment tick
  506. *
  507. * @return RT_EOK
  508. */
  509. rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick)
  510. {
  511. register rt_base_t level;
  512. struct rt_thread *thread;
  513. RT_ASSERT(tick != RT_NULL);
  514. /* set to current thread */
  515. thread = rt_thread_self();
  516. RT_ASSERT(thread != RT_NULL);
  517. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  518. /* disable interrupt */
  519. level = rt_hw_interrupt_disable();
  520. if (rt_tick_get() - *tick < inc_tick)
  521. {
  522. *tick = *tick + inc_tick - rt_tick_get();
  523. /* suspend thread */
  524. rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
  525. /* reset the timeout of thread timer and start it */
  526. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, tick);
  527. rt_timer_start(&(thread->thread_timer));
  528. /* enable interrupt */
  529. rt_hw_interrupt_enable(level);
  530. rt_schedule();
  531. /* clear error number of this thread to RT_EOK */
  532. if (thread->error == -RT_ETIMEOUT)
  533. {
  534. thread->error = RT_EOK;
  535. }
  536. }
  537. else
  538. {
  539. rt_hw_interrupt_enable(level);
  540. }
  541. /* get the wakeup tick */
  542. *tick = rt_tick_get();
  543. return RT_EOK;
  544. }
  545. RTM_EXPORT(rt_thread_delay_until);
  546. /**
  547. * This function will let current thread delay for some milliseconds.
  548. *
  549. * @param ms the delay ms time
  550. *
  551. * @return RT_EOK
  552. */
  553. rt_err_t rt_thread_mdelay(rt_int32_t ms)
  554. {
  555. rt_tick_t tick;
  556. tick = rt_tick_from_millisecond(ms);
  557. return rt_thread_sleep(tick);
  558. }
  559. RTM_EXPORT(rt_thread_mdelay);
  560. /**
  561. * This function will control thread behaviors according to control command.
  562. *
  563. * @param thread the specified thread to be controlled
  564. * @param cmd the control command, which includes
  565. * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
  566. * RT_THREAD_CTRL_STARTUP for starting a thread;
  567. * RT_THREAD_CTRL_CLOSE for delete a thread;
  568. * RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.
  569. * @param arg the argument of control command
  570. *
  571. * @return RT_EOK
  572. */
  573. rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
  574. {
  575. register rt_base_t temp;
  576. /* thread check */
  577. RT_ASSERT(thread != RT_NULL);
  578. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  579. switch (cmd)
  580. {
  581. case RT_THREAD_CTRL_CHANGE_PRIORITY:
  582. /* disable interrupt */
  583. temp = rt_hw_interrupt_disable();
  584. /* for ready thread, change queue */
  585. if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
  586. {
  587. /* remove thread from schedule queue first */
  588. rt_schedule_remove_thread(thread);
  589. /* change thread priority */
  590. thread->current_priority = *(rt_uint8_t *)arg;
  591. /* recalculate priority attribute */
  592. #if RT_THREAD_PRIORITY_MAX > 32
  593. thread->number = thread->current_priority >> 3; /* 5bit */
  594. thread->number_mask = 1 << thread->number;
  595. thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
  596. #else
  597. thread->number_mask = 1 << thread->current_priority;
  598. #endif
  599. /* insert thread to schedule queue again */
  600. rt_schedule_insert_thread(thread);
  601. }
  602. else
  603. {
  604. thread->current_priority = *(rt_uint8_t *)arg;
  605. /* recalculate priority attribute */
  606. #if RT_THREAD_PRIORITY_MAX > 32
  607. thread->number = thread->current_priority >> 3; /* 5bit */
  608. thread->number_mask = 1 << thread->number;
  609. thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
  610. #else
  611. thread->number_mask = 1 << thread->current_priority;
  612. #endif
  613. }
  614. /* enable interrupt */
  615. rt_hw_interrupt_enable(temp);
  616. break;
  617. case RT_THREAD_CTRL_STARTUP:
  618. return rt_thread_startup(thread);
  619. case RT_THREAD_CTRL_CLOSE:
  620. if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
  621. {
  622. return rt_thread_detach(thread);
  623. }
  624. #ifdef RT_USING_HEAP
  625. else
  626. {
  627. return rt_thread_delete(thread);
  628. }
  629. #endif
  630. #ifdef RT_USING_SMP
  631. case RT_THREAD_CTRL_BIND_CPU:
  632. {
  633. rt_uint8_t cpu;
  634. if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
  635. {
  636. /* we only support bind cpu before started phase. */
  637. return RT_ERROR;
  638. }
  639. cpu = (rt_uint8_t)(size_t)arg;
  640. thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu;
  641. break;
  642. }
  643. #endif /*RT_USING_SMP*/
  644. default:
  645. break;
  646. }
  647. return RT_EOK;
  648. }
  649. RTM_EXPORT(rt_thread_control);
  650. #ifdef RT_USING_LWP
  651. int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag);
  652. #endif
  653. /**
  654. * This function will suspend the specified thread.
  655. *
  656. * @param thread the thread to be suspended
  657. * @param suspend_flag status flag of the thread to be suspended
  658. *
  659. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  660. *
  661. * @note if suspend self thread, after this function call, the
  662. * rt_schedule() must be invoked.
  663. */
  664. rt_err_t rt_thread_suspend_with_flag(rt_thread_t thread, int suspend_flag)
  665. {
  666. register rt_base_t stat;
  667. register rt_base_t temp;
  668. /* thread check */
  669. RT_ASSERT(thread != RT_NULL);
  670. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  671. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
  672. stat = thread->stat & RT_THREAD_STAT_MASK;
  673. if ((stat != RT_THREAD_READY) && (stat != RT_THREAD_RUNNING))
  674. {
  675. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
  676. thread->stat));
  677. return -RT_ERROR;
  678. }
  679. /* disable interrupt */
  680. temp = rt_hw_interrupt_disable();
  681. if (stat == RT_THREAD_RUNNING)
  682. {
  683. /* not suspend running status thread on other core */
  684. RT_ASSERT(thread == rt_thread_self());
  685. }
  686. #ifdef RT_USING_LWP
  687. if (lwp_suspend_sigcheck(thread, suspend_flag) == 0)
  688. {
  689. /* not to suspend */
  690. rt_hw_interrupt_enable(temp);
  691. return -RT_EINTR;
  692. }
  693. #endif
  694. /* change thread stat */
  695. rt_schedule_remove_thread(thread);
  696. rt_thread_set_suspend_state(thread, suspend_flag);
  697. /* stop thread timer anyway */
  698. rt_timer_stop(&(thread->thread_timer));
  699. /* enable interrupt */
  700. rt_hw_interrupt_enable(temp);
  701. RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
  702. return RT_EOK;
  703. }
  704. RTM_EXPORT(rt_thread_suspend_with_flag);
  705. rt_err_t rt_thread_suspend(rt_thread_t thread)
  706. {
  707. return rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE);
  708. }
  709. RTM_EXPORT(rt_thread_suspend);
  710. /**
  711. * This function will resume a thread and put it to system ready queue.
  712. *
  713. * @param thread the thread to be resumed
  714. *
  715. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  716. */
  717. rt_err_t rt_thread_resume(rt_thread_t thread)
  718. {
  719. register rt_base_t temp;
  720. /* thread check */
  721. RT_ASSERT(thread != RT_NULL);
  722. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  723. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
  724. if ((thread->stat & RT_THREAD_SUSPEND_MASK) != RT_THREAD_SUSPEND_MASK)
  725. {
  726. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
  727. thread->stat));
  728. return -RT_ERROR;
  729. }
  730. /* disable interrupt */
  731. temp = rt_hw_interrupt_disable();
  732. /* remove from suspend list */
  733. rt_list_remove(&(thread->tlist));
  734. rt_timer_stop(&thread->thread_timer);
  735. #ifdef RT_USING_LWP
  736. thread->wakeup.func = RT_NULL;
  737. #endif
  738. /* enable interrupt */
  739. rt_hw_interrupt_enable(temp);
  740. /* insert to schedule ready list */
  741. rt_schedule_insert_thread(thread);
  742. RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
  743. return RT_EOK;
  744. }
  745. RTM_EXPORT(rt_thread_resume);
  746. #ifdef RT_USING_LWP
  747. /**
  748. * This function will wakeup a thread with customized operation.
  749. *
  750. * @param thread the thread to be resumed
  751. *
  752. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  753. */
  754. rt_err_t rt_thread_wakeup(rt_thread_t thread)
  755. {
  756. register rt_base_t temp;
  757. rt_err_t ret;
  758. RT_ASSERT(thread != RT_NULL);
  759. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  760. /* disable interrupt */
  761. temp = rt_hw_interrupt_disable();
  762. if (thread->wakeup.func)
  763. {
  764. ret = thread->wakeup.func(thread->wakeup.user_data, thread);
  765. thread->wakeup.func = RT_NULL;
  766. }
  767. else
  768. {
  769. ret = rt_thread_resume(thread);
  770. }
  771. rt_hw_interrupt_enable(temp);
  772. return ret;
  773. }
  774. RTM_EXPORT(rt_thread_wakeup);
  775. void rt_thread_wakeup_set(struct rt_thread *thread, rt_wakeup_func_t func, void* user_data)
  776. {
  777. register rt_base_t temp;
  778. RT_ASSERT(thread != RT_NULL);
  779. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  780. temp = rt_hw_interrupt_disable();
  781. thread->wakeup.func = func;
  782. thread->wakeup.user_data = user_data;
  783. rt_hw_interrupt_enable(temp);
  784. }
  785. RTM_EXPORT(rt_thread_wakeup_set);
  786. #endif
  787. /**
  788. * This function is the timeout function for thread, normally which is invoked
  789. * when thread is timeout to wait some resource.
  790. *
  791. * @param parameter the parameter of thread timeout function
  792. */
  793. void rt_thread_timeout(void *parameter)
  794. {
  795. struct rt_thread *thread;
  796. thread = (struct rt_thread *)parameter;
  797. /* thread check */
  798. RT_ASSERT(thread != RT_NULL);
  799. RT_ASSERT((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK);
  800. RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
  801. /* set error number */
  802. thread->error = -RT_ETIMEOUT;
  803. /* remove from suspend list */
  804. rt_list_remove(&(thread->tlist));
  805. /* insert to schedule ready list */
  806. rt_schedule_insert_thread(thread);
  807. /* do schedule */
  808. rt_schedule();
  809. }
  810. RTM_EXPORT(rt_thread_timeout);
  811. /**
  812. * This function will find the specified thread.
  813. *
  814. * @param name the name of thread finding
  815. *
  816. * @return the found thread
  817. *
  818. * @note please don't invoke this function in interrupt status.
  819. */
  820. rt_thread_t rt_thread_find(char *name)
  821. {
  822. struct rt_object_information *information;
  823. struct rt_object *object;
  824. struct rt_list_node *node;
  825. /* enter critical */
  826. if (rt_thread_self() != RT_NULL)
  827. rt_enter_critical();
  828. /* try to find device object */
  829. information = rt_object_get_information(RT_Object_Class_Thread);
  830. RT_ASSERT(information != RT_NULL);
  831. for (node = information->object_list.next;
  832. node != &(information->object_list);
  833. node = node->next)
  834. {
  835. object = rt_list_entry(node, struct rt_object, list);
  836. if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
  837. {
  838. /* leave critical */
  839. if (rt_thread_self() != RT_NULL)
  840. rt_exit_critical();
  841. return (rt_thread_t)object;
  842. }
  843. }
  844. /* leave critical */
  845. if (rt_thread_self() != RT_NULL)
  846. rt_exit_critical();
  847. /* not found */
  848. return RT_NULL;
  849. }
  850. RTM_EXPORT(rt_thread_find);
  851. /**@}*/