thread.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /*
  2. * File : thread.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2006-03-28 Bernard first version
  13. * 2006-04-29 Bernard implement thread timer
  14. * 2006-04-30 Bernard added THREAD_DEBUG
  15. * 2006-05-27 Bernard fixed the rt_thread_yield bug
  16. * 2006-06-03 Bernard fixed the thread timer init bug
  17. * 2006-08-10 Bernard fixed the timer bug in thread_sleep
  18. * 2006-09-03 Bernard changed rt_timer_delete to rt_timer_detach
  19. * 2006-09-03 Bernard implement rt_thread_detach
  20. * 2008-02-16 Bernard fixed the rt_thread_timeout bug
  21. * 2010-03-21 Bernard change the errno of rt_thread_delay/sleep to RT_EOK.
  22. * 2010-11-10 Bernard add cleanup callback function in thread exit.
  23. * 2011-09-01 Bernard fixed rt_thread_exit issue when the current thread preempted,
  24. * which reported by Jiaxing Lee.
  25. * 2011-09-08 Bernard fixed the scheduling issue in rt_thread_startup.
  26. */
  27. #include <rtthread.h>
  28. #include <rthw.h>
  29. #include "kservice.h"
  30. extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
  31. extern struct rt_thread *rt_current_thread;
  32. extern rt_uint8_t rt_current_priority;
  33. extern rt_list_t rt_thread_defunct;
  34. static void rt_thread_exit(void)
  35. {
  36. struct rt_thread *thread;
  37. register rt_base_t level;
  38. /* get current thread */
  39. thread = rt_current_thread;
  40. /* disable interrupt */
  41. level = rt_hw_interrupt_disable();
  42. /* remove from schedule */
  43. rt_schedule_remove_thread(thread);
  44. /* change stat */
  45. thread->stat = RT_THREAD_CLOSE;
  46. /* remove it from timer list */
  47. rt_list_remove(&(thread->thread_timer.list));
  48. rt_object_detach((rt_object_t)&(thread->thread_timer));
  49. if ((rt_object_is_systemobject((rt_object_t)thread) == RT_EOK) &&
  50. thread->cleanup == RT_NULL)
  51. {
  52. rt_object_detach((rt_object_t)thread);
  53. }
  54. else
  55. {
  56. /* insert to defunct thread list */
  57. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  58. }
  59. /* enable interrupt */
  60. rt_hw_interrupt_enable(level);
  61. /* switch to next task */
  62. rt_schedule();
  63. }
  64. static rt_err_t _rt_thread_init(struct rt_thread *thread,
  65. const char *name,
  66. void (*entry)(void *parameter), void *parameter,
  67. void *stack_start, rt_uint32_t stack_size,
  68. rt_uint8_t priority, rt_uint32_t tick)
  69. {
  70. /* init thread list */
  71. rt_list_init(&(thread->tlist));
  72. thread->entry = (void *)entry;
  73. thread->parameter = parameter;
  74. /* stack init */
  75. thread->stack_addr = stack_start;
  76. thread->stack_size = stack_size;
  77. /* init thread stack */
  78. rt_memset(thread->stack_addr, '#', thread->stack_size);
  79. thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
  80. (void *) ((char *)thread->stack_addr + thread->stack_size - 4),
  81. (void *)rt_thread_exit);
  82. /* priority init */
  83. RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
  84. thread->init_priority = priority;
  85. thread->current_priority = priority;
  86. /* tick init */
  87. thread->init_tick = tick;
  88. thread->remaining_tick = tick;
  89. /* error and flags */
  90. thread->error = RT_EOK;
  91. thread->stat = RT_THREAD_INIT;
  92. /* initialize cleanup function and user data */
  93. thread->cleanup = 0;
  94. thread->user_data = 0;
  95. /* init thread timer */
  96. rt_timer_init(&(thread->thread_timer),
  97. thread->name,
  98. rt_thread_timeout,
  99. thread,
  100. 0,
  101. RT_TIMER_FLAG_ONE_SHOT);
  102. return RT_EOK;
  103. }
  104. /**
  105. * @addtogroup Thread
  106. */
  107. /*@{*/
  108. /**
  109. * This function will initialize a thread, normally it's used to initialize a
  110. * static thread object.
  111. *
  112. * @param thread the static thread object
  113. * @param name the name of thread, which shall be unique
  114. * @param entry the entry function of thread
  115. * @param parameter the parameter of thread enter function
  116. * @param stack_start the start address of thread stack
  117. * @param stack_size the size of thread stack
  118. * @param priority the priority of thread
  119. * @param tick the time slice if there are same priority thread
  120. *
  121. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  122. */
  123. rt_err_t rt_thread_init(struct rt_thread *thread,
  124. const char *name,
  125. void (*entry)(void *parameter), void *parameter,
  126. void *stack_start, rt_uint32_t stack_size,
  127. rt_uint8_t priority, rt_uint32_t tick)
  128. {
  129. /* thread check */
  130. RT_ASSERT(thread != RT_NULL);
  131. RT_ASSERT(stack_start != RT_NULL);
  132. /* init thread object */
  133. rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
  134. return _rt_thread_init(thread, name, entry, parameter,
  135. stack_start, stack_size,
  136. priority, tick);
  137. }
  138. /**
  139. * This function will return self thread object
  140. *
  141. * @return the self thread object
  142. */
  143. rt_thread_t rt_thread_self(void)
  144. {
  145. return rt_current_thread;
  146. }
  147. /**
  148. * This function will start a thread and put it to system ready queue
  149. *
  150. * @param thread the thread to be started
  151. *
  152. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  153. */
  154. rt_err_t rt_thread_startup(rt_thread_t thread)
  155. {
  156. /* thread check */
  157. RT_ASSERT(thread != RT_NULL);
  158. RT_ASSERT(thread->stat == RT_THREAD_INIT);
  159. /* set current priority to init priority */
  160. thread->current_priority = thread->init_priority;
  161. /* calculate priority attribute */
  162. #if RT_THREAD_PRIORITY_MAX > 32
  163. thread->number = thread->current_priority >> 3; /* 5bit */
  164. thread->number_mask = 1L << thread->number;
  165. thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
  166. #else
  167. thread->number_mask = 1L << thread->current_priority;
  168. #endif
  169. RT_DEBUG_LOG(RT_DEBUG_THREAD,\
  170. ("startup a thread:%s with priority:%d\n", thread->name, thread->init_priority));
  171. /* change thread stat */
  172. thread->stat = RT_THREAD_SUSPEND;
  173. /* then resume it */
  174. rt_thread_resume(thread);
  175. if (rt_thread_self() != RT_NULL)
  176. {
  177. /* do a scheduling */
  178. rt_schedule();
  179. }
  180. return RT_EOK;
  181. }
  182. /**
  183. * This function will detach a thread. The thread object will be removed from
  184. * thread queue and detached/deleted from system object management.
  185. *
  186. * @param thread the thread to be deleted
  187. *
  188. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  189. */
  190. rt_err_t rt_thread_detach(rt_thread_t thread)
  191. {
  192. rt_base_t lock;
  193. /* thread check */
  194. RT_ASSERT(thread != RT_NULL);
  195. /* remove from schedule */
  196. rt_schedule_remove_thread(thread);
  197. /* release thread timer */
  198. rt_timer_detach(&(thread->thread_timer));
  199. /* change stat */
  200. thread->stat = RT_THREAD_CLOSE;
  201. /* detach object */
  202. rt_object_detach((rt_object_t)thread);
  203. if (thread->cleanup != RT_NULL)
  204. {
  205. /* disable interrupt */
  206. lock = rt_hw_interrupt_disable();
  207. /* insert to defunct thread list */
  208. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  209. /* enable interrupt */
  210. rt_hw_interrupt_enable(lock);
  211. }
  212. return RT_EOK;
  213. }
  214. #ifdef RT_USING_HEAP
  215. /**
  216. * This function will create a thread object and allocate thread object memory
  217. * and stack.
  218. *
  219. * @param name the name of thread, which shall be unique
  220. * @param entry the entry function of thread
  221. * @param parameter the parameter of thread enter function
  222. * @param stack_size the size of thread stack
  223. * @param priority the priority of thread
  224. * @param tick the time slice if there are same priority thread
  225. *
  226. * @return the created thread object
  227. */
  228. rt_thread_t rt_thread_create(const char *name,
  229. void (*entry)(void *parameter), void *parameter,
  230. rt_uint32_t stack_size,
  231. rt_uint8_t priority,
  232. rt_uint32_t tick)
  233. {
  234. struct rt_thread *thread;
  235. void *stack_start;
  236. thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread, name);
  237. if (thread == RT_NULL)
  238. return RT_NULL;
  239. stack_start = (void *)rt_malloc(stack_size);
  240. if (stack_start == RT_NULL)
  241. {
  242. /* allocate stack failure */
  243. rt_object_delete((rt_object_t)thread);
  244. return RT_NULL;
  245. }
  246. _rt_thread_init(thread, name, entry, parameter,
  247. stack_start, stack_size,
  248. priority, tick);
  249. return thread;
  250. }
  251. /**
  252. * This function will delete a thread. The thread object will be removed from
  253. * thread queue and detached/deleted from system object management.
  254. *
  255. * @param thread the thread to be deleted
  256. *
  257. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  258. */
  259. rt_err_t rt_thread_delete(rt_thread_t thread)
  260. {
  261. rt_base_t lock;
  262. /* thread check */
  263. RT_ASSERT(thread != RT_NULL);
  264. /* remove from schedule */
  265. rt_schedule_remove_thread(thread);
  266. /* release thread timer */
  267. rt_timer_detach(&(thread->thread_timer));
  268. /* change stat */
  269. thread->stat = RT_THREAD_CLOSE;
  270. /* disable interrupt */
  271. lock = rt_hw_interrupt_disable();
  272. /* insert to defunct thread list */
  273. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  274. /* enable interrupt */
  275. rt_hw_interrupt_enable(lock);
  276. return RT_EOK;
  277. }
  278. #endif
  279. /**
  280. * This function will let current thread yield processor, and scheduler will
  281. * choose a highest thread to run. After yield processor, the current thread
  282. * is still in READY state.
  283. *
  284. * @return RT_EOK
  285. */
  286. rt_err_t rt_thread_yield(void)
  287. {
  288. register rt_base_t level;
  289. struct rt_thread *thread;
  290. /* disable interrupt */
  291. level = rt_hw_interrupt_disable();
  292. /* set to current thread */
  293. thread = rt_current_thread;
  294. /* if the thread stat is READY and on ready queue list */
  295. if (thread->stat == RT_THREAD_READY && thread->tlist.next != thread->tlist.prev)
  296. {
  297. /* remove thread from thread list */
  298. rt_list_remove(&(thread->tlist));
  299. /* put thread to end of ready queue */
  300. rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
  301. &(thread->tlist));
  302. /* enable interrupt */
  303. rt_hw_interrupt_enable(level);
  304. rt_schedule();
  305. return RT_EOK;
  306. }
  307. /* enable interrupt */
  308. rt_hw_interrupt_enable(level);
  309. return RT_EOK;
  310. }
  311. /**
  312. * This function will let current thread sleep for some ticks.
  313. *
  314. * @param tick the sleep ticks
  315. *
  316. * @return RT_EOK
  317. */
  318. rt_err_t rt_thread_sleep(rt_tick_t tick)
  319. {
  320. register rt_base_t temp;
  321. struct rt_thread *thread;
  322. /* disable interrupt */
  323. temp = rt_hw_interrupt_disable();
  324. /* set to current thread */
  325. thread = rt_current_thread;
  326. RT_ASSERT(thread != RT_NULL);
  327. /* suspend thread */
  328. rt_thread_suspend(thread);
  329. /* reset the timeout of thread timer and start it */
  330. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
  331. rt_timer_start(&(thread->thread_timer));
  332. /* enable interrupt */
  333. rt_hw_interrupt_enable(temp);
  334. rt_schedule();
  335. /* clear error number of this thread to RT_EOK */
  336. if (thread->error == -RT_ETIMEOUT)
  337. thread->error = RT_EOK;
  338. return RT_EOK;
  339. }
  340. /**
  341. * This function will let current thread delay for some ticks.
  342. *
  343. * @param tick the delay ticks
  344. *
  345. * @return RT_EOK
  346. */
  347. rt_err_t rt_thread_delay(rt_tick_t tick)
  348. {
  349. return rt_thread_sleep(tick);
  350. }
  351. /**
  352. * This function will control thread behaviors according to control command.
  353. *
  354. * @param thread the specified thread to be controlled
  355. * @param cmd the control command, which includes
  356. * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
  357. * RT_THREAD_CTRL_STARTUP for starting a thread;
  358. * RT_THREAD_CTRL_CLOSE for delete a thread.
  359. * @param arg the argument of control command
  360. *
  361. * @return RT_EOK
  362. */
  363. rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void *arg)
  364. {
  365. register rt_base_t temp;
  366. /* thread check */
  367. RT_ASSERT(thread != RT_NULL);
  368. switch (cmd)
  369. {
  370. case RT_THREAD_CTRL_CHANGE_PRIORITY:
  371. /* disable interrupt */
  372. temp = rt_hw_interrupt_disable();
  373. /* for ready thread, change queue */
  374. if (thread->stat == RT_THREAD_READY)
  375. {
  376. /* remove thread from schedule queue first */
  377. rt_schedule_remove_thread(thread);
  378. /* change thread priority */
  379. thread->current_priority = *(rt_uint8_t *)arg;
  380. /* recalculate priority attribute */
  381. #if RT_THREAD_PRIORITY_MAX > 32
  382. thread->number = thread->current_priority >> 3; /* 5bit */
  383. thread->number_mask = 1 << thread->number;
  384. thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
  385. #else
  386. thread->number_mask = 1 << thread->current_priority;
  387. #endif
  388. /* insert thread to schedule queue again */
  389. rt_schedule_insert_thread(thread);
  390. }
  391. else
  392. {
  393. thread->current_priority = *(rt_uint8_t *)arg;
  394. /* recalculate priority attribute */
  395. #if RT_THREAD_PRIORITY_MAX > 32
  396. thread->number = thread->current_priority >> 3; /* 5bit */
  397. thread->number_mask = 1 << thread->number;
  398. thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
  399. #else
  400. thread->number_mask = 1 << thread->current_priority;
  401. #endif
  402. }
  403. /* enable interrupt */
  404. rt_hw_interrupt_enable(temp);
  405. break;
  406. case RT_THREAD_CTRL_STARTUP:
  407. return rt_thread_startup(thread);
  408. #ifdef RT_USING_HEAP
  409. case RT_THREAD_CTRL_CLOSE:
  410. return rt_thread_delete(thread);
  411. #endif
  412. default:
  413. break;
  414. }
  415. return RT_EOK;
  416. }
  417. /**
  418. * This function will suspend the specified thread.
  419. *
  420. * @param thread the thread to be suspended
  421. *
  422. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  423. *
  424. * @note if suspend self thread, after this function call, the
  425. * rt_schedule() must be invoked.
  426. */
  427. rt_err_t rt_thread_suspend(rt_thread_t thread)
  428. {
  429. register rt_base_t temp;
  430. /* thread check */
  431. RT_ASSERT(thread != RT_NULL);
  432. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
  433. if (thread->stat != RT_THREAD_READY)
  434. {
  435. RT_DEBUG_LOG(RT_DEBUG_THREAD,\
  436. ("thread suspend: thread disorder, %d\n", thread->stat));
  437. return -RT_ERROR;
  438. }
  439. /* disable interrupt */
  440. temp = rt_hw_interrupt_disable();
  441. /* change thread stat */
  442. thread->stat = RT_THREAD_SUSPEND;
  443. rt_schedule_remove_thread(thread);
  444. /* enable interrupt */
  445. rt_hw_interrupt_enable(temp);
  446. return RT_EOK;
  447. }
  448. /**
  449. * This function will resume a thread and put it to system ready queue.
  450. *
  451. * @param thread the thread to be resumed
  452. *
  453. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  454. */
  455. rt_err_t rt_thread_resume(rt_thread_t thread)
  456. {
  457. register rt_base_t temp;
  458. /* thread check */
  459. RT_ASSERT(thread != RT_NULL);
  460. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
  461. if (thread->stat != RT_THREAD_SUSPEND)
  462. {
  463. RT_DEBUG_LOG(RT_DEBUG_THREAD, \
  464. ("thread resume: thread disorder, %d\n", thread->stat));
  465. return -RT_ERROR;
  466. }
  467. /* disable interrupt */
  468. temp = rt_hw_interrupt_disable();
  469. /* remove from suspend list */
  470. rt_list_remove(&(thread->tlist));
  471. /* remove thread timer */
  472. rt_list_remove(&(thread->thread_timer.list));
  473. /* change timer state */
  474. thread->thread_timer.parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  475. /* enable interrupt */
  476. rt_hw_interrupt_enable(temp);
  477. /* insert to schedule ready list */
  478. rt_schedule_insert_thread(thread);
  479. return RT_EOK;
  480. }
  481. /**
  482. * This function is the timeout function for thread, normally which is invoked
  483. * when thread is timeout to wait some resource.
  484. *
  485. * @param parameter the parameter of thread timeout function
  486. */
  487. void rt_thread_timeout(void *parameter)
  488. {
  489. struct rt_thread *thread;
  490. thread = (struct rt_thread *)parameter;
  491. /* thread check */
  492. RT_ASSERT(thread != RT_NULL);
  493. RT_ASSERT(thread->stat == RT_THREAD_SUSPEND);
  494. /* set error number */
  495. thread->error = -RT_ETIMEOUT;
  496. /* remove from suspend list */
  497. rt_list_remove(&(thread->tlist));
  498. /* insert to schedule ready list */
  499. rt_schedule_insert_thread(thread);
  500. /* do schedule */
  501. rt_schedule();
  502. }
  503. /**
  504. * This function will find the specified thread.
  505. *
  506. * @param name the name of thread finding
  507. *
  508. * @return the found thread
  509. *
  510. * @note please don't invoke this function in interrupt status.
  511. */
  512. rt_thread_t rt_thread_find(char *name)
  513. {
  514. struct rt_object_information *information;
  515. struct rt_object *object;
  516. struct rt_list_node *node;
  517. extern struct rt_object_information rt_object_container[];
  518. /* enter critical */
  519. if (rt_thread_self() != RT_NULL)
  520. rt_enter_critical();
  521. /* try to find device object */
  522. information = &rt_object_container[RT_Object_Class_Thread];
  523. for (node = information->object_list.next; node != &(information->object_list); node = node->next)
  524. {
  525. object = rt_list_entry(node, struct rt_object, list);
  526. if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
  527. {
  528. /* leave critical */
  529. if (rt_thread_self() != RT_NULL)
  530. rt_exit_critical();
  531. return (rt_thread_t)object;
  532. }
  533. }
  534. /* leave critical */
  535. if (rt_thread_self() != RT_NULL)
  536. rt_exit_critical();
  537. /* not found */
  538. return RT_NULL;
  539. }
  540. /*@}*/