ipc.c 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209
  1. /*
  2. * File : ipc.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006, 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-14 Bernard the first version
  13. * 2006-04-25 Bernard implement semaphore
  14. * 2006-05-03 Bernard add IPC_DEBUG
  15. * modify the type of IPC waiting time to rt_int32_t
  16. * 2006-05-10 Bernard fix the semaphore take bug and add IPC object
  17. * 2006-05-12 Bernard implement mailbox and message queue
  18. * 2006-05-20 Bernard implement mutex
  19. * 2006-05-23 Bernard implement fast event
  20. * 2006-05-24 Bernard implement event
  21. * 2006-06-03 Bernard fix the thread timer init bug
  22. * 2006-06-05 Bernard fix the mutex release bug
  23. * 2006-06-07 Bernard fix the message queue send bug
  24. * 2006-08-04 Bernard add hook support
  25. * 2009-05-21 Yi.qiu fix the sem release bug
  26. * 2009-07-18 Bernard fix the event clear bug
  27. */
  28. #include <rtthread.h>
  29. #include <rthw.h>
  30. #include "kservice.h"
  31. /* #define IPC_DEBUG */
  32. #ifdef RT_USING_HOOK
  33. extern void (*rt_object_trytake_hook)(struct rt_object* object);
  34. extern void (*rt_object_take_hook)(struct rt_object* object);
  35. extern void (*rt_object_put_hook)(struct rt_object* object);
  36. #endif
  37. /**
  38. * @addtogroup IPC
  39. */
  40. /*@{*/
  41. /**
  42. * This function will initialize an IPC object
  43. *
  44. * @param ipc the IPC object
  45. *
  46. * @return the operation status, RT_EOK on successful
  47. */
  48. rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc)
  49. {
  50. /* init ipc object */
  51. rt_list_init(&(ipc->suspend_thread));
  52. ipc->suspend_thread_count = 0;
  53. return RT_EOK;
  54. }
  55. /**
  56. * This function will suspend a thread for a specified IPC object and put the
  57. * thread into suspend queue of IPC object
  58. *
  59. * @param ipc the IPC object
  60. * @param thread the thread object to be suspended
  61. *
  62. * @return the operation status, RT_EOK on successful
  63. */
  64. rt_inline rt_err_t rt_ipc_object_suspend(struct rt_ipc_object *ipc, struct rt_thread *thread)
  65. {
  66. /* suspend thread */
  67. rt_thread_suspend(thread);
  68. ipc->suspend_thread_count ++;
  69. switch (ipc->parent.flag)
  70. {
  71. case RT_IPC_FLAG_FIFO:
  72. rt_list_insert_before(&(ipc->suspend_thread), &(thread->tlist));
  73. break;
  74. case RT_IPC_FLAG_PRIO:
  75. {
  76. struct rt_list_node* n;
  77. struct rt_thread* sthread;
  78. /* find a suitable position */
  79. for (n = ipc->suspend_thread.next; n != &(ipc->suspend_thread);
  80. n = n->next)
  81. {
  82. sthread = rt_list_entry(n, struct rt_thread, tlist);
  83. /* find out */
  84. if (thread->current_priority < sthread->current_priority) break;
  85. }
  86. rt_list_insert_before(&(ipc->suspend_thread), &(thread->tlist));
  87. }
  88. break;
  89. }
  90. return RT_EOK;
  91. }
  92. /**
  93. * This function will resume a thread from an IPC object:
  94. * - remove the thread from suspend queue of IPC object
  95. * - put the thread into system ready queue
  96. *
  97. * @param ipc the IPC object
  98. *
  99. * @return the operation status, RT_EOK on successful
  100. */
  101. rt_inline rt_err_t rt_ipc_object_resume(struct rt_ipc_object* ipc)
  102. {
  103. struct rt_thread *thread;
  104. /* get thread entry */
  105. thread = rt_list_entry(ipc->suspend_thread.next, struct rt_thread, tlist);
  106. #ifdef IPC_DEBUG
  107. rt_kprintf("resume thread:%s\n", thread->name);
  108. #endif
  109. /* resume it */
  110. rt_thread_resume(thread);
  111. /* decrease suspended thread count */
  112. ipc->suspend_thread_count --;
  113. return RT_EOK;
  114. }
  115. /**
  116. * This function will resume all suspended threads in an IPC object.
  117. *
  118. * @param ipc the IPC object
  119. *
  120. * @return the operation status, RT_EOK on successful
  121. */
  122. rt_inline rt_err_t rt_ipc_object_resume_all(struct rt_ipc_object* ipc)
  123. {
  124. struct rt_thread* thread;
  125. register rt_ubase_t temp;
  126. /* wakeup all suspend threads */
  127. while (!rt_list_isempty(&(ipc->suspend_thread)))
  128. {
  129. /* disable interrupt */
  130. temp = rt_hw_interrupt_disable();
  131. /* get next suspend thread */
  132. thread = rt_list_entry(ipc->suspend_thread.next, struct rt_thread, tlist);
  133. /* set error code to RT_ERROR */
  134. thread->error = -RT_ERROR;
  135. /*
  136. * resume thread
  137. * In rt_thread_resume function, it will remove current thread from
  138. * suspend list
  139. */
  140. rt_thread_resume(thread);
  141. /* decrease suspended thread count */
  142. ipc->suspend_thread_count --;
  143. /* enable interrupt */
  144. rt_hw_interrupt_enable(temp);
  145. }
  146. return RT_EOK;
  147. }
  148. /* decrease ipc suspended thread number when thread can not take resource successfully */
  149. rt_inline void rt_ipc_object_decrease(struct rt_ipc_object* ipc)
  150. {
  151. register rt_ubase_t level;
  152. /* disable interrupt */
  153. level = rt_hw_interrupt_disable();
  154. /* decrease suspended thread count */
  155. ipc->suspend_thread_count --;
  156. /* enable interrupt */
  157. rt_hw_interrupt_enable(level);
  158. }
  159. #ifdef RT_USING_SEMAPHORE
  160. /**
  161. * This function will initialize a semaphore and put it under control of resource
  162. * management.
  163. *
  164. * @param sem the semaphore object
  165. * @param name the name of semaphore
  166. * @param value the init value of semaphore
  167. * @param flag the flag of semaphore
  168. *
  169. * @return the operation status, RT_EOK on successful
  170. */
  171. rt_err_t rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag)
  172. {
  173. RT_ASSERT(sem != RT_NULL);
  174. /* init object */
  175. rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
  176. /* init ipc object */
  177. rt_ipc_object_init(&(sem->parent));
  178. /* set init value */
  179. sem->value = value;
  180. /* set parent */
  181. sem->parent.parent.flag = flag;
  182. return RT_EOK;
  183. }
  184. /**
  185. * This function will detach a semaphore from resource management
  186. *
  187. * @param sem the semaphore object
  188. *
  189. * @return the operation status, RT_EOK on successful
  190. *
  191. * @see rt_sem_delete
  192. */
  193. rt_err_t rt_sem_detach (rt_sem_t sem)
  194. {
  195. RT_ASSERT(sem != RT_NULL);
  196. /* wakeup all suspend threads */
  197. rt_ipc_object_resume_all(&(sem->parent));
  198. /* detach semaphore object */
  199. rt_object_detach(&(sem->parent.parent));
  200. return RT_EOK;
  201. }
  202. #ifdef RT_USING_HEAP
  203. /**
  204. * This function will create a semaphore from system resource
  205. *
  206. * @param name the name of semaphore
  207. * @param value the init value of semaphore
  208. * @param flag the flag of semaphore
  209. *
  210. * @return the created semaphore, RT_NULL on error happen
  211. *
  212. * @see rt_sem_init
  213. */
  214. rt_sem_t rt_sem_create (const char* name, rt_uint32_t value, rt_uint8_t flag)
  215. {
  216. rt_sem_t sem;
  217. /* allocate object */
  218. sem = (rt_sem_t) rt_object_allocate(RT_Object_Class_Semaphore, name);
  219. if (sem == RT_NULL) return sem;
  220. /* init ipc object */
  221. rt_ipc_object_init(&(sem->parent));
  222. /* set init value */
  223. sem->value = value;
  224. /* set parent */
  225. sem->parent.parent.flag = flag;
  226. return sem;
  227. }
  228. /**
  229. * This function will delete a semaphore object and release the memory
  230. *
  231. * @param sem the semaphore object
  232. *
  233. * @return the error code
  234. *
  235. * @see rt_sem_detach
  236. */
  237. rt_err_t rt_sem_delete (rt_sem_t sem)
  238. {
  239. RT_ASSERT(sem != RT_NULL);
  240. /* wakeup all suspend threads */
  241. rt_ipc_object_resume_all(&(sem->parent));
  242. /* delete semaphore object */
  243. rt_object_delete(&(sem->parent.parent));
  244. return RT_EOK;
  245. }
  246. #endif
  247. /**
  248. * This function will take a semaphore, if the semaphore is unavailable, the
  249. * thread shall wait for a specified time.
  250. *
  251. * @param sem the semaphore object
  252. * @param time the waiting time
  253. *
  254. * @return the error code
  255. */
  256. rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time)
  257. {
  258. register rt_base_t temp;
  259. struct rt_thread* thread;
  260. RT_ASSERT(sem != RT_NULL);
  261. #ifdef RT_USING_HOOK
  262. if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(sem->parent.parent));
  263. #endif
  264. /* disable interrupt */
  265. temp = rt_hw_interrupt_disable();
  266. #ifdef IPC_DEBUG
  267. rt_kprintf("thread %s take sem:%s, which value is: %d\n", rt_thread_self()->name,
  268. ((struct rt_object*)sem)->name, sem->value);
  269. #endif
  270. if (sem->value > 0)
  271. {
  272. /* semaphore is available */
  273. sem->value --;
  274. /* enable interrupt */
  275. rt_hw_interrupt_enable(temp);
  276. }
  277. else
  278. {
  279. /* no waiting, return with timeout */
  280. if (time == 0 )
  281. {
  282. rt_hw_interrupt_enable(temp);
  283. return -RT_ETIMEOUT;
  284. }
  285. else
  286. {
  287. /* semaphore is unavailable, push to suspend list */
  288. sem->value --;
  289. /* get current thread */
  290. thread = rt_thread_self();
  291. /* reset thread error number */
  292. thread->error = RT_EOK;
  293. #ifdef IPC_DEBUG
  294. rt_kprintf("sem take: suspend thread - %s\n", thread->name);
  295. #endif
  296. /* suspend thread */
  297. rt_ipc_object_suspend(&(sem->parent), thread);
  298. /* has waiting time, start thread timer */
  299. if (time > 0)
  300. {
  301. #ifdef IPC_DEBUG
  302. rt_kprintf("set thread:%s to timer list\n", thread->name);
  303. #endif
  304. /* reset the timeout of thread timer and start it */
  305. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);
  306. rt_timer_start(&(thread->thread_timer));
  307. }
  308. /* enable interrupt */
  309. rt_hw_interrupt_enable(temp);
  310. /* do schedule */
  311. rt_schedule();
  312. if (thread->error != RT_EOK)
  313. {
  314. /* decrease suspended thread count */
  315. rt_ipc_object_decrease(&(sem->parent));
  316. return thread->error;
  317. }
  318. }
  319. }
  320. #ifdef RT_USING_HOOK
  321. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(sem->parent.parent));
  322. #endif
  323. return RT_EOK;
  324. }
  325. /**
  326. * This function will try to take a semaphore and immediately return
  327. *
  328. * @param sem the semaphore object
  329. *
  330. * @return the error code
  331. */
  332. rt_err_t rt_sem_trytake(rt_sem_t sem)
  333. {
  334. return rt_sem_take(sem, 0);
  335. }
  336. /**
  337. * This function will release a semaphore, if there are threads suspended on
  338. * semaphore, it will be waked up.
  339. *
  340. * @param sem the semaphore object
  341. *
  342. * @return the error code
  343. */
  344. rt_err_t rt_sem_release(rt_sem_t sem)
  345. {
  346. register rt_base_t temp;
  347. #ifdef RT_USING_HOOK
  348. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(sem->parent.parent));
  349. #endif
  350. /* disable interrupt */
  351. temp = rt_hw_interrupt_disable();
  352. #ifdef IPC_DEBUG
  353. rt_kprintf("thread %s releases sem:%s, which value is: %d\n", rt_thread_self()->name,
  354. ((struct rt_object*)sem)->name, sem->value);
  355. #endif
  356. /* increase value */
  357. sem->value ++;
  358. if (sem->value <= 0 && sem->parent.suspend_thread_count > 0)
  359. {
  360. rt_ipc_object_resume(&(sem->parent));
  361. /* enable interrupt */
  362. rt_hw_interrupt_enable(temp);
  363. /* resume a thread, re-schedule */
  364. rt_schedule();
  365. return RT_EOK;
  366. }
  367. /* enable interrupt */
  368. rt_hw_interrupt_enable(temp);
  369. return RT_EOK;
  370. }
  371. /**
  372. * This function can get or set some extra attributions of a semaphore object.
  373. *
  374. * @param sem the semaphore object
  375. * @param cmd the execution command
  376. * @param arg the execution argument
  377. *
  378. * @return the error code
  379. */
  380. rt_err_t rt_sem_control(rt_sem_t sem, rt_uint8_t cmd, void* arg)
  381. {
  382. return RT_EOK;
  383. }
  384. #endif /* end of RT_USING_SEMAPHORE */
  385. #ifdef RT_USING_MUTEX
  386. /**
  387. * This function will initialize a mutex and put it under control of resource
  388. * management.
  389. *
  390. * @param mutex the mutex object
  391. * @param name the name of mutex
  392. * @param flag the flag of mutex
  393. *
  394. * @return the operation status, RT_EOK on successful
  395. */
  396. rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag)
  397. {
  398. RT_ASSERT(mutex != RT_NULL);
  399. /* init object */
  400. rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name);
  401. /* init ipc object */
  402. rt_ipc_object_init(&(mutex->parent));
  403. mutex->value = 1;
  404. mutex->owner = RT_NULL;
  405. mutex->original_priority = 0xFF;
  406. mutex->hold = 0;
  407. /* set flag */
  408. mutex->parent.parent.flag = flag;
  409. return RT_EOK;
  410. }
  411. /**
  412. * This function will detach a mutex from resource management
  413. *
  414. * @param mutex the mutex object
  415. *
  416. * @return the operation status, RT_EOK on successful
  417. *
  418. * @see rt_mutex_delete
  419. */
  420. rt_err_t rt_mutex_detach (rt_mutex_t mutex)
  421. {
  422. RT_ASSERT(mutex != RT_NULL);
  423. /* wakeup all suspend threads */
  424. rt_ipc_object_resume_all(&(mutex->parent));
  425. /* detach semaphore object */
  426. rt_object_detach(&(mutex->parent.parent));
  427. return RT_EOK;
  428. }
  429. #ifdef RT_USING_HEAP
  430. /**
  431. * This function will create a mutex from system resource
  432. *
  433. * @param name the name of mutex
  434. * @param flag the flag of mutex
  435. *
  436. * @return the created mutex, RT_NULL on error happen
  437. *
  438. * @see rt_mutex_init
  439. */
  440. rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag)
  441. {
  442. struct rt_mutex *mutex;
  443. /* allocate object */
  444. mutex = (rt_mutex_t) rt_object_allocate(RT_Object_Class_Mutex, name);
  445. if (mutex == RT_NULL) return mutex;
  446. /* init ipc object */
  447. rt_ipc_object_init(&(mutex->parent));
  448. mutex->value = 1;
  449. mutex->owner = RT_NULL;
  450. mutex->original_priority = 0xFF;
  451. mutex->hold = 0;
  452. /* set flag */
  453. mutex->parent.parent.flag = flag;
  454. return mutex;
  455. }
  456. /**
  457. * This function will delete a mutex object and release the memory
  458. *
  459. * @param mutex the mutex object
  460. *
  461. * @return the error code
  462. *
  463. * @see rt_mutex_detach
  464. */
  465. rt_err_t rt_mutex_delete (rt_mutex_t mutex)
  466. {
  467. RT_ASSERT(mutex != RT_NULL);
  468. /* wakeup all suspend threads */
  469. rt_ipc_object_resume_all(&(mutex->parent));
  470. /* delete semaphore object */
  471. rt_object_delete(&(mutex->parent.parent));
  472. return RT_EOK;
  473. }
  474. #endif
  475. /**
  476. * This function will take a mutex, if the mutex is unavailable, the
  477. * thread shall wait for a specified time.
  478. *
  479. * @param mutex the mutex object
  480. * @param time the waiting time
  481. *
  482. * @return the error code
  483. */
  484. rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time)
  485. {
  486. register rt_base_t temp;
  487. struct rt_thread* thread;
  488. RT_ASSERT(mutex != RT_NULL);
  489. #ifdef RT_USING_HOOK
  490. if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(mutex->parent.parent));
  491. #endif
  492. /* disable interrupt */
  493. temp = rt_hw_interrupt_disable();
  494. #ifdef IPC_DEBUG
  495. rt_kprintf("mutex_take:mutex value: %d, hold: %d\n", mutex->value, mutex->hold);
  496. #endif
  497. /* get current thread */
  498. thread = rt_thread_self();
  499. /* reset thread error */
  500. thread->error = RT_EOK;
  501. if (mutex->owner == thread)
  502. {
  503. /* it's the same thread */
  504. mutex->hold ++;
  505. }
  506. else
  507. {
  508. if (mutex->value > 0)
  509. {
  510. /* mutex is available */
  511. mutex->value --;
  512. /* set mutex owner and original priority */
  513. mutex->owner = thread;
  514. mutex->original_priority = thread->current_priority;
  515. mutex->hold ++;
  516. }
  517. else
  518. {
  519. /* no waiting, return with timeout */
  520. if (time == 0 )
  521. {
  522. /* set error as timeout */
  523. thread->error = -RT_ETIMEOUT;
  524. /* enable interrupt */
  525. rt_hw_interrupt_enable(temp);
  526. return -RT_ETIMEOUT;
  527. }
  528. else
  529. {
  530. /* mutex is unavailable, push to suspend list */
  531. mutex->value --;
  532. #ifdef IPC_DEBUG
  533. rt_kprintf("sem take: suspend thread: %s\n", thread->name);
  534. #endif
  535. /* change the owner thread priority of mutex */
  536. if (thread->current_priority < mutex->owner->current_priority)
  537. {
  538. /* change the owner thread priority */
  539. rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY,
  540. &thread->current_priority);
  541. }
  542. /* suspend current thread */
  543. rt_ipc_object_suspend(&(mutex->parent), thread);
  544. /* has waiting time, start thread timer */
  545. if (time > 0)
  546. {
  547. #ifdef IPC_DEBUG
  548. rt_kprintf("set thread:%s to timer list\n", thread->name);
  549. #endif
  550. /* reset the timeout of thread timer and start it */
  551. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &time);
  552. rt_timer_start(&(thread->thread_timer));
  553. }
  554. /* enable interrupt */
  555. rt_hw_interrupt_enable(temp);
  556. /* do schedule */
  557. rt_schedule();
  558. if (thread->error != RT_EOK)
  559. {
  560. /* decrease suspended thread count */
  561. rt_ipc_object_decrease(&(mutex->parent));
  562. /* return error */
  563. return thread->error;
  564. }
  565. else
  566. {
  567. /* disable interrupt */
  568. temp = rt_hw_interrupt_disable();
  569. /* take mutex */
  570. mutex->owner = thread;
  571. mutex->hold ++;
  572. /* set thread error */
  573. thread->error = RT_EOK;
  574. }
  575. }
  576. }
  577. }
  578. /* enable interrupt */
  579. rt_hw_interrupt_enable(temp);
  580. #ifdef RT_USING_HOOK
  581. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(mutex->parent.parent));
  582. #endif
  583. return RT_EOK;
  584. }
  585. /**
  586. * This function will release a mutex, if there are threads suspended on mutex,
  587. * it will be waked up.
  588. *
  589. * @param mutex the mutex object
  590. *
  591. * @return the error code
  592. */
  593. rt_err_t rt_mutex_release(rt_mutex_t mutex)
  594. {
  595. register rt_base_t temp;
  596. struct rt_thread* thread;
  597. /* disable interrupt */
  598. temp = rt_hw_interrupt_disable();
  599. #ifdef IPC_DEBUG
  600. rt_kprintf("mutex_release:mutex value: %d, hold: %d\n", mutex->value, mutex->hold);
  601. #endif
  602. #ifdef RT_USING_HOOK
  603. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mutex->parent.parent));
  604. #endif
  605. /* get current thread */
  606. thread = rt_thread_self();
  607. /* mutex is only released by owner */
  608. if (thread != mutex->owner)
  609. {
  610. thread->error = -RT_ERROR;
  611. /* enable interrupt */
  612. rt_hw_interrupt_enable(temp);
  613. return -RT_ERROR;
  614. }
  615. /* decrease hold */
  616. mutex->hold --;
  617. /* if no hold */
  618. if (mutex->hold == 0)
  619. {
  620. /* change the owner thread to original priority */
  621. if (mutex->owner->init_priority != mutex->owner->current_priority)
  622. {
  623. rt_thread_control(mutex->owner, RT_THREAD_CTRL_CHANGE_PRIORITY,
  624. &(mutex->owner->init_priority));
  625. }
  626. /* wakeup suspended thread */
  627. if (mutex->value <= 0 && mutex->parent.suspend_thread_count > 0)
  628. {
  629. #ifdef IPC_DEBUG
  630. rt_kprintf("mutex release: resume thread: %s\n", thread->name);
  631. #endif
  632. /* resume thread */
  633. rt_ipc_object_resume(&(mutex->parent));
  634. }
  635. /* increase value */
  636. mutex->value ++;
  637. /* enable interrupt */
  638. rt_hw_interrupt_enable(temp);
  639. rt_schedule();
  640. return RT_EOK;
  641. }
  642. /* enable interrupt */
  643. rt_hw_interrupt_enable(temp);
  644. return RT_EOK;
  645. }
  646. /**
  647. * This function can get or set some extra attributions of a mutex object.
  648. *
  649. * @param mutex the mutex object
  650. * @param cmd the execution command
  651. * @param arg the execution argument
  652. *
  653. * @return the error code
  654. */
  655. rt_err_t rt_mutex_control(rt_mutex_t mutex, rt_uint8_t cmd, void* arg)
  656. {
  657. return RT_EOK;
  658. }
  659. #endif /* end of RT_USING_MUTEX */
  660. #ifdef RT_USING_FASTEVENT
  661. /**
  662. * This function will initialize a fast event and put it under control of resource
  663. * management.
  664. *
  665. * @param event the fast event object
  666. * @param name the name of fast event
  667. * @param flag the flag of fast event
  668. *
  669. * @return the operation status, RT_EOK on successful
  670. */
  671. rt_err_t rt_fast_event_init(rt_fast_event_t event, const char* name, rt_uint8_t flag)
  672. {
  673. register rt_base_t offset;
  674. RT_ASSERT(event != RT_NULL);
  675. /* init object */
  676. rt_object_init(&(event->parent), RT_Object_Class_FastEvent, name);
  677. /* set parent */
  678. event->parent.flag = flag;
  679. /* clear event set */
  680. event->set = 0x00;
  681. /* init thread list */
  682. for (offset = 0; offset < 32; offset ++)
  683. {
  684. rt_list_init(&(event->thread_list[offset]));
  685. }
  686. return RT_EOK;
  687. }
  688. /**
  689. * This function will detach a fast event from resource management
  690. *
  691. * @param event the fast event object
  692. *
  693. * @return the operation status, RT_EOK on successful
  694. */
  695. rt_err_t rt_fast_event_detach(rt_fast_event_t event)
  696. {
  697. register rt_base_t bit;
  698. struct rt_thread* thread;
  699. register rt_ubase_t level;
  700. RT_ASSERT(event != RT_NULL);
  701. for (bit = 0; bit < RT_EVENT_LENGTH; bit ++)
  702. {
  703. /* resume all suspend thread */
  704. if (!rt_list_isempty(&(event->thread_list[bit])))
  705. {
  706. /* wakeup all suspend threads */
  707. while (!rt_list_isempty(&(event->thread_list[bit])))
  708. {
  709. /* disable interrupt */
  710. level = rt_hw_interrupt_disable();
  711. /* get next suspend thread */
  712. thread = rt_list_entry(event->thread_list[bit].next, struct rt_thread, tlist);
  713. /* set error code to RT_ERROR */
  714. thread->error = -RT_ERROR;
  715. /* resume thread */
  716. rt_thread_resume(thread);
  717. /* enable interrupt */
  718. rt_hw_interrupt_enable(level);
  719. }
  720. }
  721. }
  722. /* detach event object */
  723. rt_object_detach(&(event->parent));
  724. return RT_EOK;
  725. }
  726. #ifdef RT_USING_HEAP
  727. /**
  728. * This function will create a fast event object from system resource
  729. *
  730. * @param name the name of fast event
  731. * @param flag the flag of fast event
  732. *
  733. * @return the created fast event, RT_NULL on error happen
  734. */
  735. rt_fast_event_t rt_fast_event_create (const char* name, rt_uint8_t flag)
  736. {
  737. rt_fast_event_t event;
  738. register rt_base_t offset;
  739. /* allocate object */
  740. event = (rt_fast_event_t) rt_object_allocate(RT_Object_Class_FastEvent, name);
  741. if (event == RT_NULL) return event;
  742. /* set parent */
  743. event->parent.flag = flag;
  744. /* clear event set */
  745. event->set = 0x00;
  746. /* init thread list */
  747. for (offset = 0; offset < 32; offset ++)
  748. {
  749. rt_list_init(&(event->thread_list[offset]));
  750. }
  751. return event;
  752. }
  753. /**
  754. * This function will delete a fast event object and release the memory
  755. *
  756. * @param event the fast event object
  757. *
  758. * @return the error code
  759. */
  760. rt_err_t rt_fast_event_delete (rt_fast_event_t event)
  761. {
  762. register rt_base_t bit;
  763. struct rt_thread* thread;
  764. register rt_ubase_t level;
  765. RT_ASSERT(event != RT_NULL);
  766. for (bit = 0; bit < RT_EVENT_LENGTH; bit ++)
  767. {
  768. /* resume all suspend thread */
  769. if (!rt_list_isempty(&(event->thread_list[bit])))
  770. {
  771. /* wakeup all suspend threads */
  772. while (!rt_list_isempty(&(event->thread_list[bit])))
  773. {
  774. /* disable interrupt */
  775. level = rt_hw_interrupt_disable();
  776. /* get next suspend thread */
  777. thread = rt_list_entry(event->thread_list[bit].next, struct rt_thread, tlist);
  778. /* set error code to RT_ERROR */
  779. thread->error = -RT_ERROR;
  780. /* resume thread */
  781. rt_thread_resume(thread);
  782. /* enable interrupt */
  783. rt_hw_interrupt_enable(level);
  784. }
  785. }
  786. }
  787. /* detach semaphore object */
  788. rt_object_delete(&(event->parent));
  789. return RT_EOK;
  790. }
  791. #endif
  792. /**
  793. * This function will send an event to the fast event object, if there are threads
  794. * suspended on fast event object, it will be waked up.
  795. *
  796. * @param event the fast event object
  797. * @param bit the event bit
  798. *
  799. * @return the error code
  800. */
  801. rt_err_t rt_fast_event_send(rt_fast_event_t event, rt_uint8_t bit)
  802. {
  803. rt_uint32_t offset;
  804. register rt_ubase_t level;
  805. struct rt_thread *thread;
  806. struct rt_list_node *n;
  807. /* parameter check */
  808. RT_ASSERT(event != RT_NULL);
  809. RT_ASSERT(bit < RT_EVENT_LENGTH);
  810. offset = 1 << bit;
  811. #ifdef RT_USING_HOOK
  812. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(event->parent));
  813. #endif
  814. /* disable interrupt */
  815. level = rt_hw_interrupt_disable();
  816. event->set |= offset;
  817. /* if thread list at offset is not empty */
  818. n = event->thread_list[bit].next;
  819. while (n != &(event->thread_list[bit]))
  820. {
  821. /* get thread */
  822. thread = rt_list_entry(n, struct rt_thread, tlist);
  823. /* move to next node */
  824. n = n->next;
  825. /* clear bit or not */
  826. if (thread->event_info & RT_EVENT_FLAG_CLEAR)
  827. event->set &= ~offset;
  828. /* resume thread */
  829. rt_thread_resume(thread);
  830. }
  831. /* enable interrupt */
  832. rt_hw_interrupt_enable(level);
  833. /* do a schedule */
  834. rt_schedule();
  835. return RT_EOK;
  836. }
  837. /**
  838. * This function will receive an event from fast event object, if the event is
  839. * unavailable, the thread shall wait for a specified time.
  840. *
  841. * @param event the fast event object
  842. * @param bit the interested event
  843. * @param option the receive option
  844. * @param timeout the waiting time
  845. *
  846. * @return the error code
  847. */
  848. rt_err_t rt_fast_event_recv(rt_fast_event_t event, rt_uint8_t bit, rt_uint8_t option, rt_int32_t timeout)
  849. {
  850. rt_base_t offset;
  851. struct rt_thread* thread;
  852. register rt_ubase_t level;
  853. /* parameter check */
  854. RT_ASSERT(event != RT_NULL);
  855. RT_ASSERT(bit < RT_EVENT_LENGTH);
  856. offset = 1 << bit;
  857. #ifdef RT_USING_HOOK
  858. if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(event->parent));
  859. #endif
  860. /* disable interrupt */
  861. level = rt_hw_interrupt_disable();
  862. /* get current thread */
  863. thread = rt_thread_self();
  864. thread->error = RT_EOK;
  865. /* get event successfully */
  866. if (event->set & offset)
  867. {
  868. if (option & RT_EVENT_FLAG_CLEAR)
  869. event->set &= ~ offset;
  870. /* enable interrupt */
  871. rt_hw_interrupt_enable(level);
  872. return RT_EOK;
  873. }
  874. /* no event happen */
  875. /* check waiting time */
  876. if (timeout == 0)
  877. {
  878. /* no waiting */
  879. thread->error = -RT_ETIMEOUT;
  880. }
  881. else
  882. {
  883. /* there are no event, suspend thread */
  884. rt_thread_suspend(thread);
  885. /* set event info in thread */
  886. thread->event_info = option;
  887. switch (event->parent.flag)
  888. {
  889. case RT_IPC_FLAG_FIFO:
  890. rt_list_insert_after(&(event->thread_list[bit]), &(thread->tlist));
  891. break;
  892. case RT_IPC_FLAG_PRIO:
  893. {
  894. struct rt_list_node* n;
  895. struct rt_thread* sthread;
  896. /* find a suitable position */
  897. for (n = event->thread_list[bit].next; n != &(event->thread_list[bit]); n = n->next)
  898. {
  899. sthread = rt_list_entry(n, struct rt_thread, tlist);
  900. /* find out */
  901. if (thread->current_priority < sthread->current_priority) break;
  902. }
  903. /* insert thread */
  904. rt_list_insert_before(&(event->thread_list[bit]), &(thread->tlist));
  905. }
  906. break;
  907. }
  908. /* if there is timeout, active thread timer */
  909. if (timeout > 0)
  910. {
  911. /* reset the timeout of thread timer and start it */
  912. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
  913. rt_timer_start(&(thread->thread_timer));
  914. }
  915. }
  916. /* enable interrupt */
  917. rt_hw_interrupt_enable(level);
  918. #ifdef RT_USING_HOOK
  919. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(event->parent));
  920. #endif
  921. return thread->error;
  922. }
  923. /**
  924. * This function can get or set some extra attributions of a fast event object.
  925. *
  926. * @param event the event object
  927. * @param cmd the execution command
  928. * @param arg the execution argument
  929. *
  930. * @return the error code
  931. */
  932. rt_err_t rt_fast_event_control (rt_fast_event_t event, rt_uint8_t cmd, void* arg)
  933. {
  934. return RT_EOK;
  935. }
  936. #endif
  937. #ifdef RT_USING_EVENT
  938. /**
  939. * This function will initialize an event and put it under control of resource
  940. * management.
  941. *
  942. * @param event the event object
  943. * @param name the name of event
  944. * @param flag the flag of event
  945. *
  946. * @return the operation status, RT_EOK on successful
  947. */
  948. rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag)
  949. {
  950. RT_ASSERT(event != RT_NULL);
  951. /* init object */
  952. rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);
  953. /* set parent flag */
  954. event->parent.parent.flag = flag;
  955. /* init ipc object */
  956. rt_ipc_object_init(&(event->parent));
  957. /* init event */
  958. event->set = 0;
  959. return RT_EOK;
  960. }
  961. /**
  962. * This function will detach an event object from resource management
  963. *
  964. * @param event the event object
  965. *
  966. * @return the operation status, RT_EOK on successful
  967. */
  968. rt_err_t rt_event_detach(rt_event_t event)
  969. {
  970. /* parameter check */
  971. RT_ASSERT(event != RT_NULL);
  972. /* resume all suspended thread */
  973. rt_ipc_object_resume_all(&(event->parent));
  974. /* detach event object */
  975. rt_object_detach(&(event->parent.parent));
  976. return RT_EOK;
  977. }
  978. #ifdef RT_USING_HEAP
  979. /**
  980. * This function will create an event object from system resource
  981. *
  982. * @param name the name of event
  983. * @param flag the flag of event
  984. *
  985. * @return the created event, RT_NULL on error happen
  986. */
  987. rt_event_t rt_event_create (const char* name, rt_uint8_t flag)
  988. {
  989. rt_event_t event;
  990. /* allocate object */
  991. event = (rt_event_t) rt_object_allocate(RT_Object_Class_Event, name);
  992. if (event == RT_NULL) return event;
  993. /* set parent */
  994. event->parent.parent.flag = flag;
  995. /* init ipc object */
  996. rt_ipc_object_init(&(event->parent));
  997. /* init event */
  998. event->set = 0;
  999. return event;
  1000. }
  1001. /**
  1002. * This function will delete an event object and release the memory
  1003. *
  1004. * @param event the event object
  1005. *
  1006. * @return the error code
  1007. */
  1008. rt_err_t rt_event_delete (rt_event_t event)
  1009. {
  1010. /* parameter check */
  1011. RT_ASSERT(event != RT_NULL);
  1012. /* resume all suspended thread */
  1013. rt_ipc_object_resume_all(&(event->parent));
  1014. /* delete event object */
  1015. rt_object_delete(&(event->parent.parent));
  1016. return RT_EOK;
  1017. }
  1018. #endif
  1019. /**
  1020. * This function will send an event to the event object, if there are threads
  1021. * suspended on event object, it will be waked up.
  1022. *
  1023. * @param event the event object
  1024. * @param set the event set
  1025. *
  1026. * @return the error code
  1027. */
  1028. rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
  1029. {
  1030. struct rt_list_node *n;
  1031. struct rt_thread *thread;
  1032. register rt_ubase_t level;
  1033. register rt_base_t status;
  1034. rt_bool_t need_schedule;
  1035. /* parameter check */
  1036. RT_ASSERT(event != RT_NULL);
  1037. if (set == 0) return -RT_ERROR;
  1038. need_schedule = RT_FALSE;
  1039. #ifdef RT_USING_HOOK
  1040. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(event->parent.parent));
  1041. #endif
  1042. /* disable interrupt */
  1043. level = rt_hw_interrupt_disable();
  1044. /* set event */
  1045. event->set |= set;
  1046. if (event->parent.suspend_thread_count > 0)
  1047. {
  1048. /* search thread list to resume thread */
  1049. n = event->parent.suspend_thread.next;
  1050. while (n != &(event->parent.suspend_thread))
  1051. {
  1052. /* get thread */
  1053. thread = rt_list_entry(n, struct rt_thread, tlist);
  1054. status = -RT_ERROR;
  1055. if (thread->event_info & RT_EVENT_FLAG_AND)
  1056. {
  1057. if ((thread->event_set & event->set) == thread->event_set)
  1058. {
  1059. /* received a AND event */
  1060. status = RT_EOK;
  1061. }
  1062. }
  1063. else if (thread->event_info & RT_EVENT_FLAG_OR)
  1064. {
  1065. if (thread->event_set & event->set)
  1066. {
  1067. /* received a OR event */
  1068. status = RT_EOK;
  1069. }
  1070. }
  1071. /* move node to the next */
  1072. n = n->next;
  1073. /* condition is satisfied, resume thread */
  1074. if (status == RT_EOK)
  1075. {
  1076. /* resume thread, and thread list breaks out */
  1077. rt_thread_resume(thread);
  1078. /* need do a scheduling */
  1079. need_schedule = RT_TRUE;
  1080. /* decrease suspended thread count */
  1081. event->parent.suspend_thread_count--;
  1082. }
  1083. }
  1084. }
  1085. /* enable interrupt */
  1086. rt_hw_interrupt_enable(level);
  1087. /* do a schedule */
  1088. if (need_schedule == RT_TRUE)
  1089. rt_schedule();
  1090. return RT_EOK;
  1091. }
  1092. /**
  1093. * This function will receive an event from event object, if the event is unavailable,
  1094. * the thread shall wait for a specified time.
  1095. *
  1096. * @param event the fast event object
  1097. * @param set the interested event set
  1098. * @param option the receive option
  1099. * @param timeout the waiting time
  1100. * @param recved the received event
  1101. *
  1102. * @return the error code
  1103. */
  1104. rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option, rt_int32_t timeout, rt_uint32_t* recved)
  1105. {
  1106. struct rt_thread *thread;
  1107. register rt_ubase_t level;
  1108. register rt_base_t status;
  1109. /* parameter check */
  1110. RT_ASSERT(event != RT_NULL);
  1111. if (set == 0) return -RT_ERROR;
  1112. /* init status */
  1113. status = -RT_ERROR;
  1114. /* get current thread */
  1115. thread = rt_thread_self();
  1116. /* reset thread error */
  1117. thread->error = RT_EOK;
  1118. #ifdef RT_USING_HOOK
  1119. if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(event->parent.parent));
  1120. #endif
  1121. /* disable interrupt */
  1122. level = rt_hw_interrupt_disable();
  1123. /* check event set */
  1124. if (option & RT_EVENT_FLAG_AND)
  1125. {
  1126. if ((event->set & set) == set) status = RT_EOK;
  1127. }
  1128. else if (option & RT_EVENT_FLAG_OR)
  1129. {
  1130. if (event->set & set) status = RT_EOK;
  1131. }
  1132. if (status == RT_EOK)
  1133. {
  1134. /* set received event */
  1135. *recved = event->set;
  1136. /* received event */
  1137. if (option & RT_EVENT_FLAG_CLEAR) event->set &= ~set;
  1138. }
  1139. else if (timeout == 0)
  1140. {
  1141. /* no waiting */
  1142. thread->error = -RT_ETIMEOUT;
  1143. }
  1144. else
  1145. {
  1146. /* fill thread event info */
  1147. thread->event_set = set;
  1148. thread->event_info = option;
  1149. /* put thread to suspended thread list */
  1150. rt_ipc_object_suspend(&(event->parent), thread);
  1151. /* if there is a waiting timeout, active thread timer */
  1152. if (timeout > 0)
  1153. {
  1154. /* reset the timeout of thread timer and start it */
  1155. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
  1156. rt_timer_start(&(thread->thread_timer));
  1157. }
  1158. /* enable interrupt */
  1159. rt_hw_interrupt_enable(level);
  1160. /* do a schedule */
  1161. rt_schedule();
  1162. if (thread->error != RT_EOK)
  1163. {
  1164. /* decrease suspended thread count */
  1165. rt_ipc_object_decrease(&(event->parent));
  1166. return thread->error;
  1167. }
  1168. /* received a event, disable interrupt to protect */
  1169. level = rt_hw_interrupt_disable();
  1170. /* get received event */
  1171. *recved = event->set;
  1172. /* clear event */
  1173. if (option & RT_EVENT_FLAG_CLEAR)
  1174. event->set &= ~set;
  1175. }
  1176. /* enable interrupt */
  1177. rt_hw_interrupt_enable(level);
  1178. #ifdef RT_USING_HOOK
  1179. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(event->parent.parent));
  1180. #endif
  1181. return thread->error;
  1182. }
  1183. /**
  1184. * This function can get or set some extra attributions of an event object.
  1185. *
  1186. * @param event the event object
  1187. * @param cmd the execution command
  1188. * @param arg the execution argument
  1189. *
  1190. * @return the error code
  1191. */
  1192. rt_err_t rt_event_control (rt_event_t event, rt_uint8_t cmd, void* arg)
  1193. {
  1194. return RT_EOK;
  1195. }
  1196. #endif /* end of RT_USING_EVENT */
  1197. #ifdef RT_USING_MAILBOX
  1198. /**
  1199. * This function will initialize a mailbox and put it under control of resource
  1200. * management.
  1201. *
  1202. * @param mb the mailbox object
  1203. * @param name the name of mailbox
  1204. * @param msgpool the begin address of buffer to save received mail
  1205. * @param size the size of mailbox
  1206. * @param flag the flag of mailbox
  1207. *
  1208. * @return the operation status, RT_EOK on successful
  1209. */
  1210. rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool, rt_size_t size, rt_uint8_t flag)
  1211. {
  1212. RT_ASSERT(mb != RT_NULL);
  1213. /* init object */
  1214. rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name);
  1215. /* set parent flag */
  1216. mb->parent.parent.flag = flag;
  1217. /* init ipc object */
  1218. rt_ipc_object_init(&(mb->parent));
  1219. /* init mailbox */
  1220. mb->msg_pool = msgpool;
  1221. mb->size = size;
  1222. mb->entry = 0;
  1223. mb->in_offset = 0;
  1224. mb->out_offset = 0;
  1225. return RT_EOK;
  1226. }
  1227. /**
  1228. * This function will detach a mailbox from resource management
  1229. *
  1230. * @param mb the mailbox object
  1231. *
  1232. * @return the operation status, RT_EOK on successful
  1233. */
  1234. rt_err_t rt_mb_detach(rt_mailbox_t mb)
  1235. {
  1236. /* parameter check */
  1237. RT_ASSERT(mb != RT_NULL);
  1238. /* resume all suspended thread */
  1239. rt_ipc_object_resume_all(&(mb->parent));
  1240. /* detach mailbox object */
  1241. rt_object_detach(&(mb->parent.parent));
  1242. return RT_EOK;
  1243. }
  1244. #ifdef RT_USING_HEAP
  1245. /**
  1246. * This function will create a mailbox object from system resource
  1247. *
  1248. * @param name the name of mailbox
  1249. * @param size the size of mailbox
  1250. * @param flag the flag of mailbox
  1251. *
  1252. * @return the created mailbox, RT_NULL on error happen
  1253. */
  1254. rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag)
  1255. {
  1256. rt_mailbox_t mb;
  1257. /* allocate object */
  1258. mb = (rt_mailbox_t) rt_object_allocate(RT_Object_Class_MailBox, name);
  1259. if (mb == RT_NULL) return mb;
  1260. /* set parent */
  1261. mb->parent.parent.flag = flag;
  1262. /* init ipc object */
  1263. rt_ipc_object_init(&(mb->parent));
  1264. /* init mailbox */
  1265. mb->size = size;
  1266. mb->msg_pool = rt_malloc(mb->size * sizeof(rt_uint32_t));
  1267. if (mb->msg_pool == RT_NULL)
  1268. {
  1269. /* delete mailbox object */
  1270. rt_object_delete(&(mb->parent.parent));
  1271. return RT_NULL;
  1272. }
  1273. mb->entry = 0;
  1274. mb->in_offset = 0;
  1275. mb->out_offset = 0;
  1276. return mb;
  1277. }
  1278. /**
  1279. * This function will delete a mailbox object and release the memory
  1280. *
  1281. * @param mb the mailbox object
  1282. *
  1283. * @return the error code
  1284. */
  1285. rt_err_t rt_mb_delete (rt_mailbox_t mb)
  1286. {
  1287. /* parameter check */
  1288. RT_ASSERT(mb != RT_NULL);
  1289. /* resume all suspended thread */
  1290. rt_ipc_object_resume_all(&(mb->parent));
  1291. /* free mailbox pool */
  1292. rt_free(mb->msg_pool);
  1293. /* delete mailbox object */
  1294. rt_object_delete(&(mb->parent.parent));
  1295. return RT_EOK;
  1296. }
  1297. #endif
  1298. /**
  1299. * This function will send a mail to mailbox object, if there are threads suspended
  1300. * on mailbox object, it will be waked up.
  1301. *
  1302. * @param mb the mailbox object
  1303. * @param value the mail
  1304. *
  1305. * @return the error code
  1306. */
  1307. rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value)
  1308. {
  1309. register rt_ubase_t temp;
  1310. /* parameter check */
  1311. RT_ASSERT(mb != RT_NULL);
  1312. #ifdef RT_USING_HOOK
  1313. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mb->parent.parent));
  1314. #endif
  1315. /* disable interrupt */
  1316. temp = rt_hw_interrupt_disable();
  1317. /* mailbox is full */
  1318. if (mb->entry == mb->size)
  1319. {
  1320. /* enable interrupt */
  1321. rt_hw_interrupt_enable(temp);
  1322. return -RT_EFULL;
  1323. }
  1324. /* set ptr */
  1325. mb->msg_pool[mb->in_offset] = value;
  1326. /* increase input offset */
  1327. ++ mb->in_offset;
  1328. mb->in_offset %= mb->size;
  1329. /* increase message entry */
  1330. mb->entry ++;
  1331. /* resume suspended thread */
  1332. if (mb->parent.suspend_thread_count > 0)
  1333. {
  1334. rt_ipc_object_resume(&(mb->parent));
  1335. /* enable interrupt */
  1336. rt_hw_interrupt_enable(temp);
  1337. rt_schedule();
  1338. return RT_EOK;
  1339. }
  1340. /* enable interrupt */
  1341. rt_hw_interrupt_enable(temp);
  1342. return RT_EOK;
  1343. }
  1344. /**
  1345. * This function will receive a mail from mailbox object, if there is no mail in
  1346. * mailbox object, the thread shall wait for a specified time.
  1347. *
  1348. * @param mb the mailbox object
  1349. * @param value the received mail will be saved in
  1350. * @param timeout the waiting time
  1351. *
  1352. * @return the error code
  1353. */
  1354. rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout)
  1355. {
  1356. struct rt_thread *thread;
  1357. register rt_ubase_t temp;
  1358. /* parameter check */
  1359. RT_ASSERT(mb != RT_NULL);
  1360. #ifdef RT_USING_HOOK
  1361. if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(mb->parent.parent));
  1362. #endif
  1363. /* disable interrupt */
  1364. temp = rt_hw_interrupt_disable();
  1365. /* mailbox is empty */
  1366. if (mb->entry == 0)
  1367. {
  1368. /* get current thread */
  1369. thread = rt_thread_self();
  1370. /* reset error number in thread */
  1371. thread->error = RT_EOK;
  1372. /* no waiting, return timeout */
  1373. if (timeout == 0)
  1374. {
  1375. /* enable interrupt */
  1376. rt_hw_interrupt_enable(temp);
  1377. thread->error = -RT_ETIMEOUT;
  1378. return -RT_ETIMEOUT;
  1379. }
  1380. /* suspend current thread */
  1381. rt_ipc_object_suspend(&(mb->parent), thread);
  1382. /* has waiting time, start thread timer */
  1383. if (timeout > 0)
  1384. {
  1385. #ifdef IPC_DEBUG
  1386. rt_kprintf("set thread:%s to timer list\n", thread->name);
  1387. #endif
  1388. /* reset the timeout of thread timer and start it */
  1389. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
  1390. rt_timer_start(&(thread->thread_timer));
  1391. }
  1392. /* enable interrupt */
  1393. rt_hw_interrupt_enable(temp);
  1394. /* re-schedule */
  1395. rt_schedule();
  1396. /* recv message */
  1397. if (thread->error != RT_EOK)
  1398. {
  1399. /* decrease suspended thread count */
  1400. rt_ipc_object_decrease(&(mb->parent));
  1401. return thread->error;
  1402. }
  1403. /* disable interrupt */
  1404. temp = rt_hw_interrupt_disable();
  1405. }
  1406. /* fill ptr */
  1407. *value = mb->msg_pool[mb->out_offset];
  1408. /* increase output offset */
  1409. ++mb->out_offset;
  1410. mb->out_offset %= mb->size;
  1411. /* decrease message entry */
  1412. mb->entry --;
  1413. /* enable interrupt */
  1414. rt_hw_interrupt_enable(temp);
  1415. #ifdef RT_USING_HOOK
  1416. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(mb->parent.parent));
  1417. #endif
  1418. return RT_EOK;
  1419. }
  1420. /**
  1421. * This function can get or set some extra attributions of a mailbox object.
  1422. *
  1423. * @param mb the mailbox object
  1424. * @param cmd the execution command
  1425. * @param arg the execution argument
  1426. *
  1427. * @return the error code
  1428. */
  1429. rt_err_t rt_mb_control(rt_mailbox_t mb, rt_uint8_t cmd, void* arg)
  1430. {
  1431. return RT_EOK;
  1432. }
  1433. #endif /* end of RT_USING_MAILBOX */
  1434. #ifdef RT_USING_MESSAGEQUEUE
  1435. struct rt_mq_message
  1436. {
  1437. struct rt_mq_message* next;
  1438. };
  1439. /**
  1440. * This function will initialize a message queue and put it under control of resource
  1441. * management.
  1442. *
  1443. * @param mq the message object
  1444. * @param name the name of message queue
  1445. * @param msgpool the beginning address of buffer to save messages
  1446. * @param msg_size the maximum size of message
  1447. * @param pool_size the size of buffer to save messages
  1448. * @param flag the flag of message queue
  1449. *
  1450. * @return the operation status, RT_EOK on successful
  1451. */
  1452. rt_err_t rt_mq_init(rt_mq_t mq, const char* name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag)
  1453. {
  1454. struct rt_mq_message* head;
  1455. register rt_base_t temp;
  1456. /* parameter check */
  1457. RT_ASSERT(mq != RT_NULL);
  1458. /* init object */
  1459. rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name);
  1460. /* set parent flag */
  1461. mq->parent.parent.flag = flag;
  1462. /* init ipc object */
  1463. rt_ipc_object_init(&(mq->parent));
  1464. /* set messasge pool */
  1465. mq->msg_pool = msgpool;
  1466. /* get correct message size */
  1467. mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
  1468. mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message));
  1469. /* init message list */
  1470. mq->msg_queue_head = RT_NULL;
  1471. mq->msg_queue_tail = RT_NULL;
  1472. /* init message empty list */
  1473. mq->msg_queue_free = RT_NULL;
  1474. for (temp = 0; temp < mq->max_msgs; temp ++)
  1475. {
  1476. head = (struct rt_mq_message*)((rt_uint8_t*)mq->msg_pool +
  1477. temp * (mq->msg_size + sizeof(struct rt_mq_message)));
  1478. head->next = mq->msg_queue_free;
  1479. mq->msg_queue_free = head;
  1480. }
  1481. /* the initial entry is zero */
  1482. mq->entry = 0;
  1483. return RT_EOK;
  1484. }
  1485. /**
  1486. * This function will detach a message queue object from resource management
  1487. *
  1488. * @param mq the message queue object
  1489. *
  1490. * @return the operation status, RT_EOK on successful
  1491. */
  1492. rt_err_t rt_mq_detach(rt_mq_t mq)
  1493. {
  1494. /* parameter check */
  1495. RT_ASSERT(mq != RT_NULL);
  1496. /* resume all suspended thread */
  1497. rt_ipc_object_resume_all((struct rt_ipc_object*)mq);
  1498. /* detach message queue object */
  1499. rt_object_detach(&(mq->parent.parent));
  1500. return RT_EOK;
  1501. }
  1502. #ifdef RT_USING_HEAP
  1503. /**
  1504. * This function will create a message queue object from system resource
  1505. *
  1506. * @param name the name of message queue
  1507. * @param msg_size the size of message
  1508. * @param max_msgs the maximum number of message in queue
  1509. * @param flag the flag of message queue
  1510. *
  1511. * @return the created message queue, RT_NULL on error happen
  1512. */
  1513. rt_mq_t rt_mq_create (const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag)
  1514. {
  1515. struct rt_messagequeue* mq;
  1516. struct rt_mq_message* head;
  1517. register rt_base_t temp;
  1518. /* allocate object */
  1519. mq = (rt_mq_t) rt_object_allocate(RT_Object_Class_MessageQueue, name);
  1520. if (mq == RT_NULL) return mq;
  1521. /* set parent */
  1522. mq->parent.parent.flag = flag;
  1523. /* init ipc object */
  1524. rt_ipc_object_init(&(mq->parent));
  1525. /* init message queue */
  1526. /* get correct message size */
  1527. mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
  1528. mq->max_msgs = max_msgs;
  1529. /* allocate message pool */
  1530. mq->msg_pool = rt_malloc((mq->msg_size + sizeof(struct rt_mq_message))* mq->max_msgs);
  1531. if (mq->msg_pool == RT_NULL)
  1532. {
  1533. rt_mq_delete(mq);
  1534. return RT_NULL;
  1535. }
  1536. /* init message list */
  1537. mq->msg_queue_head = RT_NULL;
  1538. mq->msg_queue_tail = RT_NULL;
  1539. /* init message empty list */
  1540. mq->msg_queue_free = RT_NULL;
  1541. for (temp = 0; temp < mq->max_msgs; temp ++)
  1542. {
  1543. head = (struct rt_mq_message*)((rt_uint8_t*)mq->msg_pool +
  1544. temp * (mq->msg_size + sizeof(struct rt_mq_message)));
  1545. head->next = mq->msg_queue_free;
  1546. mq->msg_queue_free = head;
  1547. }
  1548. /* the initial entry is zero */
  1549. mq->entry = 0;
  1550. return mq;
  1551. }
  1552. /**
  1553. * This function will delete a message queue object and release the memory
  1554. *
  1555. * @param mq the message queue object
  1556. *
  1557. * @return the error code
  1558. */
  1559. rt_err_t rt_mq_delete (rt_mq_t mq)
  1560. {
  1561. /* parameter check */
  1562. RT_ASSERT(mq != RT_NULL);
  1563. /* resume all suspended thread */
  1564. rt_ipc_object_resume_all(&(mq->parent));
  1565. /* free mailbox pool */
  1566. rt_free(mq->msg_pool);
  1567. /* delete mailbox object */
  1568. rt_object_delete(&(mq->parent.parent));
  1569. return RT_EOK;
  1570. }
  1571. #endif
  1572. /**
  1573. * This function will send a message to message queue object, if there are threads
  1574. * suspended on message queue object, it will be waked up.
  1575. *
  1576. * @param mq the message queue object
  1577. * @param buffer the message
  1578. * @param size the size of buffer
  1579. *
  1580. * @return the error code
  1581. */
  1582. rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size)
  1583. {
  1584. register rt_ubase_t temp;
  1585. struct rt_mq_message *msg;
  1586. /* greater than one message size */
  1587. if (size > mq->msg_size) return -RT_ERROR;
  1588. #ifdef RT_USING_HOOK
  1589. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mq->parent.parent));
  1590. #endif
  1591. /* disable interrupt */
  1592. temp = rt_hw_interrupt_disable();
  1593. /* get a free list, there must be an empty item */
  1594. msg = (struct rt_mq_message*)mq->msg_queue_free;
  1595. /* message queue is full */
  1596. if (msg == RT_NULL)
  1597. {
  1598. /* enable interrupt */
  1599. rt_hw_interrupt_enable(temp);
  1600. return -RT_EFULL;
  1601. }
  1602. /* move free list pointer */
  1603. mq->msg_queue_free = msg->next;
  1604. /* copy buffer */
  1605. rt_memcpy(msg + 1, buffer, size);
  1606. /* link msg to message queue */
  1607. if (mq->msg_queue_tail != RT_NULL)
  1608. {
  1609. /* if the tail exists, */
  1610. ((struct rt_mq_message*)mq->msg_queue_tail)->next = msg;
  1611. }
  1612. /* the msg is the new tail of list, the next shall be NULL */
  1613. msg->next = RT_NULL;
  1614. /* set new tail */
  1615. mq->msg_queue_tail = msg;
  1616. /* if the head is empty, set head */
  1617. if (mq->msg_queue_head == RT_NULL)mq->msg_queue_head = msg;
  1618. /* increase message entry */
  1619. mq->entry ++;
  1620. /* resume suspended thread */
  1621. if (mq->parent.suspend_thread_count > 0)
  1622. {
  1623. rt_ipc_object_resume(&(mq->parent));
  1624. /* enable interrupt */
  1625. rt_hw_interrupt_enable(temp);
  1626. rt_schedule();
  1627. return RT_EOK;
  1628. }
  1629. /* enable interrupt */
  1630. rt_hw_interrupt_enable(temp);
  1631. return RT_EOK;
  1632. }
  1633. /**
  1634. * This function will send urgently a message to message queue object, which means
  1635. * the message will be inserted to the head of message queue. If there are threads
  1636. * suspended on message queue object, it will be waked up.
  1637. *
  1638. * @param mq the message queue object
  1639. * @param buffer the message
  1640. * @param size the size of buffer
  1641. *
  1642. * @return the error code
  1643. */
  1644. rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size)
  1645. {
  1646. register rt_ubase_t temp;
  1647. struct rt_mq_message *msg;
  1648. /* greater than one message size */
  1649. if (size > mq->msg_size) return -RT_ERROR;
  1650. #ifdef RT_USING_HOOK
  1651. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(mq->parent.parent));
  1652. #endif
  1653. /* disable interrupt */
  1654. temp = rt_hw_interrupt_disable();
  1655. /* get a free list, there must be an empty item */
  1656. msg = (struct rt_mq_message*)mq->msg_queue_free;
  1657. /* message queue is full */
  1658. if (msg == RT_NULL)
  1659. {
  1660. /* enable interrupt */
  1661. rt_hw_interrupt_enable(temp);
  1662. return -RT_EFULL;
  1663. }
  1664. /* move free list pointer */
  1665. mq->msg_queue_free = msg->next;
  1666. /* copy buffer */
  1667. rt_memcpy(msg + 1, buffer, size);
  1668. /* link msg to the beginning of message queue */
  1669. msg->next = mq->msg_queue_head;
  1670. mq->msg_queue_head = msg;
  1671. /* if there is no tail */
  1672. if (mq->msg_queue_tail == RT_NULL) mq->msg_queue_tail = msg;
  1673. /* increase message entry */
  1674. mq->entry ++;
  1675. /* resume suspended thread */
  1676. if (mq->parent.suspend_thread_count > 0)
  1677. {
  1678. rt_ipc_object_resume(&(mq->parent));
  1679. /* enable interrupt */
  1680. rt_hw_interrupt_enable(temp);
  1681. rt_schedule();
  1682. return RT_EOK;
  1683. }
  1684. /* enable interrupt */
  1685. rt_hw_interrupt_enable(temp);
  1686. return RT_EOK;
  1687. }
  1688. /**
  1689. * This function will receive a message from message queue object, if there is no
  1690. * message in message queue object, the thread shall wait for a specified time.
  1691. *
  1692. * @param mq the message queue object
  1693. * @param buffer the received message will be saved in
  1694. * @param size the size of buffer
  1695. * @param timeout the waiting time
  1696. *
  1697. * @return the error code
  1698. */
  1699. rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout)
  1700. {
  1701. struct rt_thread *thread;
  1702. register rt_ubase_t temp;
  1703. struct rt_mq_message *msg;
  1704. #ifdef RT_USING_HOOK
  1705. if (rt_object_trytake_hook != RT_NULL) rt_object_trytake_hook(&(mq->parent.parent));
  1706. #endif
  1707. /* disable interrupt */
  1708. temp = rt_hw_interrupt_disable();
  1709. /* mailbox is empty */
  1710. if (mq->entry == 0)
  1711. {
  1712. /* get current thread */
  1713. thread = rt_thread_self();
  1714. /* reset error number in thread */
  1715. thread->error = RT_EOK;
  1716. /* no waiting, return timeout */
  1717. if (timeout == 0)
  1718. {
  1719. /* enable interrupt */
  1720. rt_hw_interrupt_enable(temp);
  1721. thread->error = -RT_ETIMEOUT;
  1722. return -RT_ETIMEOUT;
  1723. }
  1724. /* suspend current thread */
  1725. rt_ipc_object_suspend(&(mq->parent), thread);
  1726. /* has waiting time, start thread timer */
  1727. if (timeout > 0)
  1728. {
  1729. #ifdef IPC_DEBUG
  1730. rt_kprintf("set thread:%s to timer list\n", thread->name);
  1731. #endif
  1732. /* reset the timeout of thread timer and start it */
  1733. rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout);
  1734. rt_timer_start(&(thread->thread_timer));
  1735. }
  1736. /* enable interrupt */
  1737. rt_hw_interrupt_enable(temp);
  1738. /* re-schedule */
  1739. rt_schedule();
  1740. /* recv message */
  1741. if (thread->error != RT_EOK)
  1742. {
  1743. /* decrease suspended thread count */
  1744. rt_ipc_object_decrease(&(mq->parent));
  1745. return thread->error;
  1746. }
  1747. /* disable interrupt */
  1748. temp = rt_hw_interrupt_disable();
  1749. }
  1750. /* get message from queue */
  1751. msg = (struct rt_mq_message*) mq->msg_queue_head;
  1752. /* move message queue head */
  1753. mq->msg_queue_head = msg->next;
  1754. /* reach queue tail, set to NULL */
  1755. if (mq->msg_queue_tail == msg) mq->msg_queue_tail = RT_NULL;
  1756. /* copy message */
  1757. rt_memcpy(buffer, msg + 1,
  1758. size > mq->msg_size? mq->msg_size : size);
  1759. /* put message to free list */
  1760. msg->next = (struct rt_mq_message*)mq->msg_queue_free;
  1761. mq->msg_queue_free = msg;
  1762. /* decrease message entry */
  1763. mq->entry --;
  1764. /* enable interrupt */
  1765. rt_hw_interrupt_enable(temp);
  1766. #ifdef RT_USING_HOOK
  1767. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(mq->parent.parent));
  1768. #endif
  1769. return RT_EOK;
  1770. }
  1771. /**
  1772. * This function can get or set some extra attributions of a message queue object.
  1773. *
  1774. * @param mq the message queue object
  1775. * @param cmd the execution command
  1776. * @param arg the execution argument
  1777. *
  1778. * @return the error code
  1779. */
  1780. rt_err_t rt_mq_control(rt_mq_t mq, rt_uint8_t cmd, void* arg)
  1781. {
  1782. return RT_EOK;
  1783. }
  1784. #endif /* end of RT_USING_MESSAGEQUEUE */
  1785. /**
  1786. * @ingroup SystemInit
  1787. * This function will init IPC module.
  1788. */
  1789. void rt_system_ipc_init()
  1790. {
  1791. /* nothing to be done */
  1792. }
  1793. /*@}*/