thread.c 15 KB

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