thread.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. * File : thread.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2011, 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. */
  124. rt_err_t rt_thread_init(struct rt_thread *thread,
  125. const char *name,
  126. void (*entry)(void *parameter), void *parameter,
  127. void *stack_start, rt_uint32_t stack_size,
  128. rt_uint8_t priority, rt_uint32_t tick)
  129. {
  130. /* thread check */
  131. RT_ASSERT(thread != RT_NULL);
  132. RT_ASSERT(stack_start != RT_NULL);
  133. /* init thread object */
  134. rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
  135. return _rt_thread_init(thread, name, entry, parameter,
  136. stack_start, stack_size,
  137. priority, tick);
  138. }
  139. /**
  140. * This function will return self thread object
  141. *
  142. * @return the self thread object
  143. *
  144. */
  145. rt_thread_t rt_thread_self(void)
  146. {
  147. return rt_current_thread;
  148. }
  149. /**
  150. * This function will start a thread and put it to system ready queue
  151. *
  152. * @param thread the thread to be started
  153. *
  154. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  155. *
  156. */
  157. rt_err_t rt_thread_startup(rt_thread_t thread)
  158. {
  159. /* thread check */
  160. RT_ASSERT(thread != RT_NULL);
  161. RT_ASSERT(thread->stat == RT_THREAD_INIT);
  162. /* set current priority to init priority */
  163. thread->current_priority = thread->init_priority;
  164. /* calculate priority attribute */
  165. #if RT_THREAD_PRIORITY_MAX > 32
  166. thread->number = thread->current_priority >> 3; /* 5bit */
  167. thread->number_mask = 1L << thread->number;
  168. thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */
  169. #else
  170. thread->number_mask = 1L << thread->current_priority;
  171. #endif
  172. RT_DEBUG_LOG(RT_DEBUG_THREAD,\
  173. ("startup a thread:%s with priority:%d\n", thread->name, thread->init_priority));
  174. /* change thread stat */
  175. thread->stat = RT_THREAD_SUSPEND;
  176. /* then resume it */
  177. rt_thread_resume(thread);
  178. if (rt_thread_self() != RT_NULL)
  179. {
  180. /* do a scheduling */
  181. rt_schedule();
  182. }
  183. return RT_EOK;
  184. }
  185. /**
  186. * This function will detach a thread. The thread object will be removed from
  187. * thread queue and detached/deleted from system object management.
  188. *
  189. * @param thread the thread to be deleted
  190. *
  191. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  192. *
  193. */
  194. rt_err_t rt_thread_detach(rt_thread_t thread)
  195. {
  196. rt_base_t lock;
  197. /* thread check */
  198. RT_ASSERT(thread != RT_NULL);
  199. /* remove from schedule */
  200. rt_schedule_remove_thread(thread);
  201. /* release thread timer */
  202. rt_timer_detach(&(thread->thread_timer));
  203. /* change stat */
  204. thread->stat = RT_THREAD_CLOSE;
  205. /* detach object */
  206. rt_object_detach((rt_object_t)thread);
  207. if (thread->cleanup != RT_NULL)
  208. {
  209. /* disable interrupt */
  210. lock = rt_hw_interrupt_disable();
  211. /* insert to defunct thread list */
  212. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  213. /* enable interrupt */
  214. rt_hw_interrupt_enable(lock);
  215. }
  216. return RT_EOK;
  217. }
  218. #ifdef RT_USING_HEAP
  219. /**
  220. * This function will create a thread object and allocate thread object memory
  221. * and stack.
  222. *
  223. * @param name the name of thread, which shall be unique
  224. * @param entry the entry function of thread
  225. * @param parameter the parameter of thread enter function
  226. * @param stack_size the size of thread stack
  227. * @param priority the priority of thread
  228. * @param tick the time slice if there are same priority thread
  229. *
  230. * @return the created thread object
  231. *
  232. */
  233. rt_thread_t rt_thread_create(const char *name,
  234. void (*entry)(void *parameter), void *parameter,
  235. rt_uint32_t stack_size,
  236. rt_uint8_t priority,
  237. rt_uint32_t tick)
  238. {
  239. struct rt_thread *thread;
  240. void *stack_start;
  241. thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread, name);
  242. if (thread == RT_NULL) return RT_NULL;
  243. stack_start = (void *)rt_malloc(stack_size);
  244. if (stack_start == RT_NULL)
  245. {
  246. /* allocate stack failure */
  247. rt_object_delete((rt_object_t)thread);
  248. return RT_NULL;
  249. }
  250. _rt_thread_init(thread, name, entry, parameter,
  251. stack_start, stack_size,
  252. priority, tick);
  253. return thread;
  254. }
  255. /**
  256. * This function will delete a thread. The thread object will be removed from
  257. * thread queue and detached/deleted from system object management.
  258. *
  259. * @param thread the thread to be deleted
  260. *
  261. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  262. *
  263. */
  264. rt_err_t rt_thread_delete(rt_thread_t thread)
  265. {
  266. rt_base_t lock;
  267. /* thread check */
  268. RT_ASSERT(thread != RT_NULL);
  269. /* remove from schedule */
  270. rt_schedule_remove_thread(thread);
  271. /* release thread timer */
  272. rt_timer_detach(&(thread->thread_timer));
  273. /* change stat */
  274. thread->stat = RT_THREAD_CLOSE;
  275. /* disable interrupt */
  276. lock = rt_hw_interrupt_disable();
  277. /* insert to defunct thread list */
  278. rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));
  279. /* enable interrupt */
  280. rt_hw_interrupt_enable(lock);
  281. return RT_EOK;
  282. }
  283. #endif
  284. /**
  285. * This function will let current thread yield processor, and scheduler will
  286. * choose a highest thread to run. After yield processor, the current thread
  287. * is still in READY state.
  288. *
  289. * @return RT_EOK
  290. *
  291. */
  292. rt_err_t rt_thread_yield(void)
  293. {
  294. register rt_base_t level;
  295. struct rt_thread *thread;
  296. /* disable interrupt */
  297. level = rt_hw_interrupt_disable();
  298. /* set to current thread */
  299. thread = rt_current_thread;
  300. /* if the thread stat is READY and on ready queue list */
  301. if (thread->stat == RT_THREAD_READY && thread->tlist.next != thread->tlist.prev)
  302. {
  303. /* remove thread from thread list */
  304. rt_list_remove(&(thread->tlist));
  305. /* put thread to end of ready queue */
  306. rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
  307. &(thread->tlist));
  308. /* enable interrupt */
  309. rt_hw_interrupt_enable(level);
  310. rt_schedule();
  311. return RT_EOK;
  312. }
  313. /* enable interrupt */
  314. rt_hw_interrupt_enable(level);
  315. return RT_EOK;
  316. }
  317. /**
  318. * This function will let current thread sleep for some ticks.
  319. *
  320. * @param tick the sleep ticks
  321. *
  322. * @return RT_EOK
  323. *
  324. */
  325. rt_err_t rt_thread_sleep(rt_tick_t tick)
  326. {
  327. register rt_base_t temp;
  328. struct rt_thread *thread;
  329. /* disable interrupt */
  330. temp = rt_hw_interrupt_disable();
  331. /* set to current thread */
  332. thread = rt_current_thread;
  333. RT_ASSERT(thread != RT_NULL);
  334. /* suspend thread */
  335. rt_thread_suspend(thread);
  336. /* reset the timeout of thread timer and start it */
  337. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
  338. rt_timer_start(&(thread->thread_timer));
  339. /* enable interrupt */
  340. rt_hw_interrupt_enable(temp);
  341. rt_schedule();
  342. /* clear error number of this thread to RT_EOK */
  343. if (thread->error == -RT_ETIMEOUT)
  344. thread->error = RT_EOK;
  345. return RT_EOK;
  346. }
  347. /**
  348. * This function will let current thread delay for some ticks.
  349. *
  350. * @param tick the delay ticks
  351. *
  352. * @return RT_EOK
  353. *
  354. */
  355. rt_err_t rt_thread_delay(rt_tick_t tick)
  356. {
  357. return rt_thread_sleep(tick);
  358. }
  359. /**
  360. * This function will control thread behaviors according to control command.
  361. *
  362. * @param thread the specified thread to be controlled
  363. * @param cmd the control command, which includes
  364. * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
  365. * RT_THREAD_CTRL_STARTUP for starting a thread;
  366. * RT_THREAD_CTRL_CLOSE for delete a thread.
  367. * @param arg the argument of control command
  368. *
  369. * @return RT_EOK
  370. */
  371. rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void *arg)
  372. {
  373. register rt_base_t temp;
  374. /* thread check */
  375. RT_ASSERT(thread != RT_NULL);
  376. switch (cmd)
  377. {
  378. case RT_THREAD_CTRL_CHANGE_PRIORITY:
  379. /* disable interrupt */
  380. temp = rt_hw_interrupt_disable();
  381. /* for ready thread, change queue */
  382. if (thread->stat == RT_THREAD_READY)
  383. {
  384. /* remove thread from schedule queue first */
  385. rt_schedule_remove_thread(thread);
  386. /* change thread priority */
  387. thread->current_priority = *(rt_uint8_t *)arg;
  388. /* recalculate priority attribute */
  389. #if RT_THREAD_PRIORITY_MAX > 32
  390. thread->number = thread->current_priority >> 3; /* 5bit */
  391. thread->number_mask = 1 << thread->number;
  392. thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
  393. #else
  394. thread->number_mask = 1 << thread->current_priority;
  395. #endif
  396. /* insert thread to schedule queue again */
  397. rt_schedule_insert_thread(thread);
  398. }
  399. else
  400. {
  401. thread->current_priority = *(rt_uint8_t *)arg;
  402. /* recalculate priority attribute */
  403. #if RT_THREAD_PRIORITY_MAX > 32
  404. thread->number = thread->current_priority >> 3; /* 5bit */
  405. thread->number_mask = 1 << thread->number;
  406. thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */
  407. #else
  408. thread->number_mask = 1 << thread->current_priority;
  409. #endif
  410. }
  411. /* enable interrupt */
  412. rt_hw_interrupt_enable(temp);
  413. break;
  414. case RT_THREAD_CTRL_STARTUP:
  415. return rt_thread_startup(thread);
  416. #ifdef RT_USING_HEAP
  417. case RT_THREAD_CTRL_CLOSE:
  418. return rt_thread_delete(thread);
  419. #endif
  420. default:
  421. break;
  422. }
  423. return RT_EOK;
  424. }
  425. /**
  426. * This function will suspend the specified thread.
  427. *
  428. * @param thread the thread to be suspended
  429. *
  430. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  431. *
  432. * @note if suspend self thread, after this function call, the
  433. * rt_schedule() must be invoked.
  434. */
  435. rt_err_t rt_thread_suspend(rt_thread_t thread)
  436. {
  437. register rt_base_t temp;
  438. /* thread check */
  439. RT_ASSERT(thread != RT_NULL);
  440. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name));
  441. if (thread->stat != RT_THREAD_READY)
  442. {
  443. RT_DEBUG_LOG(RT_DEBUG_THREAD,\
  444. ("thread suspend: thread disorder, %d\n", thread->stat));
  445. return -RT_ERROR;
  446. }
  447. /* disable interrupt */
  448. temp = rt_hw_interrupt_disable();
  449. /* change thread stat */
  450. thread->stat = RT_THREAD_SUSPEND;
  451. rt_schedule_remove_thread(thread);
  452. /* enable interrupt */
  453. rt_hw_interrupt_enable(temp);
  454. return RT_EOK;
  455. }
  456. /**
  457. * This function will resume a thread and put it to system ready queue.
  458. *
  459. * @param thread the thread to be resumed
  460. *
  461. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  462. *
  463. */
  464. rt_err_t rt_thread_resume(rt_thread_t thread)
  465. {
  466. register rt_base_t temp;
  467. /* thread check */
  468. RT_ASSERT(thread != RT_NULL);
  469. RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name));
  470. if (thread->stat != RT_THREAD_SUSPEND)
  471. {
  472. RT_DEBUG_LOG(RT_DEBUG_THREAD, \
  473. ("thread resume: thread disorder, %d\n", thread->stat));
  474. return -RT_ERROR;
  475. }
  476. /* disable interrupt */
  477. temp = rt_hw_interrupt_disable();
  478. /* remove from suspend list */
  479. rt_list_remove(&(thread->tlist));
  480. /* remove thread timer */
  481. rt_list_remove(&(thread->thread_timer.list));
  482. /* change timer state */
  483. thread->thread_timer.parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  484. /* enable interrupt */
  485. rt_hw_interrupt_enable(temp);
  486. /* insert to schedule ready list */
  487. rt_schedule_insert_thread(thread);
  488. return RT_EOK;
  489. }
  490. /**
  491. * This function is the timeout function for thread, normally which is invoked
  492. * when thread is timeout to wait some resourse.
  493. *
  494. * @param parameter the parameter of thread timeout function
  495. *
  496. */
  497. void rt_thread_timeout(void *parameter)
  498. {
  499. struct rt_thread *thread;
  500. thread = (struct rt_thread *)parameter;
  501. /* thread check */
  502. RT_ASSERT(thread != RT_NULL);
  503. RT_ASSERT(thread->stat == RT_THREAD_SUSPEND);
  504. /* set error number */
  505. thread->error = -RT_ETIMEOUT;
  506. /* remove from suspend list */
  507. rt_list_remove(&(thread->tlist));
  508. /* insert to schedule ready list */
  509. rt_schedule_insert_thread(thread);
  510. /* do schedule */
  511. rt_schedule();
  512. }
  513. /**
  514. * This function will find the specified thread.
  515. *
  516. * @param name the name of thread finding
  517. *
  518. * @return the found thread
  519. *
  520. * @note please don't invoke this function in interrupt status.
  521. */
  522. rt_thread_t rt_thread_find(char *name)
  523. {
  524. struct rt_object_information *information;
  525. struct rt_object *object;
  526. struct rt_list_node *node;
  527. extern struct rt_object_information rt_object_container[];
  528. /* enter critical */
  529. if (rt_thread_self() != RT_NULL)
  530. rt_enter_critical();
  531. /* try to find device object */
  532. information = &rt_object_container[RT_Object_Class_Thread];
  533. for (node = information->object_list.next; node != &(information->object_list); node = node->next)
  534. {
  535. object = rt_list_entry(node, struct rt_object, list);
  536. if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
  537. {
  538. /* leave critical */
  539. if (rt_thread_self() != RT_NULL)
  540. rt_exit_critical();
  541. return (rt_thread_t)object;
  542. }
  543. }
  544. /* leave critical */
  545. if (rt_thread_self() != RT_NULL)
  546. rt_exit_critical();
  547. /* not found */
  548. return RT_NULL;
  549. }
  550. /*@}*/