thread.c 15 KB

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