ipc.c 126 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2006-03-14 Bernard the first version
  9. * 2006-04-25 Bernard implement semaphore
  10. * 2006-05-03 Bernard add RT_IPC_DEBUG
  11. * modify the type of IPC waiting time to rt_int32_t
  12. * 2006-05-10 Bernard fix the semaphore take bug and add IPC object
  13. * 2006-05-12 Bernard implement mailbox and message queue
  14. * 2006-05-20 Bernard implement mutex
  15. * 2006-05-23 Bernard implement fast event
  16. * 2006-05-24 Bernard implement event
  17. * 2006-06-03 Bernard fix the thread timer init bug
  18. * 2006-06-05 Bernard fix the mutex release bug
  19. * 2006-06-07 Bernard fix the message queue send bug
  20. * 2006-08-04 Bernard add hook support
  21. * 2009-05-21 Yi.qiu fix the sem release bug
  22. * 2009-07-18 Bernard fix the event clear bug
  23. * 2009-09-09 Bernard remove fast event and fix ipc release bug
  24. * 2009-10-10 Bernard change semaphore and mutex value to unsigned value
  25. * 2009-10-25 Bernard change the mb/mq receive timeout to 0 if the
  26. * re-calculated delta tick is a negative number.
  27. * 2009-12-16 Bernard fix the rt_ipc_object_suspend issue when IPC flag
  28. * is RT_IPC_FLAG_PRIO
  29. * 2010-01-20 mbbill remove rt_ipc_object_decrease function.
  30. * 2010-04-20 Bernard move memcpy outside interrupt disable in mq
  31. * 2010-10-26 yi.qiu add module support in rt_mp_delete and rt_mq_delete
  32. * 2010-11-10 Bernard add IPC reset command implementation.
  33. * 2011-12-18 Bernard add more parameter checking in message queue
  34. * 2013-09-14 Grissiom add an option check in rt_event_recv
  35. * 2018-10-02 Bernard add 64bit support for mailbox
  36. * 2019-09-16 tyx add send wait support for message queue
  37. * 2020-07-29 Meco Man fix thread->event_set/event_info when received an
  38. * event without pending
  39. * 2020-10-11 Meco Man add value overflow-check code
  40. * 2021-01-03 Meco Man implement rt_mb_urgent()
  41. * 2021-05-30 Meco Man implement rt_mutex_trytake()
  42. * 2022-01-07 Gabriel Moving __on_rt_xxxxx_hook to ipc.c
  43. * 2022-01-24 THEWON let rt_mutex_take return thread->error when using signal
  44. * 2022-04-08 Stanley Correct descriptions
  45. * 2022-10-15 Bernard add nested mutex feature
  46. * 2022-10-16 Bernard add prioceiling feature in mutex
  47. */
  48. #include <rtthread.h>
  49. #include <rthw.h>
  50. #ifndef __on_rt_object_trytake_hook
  51. #define __on_rt_object_trytake_hook(parent) __ON_HOOK_ARGS(rt_object_trytake_hook, (parent))
  52. #endif
  53. #ifndef __on_rt_object_take_hook
  54. #define __on_rt_object_take_hook(parent) __ON_HOOK_ARGS(rt_object_take_hook, (parent))
  55. #endif
  56. #ifndef __on_rt_object_put_hook
  57. #define __on_rt_object_put_hook(parent) __ON_HOOK_ARGS(rt_object_put_hook, (parent))
  58. #endif
  59. #if defined(RT_USING_HOOK) && defined(RT_HOOK_USING_FUNC_PTR)
  60. extern void (*rt_object_trytake_hook)(struct rt_object *object);
  61. extern void (*rt_object_take_hook)(struct rt_object *object);
  62. extern void (*rt_object_put_hook)(struct rt_object *object);
  63. #endif /* RT_USING_HOOK */
  64. /**
  65. * @addtogroup IPC
  66. */
  67. /**@{*/
  68. /**
  69. * @brief This function will initialize an IPC object, such as semaphore, mutex, messagequeue and mailbox.
  70. *
  71. * @note Executing this function will complete an initialization of the suspend thread list of the ipc object.
  72. *
  73. * @param ipc is a pointer to the IPC object.
  74. *
  75. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  76. * When the return value is any other values, it means the initialization failed.
  77. *
  78. * @warning This function can be called from all IPC initialization and creation.
  79. */
  80. rt_inline rt_err_t _ipc_object_init(struct rt_ipc_object *ipc)
  81. {
  82. /* initialize ipc object */
  83. rt_list_init(&(ipc->suspend_thread));
  84. return RT_EOK;
  85. }
  86. /**
  87. * @brief This function will suspend a thread to a IPC object list.
  88. *
  89. * @param list is a pointer to a suspended thread list of the IPC object.
  90. *
  91. * @param thread is a pointer to the thread object to be suspended.
  92. *
  93. * @param flag is a flag for the thread object to be suspended. It determines how the thread is suspended.
  94. * The flag can be ONE of the following values:
  95. *
  96. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  97. *
  98. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  99. * (also known as first-come-first-served (FCFS) scheduling strategy).
  100. *
  101. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to use
  102. * RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  103. * the first-in-first-out principle, and you clearly understand that all threads involved in
  104. * this semaphore will become non-real-time threads.
  105. *
  106. * @return Return the operation status. When the return value is RT_EOK, the function is successfully executed.
  107. * When the return value is any other values, it means the initialization failed.
  108. *
  109. * @warning This function can ONLY be called in the thread context, you can use RT_DEBUG_IN_THREAD_CONTEXT to
  110. * check the context.
  111. * In addition, this function is generally called by the following functions:
  112. * rt_sem_take(), rt_mutex_take(), rt_event_recv(), rt_mb_send_wait(),
  113. * rt_mb_recv(), rt_mq_recv(), rt_mq_send_wait()
  114. */
  115. rt_inline rt_err_t _ipc_list_suspend(rt_list_t *list,
  116. struct rt_thread *thread,
  117. rt_uint8_t flag,
  118. int suspend_flag)
  119. {
  120. rt_err_t ret = rt_thread_suspend_with_flag(thread, suspend_flag);
  121. /* suspend thread */
  122. if (ret != RT_EOK)
  123. {
  124. return ret;
  125. }
  126. switch (flag)
  127. {
  128. case RT_IPC_FLAG_FIFO:
  129. rt_list_insert_before(list, &(thread->tlist));
  130. break; /* RT_IPC_FLAG_FIFO */
  131. case RT_IPC_FLAG_PRIO:
  132. {
  133. struct rt_list_node *n;
  134. struct rt_thread *sthread;
  135. /* find a suitable position */
  136. for (n = list->next; n != list; n = n->next)
  137. {
  138. sthread = rt_list_entry(n, struct rt_thread, tlist);
  139. /* find out */
  140. if (thread->current_priority < sthread->current_priority)
  141. {
  142. /* insert this thread before the sthread */
  143. rt_list_insert_before(&(sthread->tlist), &(thread->tlist));
  144. break;
  145. }
  146. }
  147. /*
  148. * not found a suitable position,
  149. * append to the end of suspend_thread list
  150. */
  151. if (n == list)
  152. rt_list_insert_before(list, &(thread->tlist));
  153. }
  154. break;/* RT_IPC_FLAG_PRIO */
  155. default:
  156. RT_ASSERT(0);
  157. break;
  158. }
  159. return RT_EOK;
  160. }
  161. /**
  162. * @brief This function will resume a thread.
  163. *
  164. * @note This function will resume the first thread in the list of a IPC object.
  165. * 1. remove the thread from suspend queue of a IPC object.
  166. * 2. put the thread into system ready queue.
  167. *
  168. * By contrast, the rt_ipc_list_resume_all() function will resume all suspended threads
  169. * in the list of a IPC object.
  170. *
  171. * @param list is a pointer to a suspended thread list of the IPC object.
  172. *
  173. * @return Return the operation status. When the return value is RT_EOK, the function is successfully executed.
  174. * When the return value is any other values, it means this operation failed.
  175. *
  176. * @warning This function is generally called by the following functions:
  177. * rt_sem_release(), rt_mutex_release(), rt_mb_send_wait(), rt_mq_send_wait(),
  178. * rt_mb_urgent(), rt_mb_recv(), rt_mq_urgent(), rt_mq_recv(),
  179. */
  180. rt_inline rt_err_t _ipc_list_resume(rt_list_t *list)
  181. {
  182. struct rt_thread *thread;
  183. /* get thread entry */
  184. thread = rt_list_entry(list->next, struct rt_thread, tlist);
  185. thread->error = RT_EOK;
  186. RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name));
  187. /* resume it */
  188. rt_thread_resume(thread);
  189. return RT_EOK;
  190. }
  191. /**
  192. * @brief This function will resume all suspended threads in the IPC object list,
  193. * including the suspended list of IPC object, and private list of mailbox etc.
  194. *
  195. * @note This function will resume all threads in the IPC object list.
  196. * By contrast, the rt_ipc_list_resume() function will resume a suspended thread in the list of a IPC object.
  197. *
  198. * @param list is a pointer to a suspended thread list of the IPC object.
  199. *
  200. * @return Return the operation status. When the return value is RT_EOK, the function is successfully executed.
  201. * When the return value is any other values, it means this operation failed.
  202. *
  203. */
  204. rt_inline rt_err_t _ipc_list_resume_all(rt_list_t *list)
  205. {
  206. struct rt_thread *thread;
  207. rt_base_t level;
  208. /* wakeup all suspended threads */
  209. while (!rt_list_isempty(list))
  210. {
  211. /* disable interrupt */
  212. level = rt_hw_interrupt_disable();
  213. /* get next suspended thread */
  214. thread = rt_list_entry(list->next, struct rt_thread, tlist);
  215. /* set error code to RT_ERROR */
  216. thread->error = -RT_ERROR;
  217. /*
  218. * resume thread
  219. * In rt_thread_resume function, it will remove current thread from
  220. * suspended list
  221. */
  222. rt_thread_resume(thread);
  223. /* enable interrupt */
  224. rt_hw_interrupt_enable(level);
  225. }
  226. return RT_EOK;
  227. }
  228. /**@}*/
  229. #ifdef RT_USING_SEMAPHORE
  230. /**
  231. * @addtogroup semaphore
  232. */
  233. /**@{*/
  234. /**
  235. * @brief This function will initialize a static semaphore object.
  236. *
  237. * @note For the static semaphore object, its memory space is allocated by the compiler during compiling,
  238. * and shall placed on the read-write data segment or on the uninitialized data segment.
  239. * By contrast, the rt_sem_create() function will allocate memory space automatically and initialize
  240. * the semaphore.
  241. *
  242. * @see rt_sem_create()
  243. *
  244. * @param sem is a pointer to the semaphore to initialize. It is assumed that storage for the semaphore will be
  245. * allocated in your application.
  246. *
  247. * @param name is a pointer to the name you would like to give the semaphore.
  248. *
  249. * @param value is the initial value for the semaphore.
  250. * If used to share resources, you should initialize the value as the number of available resources.
  251. * If used to signal the occurrence of an event, you should initialize the value as 0.
  252. *
  253. * @param flag is the semaphore flag, which determines the queuing way of how multiple threads wait
  254. * when the semaphore is not available.
  255. * The semaphore flag can be ONE of the following values:
  256. *
  257. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  258. *
  259. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  260. * (also known as first-come-first-served (FCFS) scheduling strategy).
  261. *
  262. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  263. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  264. * the first-in-first-out principle, and you clearly understand that all threads involved in
  265. * this semaphore will become non-real-time threads.
  266. *
  267. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  268. * If the return value is any other values, it represents the initialization failed.
  269. *
  270. * @warning This function can ONLY be called from threads.
  271. */
  272. rt_err_t rt_sem_init(rt_sem_t sem,
  273. const char *name,
  274. rt_uint32_t value,
  275. rt_uint8_t flag)
  276. {
  277. RT_ASSERT(sem != RT_NULL);
  278. RT_ASSERT(value < 0x10000U);
  279. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  280. /* initialize object */
  281. rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name);
  282. /* initialize ipc object */
  283. _ipc_object_init(&(sem->parent));
  284. /* set initial value */
  285. sem->value = (rt_uint16_t)value;
  286. /* set parent */
  287. sem->parent.parent.flag = flag;
  288. return RT_EOK;
  289. }
  290. RTM_EXPORT(rt_sem_init);
  291. /**
  292. * @brief This function will detach a static semaphore object.
  293. *
  294. * @note This function is used to detach a static semaphore object which is initialized by rt_sem_init() function.
  295. * By contrast, the rt_sem_delete() function will delete a semaphore object.
  296. * When the semaphore is successfully detached, it will resume all suspended threads in the semaphore list.
  297. *
  298. * @see rt_sem_delete()
  299. *
  300. * @param sem is a pointer to a semaphore object to be detached.
  301. *
  302. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  303. * If the return value is any other values, it means that the semaphore detach failed.
  304. *
  305. * @warning This function can ONLY detach a static semaphore initialized by the rt_sem_init() function.
  306. * If the semaphore is created by the rt_sem_create() function, you MUST NOT USE this function to detach it,
  307. * ONLY USE the rt_sem_delete() function to complete the deletion.
  308. */
  309. rt_err_t rt_sem_detach(rt_sem_t sem)
  310. {
  311. /* parameter check */
  312. RT_ASSERT(sem != RT_NULL);
  313. RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
  314. RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent));
  315. /* wakeup all suspended threads */
  316. _ipc_list_resume_all(&(sem->parent.suspend_thread));
  317. /* detach semaphore object */
  318. rt_object_detach(&(sem->parent.parent));
  319. return RT_EOK;
  320. }
  321. RTM_EXPORT(rt_sem_detach);
  322. #ifdef RT_USING_HEAP
  323. /**
  324. * @brief Creating a semaphore object.
  325. *
  326. * @note For the semaphore object, its memory space is allocated automatically.
  327. * By contrast, the rt_sem_init() function will initialize a static semaphore object.
  328. *
  329. * @see rt_sem_init()
  330. *
  331. * @param name is a pointer to the name you would like to give the semaphore.
  332. *
  333. * @param value is the initial value for the semaphore.
  334. * If used to share resources, you should initialize the value as the number of available resources.
  335. * If used to signal the occurrence of an event, you should initialize the value as 0.
  336. *
  337. * @param flag is the semaphore flag, which determines the queuing way of how multiple threads wait
  338. * when the semaphore is not available.
  339. * The semaphore flag can be ONE of the following values:
  340. *
  341. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  342. *
  343. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  344. * (also known as first-come-first-served (FCFS) scheduling strategy).
  345. *
  346. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  347. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  348. * the first-in-first-out principle, and you clearly understand that all threads involved in
  349. * this semaphore will become non-real-time threads.
  350. *
  351. * @return Return a pointer to the semaphore object. When the return value is RT_NULL, it means the creation failed.
  352. *
  353. * @warning This function can NOT be called in interrupt context. You can use macor RT_DEBUG_NOT_IN_INTERRUPT to check it.
  354. */
  355. rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
  356. {
  357. rt_sem_t sem;
  358. RT_ASSERT(value < 0x10000U);
  359. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  360. RT_DEBUG_NOT_IN_INTERRUPT;
  361. /* allocate object */
  362. sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
  363. if (sem == RT_NULL)
  364. return sem;
  365. /* initialize ipc object */
  366. _ipc_object_init(&(sem->parent));
  367. /* set initial value */
  368. sem->value = value;
  369. /* set parent */
  370. sem->parent.parent.flag = flag;
  371. return sem;
  372. }
  373. RTM_EXPORT(rt_sem_create);
  374. /**
  375. * @brief This function will delete a semaphore object and release the memory space.
  376. *
  377. * @note This function is used to delete a semaphore object which is created by the rt_sem_create() function.
  378. * By contrast, the rt_sem_detach() function will detach a static semaphore object.
  379. * When the semaphore is successfully deleted, it will resume all suspended threads in the semaphore list.
  380. *
  381. * @see rt_sem_detach()
  382. *
  383. * @param sem is a pointer to a semaphore object to be deleted.
  384. *
  385. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  386. * If the return value is any other values, it means that the semaphore detach failed.
  387. *
  388. * @warning This function can ONLY delete a semaphore initialized by the rt_sem_create() function.
  389. * If the semaphore is initialized by the rt_sem_init() function, you MUST NOT USE this function to delete it,
  390. * ONLY USE the rt_sem_detach() function to complete the detachment.
  391. */
  392. rt_err_t rt_sem_delete(rt_sem_t sem)
  393. {
  394. /* parameter check */
  395. RT_ASSERT(sem != RT_NULL);
  396. RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
  397. RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent) == RT_FALSE);
  398. RT_DEBUG_NOT_IN_INTERRUPT;
  399. /* wakeup all suspended threads */
  400. _ipc_list_resume_all(&(sem->parent.suspend_thread));
  401. /* delete semaphore object */
  402. rt_object_delete(&(sem->parent.parent));
  403. return RT_EOK;
  404. }
  405. RTM_EXPORT(rt_sem_delete);
  406. #endif /* RT_USING_HEAP */
  407. /**
  408. * @brief This function will take a semaphore, if the semaphore is unavailable, the thread shall wait for
  409. * the semaphore up to a specified time.
  410. *
  411. * @note When this function is called, the count value of the sem->value will decrease 1 until it is equal to 0.
  412. * When the sem->value is 0, it means that the semaphore is unavailable. At this time, it will suspend the
  413. * thread preparing to take the semaphore.
  414. * On the contrary, the rt_sem_release() function will increase the count value of sem->value by 1 each time.
  415. *
  416. * @see rt_sem_trytake()
  417. *
  418. * @param sem is a pointer to a semaphore object.
  419. *
  420. * @param timeout is a timeout period (unit: an OS tick). If the semaphore is unavailable, the thread will wait for
  421. * the semaphore up to the amount of time specified by this parameter.
  422. *
  423. * NOTE:
  424. * If use Macro RT_WAITING_FOREVER to set this parameter, which means that when the
  425. * message is unavailable in the queue, the thread will be waiting forever.
  426. * If use macro RT_WAITING_NO to set this parameter, which means that this
  427. * function is non-blocking and will return immediately.
  428. *
  429. * @return Return the operation status. ONLY When the return value is RT_EOK, the operation is successful.
  430. * If the return value is any other values, it means that the semaphore take failed.
  431. *
  432. * @warning This function can ONLY be called in the thread context. It MUST NOT BE called in interrupt context.
  433. */
  434. static rt_err_t _rt_sem_take(rt_sem_t sem, rt_int32_t timeout, int suspend_flag)
  435. {
  436. rt_base_t level;
  437. struct rt_thread *thread;
  438. rt_err_t ret;
  439. /* parameter check */
  440. RT_ASSERT(sem != RT_NULL);
  441. RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
  442. RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));
  443. /* disable interrupt */
  444. level = rt_hw_interrupt_disable();
  445. RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n",
  446. rt_thread_self()->name,
  447. ((struct rt_object *)sem)->name,
  448. sem->value));
  449. if (sem->value > 0)
  450. {
  451. /* semaphore is available */
  452. sem->value --;
  453. /* enable interrupt */
  454. rt_hw_interrupt_enable(level);
  455. }
  456. else
  457. {
  458. /* no waiting, return with timeout */
  459. if (timeout == 0)
  460. {
  461. rt_hw_interrupt_enable(level);
  462. return -RT_ETIMEOUT;
  463. }
  464. else
  465. {
  466. /* current context checking */
  467. RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
  468. /* semaphore is unavailable, push to suspend list */
  469. /* get current thread */
  470. thread = rt_thread_self();
  471. /* reset thread error number */
  472. thread->error = -RT_EINTR;
  473. RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",
  474. thread->name));
  475. /* suspend thread */
  476. ret = _ipc_list_suspend(&(sem->parent.suspend_thread),
  477. thread,
  478. sem->parent.parent.flag,
  479. suspend_flag);
  480. if (ret != RT_EOK)
  481. {
  482. rt_hw_interrupt_enable(level);
  483. return ret;
  484. }
  485. /* has waiting time, start thread timer */
  486. if (timeout > 0)
  487. {
  488. RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
  489. thread->name));
  490. /* reset the timeout of thread timer and start it */
  491. rt_timer_control(&(thread->thread_timer),
  492. RT_TIMER_CTRL_SET_TIME,
  493. &timeout);
  494. rt_timer_start(&(thread->thread_timer));
  495. }
  496. /* enable interrupt */
  497. rt_hw_interrupt_enable(level);
  498. /* do schedule */
  499. rt_schedule();
  500. if (thread->error != RT_EOK)
  501. {
  502. return thread->error;
  503. }
  504. }
  505. }
  506. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));
  507. return RT_EOK;
  508. }
  509. rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
  510. {
  511. return _rt_sem_take(sem, time, RT_UNINTERRUPTIBLE);
  512. }
  513. RTM_EXPORT(rt_sem_take);
  514. rt_err_t rt_sem_take_interruptible(rt_sem_t sem, rt_int32_t time)
  515. {
  516. return _rt_sem_take(sem, time, RT_INTERRUPTIBLE);
  517. }
  518. RTM_EXPORT(rt_sem_take_interruptible);
  519. rt_err_t rt_sem_take_killable(rt_sem_t sem, rt_int32_t time)
  520. {
  521. return _rt_sem_take(sem, time, RT_KILLABLE);
  522. }
  523. RTM_EXPORT(rt_sem_take_killable);
  524. /**
  525. * @brief This function will try to take a semaphore, if the semaphore is unavailable, the thread returns immediately.
  526. *
  527. * @note This function is very similar to the rt_sem_take() function, when the semaphore is not available,
  528. * the rt_sem_trytake() function will return immediately without waiting for a timeout.
  529. * In other words, rt_sem_trytake(sem) has the same effect as rt_sem_take(sem, 0).
  530. *
  531. * @see rt_sem_take()
  532. *
  533. * @param sem is a pointer to a semaphore object.
  534. *
  535. * @return Return the operation status. ONLY When the return value is RT_EOK, the operation is successful.
  536. * If the return value is any other values, it means that the semaphore take failed.
  537. */
  538. rt_err_t rt_sem_trytake(rt_sem_t sem)
  539. {
  540. return rt_sem_take(sem, RT_WAITING_NO);
  541. }
  542. RTM_EXPORT(rt_sem_trytake);
  543. /**
  544. * @brief This function will release a semaphore. If there is thread suspended on the semaphore, it will get resumed.
  545. *
  546. * @note If there are threads suspended on this semaphore, the first thread in the list of this semaphore object
  547. * will be resumed, and a thread scheduling (rt_schedule) will be executed.
  548. * If no threads are suspended on this semaphore, the count value sem->value of this semaphore will increase by 1.
  549. *
  550. * @param sem is a pointer to a semaphore object.
  551. *
  552. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  553. * If the return value is any other values, it means that the semaphore release failed.
  554. */
  555. rt_err_t rt_sem_release(rt_sem_t sem)
  556. {
  557. rt_base_t level;
  558. rt_bool_t need_schedule;
  559. /* parameter check */
  560. RT_ASSERT(sem != RT_NULL);
  561. RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
  562. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));
  563. need_schedule = RT_FALSE;
  564. /* disable interrupt */
  565. level = rt_hw_interrupt_disable();
  566. RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",
  567. rt_thread_self()->name,
  568. ((struct rt_object *)sem)->name,
  569. sem->value));
  570. if (!rt_list_isempty(&sem->parent.suspend_thread))
  571. {
  572. /* resume the suspended thread */
  573. _ipc_list_resume(&(sem->parent.suspend_thread));
  574. need_schedule = RT_TRUE;
  575. }
  576. else
  577. {
  578. if(sem->value < RT_SEM_VALUE_MAX)
  579. {
  580. sem->value ++; /* increase value */
  581. }
  582. else
  583. {
  584. rt_hw_interrupt_enable(level); /* enable interrupt */
  585. return -RT_EFULL; /* value overflowed */
  586. }
  587. }
  588. /* enable interrupt */
  589. rt_hw_interrupt_enable(level);
  590. /* resume a thread, re-schedule */
  591. if (need_schedule == RT_TRUE)
  592. rt_schedule();
  593. return RT_EOK;
  594. }
  595. RTM_EXPORT(rt_sem_release);
  596. /**
  597. * @brief This function will set some extra attributions of a semaphore object.
  598. *
  599. * @note Currently this function only supports the RT_IPC_CMD_RESET command to reset the semaphore.
  600. *
  601. * @param sem is a pointer to a semaphore object.
  602. *
  603. * @param cmd is a command word used to configure some attributions of the semaphore.
  604. *
  605. * @param arg is the argument of the function to execute the command.
  606. *
  607. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  608. * If the return value is any other values, it means that this function failed to execute.
  609. */
  610. rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg)
  611. {
  612. rt_base_t level;
  613. /* parameter check */
  614. RT_ASSERT(sem != RT_NULL);
  615. RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore);
  616. if (cmd == RT_IPC_CMD_RESET)
  617. {
  618. rt_ubase_t value;
  619. /* get value */
  620. value = (rt_ubase_t)arg;
  621. /* disable interrupt */
  622. level = rt_hw_interrupt_disable();
  623. /* resume all waiting thread */
  624. _ipc_list_resume_all(&sem->parent.suspend_thread);
  625. /* set new value */
  626. sem->value = (rt_uint16_t)value;
  627. /* enable interrupt */
  628. rt_hw_interrupt_enable(level);
  629. rt_schedule();
  630. return RT_EOK;
  631. }
  632. return -RT_ERROR;
  633. }
  634. RTM_EXPORT(rt_sem_control);
  635. /**@}*/
  636. #endif /* RT_USING_SEMAPHORE */
  637. #ifdef RT_USING_MUTEX
  638. rt_inline rt_uint8_t _mutex_update_priority(struct rt_mutex *mutex)
  639. {
  640. struct rt_thread *thread;
  641. if (!rt_list_isempty(&mutex->parent.suspend_thread))
  642. {
  643. thread = rt_list_entry(mutex->parent.suspend_thread.next, struct rt_thread, tlist);
  644. mutex->priority = thread->current_priority;
  645. }
  646. else
  647. {
  648. mutex->priority = 0xff;
  649. }
  650. return mutex->priority;
  651. }
  652. rt_inline rt_uint8_t _thread_get_mutex_priority(struct rt_thread* thread)
  653. {
  654. rt_list_t *node = RT_NULL;
  655. struct rt_mutex *mutex = RT_NULL;
  656. rt_uint8_t priority = thread->init_priority;
  657. rt_list_for_each(node, &(thread->taken_object_list))
  658. {
  659. mutex = rt_list_entry(node, struct rt_mutex, taken_list);
  660. if (priority > mutex->priority)
  661. {
  662. priority = mutex->priority;
  663. }
  664. }
  665. return priority;
  666. }
  667. rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t priority, int suspend_flag)
  668. {
  669. rt_err_t ret;
  670. RT_DEBUG_LOG(RT_DEBUG_IPC,
  671. ("thread:%s priority -> %d\n", thread->name, priority));
  672. /* change priority of the thread */
  673. rt_thread_control(thread,
  674. RT_THREAD_CTRL_CHANGE_PRIORITY,
  675. &priority);
  676. if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)
  677. {
  678. /* whether change the priority of taken mutex */
  679. struct rt_object* pending_obj = thread->pending_object;
  680. if (pending_obj && rt_object_get_type(pending_obj) == RT_Object_Class_Mutex)
  681. {
  682. rt_uint8_t mutex_priority;
  683. struct rt_mutex* pending_mutex = (struct rt_mutex *)pending_obj;
  684. /* re-insert thread to suspended thread list */
  685. rt_list_remove(&(thread->tlist));
  686. ret = _ipc_list_suspend(&(pending_mutex->parent.suspend_thread),
  687. thread,
  688. pending_mutex->parent.parent.flag,
  689. suspend_flag);
  690. if (ret != RT_EOK)
  691. {
  692. /* TODO */
  693. return ;
  694. }
  695. /* update priority */
  696. _mutex_update_priority(pending_mutex);
  697. /* change the priority of mutex owner thread */
  698. RT_DEBUG_LOG(RT_DEBUG_IPC,
  699. ("mutex: %s priority -> %d\n", pending_mutex->parent.parent.name,
  700. pending_mutex->priority));
  701. mutex_priority = _thread_get_mutex_priority(pending_mutex->owner);
  702. if (mutex_priority != pending_mutex->owner->current_priority)
  703. {
  704. _thread_update_priority(pending_mutex->owner, mutex_priority, suspend_flag);
  705. }
  706. }
  707. }
  708. }
  709. /**
  710. * @addtogroup mutex
  711. */
  712. /**@{*/
  713. /**
  714. * @brief Initialize a static mutex object.
  715. *
  716. * @note For the static mutex object, its memory space is allocated by the compiler during compiling,
  717. * and shall placed on the read-write data segment or on the uninitialized data segment.
  718. * By contrast, the rt_mutex_create() function will automatically allocate memory space
  719. * and initialize the mutex.
  720. *
  721. * @see rt_mutex_create()
  722. *
  723. * @param mutex is a pointer to the mutex to initialize. It is assumed that storage for the mutex will be
  724. * allocated in your application.
  725. *
  726. * @param name is a pointer to the name that given to the mutex.
  727. *
  728. * @param flag is the mutex flag, which determines the queuing way of how multiple threads wait
  729. * when the mutex is not available.
  730. * NOTE: This parameter has been obsoleted. It can be RT_IPC_FLAG_PRIO, RT_IPC_FLAG_FIFO or RT_NULL.
  731. *
  732. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  733. * If the return value is any other values, it represents the initialization failed.
  734. *
  735. * @warning This function can ONLY be called from threads.
  736. */
  737. rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)
  738. {
  739. /* flag parameter has been obsoleted */
  740. RT_UNUSED(flag);
  741. /* parameter check */
  742. RT_ASSERT(mutex != RT_NULL);
  743. /* initialize object */
  744. rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name);
  745. /* initialize ipc object */
  746. _ipc_object_init(&(mutex->parent));
  747. mutex->owner = RT_NULL;
  748. mutex->priority = 0xFF;
  749. mutex->hold = 0;
  750. mutex->ceiling_priority = 0xFF;
  751. rt_list_init(&(mutex->taken_list));
  752. /* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */
  753. mutex->parent.parent.flag = RT_IPC_FLAG_PRIO;
  754. return RT_EOK;
  755. }
  756. RTM_EXPORT(rt_mutex_init);
  757. /**
  758. * @brief This function will detach a static mutex object.
  759. *
  760. * @note This function is used to detach a static mutex object which is initialized by rt_mutex_init() function.
  761. * By contrast, the rt_mutex_delete() function will delete a mutex object.
  762. * When the mutex is successfully detached, it will resume all suspended threads in the mutex list.
  763. *
  764. * @see rt_mutex_delete()
  765. *
  766. * @param mutex is a pointer to a mutex object to be detached.
  767. *
  768. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  769. * If the return value is any other values, it means that the mutex detach failed.
  770. *
  771. * @warning This function can ONLY detach a static mutex initialized by the rt_mutex_init() function.
  772. * If the mutex is created by the rt_mutex_create() function, you MUST NOT USE this function to detach it,
  773. * ONLY USE the rt_mutex_delete() function to complete the deletion.
  774. */
  775. rt_err_t rt_mutex_detach(rt_mutex_t mutex)
  776. {
  777. rt_ubase_t level;
  778. /* parameter check */
  779. RT_ASSERT(mutex != RT_NULL);
  780. RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
  781. RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent));
  782. level = rt_hw_interrupt_disable();
  783. /* wakeup all suspended threads */
  784. _ipc_list_resume_all(&(mutex->parent.suspend_thread));
  785. /* remove mutex from thread's taken list */
  786. rt_list_remove(&mutex->taken_list);
  787. rt_hw_interrupt_enable(level);
  788. /* detach mutex object */
  789. rt_object_detach(&(mutex->parent.parent));
  790. return RT_EOK;
  791. }
  792. RTM_EXPORT(rt_mutex_detach);
  793. /* drop a thread from the suspend list of mutex */
  794. /**
  795. * @brief drop a thread from the suspend list of mutex
  796. *
  797. * @param mutex is a pointer to a mutex object.
  798. * @param thread is the thread should be dropped from mutex.
  799. */
  800. void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread)
  801. {
  802. rt_uint8_t priority;
  803. rt_bool_t need_update = RT_FALSE;
  804. rt_list_remove(&(thread->tlist));
  805. /* should change the priority of mutex owner thread */
  806. if (mutex->owner->current_priority == thread->current_priority)
  807. need_update = RT_TRUE;
  808. /* update the priority of mutex */
  809. if (!rt_list_isempty(&mutex->parent.suspend_thread))
  810. {
  811. /* more thread suspended in the list */
  812. struct rt_thread *th;
  813. th = rt_list_entry(mutex->parent.suspend_thread.next,
  814. struct rt_thread,
  815. tlist);
  816. /* update the priority of mutex */
  817. mutex->priority = th->current_priority;
  818. }
  819. else
  820. {
  821. /* set mutex priority to maximal priority */
  822. mutex->priority = 0xff;
  823. }
  824. /* try to change the priority of mutex owner thread */
  825. if (need_update)
  826. {
  827. /* get the maximal priority of mutex in thread */
  828. priority = _thread_get_mutex_priority(mutex->owner);
  829. if (priority != mutex->owner->current_priority)
  830. {
  831. _thread_update_priority(mutex->owner, priority, RT_UNINTERRUPTIBLE);
  832. }
  833. }
  834. }
  835. /**
  836. * @brief set the prioceiling attribute of the mutex.
  837. *
  838. * @param mutex is a pointer to a mutex object.
  839. * @param priority is the priority should be set to mutex.
  840. *
  841. * @return return the old priority ceiling
  842. */
  843. rt_uint8_t rt_mutex_setprioceiling(rt_mutex_t mutex, rt_uint8_t priority)
  844. {
  845. rt_uint8_t ret_priority = 0xFF;
  846. if ((mutex) && (priority < RT_THREAD_PRIORITY_MAX))
  847. {
  848. ret_priority = mutex->ceiling_priority;
  849. mutex->ceiling_priority = priority;
  850. }
  851. else
  852. {
  853. rt_set_errno(-RT_EINVAL);
  854. }
  855. return ret_priority;
  856. }
  857. RTM_EXPORT(rt_mutex_setprioceiling);
  858. /**
  859. * @brief set the prioceiling attribute of the mutex.
  860. *
  861. * @param mutex is a pointer to a mutex object.
  862. *
  863. * @return return the current priority ceiling of the mutex.
  864. */
  865. rt_uint8_t rt_mutex_getprioceiling(rt_mutex_t mutex)
  866. {
  867. rt_uint8_t prio = 0xFF;
  868. if (mutex)
  869. {
  870. prio = mutex->ceiling_priority;
  871. }
  872. return prio;
  873. }
  874. RTM_EXPORT(rt_mutex_getprioceiling);
  875. #ifdef RT_USING_HEAP
  876. /**
  877. * @brief This function will create a mutex object.
  878. *
  879. * @note For the mutex object, its memory space is automatically allocated.
  880. * By contrast, the rt_mutex_init() function will initialize a static mutex object.
  881. *
  882. * @see rt_mutex_init()
  883. *
  884. * @param name is a pointer to the name that given to the mutex.
  885. *
  886. * @param flag is the mutex flag, which determines the queuing way of how multiple threads wait
  887. * when the mutex is not available.
  888. * NOTE: This parameter has been obsoleted. It can be RT_IPC_FLAG_PRIO, RT_IPC_FLAG_FIFO or RT_NULL.
  889. *
  890. * @return Return a pointer to the mutex object. When the return value is RT_NULL, it means the creation failed.
  891. *
  892. * @warning This function can ONLY be called from threads.
  893. */
  894. rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
  895. {
  896. struct rt_mutex *mutex;
  897. /* flag parameter has been obsoleted */
  898. RT_UNUSED(flag);
  899. RT_DEBUG_NOT_IN_INTERRUPT;
  900. /* allocate object */
  901. mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
  902. if (mutex == RT_NULL)
  903. return mutex;
  904. /* initialize ipc object */
  905. _ipc_object_init(&(mutex->parent));
  906. mutex->owner = RT_NULL;
  907. mutex->priority = 0xFF;
  908. mutex->hold = 0;
  909. mutex->ceiling_priority = 0xFF;
  910. rt_list_init(&(mutex->taken_list));
  911. /* flag can only be RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO cannot solve the unbounded priority inversion problem */
  912. mutex->parent.parent.flag = RT_IPC_FLAG_PRIO;
  913. return mutex;
  914. }
  915. RTM_EXPORT(rt_mutex_create);
  916. /**
  917. * @brief This function will delete a mutex object and release this memory space.
  918. *
  919. * @note This function is used to delete a mutex object which is created by the rt_mutex_create() function.
  920. * By contrast, the rt_mutex_detach() function will detach a static mutex object.
  921. * When the mutex is successfully deleted, it will resume all suspended threads in the mutex list.
  922. *
  923. * @see rt_mutex_detach()
  924. *
  925. * @param mutex is a pointer to a mutex object to be deleted.
  926. *
  927. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  928. * If the return value is any other values, it means that the mutex detach failed.
  929. *
  930. * @warning This function can ONLY delete a mutex initialized by the rt_mutex_create() function.
  931. * If the mutex is initialized by the rt_mutex_init() function, you MUST NOT USE this function to delete it,
  932. * ONLY USE the rt_mutex_detach() function to complete the detachment.
  933. */
  934. rt_err_t rt_mutex_delete(rt_mutex_t mutex)
  935. {
  936. rt_ubase_t level;
  937. /* parameter check */
  938. RT_ASSERT(mutex != RT_NULL);
  939. RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
  940. RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent) == RT_FALSE);
  941. RT_DEBUG_NOT_IN_INTERRUPT;
  942. level = rt_hw_interrupt_disable();
  943. /* wakeup all suspended threads */
  944. _ipc_list_resume_all(&(mutex->parent.suspend_thread));
  945. /* remove mutex from thread's taken list */
  946. rt_list_remove(&mutex->taken_list);
  947. rt_hw_interrupt_enable(level);
  948. /* delete mutex object */
  949. rt_object_delete(&(mutex->parent.parent));
  950. return RT_EOK;
  951. }
  952. RTM_EXPORT(rt_mutex_delete);
  953. #endif /* RT_USING_HEAP */
  954. /**
  955. * @brief This function will take a mutex, if the mutex is unavailable, the thread shall wait for
  956. * the mutex up to a specified time.
  957. *
  958. * @note When this function is called, the count value of the mutex->value will decrease 1 until it is equal to 0.
  959. * When the mutex->value is 0, it means that the mutex is unavailable. At this time, it will suspend the
  960. * thread preparing to take the mutex.
  961. * On the contrary, the rt_mutex_release() function will increase the count value of mutex->value by 1 each time.
  962. *
  963. * @see rt_mutex_trytake()
  964. *
  965. * @param mutex is a pointer to a mutex object.
  966. *
  967. * @param timeout is a timeout period (unit: an OS tick). If the mutex is unavailable, the thread will wait for
  968. * the mutex up to the amount of time specified by the argument.
  969. * NOTE: Generally, we set this parameter to RT_WAITING_FOREVER, which means that when the mutex is unavailable,
  970. * the thread will be waitting forever.
  971. *
  972. * @return Return the operation status. ONLY When the return value is RT_EOK, the operation is successful.
  973. * If the return value is any other values, it means that the mutex take failed.
  974. *
  975. * @warning This function can ONLY be called in the thread context. It MUST NOT BE called in interrupt context.
  976. */
  977. static rt_err_t _rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout, int suspend_flag)
  978. {
  979. rt_base_t level;
  980. struct rt_thread *thread;
  981. rt_err_t ret;
  982. /* this function must not be used in interrupt even if time = 0 */
  983. /* current context checking */
  984. RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
  985. /* parameter check */
  986. RT_ASSERT(mutex != RT_NULL);
  987. RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
  988. /* get current thread */
  989. thread = rt_thread_self();
  990. /* disable interrupt */
  991. level = rt_hw_interrupt_disable();
  992. RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent)));
  993. RT_DEBUG_LOG(RT_DEBUG_IPC,
  994. ("mutex_take: current thread %s, hold: %d\n",
  995. thread->name, mutex->hold));
  996. /* reset thread error */
  997. thread->error = RT_EOK;
  998. if (mutex->owner == thread)
  999. {
  1000. if(mutex->hold < RT_MUTEX_HOLD_MAX)
  1001. {
  1002. /* it's the same thread */
  1003. mutex->hold ++;
  1004. }
  1005. else
  1006. {
  1007. rt_hw_interrupt_enable(level); /* enable interrupt */
  1008. return -RT_EFULL; /* value overflowed */
  1009. }
  1010. }
  1011. else
  1012. {
  1013. /* whether the mutex has owner thread. */
  1014. if (mutex->owner == RT_NULL)
  1015. {
  1016. /* set mutex owner and original priority */
  1017. mutex->owner = thread;
  1018. mutex->priority = 0xff;
  1019. mutex->hold = 1;
  1020. if (mutex->ceiling_priority != 0xFF)
  1021. {
  1022. /* set the priority of thread to the ceiling priority */
  1023. if (mutex->ceiling_priority < mutex->owner->current_priority)
  1024. _thread_update_priority(mutex->owner, mutex->ceiling_priority, suspend_flag);
  1025. }
  1026. else
  1027. {
  1028. /* insert mutex to thread's taken object list */
  1029. rt_list_insert_after(&thread->taken_object_list, &mutex->taken_list);
  1030. }
  1031. }
  1032. else
  1033. {
  1034. /* no waiting, return with timeout */
  1035. if (timeout == 0)
  1036. {
  1037. /* set error as timeout */
  1038. thread->error = -RT_ETIMEOUT;
  1039. /* enable interrupt */
  1040. rt_hw_interrupt_enable(level);
  1041. return -RT_ETIMEOUT;
  1042. }
  1043. else
  1044. {
  1045. rt_uint8_t priority = thread->current_priority;
  1046. /* mutex is unavailable, push to suspend list */
  1047. RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
  1048. thread->name));
  1049. /* suspend current thread */
  1050. ret = _ipc_list_suspend(&(mutex->parent.suspend_thread),
  1051. thread,
  1052. mutex->parent.parent.flag,
  1053. suspend_flag);
  1054. if (ret != RT_EOK)
  1055. {
  1056. rt_hw_interrupt_enable(level);
  1057. return ret;
  1058. }
  1059. /* set pending object in thread to this mutex */
  1060. thread->pending_object = &(mutex->parent.parent);
  1061. /* update the priority level of mutex */
  1062. if (priority < mutex->priority)
  1063. {
  1064. mutex->priority = priority;
  1065. if (mutex->priority < mutex->owner->current_priority)
  1066. {
  1067. _thread_update_priority(mutex->owner, priority, RT_UNINTERRUPTIBLE); /* TODO */
  1068. }
  1069. }
  1070. /* has waiting time, start thread timer */
  1071. if (timeout > 0)
  1072. {
  1073. RT_DEBUG_LOG(RT_DEBUG_IPC,
  1074. ("mutex_take: start the timer of thread:%s\n",
  1075. thread->name));
  1076. /* reset the timeout of thread timer and start it */
  1077. rt_timer_control(&(thread->thread_timer),
  1078. RT_TIMER_CTRL_SET_TIME,
  1079. &timeout);
  1080. rt_timer_start(&(thread->thread_timer));
  1081. }
  1082. /* enable interrupt */
  1083. rt_hw_interrupt_enable(level);
  1084. /* do schedule */
  1085. rt_schedule();
  1086. /* disable interrupt */
  1087. level = rt_hw_interrupt_disable();
  1088. if (thread->error == RT_EOK)
  1089. {
  1090. /* get mutex successfully */
  1091. }
  1092. else
  1093. {
  1094. /* the mutex has not been taken and thread has detach from the pending list. */
  1095. rt_bool_t need_update = RT_FALSE;
  1096. /* should change the priority of mutex owner thread */
  1097. if (mutex->owner->current_priority == thread->current_priority)
  1098. need_update = RT_TRUE;
  1099. /* update the priority of mutex */
  1100. if (!rt_list_isempty(&mutex->parent.suspend_thread))
  1101. {
  1102. /* more thread suspended in the list */
  1103. struct rt_thread *th;
  1104. th = rt_list_entry(mutex->parent.suspend_thread.next,
  1105. struct rt_thread,
  1106. tlist);
  1107. /* update the priority of mutex */
  1108. mutex->priority = th->current_priority;
  1109. }
  1110. else
  1111. {
  1112. /* set mutex priority to maximal priority */
  1113. mutex->priority = 0xff;
  1114. }
  1115. /* try to change the priority of mutex owner thread */
  1116. if (need_update)
  1117. {
  1118. /* get the maximal priority of mutex in thread */
  1119. priority = _thread_get_mutex_priority(mutex->owner);
  1120. if (priority != mutex->owner->current_priority)
  1121. {
  1122. _thread_update_priority(mutex->owner, priority, RT_UNINTERRUPTIBLE);
  1123. }
  1124. }
  1125. /* enable interrupt */
  1126. rt_hw_interrupt_enable(level);
  1127. /* return error */
  1128. return thread->error;
  1129. }
  1130. }
  1131. }
  1132. }
  1133. /* enable interrupt */
  1134. rt_hw_interrupt_enable(level);
  1135. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mutex->parent.parent)));
  1136. return RT_EOK;
  1137. }
  1138. rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
  1139. {
  1140. return _rt_mutex_take(mutex, time, RT_UNINTERRUPTIBLE);
  1141. }
  1142. RTM_EXPORT(rt_mutex_take);
  1143. rt_err_t rt_mutex_take_interruptible(rt_mutex_t mutex, rt_int32_t time)
  1144. {
  1145. return _rt_mutex_take(mutex, time, RT_INTERRUPTIBLE);
  1146. }
  1147. RTM_EXPORT(rt_mutex_take_interruptible);
  1148. rt_err_t rt_mutex_take_killable(rt_mutex_t mutex, rt_int32_t time)
  1149. {
  1150. return _rt_mutex_take(mutex, time, RT_KILLABLE);
  1151. }
  1152. RTM_EXPORT(rt_mutex_take_killable);
  1153. /**
  1154. * @brief This function will try to take a mutex, if the mutex is unavailable, the thread returns immediately.
  1155. *
  1156. * @note This function is very similar to the rt_mutex_take() function, when the mutex is not available,
  1157. * except that rt_mutex_trytake() will return immediately without waiting for a timeout
  1158. * when the mutex is not available.
  1159. * In other words, rt_mutex_trytake(mutex) has the same effect as rt_mutex_take(mutex, 0).
  1160. *
  1161. * @see rt_mutex_take()
  1162. *
  1163. * @param mutex is a pointer to a mutex object.
  1164. *
  1165. * @return Return the operation status. ONLY When the return value is RT_EOK, the operation is successful.
  1166. * If the return value is any other values, it means that the mutex take failed.
  1167. */
  1168. rt_err_t rt_mutex_trytake(rt_mutex_t mutex)
  1169. {
  1170. return rt_mutex_take(mutex, RT_WAITING_NO);
  1171. }
  1172. RTM_EXPORT(rt_mutex_trytake);
  1173. /**
  1174. * @brief This function will release a mutex. If there is thread suspended on the mutex, the thread will be resumed.
  1175. *
  1176. * @note If there are threads suspended on this mutex, the first thread in the list of this mutex object
  1177. * will be resumed, and a thread scheduling (rt_schedule) will be executed.
  1178. * If no threads are suspended on this mutex, the count value mutex->value of this mutex will increase by 1.
  1179. *
  1180. * @param mutex is a pointer to a mutex object.
  1181. *
  1182. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1183. * If the return value is any other values, it means that the mutex release failed.
  1184. */
  1185. rt_err_t rt_mutex_release(rt_mutex_t mutex)
  1186. {
  1187. rt_base_t level;
  1188. struct rt_thread *thread;
  1189. rt_bool_t need_schedule;
  1190. /* parameter check */
  1191. RT_ASSERT(mutex != RT_NULL);
  1192. RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
  1193. need_schedule = RT_FALSE;
  1194. /* only thread could release mutex because we need test the ownership */
  1195. RT_DEBUG_IN_THREAD_CONTEXT;
  1196. /* get current thread */
  1197. thread = rt_thread_self();
  1198. /* disable interrupt */
  1199. level = rt_hw_interrupt_disable();
  1200. RT_DEBUG_LOG(RT_DEBUG_IPC,
  1201. ("mutex_release:current thread %s, hold: %d\n",
  1202. thread->name, mutex->hold));
  1203. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));
  1204. /* mutex only can be released by owner */
  1205. if (thread != mutex->owner)
  1206. {
  1207. thread->error = -RT_ERROR;
  1208. /* enable interrupt */
  1209. rt_hw_interrupt_enable(level);
  1210. return -RT_ERROR;
  1211. }
  1212. /* decrease hold */
  1213. mutex->hold --;
  1214. /* if no hold */
  1215. if (mutex->hold == 0)
  1216. {
  1217. /* remove mutex from thread's taken list */
  1218. rt_list_remove(&mutex->taken_list);
  1219. /* whether change the thread priority */
  1220. if ((mutex->ceiling_priority != 0xFF) || (thread->current_priority == mutex->priority))
  1221. {
  1222. rt_uint8_t priority = 0xff;
  1223. /* get the highest priority in the taken list of thread */
  1224. priority = _thread_get_mutex_priority(thread);
  1225. rt_thread_control(thread,
  1226. RT_THREAD_CTRL_CHANGE_PRIORITY,
  1227. &priority);
  1228. need_schedule = RT_TRUE;
  1229. }
  1230. /* wakeup suspended thread */
  1231. if (!rt_list_isempty(&mutex->parent.suspend_thread))
  1232. {
  1233. /* get the first suspended thread */
  1234. struct rt_thread *next_thread = rt_list_entry(mutex->parent.suspend_thread.next,
  1235. struct rt_thread,
  1236. tlist);
  1237. RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n",
  1238. next_thread->name));
  1239. /* remove the thread from the suspended list of mutex */
  1240. rt_list_remove(&(next_thread->tlist));
  1241. /* set new owner and put mutex into taken list of thread */
  1242. mutex->owner = next_thread;
  1243. mutex->hold = 1;
  1244. rt_list_insert_after(&next_thread->taken_object_list, &mutex->taken_list);
  1245. /* cleanup pending object */
  1246. next_thread->pending_object = RT_NULL;
  1247. /* resume thread */
  1248. rt_thread_resume(next_thread);
  1249. /* update mutex priority */
  1250. if (!rt_list_isempty(&(mutex->parent.suspend_thread)))
  1251. {
  1252. struct rt_thread *th;
  1253. th = rt_list_entry(mutex->parent.suspend_thread.next,
  1254. struct rt_thread,
  1255. tlist);
  1256. mutex->priority = th->current_priority;
  1257. }
  1258. else
  1259. {
  1260. mutex->priority = 0xff;
  1261. }
  1262. need_schedule = RT_TRUE;
  1263. }
  1264. else
  1265. {
  1266. /* clear owner */
  1267. mutex->owner = RT_NULL;
  1268. mutex->priority = 0xff;
  1269. }
  1270. }
  1271. /* enable interrupt */
  1272. rt_hw_interrupt_enable(level);
  1273. /* perform a schedule */
  1274. if (need_schedule == RT_TRUE)
  1275. rt_schedule();
  1276. return RT_EOK;
  1277. }
  1278. RTM_EXPORT(rt_mutex_release);
  1279. /**
  1280. * @brief This function will set some extra attributions of a mutex object.
  1281. *
  1282. * @note Currently this function does not implement the control function.
  1283. *
  1284. * @param mutex is a pointer to a mutex object.
  1285. *
  1286. * @param cmd is a command word used to configure some attributions of the mutex.
  1287. *
  1288. * @param arg is the argument of the function to execute the command.
  1289. *
  1290. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1291. * If the return value is any other values, it means that this function failed to execute.
  1292. */
  1293. rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg)
  1294. {
  1295. /* parameter check */
  1296. RT_ASSERT(mutex != RT_NULL);
  1297. RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
  1298. return -RT_ERROR;
  1299. }
  1300. RTM_EXPORT(rt_mutex_control);
  1301. /**@}*/
  1302. #endif /* RT_USING_MUTEX */
  1303. #ifdef RT_USING_EVENT
  1304. /**
  1305. * @addtogroup event
  1306. */
  1307. /**@{*/
  1308. /**
  1309. * @brief The function will initialize a static event object.
  1310. *
  1311. * @note For the static event object, its memory space is allocated by the compiler during compiling,
  1312. * and shall placed on the read-write data segment or on the uninitialized data segment.
  1313. * By contrast, the rt_event_create() function will allocate memory space automatically
  1314. * and initialize the event.
  1315. *
  1316. * @see rt_event_create()
  1317. *
  1318. * @param event is a pointer to the event to initialize. It is assumed that storage for the event
  1319. * will be allocated in your application.
  1320. *
  1321. * @param name is a pointer to the name that given to the event.
  1322. *
  1323. * @param flag is the event flag, which determines the queuing way of how multiple threads wait
  1324. * when the event is not available.
  1325. * The event flag can be ONE of the following values:
  1326. *
  1327. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  1328. *
  1329. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  1330. * (also known as first-come-first-served (FCFS) scheduling strategy).
  1331. *
  1332. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  1333. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  1334. * the first-in-first-out principle, and you clearly understand that all threads involved in
  1335. * this event will become non-real-time threads.
  1336. *
  1337. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  1338. * If the return value is any other values, it represents the initialization failed.
  1339. *
  1340. * @warning This function can ONLY be called from threads.
  1341. */
  1342. rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag)
  1343. {
  1344. /* parameter check */
  1345. RT_ASSERT(event != RT_NULL);
  1346. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  1347. /* initialize object */
  1348. rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name);
  1349. /* set parent flag */
  1350. event->parent.parent.flag = flag;
  1351. /* initialize ipc object */
  1352. _ipc_object_init(&(event->parent));
  1353. /* initialize event */
  1354. event->set = 0;
  1355. return RT_EOK;
  1356. }
  1357. RTM_EXPORT(rt_event_init);
  1358. /**
  1359. * @brief This function will detach a static event object.
  1360. *
  1361. * @note This function is used to detach a static event object which is initialized by rt_event_init() function.
  1362. * By contrast, the rt_event_delete() function will delete an event object.
  1363. * When the event is successfully detached, it will resume all suspended threads in the event list.
  1364. *
  1365. * @see rt_event_delete()
  1366. *
  1367. * @param event is a pointer to an event object to be detached.
  1368. *
  1369. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  1370. * If the return value is any other values, it means that the event detach failed.
  1371. *
  1372. * @warning This function can ONLY detach a static event initialized by the rt_event_init() function.
  1373. * If the event is created by the rt_event_create() function, you MUST NOT USE this function to detach it,
  1374. * ONLY USE the rt_event_delete() function to complete the deletion.
  1375. */
  1376. rt_err_t rt_event_detach(rt_event_t event)
  1377. {
  1378. /* parameter check */
  1379. RT_ASSERT(event != RT_NULL);
  1380. RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
  1381. RT_ASSERT(rt_object_is_systemobject(&event->parent.parent));
  1382. /* resume all suspended thread */
  1383. _ipc_list_resume_all(&(event->parent.suspend_thread));
  1384. /* detach event object */
  1385. rt_object_detach(&(event->parent.parent));
  1386. return RT_EOK;
  1387. }
  1388. RTM_EXPORT(rt_event_detach);
  1389. #ifdef RT_USING_HEAP
  1390. /**
  1391. * @brief Creating an event object.
  1392. *
  1393. * @note For the event object, its memory space is allocated automatically.
  1394. * By contrast, the rt_event_init() function will initialize a static event object.
  1395. *
  1396. * @see rt_event_init()
  1397. *
  1398. * @param name is a pointer to the name that given to the event.
  1399. *
  1400. * @param flag is the event flag, which determines the queuing way of how multiple threads wait when the event
  1401. * is not available.
  1402. * The event flag can be ONE of the following values:
  1403. *
  1404. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  1405. *
  1406. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  1407. * (also known as first-come-first-served (FCFS) scheduling strategy).
  1408. *
  1409. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  1410. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  1411. * the first-in-first-out principle, and you clearly understand that all threads involved in
  1412. * this event will become non-real-time threads.
  1413. *
  1414. * @return Return a pointer to the event object. When the return value is RT_NULL, it means the creation failed.
  1415. *
  1416. * @warning This function can ONLY be called from threads.
  1417. */
  1418. rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
  1419. {
  1420. rt_event_t event;
  1421. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  1422. RT_DEBUG_NOT_IN_INTERRUPT;
  1423. /* allocate object */
  1424. event = (rt_event_t)rt_object_allocate(RT_Object_Class_Event, name);
  1425. if (event == RT_NULL)
  1426. return event;
  1427. /* set parent */
  1428. event->parent.parent.flag = flag;
  1429. /* initialize ipc object */
  1430. _ipc_object_init(&(event->parent));
  1431. /* initialize event */
  1432. event->set = 0;
  1433. return event;
  1434. }
  1435. RTM_EXPORT(rt_event_create);
  1436. /**
  1437. * @brief This function will delete an event object and release the memory space.
  1438. *
  1439. * @note This function is used to delete an event object which is created by the rt_event_create() function.
  1440. * By contrast, the rt_event_detach() function will detach a static event object.
  1441. * When the event is successfully deleted, it will resume all suspended threads in the event list.
  1442. *
  1443. * @see rt_event_detach()
  1444. *
  1445. * @param event is a pointer to an event object to be deleted.
  1446. *
  1447. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1448. * If the return value is any other values, it means that the event detach failed.
  1449. *
  1450. * @warning This function can ONLY delete an event initialized by the rt_event_create() function.
  1451. * If the event is initialized by the rt_event_init() function, you MUST NOT USE this function to delete it,
  1452. * ONLY USE the rt_event_detach() function to complete the detachment.
  1453. */
  1454. rt_err_t rt_event_delete(rt_event_t event)
  1455. {
  1456. /* parameter check */
  1457. RT_ASSERT(event != RT_NULL);
  1458. RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
  1459. RT_ASSERT(rt_object_is_systemobject(&event->parent.parent) == RT_FALSE);
  1460. RT_DEBUG_NOT_IN_INTERRUPT;
  1461. /* resume all suspended thread */
  1462. _ipc_list_resume_all(&(event->parent.suspend_thread));
  1463. /* delete event object */
  1464. rt_object_delete(&(event->parent.parent));
  1465. return RT_EOK;
  1466. }
  1467. RTM_EXPORT(rt_event_delete);
  1468. #endif /* RT_USING_HEAP */
  1469. /**
  1470. * @brief This function will send an event to the event object.
  1471. * If there is a thread suspended on the event, the thread will be resumed.
  1472. *
  1473. * @note When using this function, you need to use the parameter (set) to specify the event flag of the event object,
  1474. * then the function will traverse the list of suspended threads waiting on the event object.
  1475. * If there is a thread suspended on the event, and the thread's event_info and the event flag of
  1476. * the current event object matches, the thread will be resumed.
  1477. *
  1478. * @param event is a pointer to the event object to be sent.
  1479. *
  1480. * @param set is a flag that you will set for this event's flag.
  1481. * You can set an event flag, or you can set multiple flags through OR logic operation.
  1482. *
  1483. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1484. * If the return value is any other values, it means that the event detach failed.
  1485. */
  1486. rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
  1487. {
  1488. struct rt_list_node *n;
  1489. struct rt_thread *thread;
  1490. rt_base_t level;
  1491. rt_base_t status;
  1492. rt_bool_t need_schedule;
  1493. /* parameter check */
  1494. RT_ASSERT(event != RT_NULL);
  1495. RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
  1496. if (set == 0)
  1497. return -RT_ERROR;
  1498. need_schedule = RT_FALSE;
  1499. /* disable interrupt */
  1500. level = rt_hw_interrupt_disable();
  1501. /* set event */
  1502. event->set |= set;
  1503. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(event->parent.parent)));
  1504. if (!rt_list_isempty(&event->parent.suspend_thread))
  1505. {
  1506. /* search thread list to resume thread */
  1507. n = event->parent.suspend_thread.next;
  1508. while (n != &(event->parent.suspend_thread))
  1509. {
  1510. /* get thread */
  1511. thread = rt_list_entry(n, struct rt_thread, tlist);
  1512. status = -RT_ERROR;
  1513. if (thread->event_info & RT_EVENT_FLAG_AND)
  1514. {
  1515. if ((thread->event_set & event->set) == thread->event_set)
  1516. {
  1517. /* received an AND event */
  1518. status = RT_EOK;
  1519. }
  1520. }
  1521. else if (thread->event_info & RT_EVENT_FLAG_OR)
  1522. {
  1523. if (thread->event_set & event->set)
  1524. {
  1525. /* save the received event set */
  1526. thread->event_set = thread->event_set & event->set;
  1527. /* received an OR event */
  1528. status = RT_EOK;
  1529. }
  1530. }
  1531. else
  1532. {
  1533. /* enable interrupt */
  1534. rt_hw_interrupt_enable(level);
  1535. return -RT_EINVAL;
  1536. }
  1537. /* move node to the next */
  1538. n = n->next;
  1539. /* condition is satisfied, resume thread */
  1540. if (status == RT_EOK)
  1541. {
  1542. /* clear event */
  1543. if (thread->event_info & RT_EVENT_FLAG_CLEAR)
  1544. event->set &= ~thread->event_set;
  1545. /* resume thread, and thread list breaks out */
  1546. rt_thread_resume(thread);
  1547. thread->error = RT_EOK;
  1548. /* need do a scheduling */
  1549. need_schedule = RT_TRUE;
  1550. }
  1551. }
  1552. }
  1553. /* enable interrupt */
  1554. rt_hw_interrupt_enable(level);
  1555. /* do a schedule */
  1556. if (need_schedule == RT_TRUE)
  1557. rt_schedule();
  1558. return RT_EOK;
  1559. }
  1560. RTM_EXPORT(rt_event_send);
  1561. /**
  1562. * @brief This function will receive an event from event object. if the event is unavailable, the thread shall wait for
  1563. * the event up to a specified time.
  1564. *
  1565. * @note If there are threads suspended on this semaphore, the first thread in the list of this semaphore object
  1566. * will be resumed, and a thread scheduling (rt_schedule) will be executed.
  1567. * If no threads are suspended on this semaphore, the count value sem->value of this semaphore will increase by 1.
  1568. *
  1569. * @param event is a pointer to the event object to be received.
  1570. *
  1571. * @param set is a flag that you will set for this event's flag.
  1572. * You can set an event flag, or you can set multiple flags through OR logic operation.
  1573. *
  1574. * @param option is the option of this receiving event, it indicates how the receiving event is operated.
  1575. * The option can be one or more of the following values, When selecting multiple values,use logical OR to operate.
  1576. * (NOTE: RT_EVENT_FLAG_OR and RT_EVENT_FLAG_AND can only select one):
  1577. *
  1578. *
  1579. * RT_EVENT_FLAG_OR The thread select to use logical OR to receive the event.
  1580. *
  1581. * RT_EVENT_FLAG_AND The thread select to use logical OR to receive the event.
  1582. *
  1583. * RT_EVENT_FLAG_CLEAR When the thread receives the corresponding event, the function
  1584. * determines whether to clear the event flag.
  1585. *
  1586. * @param timeout is a timeout period (unit: an OS tick).
  1587. *
  1588. * @param recved is a pointer to the received event. If you don't care about this value, you can use RT_NULL to set.
  1589. *
  1590. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1591. * If the return value is any other values, it means that the semaphore release failed.
  1592. */
  1593. static rt_err_t _rt_event_recv(rt_event_t event,
  1594. rt_uint32_t set,
  1595. rt_uint8_t option,
  1596. rt_int32_t timeout,
  1597. rt_uint32_t *recved,
  1598. int suspend_flag)
  1599. {
  1600. struct rt_thread *thread;
  1601. rt_base_t level;
  1602. rt_base_t status;
  1603. rt_err_t ret;
  1604. /* parameter check */
  1605. RT_ASSERT(event != RT_NULL);
  1606. RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
  1607. /* current context checking */
  1608. RT_DEBUG_SCHEDULER_AVAILABLE(RT_TRUE);
  1609. if (set == 0)
  1610. return -RT_ERROR;
  1611. /* initialize status */
  1612. status = -RT_ERROR;
  1613. /* get current thread */
  1614. thread = rt_thread_self();
  1615. /* reset thread error */
  1616. thread->error = -RT_EINTR;
  1617. RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(event->parent.parent)));
  1618. /* disable interrupt */
  1619. level = rt_hw_interrupt_disable();
  1620. /* check event set */
  1621. if (option & RT_EVENT_FLAG_AND)
  1622. {
  1623. if ((event->set & set) == set)
  1624. status = RT_EOK;
  1625. }
  1626. else if (option & RT_EVENT_FLAG_OR)
  1627. {
  1628. if (event->set & set)
  1629. status = RT_EOK;
  1630. }
  1631. else
  1632. {
  1633. /* either RT_EVENT_FLAG_AND or RT_EVENT_FLAG_OR should be set */
  1634. RT_ASSERT(0);
  1635. }
  1636. if (status == RT_EOK)
  1637. {
  1638. thread->error = RT_EOK;
  1639. /* set received event */
  1640. if (recved)
  1641. *recved = (event->set & set);
  1642. /* fill thread event info */
  1643. thread->event_set = (event->set & set);
  1644. thread->event_info = option;
  1645. /* received event */
  1646. if (option & RT_EVENT_FLAG_CLEAR)
  1647. event->set &= ~set;
  1648. }
  1649. else if (timeout == 0)
  1650. {
  1651. /* no waiting */
  1652. thread->error = -RT_ETIMEOUT;
  1653. /* enable interrupt */
  1654. rt_hw_interrupt_enable(level);
  1655. return -RT_ETIMEOUT;
  1656. }
  1657. else
  1658. {
  1659. /* fill thread event info */
  1660. thread->event_set = set;
  1661. thread->event_info = option;
  1662. /* put thread to suspended thread list */
  1663. ret = _ipc_list_suspend(&(event->parent.suspend_thread),
  1664. thread,
  1665. event->parent.parent.flag,
  1666. suspend_flag);
  1667. if (ret != RT_EOK)
  1668. {
  1669. rt_hw_interrupt_enable(level);
  1670. return ret;
  1671. }
  1672. /* if there is a waiting timeout, active thread timer */
  1673. if (timeout > 0)
  1674. {
  1675. /* reset the timeout of thread timer and start it */
  1676. rt_timer_control(&(thread->thread_timer),
  1677. RT_TIMER_CTRL_SET_TIME,
  1678. &timeout);
  1679. rt_timer_start(&(thread->thread_timer));
  1680. }
  1681. /* enable interrupt */
  1682. rt_hw_interrupt_enable(level);
  1683. /* do a schedule */
  1684. rt_schedule();
  1685. if (thread->error != RT_EOK)
  1686. {
  1687. /* return error */
  1688. return thread->error;
  1689. }
  1690. /* received an event, disable interrupt to protect */
  1691. level = rt_hw_interrupt_disable();
  1692. /* set received event */
  1693. if (recved)
  1694. *recved = thread->event_set;
  1695. }
  1696. /* enable interrupt */
  1697. rt_hw_interrupt_enable(level);
  1698. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(event->parent.parent)));
  1699. return thread->error;
  1700. }
  1701. rt_err_t rt_event_recv(rt_event_t event,
  1702. rt_uint32_t set,
  1703. rt_uint8_t option,
  1704. rt_int32_t timeout,
  1705. rt_uint32_t *recved)
  1706. {
  1707. return _rt_event_recv(event, set, option, timeout, recved, RT_UNINTERRUPTIBLE);
  1708. }
  1709. RTM_EXPORT(rt_event_recv);
  1710. rt_err_t rt_event_recv_interruptible(rt_event_t event,
  1711. rt_uint32_t set,
  1712. rt_uint8_t option,
  1713. rt_int32_t timeout,
  1714. rt_uint32_t *recved)
  1715. {
  1716. return _rt_event_recv(event, set, option, timeout, recved, RT_INTERRUPTIBLE);
  1717. }
  1718. RTM_EXPORT(rt_event_recv_interruptible);
  1719. rt_err_t rt_event_recv_killable(rt_event_t event,
  1720. rt_uint32_t set,
  1721. rt_uint8_t option,
  1722. rt_int32_t timeout,
  1723. rt_uint32_t *recved)
  1724. {
  1725. return _rt_event_recv(event, set, option, timeout, recved, RT_KILLABLE);
  1726. }
  1727. RTM_EXPORT(rt_event_recv_killable);
  1728. /**
  1729. * @brief This function will set some extra attributions of an event object.
  1730. *
  1731. * @note Currently this function only supports the RT_IPC_CMD_RESET command to reset the event.
  1732. *
  1733. * @param event is a pointer to an event object.
  1734. *
  1735. * @param cmd is a command word used to configure some attributions of the event.
  1736. *
  1737. * @param arg is the argument of the function to execute the command.
  1738. *
  1739. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1740. * If the return value is any other values, it means that this function failed to execute.
  1741. */
  1742. rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg)
  1743. {
  1744. rt_base_t level;
  1745. /* parameter check */
  1746. RT_ASSERT(event != RT_NULL);
  1747. RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event);
  1748. if (cmd == RT_IPC_CMD_RESET)
  1749. {
  1750. /* disable interrupt */
  1751. level = rt_hw_interrupt_disable();
  1752. /* resume all waiting thread */
  1753. _ipc_list_resume_all(&event->parent.suspend_thread);
  1754. /* initialize event set */
  1755. event->set = 0;
  1756. /* enable interrupt */
  1757. rt_hw_interrupt_enable(level);
  1758. rt_schedule();
  1759. return RT_EOK;
  1760. }
  1761. return -RT_ERROR;
  1762. }
  1763. RTM_EXPORT(rt_event_control);
  1764. /**@}*/
  1765. #endif /* RT_USING_EVENT */
  1766. #ifdef RT_USING_MAILBOX
  1767. /**
  1768. * @addtogroup mailbox
  1769. */
  1770. /**@{*/
  1771. /**
  1772. * @brief Initialize a static mailbox object.
  1773. *
  1774. * @note For the static mailbox object, its memory space is allocated by the compiler during compiling,
  1775. * and shall placed on the read-write data segment or on the uninitialized data segment.
  1776. * By contrast, the rt_mb_create() function will allocate memory space automatically and initialize the mailbox.
  1777. *
  1778. * @see rt_mb_create()
  1779. *
  1780. * @param mb is a pointer to the mailbox to initialize.
  1781. * It is assumed that storage for the mailbox will be allocated in your application.
  1782. *
  1783. * @param name is a pointer to the name that given to the mailbox.
  1784. *
  1785. * @param size is the maximum number of mails in the mailbox.
  1786. * For example, when the mailbox buffer capacity is N, size is N/4.
  1787. *
  1788. * @param flag is the mailbox flag, which determines the queuing way of how multiple threads wait
  1789. * when the mailbox is not available.
  1790. * The mailbox flag can be ONE of the following values:
  1791. *
  1792. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  1793. *
  1794. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  1795. * (also known as first-come-first-served (FCFS) scheduling strategy).
  1796. *
  1797. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  1798. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  1799. * the first-in-first-out principle, and you clearly understand that all threads involved in
  1800. * this mailbox will become non-real-time threads.
  1801. *
  1802. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  1803. * If the return value is any other values, it represents the initialization failed.
  1804. *
  1805. * @warning This function can ONLY be called from threads.
  1806. */
  1807. rt_err_t rt_mb_init(rt_mailbox_t mb,
  1808. const char *name,
  1809. void *msgpool,
  1810. rt_size_t size,
  1811. rt_uint8_t flag)
  1812. {
  1813. RT_ASSERT(mb != RT_NULL);
  1814. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  1815. /* initialize object */
  1816. rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name);
  1817. /* set parent flag */
  1818. mb->parent.parent.flag = flag;
  1819. /* initialize ipc object */
  1820. _ipc_object_init(&(mb->parent));
  1821. /* initialize mailbox */
  1822. mb->msg_pool = (rt_ubase_t *)msgpool;
  1823. mb->size = (rt_uint16_t)size;
  1824. mb->entry = 0;
  1825. mb->in_offset = 0;
  1826. mb->out_offset = 0;
  1827. /* initialize an additional list of sender suspend thread */
  1828. rt_list_init(&(mb->suspend_sender_thread));
  1829. return RT_EOK;
  1830. }
  1831. RTM_EXPORT(rt_mb_init);
  1832. /**
  1833. * @brief This function will detach a static mailbox object.
  1834. *
  1835. * @note This function is used to detach a static mailbox object which is initialized by rt_mb_init() function.
  1836. * By contrast, the rt_mb_delete() function will delete a mailbox object.
  1837. * When the mailbox is successfully detached, it will resume all suspended threads in the mailbox list.
  1838. *
  1839. * @see rt_mb_delete()
  1840. *
  1841. * @param mb is a pointer to a mailbox object to be detached.
  1842. *
  1843. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  1844. * If the return value is any other values, it means that the mailbox detach failed.
  1845. *
  1846. * @warning This function can ONLY detach a static mailbox initialized by the rt_mb_init() function.
  1847. * If the mailbox is created by the rt_mb_create() function, you MUST NOT USE this function to detach it,
  1848. * ONLY USE the rt_mb_delete() function to complete the deletion.
  1849. */
  1850. rt_err_t rt_mb_detach(rt_mailbox_t mb)
  1851. {
  1852. /* parameter check */
  1853. RT_ASSERT(mb != RT_NULL);
  1854. RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
  1855. RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent));
  1856. /* resume all suspended thread */
  1857. _ipc_list_resume_all(&(mb->parent.suspend_thread));
  1858. /* also resume all mailbox private suspended thread */
  1859. _ipc_list_resume_all(&(mb->suspend_sender_thread));
  1860. /* detach mailbox object */
  1861. rt_object_detach(&(mb->parent.parent));
  1862. return RT_EOK;
  1863. }
  1864. RTM_EXPORT(rt_mb_detach);
  1865. #ifdef RT_USING_HEAP
  1866. /**
  1867. * @brief Creating a mailbox object.
  1868. *
  1869. * @note For the mailbox object, its memory space is allocated automatically.
  1870. * By contrast, the rt_mb_init() function will initialize a static mailbox object.
  1871. *
  1872. * @see rt_mb_init()
  1873. *
  1874. * @param name is a pointer that given to the mailbox.
  1875. *
  1876. * @param size is the maximum number of mails in the mailbox.
  1877. * For example, when mailbox buffer capacity is N, size is N/4.
  1878. *
  1879. * @param flag is the mailbox flag, which determines the queuing way of how multiple threads wait
  1880. * when the mailbox is not available.
  1881. * The mailbox flag can be ONE of the following values:
  1882. *
  1883. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  1884. *
  1885. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  1886. * (also known as first-come-first-served (FCFS) scheduling strategy).
  1887. *
  1888. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  1889. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  1890. * the first-in-first-out principle, and you clearly understand that all threads involved in
  1891. * this mailbox will become non-real-time threads.
  1892. *
  1893. * @return Return a pointer to the mailbox object. When the return value is RT_NULL, it means the creation failed.
  1894. *
  1895. * @warning This function can ONLY be called from threads.
  1896. */
  1897. rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
  1898. {
  1899. rt_mailbox_t mb;
  1900. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  1901. RT_DEBUG_NOT_IN_INTERRUPT;
  1902. /* allocate object */
  1903. mb = (rt_mailbox_t)rt_object_allocate(RT_Object_Class_MailBox, name);
  1904. if (mb == RT_NULL)
  1905. return mb;
  1906. /* set parent */
  1907. mb->parent.parent.flag = flag;
  1908. /* initialize ipc object */
  1909. _ipc_object_init(&(mb->parent));
  1910. /* initialize mailbox */
  1911. mb->size = (rt_uint16_t)size;
  1912. mb->msg_pool = (rt_ubase_t *)RT_KERNEL_MALLOC(mb->size * sizeof(rt_ubase_t));
  1913. if (mb->msg_pool == RT_NULL)
  1914. {
  1915. /* delete mailbox object */
  1916. rt_object_delete(&(mb->parent.parent));
  1917. return RT_NULL;
  1918. }
  1919. mb->entry = 0;
  1920. mb->in_offset = 0;
  1921. mb->out_offset = 0;
  1922. /* initialize an additional list of sender suspend thread */
  1923. rt_list_init(&(mb->suspend_sender_thread));
  1924. return mb;
  1925. }
  1926. RTM_EXPORT(rt_mb_create);
  1927. /**
  1928. * @brief This function will delete a mailbox object and release the memory space.
  1929. *
  1930. * @note This function is used to delete a mailbox object which is created by the rt_mb_create() function.
  1931. * By contrast, the rt_mb_detach() function will detach a static mailbox object.
  1932. * When the mailbox is successfully deleted, it will resume all suspended threads in the mailbox list.
  1933. *
  1934. * @see rt_mb_detach()
  1935. *
  1936. * @param mb is a pointer to a mailbox object to be deleted.
  1937. *
  1938. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1939. * If the return value is any other values, it means that the mailbox detach failed.
  1940. *
  1941. * @warning This function can only delete mailbox created by the rt_mb_create() function.
  1942. * If the mailbox is initialized by the rt_mb_init() function, you MUST NOT USE this function to delete it,
  1943. * ONLY USE the rt_mb_detach() function to complete the detachment.
  1944. */
  1945. rt_err_t rt_mb_delete(rt_mailbox_t mb)
  1946. {
  1947. /* parameter check */
  1948. RT_ASSERT(mb != RT_NULL);
  1949. RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
  1950. RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent) == RT_FALSE);
  1951. RT_DEBUG_NOT_IN_INTERRUPT;
  1952. /* resume all suspended thread */
  1953. _ipc_list_resume_all(&(mb->parent.suspend_thread));
  1954. /* also resume all mailbox private suspended thread */
  1955. _ipc_list_resume_all(&(mb->suspend_sender_thread));
  1956. /* free mailbox pool */
  1957. RT_KERNEL_FREE(mb->msg_pool);
  1958. /* delete mailbox object */
  1959. rt_object_delete(&(mb->parent.parent));
  1960. return RT_EOK;
  1961. }
  1962. RTM_EXPORT(rt_mb_delete);
  1963. #endif /* RT_USING_HEAP */
  1964. /**
  1965. * @brief This function will send an mail to the mailbox object. If there is a thread suspended on the mailbox,
  1966. * the thread will be resumed.
  1967. *
  1968. * @note When using this function to send a mail, if the mailbox if fully used, the current thread will
  1969. * wait for a timeout. If the set timeout time is reached and there is still no space available,
  1970. * the sending thread will be resumed and an error code will be returned.
  1971. * By contrast, the rt_mb_send() function will return an error code immediately without waiting time
  1972. * when the mailbox if fully used.
  1973. *
  1974. * @see rt_mb_send()
  1975. *
  1976. * @param mb is a pointer to the mailbox object to be sent.
  1977. *
  1978. * @param value is a value to the content of the mail you want to send.
  1979. *
  1980. * @param timeout is a timeout period (unit: an OS tick).
  1981. *
  1982. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  1983. * If the return value is any other values, it means that the mailbox detach failed.
  1984. *
  1985. * @warning This function can be called in interrupt context and thread context.
  1986. */
  1987. static rt_err_t _rt_mb_send_wait(rt_mailbox_t mb,
  1988. rt_ubase_t value,
  1989. rt_int32_t timeout,
  1990. int suspend_flag)
  1991. {
  1992. struct rt_thread *thread;
  1993. rt_base_t level;
  1994. rt_uint32_t tick_delta;
  1995. rt_err_t ret;
  1996. /* parameter check */
  1997. RT_ASSERT(mb != RT_NULL);
  1998. RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
  1999. /* current context checking */
  2000. RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
  2001. /* initialize delta tick */
  2002. tick_delta = 0;
  2003. /* get current thread */
  2004. thread = rt_thread_self();
  2005. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));
  2006. /* disable interrupt */
  2007. level = rt_hw_interrupt_disable();
  2008. /* for non-blocking call */
  2009. if (mb->entry == mb->size && timeout == 0)
  2010. {
  2011. rt_hw_interrupt_enable(level);
  2012. return -RT_EFULL;
  2013. }
  2014. /* mailbox is full */
  2015. while (mb->entry == mb->size)
  2016. {
  2017. /* reset error number in thread */
  2018. thread->error = -RT_EINTR;
  2019. /* no waiting, return timeout */
  2020. if (timeout == 0)
  2021. {
  2022. /* enable interrupt */
  2023. rt_hw_interrupt_enable(level);
  2024. return -RT_EFULL;
  2025. }
  2026. /* suspend current thread */
  2027. ret = _ipc_list_suspend(&(mb->suspend_sender_thread),
  2028. thread,
  2029. mb->parent.parent.flag,
  2030. suspend_flag);
  2031. if (ret != RT_EOK)
  2032. {
  2033. rt_hw_interrupt_enable(level);
  2034. return ret;
  2035. }
  2036. /* has waiting time, start thread timer */
  2037. if (timeout > 0)
  2038. {
  2039. /* get the start tick of timer */
  2040. tick_delta = rt_tick_get();
  2041. RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_send_wait: start timer of thread:%s\n",
  2042. thread->name));
  2043. /* reset the timeout of thread timer and start it */
  2044. rt_timer_control(&(thread->thread_timer),
  2045. RT_TIMER_CTRL_SET_TIME,
  2046. &timeout);
  2047. rt_timer_start(&(thread->thread_timer));
  2048. }
  2049. /* enable interrupt */
  2050. rt_hw_interrupt_enable(level);
  2051. /* re-schedule */
  2052. rt_schedule();
  2053. /* resume from suspend state */
  2054. if (thread->error != RT_EOK)
  2055. {
  2056. /* return error */
  2057. return thread->error;
  2058. }
  2059. /* disable interrupt */
  2060. level = rt_hw_interrupt_disable();
  2061. /* if it's not waiting forever and then re-calculate timeout tick */
  2062. if (timeout > 0)
  2063. {
  2064. tick_delta = rt_tick_get() - tick_delta;
  2065. timeout -= tick_delta;
  2066. if (timeout < 0)
  2067. timeout = 0;
  2068. }
  2069. }
  2070. /* set ptr */
  2071. mb->msg_pool[mb->in_offset] = value;
  2072. /* increase input offset */
  2073. ++ mb->in_offset;
  2074. if (mb->in_offset >= mb->size)
  2075. mb->in_offset = 0;
  2076. if(mb->entry < RT_MB_ENTRY_MAX)
  2077. {
  2078. /* increase message entry */
  2079. mb->entry ++;
  2080. }
  2081. else
  2082. {
  2083. rt_hw_interrupt_enable(level); /* enable interrupt */
  2084. return -RT_EFULL; /* value overflowed */
  2085. }
  2086. /* resume suspended thread */
  2087. if (!rt_list_isempty(&mb->parent.suspend_thread))
  2088. {
  2089. _ipc_list_resume(&(mb->parent.suspend_thread));
  2090. /* enable interrupt */
  2091. rt_hw_interrupt_enable(level);
  2092. rt_schedule();
  2093. return RT_EOK;
  2094. }
  2095. /* enable interrupt */
  2096. rt_hw_interrupt_enable(level);
  2097. return RT_EOK;
  2098. }
  2099. rt_err_t rt_mb_send_wait(rt_mailbox_t mb,
  2100. rt_ubase_t value,
  2101. rt_int32_t timeout)
  2102. {
  2103. return _rt_mb_send_wait(mb, value, timeout, RT_UNINTERRUPTIBLE);
  2104. }
  2105. RTM_EXPORT(rt_mb_send_wait);
  2106. rt_err_t rt_mb_send_wait_interruptible(rt_mailbox_t mb,
  2107. rt_ubase_t value,
  2108. rt_int32_t timeout)
  2109. {
  2110. return _rt_mb_send_wait(mb, value, timeout, RT_INTERRUPTIBLE);
  2111. }
  2112. RTM_EXPORT(rt_mb_send_wait_interruptible);
  2113. rt_err_t rt_mb_send_wait_killable(rt_mailbox_t mb,
  2114. rt_ubase_t value,
  2115. rt_int32_t timeout)
  2116. {
  2117. return _rt_mb_send_wait(mb, value, timeout, RT_KILLABLE);
  2118. }
  2119. RTM_EXPORT(rt_mb_send_wait_killable);
  2120. /**
  2121. * @brief This function will send an mail to the mailbox object. If there is a thread suspended on the mailbox,
  2122. * the thread will be resumed.
  2123. *
  2124. * @note When using this function to send a mail, if the mailbox is fully used, this function will return an error
  2125. * code immediately without waiting time.
  2126. * By contrast, the rt_mb_send_wait() function is set a timeout to wait for the mail to be sent.
  2127. *
  2128. * @see rt_mb_send_wait()
  2129. *
  2130. * @param mb is a pointer to the mailbox object to be sent.
  2131. *
  2132. * @param value is a value to the content of the mail you want to send.
  2133. *
  2134. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2135. * If the return value is any other values, it means that the mailbox detach failed.
  2136. */
  2137. rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value)
  2138. {
  2139. return rt_mb_send_wait(mb, value, 0);
  2140. }
  2141. RTM_EXPORT(rt_mb_send);
  2142. rt_err_t rt_mb_send_interruptible(rt_mailbox_t mb, rt_ubase_t value)
  2143. {
  2144. return rt_mb_send_wait_interruptible(mb, value, 0);
  2145. }
  2146. RTM_EXPORT(rt_mb_send_interruptible);
  2147. rt_err_t rt_mb_send_killable(rt_mailbox_t mb, rt_ubase_t value)
  2148. {
  2149. return rt_mb_send_wait_killable(mb, value, 0);
  2150. }
  2151. RTM_EXPORT(rt_mb_send_killable);
  2152. /**
  2153. * @brief This function will send an urgent mail to the mailbox object.
  2154. *
  2155. * @note This function is almost the same as the rt_mb_send() function. The only difference is that
  2156. * when sending an urgent mail, the mail will be placed at the head of the mail queue so that
  2157. * the recipient can receive the urgent mail first.
  2158. *
  2159. * @see rt_mb_send()
  2160. *
  2161. * @param mb is a pointer to the mailbox object to be sent.
  2162. *
  2163. * @param value is the content of the mail you want to send.
  2164. *
  2165. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2166. * If the return value is any other values, it means that the mailbox detach failed.
  2167. */
  2168. rt_err_t rt_mb_urgent(rt_mailbox_t mb, rt_ubase_t value)
  2169. {
  2170. rt_base_t level;
  2171. /* parameter check */
  2172. RT_ASSERT(mb != RT_NULL);
  2173. RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
  2174. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));
  2175. /* disable interrupt */
  2176. level = rt_hw_interrupt_disable();
  2177. if (mb->entry == mb->size)
  2178. {
  2179. rt_hw_interrupt_enable(level);
  2180. return -RT_EFULL;
  2181. }
  2182. /* rewind to the previous position */
  2183. if (mb->out_offset > 0)
  2184. {
  2185. mb->out_offset --;
  2186. }
  2187. else
  2188. {
  2189. mb->out_offset = mb->size - 1;
  2190. }
  2191. /* set ptr */
  2192. mb->msg_pool[mb->out_offset] = value;
  2193. /* increase message entry */
  2194. mb->entry ++;
  2195. /* resume suspended thread */
  2196. if (!rt_list_isempty(&mb->parent.suspend_thread))
  2197. {
  2198. _ipc_list_resume(&(mb->parent.suspend_thread));
  2199. /* enable interrupt */
  2200. rt_hw_interrupt_enable(level);
  2201. rt_schedule();
  2202. return RT_EOK;
  2203. }
  2204. /* enable interrupt */
  2205. rt_hw_interrupt_enable(level);
  2206. return RT_EOK;
  2207. }
  2208. RTM_EXPORT(rt_mb_urgent);
  2209. /**
  2210. * @brief This function will receive a mail from mailbox object, if there is no mail in mailbox object,
  2211. * the thread shall wait for a specified time.
  2212. *
  2213. * @note Only when there is mail in the mailbox, the receiving thread can get the mail immediately and
  2214. * return RT_EOK, otherwise the receiving thread will be suspended until the set timeout. If the mail
  2215. * is still not received within the specified time, it will return-RT_ETIMEOUT.
  2216. *
  2217. * @param mb is a pointer to the mailbox object to be received.
  2218. *
  2219. * @param value is a flag that you will set for this mailbox's flag.
  2220. * You can set an mailbox flag, or you can set multiple flags through OR logic operations.
  2221. *
  2222. * @param timeout is a timeout period (unit: an OS tick). If the mailbox object is not avaliable in the queue,
  2223. * the thread will wait for the object in the queue up to the amount of time specified by this parameter.
  2224. *
  2225. * NOTE:
  2226. * If use Macro RT_WAITING_FOREVER to set this parameter, which means that when the
  2227. * mailbox object is unavailable in the queue, the thread will be waiting forever.
  2228. * If use macro RT_WAITING_NO to set this parameter, which means that this
  2229. * function is non-blocking and will return immediately.
  2230. *
  2231. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2232. * If the return value is any other values, it means that the mailbox release failed.
  2233. */
  2234. static rt_err_t _rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout, int suspend_flag)
  2235. {
  2236. struct rt_thread *thread;
  2237. rt_base_t level;
  2238. rt_uint32_t tick_delta;
  2239. rt_err_t ret;
  2240. /* parameter check */
  2241. RT_ASSERT(mb != RT_NULL);
  2242. RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
  2243. /* current context checking */
  2244. RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
  2245. /* initialize delta tick */
  2246. tick_delta = 0;
  2247. /* get current thread */
  2248. thread = rt_thread_self();
  2249. RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mb->parent.parent)));
  2250. /* disable interrupt */
  2251. level = rt_hw_interrupt_disable();
  2252. /* for non-blocking call */
  2253. if (mb->entry == 0 && timeout == 0)
  2254. {
  2255. rt_hw_interrupt_enable(level);
  2256. return -RT_ETIMEOUT;
  2257. }
  2258. /* mailbox is empty */
  2259. while (mb->entry == 0)
  2260. {
  2261. /* reset error number in thread */
  2262. thread->error = -RT_EINTR;
  2263. /* no waiting, return timeout */
  2264. if (timeout == 0)
  2265. {
  2266. /* enable interrupt */
  2267. rt_hw_interrupt_enable(level);
  2268. thread->error = -RT_ETIMEOUT;
  2269. return -RT_ETIMEOUT;
  2270. }
  2271. /* suspend current thread */
  2272. ret = _ipc_list_suspend(&(mb->parent.suspend_thread),
  2273. thread,
  2274. mb->parent.parent.flag,
  2275. suspend_flag);
  2276. if (ret != RT_EOK)
  2277. {
  2278. rt_hw_interrupt_enable(level);
  2279. return ret;
  2280. }
  2281. /* has waiting time, start thread timer */
  2282. if (timeout > 0)
  2283. {
  2284. /* get the start tick of timer */
  2285. tick_delta = rt_tick_get();
  2286. RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_recv: start timer of thread:%s\n",
  2287. thread->name));
  2288. /* reset the timeout of thread timer and start it */
  2289. rt_timer_control(&(thread->thread_timer),
  2290. RT_TIMER_CTRL_SET_TIME,
  2291. &timeout);
  2292. rt_timer_start(&(thread->thread_timer));
  2293. }
  2294. /* enable interrupt */
  2295. rt_hw_interrupt_enable(level);
  2296. /* re-schedule */
  2297. rt_schedule();
  2298. /* resume from suspend state */
  2299. if (thread->error != RT_EOK)
  2300. {
  2301. /* return error */
  2302. return thread->error;
  2303. }
  2304. /* disable interrupt */
  2305. level = rt_hw_interrupt_disable();
  2306. /* if it's not waiting forever and then re-calculate timeout tick */
  2307. if (timeout > 0)
  2308. {
  2309. tick_delta = rt_tick_get() - tick_delta;
  2310. timeout -= tick_delta;
  2311. if (timeout < 0)
  2312. timeout = 0;
  2313. }
  2314. }
  2315. /* fill ptr */
  2316. *value = mb->msg_pool[mb->out_offset];
  2317. /* increase output offset */
  2318. ++ mb->out_offset;
  2319. if (mb->out_offset >= mb->size)
  2320. mb->out_offset = 0;
  2321. /* decrease message entry */
  2322. if(mb->entry > 0)
  2323. {
  2324. mb->entry --;
  2325. }
  2326. /* resume suspended thread */
  2327. if (!rt_list_isempty(&(mb->suspend_sender_thread)))
  2328. {
  2329. _ipc_list_resume(&(mb->suspend_sender_thread));
  2330. /* enable interrupt */
  2331. rt_hw_interrupt_enable(level);
  2332. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent)));
  2333. rt_schedule();
  2334. return RT_EOK;
  2335. }
  2336. /* enable interrupt */
  2337. rt_hw_interrupt_enable(level);
  2338. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent)));
  2339. return RT_EOK;
  2340. }
  2341. rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
  2342. {
  2343. return _rt_mb_recv(mb, value, timeout, RT_UNINTERRUPTIBLE);
  2344. }
  2345. RTM_EXPORT(rt_mb_recv);
  2346. rt_err_t rt_mb_recv_interruptibale(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
  2347. {
  2348. return _rt_mb_recv(mb, value, timeout, RT_INTERRUPTIBLE);
  2349. }
  2350. RTM_EXPORT(rt_mb_recv_interruptibale);
  2351. rt_err_t rt_mb_recv_killable(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout)
  2352. {
  2353. return _rt_mb_recv(mb, value, timeout, RT_KILLABLE);
  2354. }
  2355. RTM_EXPORT(rt_mb_recv_killable);
  2356. /**
  2357. * @brief This function will set some extra attributions of a mailbox object.
  2358. *
  2359. * @note Currently this function only supports the RT_IPC_CMD_RESET command to reset the mailbox.
  2360. *
  2361. * @param mb is a pointer to a mailbox object.
  2362. *
  2363. * @param cmd is a command used to configure some attributions of the mailbox.
  2364. *
  2365. * @param arg is the argument of the function to execute the command.
  2366. *
  2367. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2368. * If the return value is any other values, it means that this function failed to execute.
  2369. */
  2370. rt_err_t rt_mb_control(rt_mailbox_t mb, int cmd, void *arg)
  2371. {
  2372. rt_base_t level;
  2373. /* parameter check */
  2374. RT_ASSERT(mb != RT_NULL);
  2375. RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox);
  2376. if (cmd == RT_IPC_CMD_RESET)
  2377. {
  2378. /* disable interrupt */
  2379. level = rt_hw_interrupt_disable();
  2380. /* resume all waiting thread */
  2381. _ipc_list_resume_all(&(mb->parent.suspend_thread));
  2382. /* also resume all mailbox private suspended thread */
  2383. _ipc_list_resume_all(&(mb->suspend_sender_thread));
  2384. /* re-init mailbox */
  2385. mb->entry = 0;
  2386. mb->in_offset = 0;
  2387. mb->out_offset = 0;
  2388. /* enable interrupt */
  2389. rt_hw_interrupt_enable(level);
  2390. rt_schedule();
  2391. return RT_EOK;
  2392. }
  2393. return -RT_ERROR;
  2394. }
  2395. RTM_EXPORT(rt_mb_control);
  2396. /**@}*/
  2397. #endif /* RT_USING_MAILBOX */
  2398. #ifdef RT_USING_MESSAGEQUEUE
  2399. /**
  2400. * @addtogroup messagequeue
  2401. */
  2402. /**@{*/
  2403. struct rt_mq_message
  2404. {
  2405. struct rt_mq_message *next;
  2406. };
  2407. /**
  2408. * @brief Initialize a static messagequeue object.
  2409. *
  2410. * @note For the static messagequeue object, its memory space is allocated by the compiler during compiling,
  2411. * and shall placed on the read-write data segment or on the uninitialized data segment.
  2412. * By contrast, the rt_mq_create() function will allocate memory space automatically
  2413. * and initialize the messagequeue.
  2414. *
  2415. * @see rt_mq_create()
  2416. *
  2417. * @param mq is a pointer to the messagequeue to initialize. It is assumed that storage for
  2418. * the messagequeue will be allocated in your application.
  2419. *
  2420. * @param name is a pointer to the name that given to the messagequeue.
  2421. *
  2422. * @param msgpool is a pointer to the starting address of the memory space you allocated for
  2423. * the messagequeue in advance.
  2424. * In other words, msgpool is a pointer to the messagequeue buffer of the starting address.
  2425. *
  2426. * @param msg_size is the maximum length of a message in the messagequeue (Unit: Byte).
  2427. *
  2428. * @param pool_size is the size of the memory space allocated for the messagequeue in advance.
  2429. *
  2430. * @param flag is the messagequeue flag, which determines the queuing way of how multiple threads wait
  2431. * when the messagequeue is not available.
  2432. * The messagequeue flag can be ONE of the following values:
  2433. *
  2434. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  2435. *
  2436. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  2437. * (also known as first-come-first-served (FCFS) scheduling strategy).
  2438. *
  2439. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  2440. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  2441. * the first-in-first-out principle, and you clearly understand that all threads involved in
  2442. * this messagequeue will become non-real-time threads.
  2443. *
  2444. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  2445. * If the return value is any other values, it represents the initialization failed.
  2446. *
  2447. * @warning This function can ONLY be called from threads.
  2448. */
  2449. rt_err_t rt_mq_init(rt_mq_t mq,
  2450. const char *name,
  2451. void *msgpool,
  2452. rt_size_t msg_size,
  2453. rt_size_t pool_size,
  2454. rt_uint8_t flag)
  2455. {
  2456. struct rt_mq_message *head;
  2457. rt_base_t temp;
  2458. register rt_size_t msg_align_size;
  2459. /* parameter check */
  2460. RT_ASSERT(mq != RT_NULL);
  2461. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  2462. /* initialize object */
  2463. rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name);
  2464. /* set parent flag */
  2465. mq->parent.parent.flag = flag;
  2466. /* initialize ipc object */
  2467. _ipc_object_init(&(mq->parent));
  2468. /* set message pool */
  2469. mq->msg_pool = msgpool;
  2470. /* get correct message size */
  2471. msg_align_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
  2472. mq->msg_size = msg_size;
  2473. mq->max_msgs = pool_size / (msg_align_size + sizeof(struct rt_mq_message));
  2474. if (0 == mq->max_msgs)
  2475. {
  2476. return -RT_EINVAL;
  2477. }
  2478. /* initialize message list */
  2479. mq->msg_queue_head = RT_NULL;
  2480. mq->msg_queue_tail = RT_NULL;
  2481. /* initialize message empty list */
  2482. mq->msg_queue_free = RT_NULL;
  2483. for (temp = 0; temp < mq->max_msgs; temp ++)
  2484. {
  2485. head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
  2486. temp * (msg_align_size + sizeof(struct rt_mq_message)));
  2487. head->next = (struct rt_mq_message *)mq->msg_queue_free;
  2488. mq->msg_queue_free = head;
  2489. }
  2490. /* the initial entry is zero */
  2491. mq->entry = 0;
  2492. /* initialize an additional list of sender suspend thread */
  2493. rt_list_init(&(mq->suspend_sender_thread));
  2494. return RT_EOK;
  2495. }
  2496. RTM_EXPORT(rt_mq_init);
  2497. /**
  2498. * @brief This function will detach a static messagequeue object.
  2499. *
  2500. * @note This function is used to detach a static messagequeue object which is initialized by rt_mq_init() function.
  2501. * By contrast, the rt_mq_delete() function will delete a messagequeue object.
  2502. * When the messagequeue is successfully detached, it will resume all suspended threads in the messagequeue list.
  2503. *
  2504. * @see rt_mq_delete()
  2505. *
  2506. * @param mq is a pointer to a messagequeue object to be detached.
  2507. *
  2508. * @return Return the operation status. When the return value is RT_EOK, the initialization is successful.
  2509. * If the return value is any other values, it means that the messagequeue detach failed.
  2510. *
  2511. * @warning This function can ONLY detach a static messagequeue initialized by the rt_mq_init() function.
  2512. * If the messagequeue is created by the rt_mq_create() function, you MUST NOT USE this function to detach it,
  2513. * and ONLY USE the rt_mq_delete() function to complete the deletion.
  2514. */
  2515. rt_err_t rt_mq_detach(rt_mq_t mq)
  2516. {
  2517. /* parameter check */
  2518. RT_ASSERT(mq != RT_NULL);
  2519. RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
  2520. RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent));
  2521. /* resume all suspended thread */
  2522. _ipc_list_resume_all(&mq->parent.suspend_thread);
  2523. /* also resume all message queue private suspended thread */
  2524. _ipc_list_resume_all(&(mq->suspend_sender_thread));
  2525. /* detach message queue object */
  2526. rt_object_detach(&(mq->parent.parent));
  2527. return RT_EOK;
  2528. }
  2529. RTM_EXPORT(rt_mq_detach);
  2530. #ifdef RT_USING_HEAP
  2531. /**
  2532. * @brief Creating a messagequeue object.
  2533. *
  2534. * @note For the messagequeue object, its memory space is allocated automatically.
  2535. * By contrast, the rt_mq_init() function will initialize a static messagequeue object.
  2536. *
  2537. * @see rt_mq_init()
  2538. *
  2539. * @param name is a pointer that given to the messagequeue.
  2540. *
  2541. * @param msg_size is the maximum length of a message in the messagequeue (Unit: Byte).
  2542. *
  2543. * @param max_msgs is the maximum number of messages in the messagequeue.
  2544. *
  2545. * @param flag is the messagequeue flag, which determines the queuing way of how multiple threads wait
  2546. * when the messagequeue is not available.
  2547. * The messagequeue flag can be ONE of the following values:
  2548. *
  2549. * RT_IPC_FLAG_PRIO The pending threads will queue in order of priority.
  2550. *
  2551. * RT_IPC_FLAG_FIFO The pending threads will queue in the first-in-first-out method
  2552. * (also known as first-come-first-served (FCFS) scheduling strategy).
  2553. *
  2554. * NOTE: RT_IPC_FLAG_FIFO is a non-real-time scheduling mode. It is strongly recommended to
  2555. * use RT_IPC_FLAG_PRIO to ensure the thread is real-time UNLESS your applications concern about
  2556. * the first-in-first-out principle, and you clearly understand that all threads involved in
  2557. * this messagequeue will become non-real-time threads.
  2558. *
  2559. * @return Return a pointer to the messagequeue object. When the return value is RT_NULL, it means the creation failed.
  2560. *
  2561. * @warning This function can NOT be called in interrupt context. You can use macor RT_DEBUG_NOT_IN_INTERRUPT to check it.
  2562. */
  2563. rt_mq_t rt_mq_create(const char *name,
  2564. rt_size_t msg_size,
  2565. rt_size_t max_msgs,
  2566. rt_uint8_t flag)
  2567. {
  2568. struct rt_messagequeue *mq;
  2569. struct rt_mq_message *head;
  2570. rt_base_t temp;
  2571. register rt_size_t msg_align_size;
  2572. RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO));
  2573. RT_DEBUG_NOT_IN_INTERRUPT;
  2574. /* allocate object */
  2575. mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name);
  2576. if (mq == RT_NULL)
  2577. return mq;
  2578. /* set parent */
  2579. mq->parent.parent.flag = flag;
  2580. /* initialize ipc object */
  2581. _ipc_object_init(&(mq->parent));
  2582. /* initialize message queue */
  2583. /* get correct message size */
  2584. msg_align_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE);
  2585. mq->msg_size = msg_size;
  2586. mq->max_msgs = max_msgs;
  2587. /* allocate message pool */
  2588. mq->msg_pool = RT_KERNEL_MALLOC((msg_align_size + sizeof(struct rt_mq_message)) * mq->max_msgs);
  2589. if (mq->msg_pool == RT_NULL)
  2590. {
  2591. rt_object_delete(&(mq->parent.parent));
  2592. return RT_NULL;
  2593. }
  2594. /* initialize message list */
  2595. mq->msg_queue_head = RT_NULL;
  2596. mq->msg_queue_tail = RT_NULL;
  2597. /* initialize message empty list */
  2598. mq->msg_queue_free = RT_NULL;
  2599. for (temp = 0; temp < mq->max_msgs; temp ++)
  2600. {
  2601. head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
  2602. temp * (msg_align_size + sizeof(struct rt_mq_message)));
  2603. head->next = (struct rt_mq_message *)mq->msg_queue_free;
  2604. mq->msg_queue_free = head;
  2605. }
  2606. /* the initial entry is zero */
  2607. mq->entry = 0;
  2608. /* initialize an additional list of sender suspend thread */
  2609. rt_list_init(&(mq->suspend_sender_thread));
  2610. return mq;
  2611. }
  2612. RTM_EXPORT(rt_mq_create);
  2613. /**
  2614. * @brief This function will delete a messagequeue object and release the memory.
  2615. *
  2616. * @note This function is used to delete a messagequeue object which is created by the rt_mq_create() function.
  2617. * By contrast, the rt_mq_detach() function will detach a static messagequeue object.
  2618. * When the messagequeue is successfully deleted, it will resume all suspended threads in the messagequeue list.
  2619. *
  2620. * @see rt_mq_detach()
  2621. *
  2622. * @param mq is a pointer to a messagequeue object to be deleted.
  2623. *
  2624. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2625. * If the return value is any other values, it means that the messagequeue detach failed.
  2626. *
  2627. * @warning This function can ONLY delete a messagequeue initialized by the rt_mq_create() function.
  2628. * If the messagequeue is initialized by the rt_mq_init() function, you MUST NOT USE this function to delete it,
  2629. * ONLY USE the rt_mq_detach() function to complete the detachment.
  2630. * for example,the rt_mq_create() function, it cannot be called in interrupt context.
  2631. */
  2632. rt_err_t rt_mq_delete(rt_mq_t mq)
  2633. {
  2634. /* parameter check */
  2635. RT_ASSERT(mq != RT_NULL);
  2636. RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
  2637. RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent) == RT_FALSE);
  2638. RT_DEBUG_NOT_IN_INTERRUPT;
  2639. /* resume all suspended thread */
  2640. _ipc_list_resume_all(&(mq->parent.suspend_thread));
  2641. /* also resume all message queue private suspended thread */
  2642. _ipc_list_resume_all(&(mq->suspend_sender_thread));
  2643. /* free message queue pool */
  2644. RT_KERNEL_FREE(mq->msg_pool);
  2645. /* delete message queue object */
  2646. rt_object_delete(&(mq->parent.parent));
  2647. return RT_EOK;
  2648. }
  2649. RTM_EXPORT(rt_mq_delete);
  2650. #endif /* RT_USING_HEAP */
  2651. /**
  2652. * @brief This function will send a message to the messagequeue object. If
  2653. * there is a thread suspended on the messagequeue, the thread will be
  2654. * resumed.
  2655. *
  2656. * @note When using this function to send a message, if the messagequeue is
  2657. * fully used, the current thread will wait for a timeout. If reaching
  2658. * the timeout and there is still no space available, the sending
  2659. * thread will be resumed and an error code will be returned. By
  2660. * contrast, the rt_mq_send() function will return an error code
  2661. * immediately without waiting when the messagequeue if fully used.
  2662. *
  2663. * @see rt_mq_send()
  2664. *
  2665. * @param mq is a pointer to the messagequeue object to be sent.
  2666. *
  2667. * @param buffer is the content of the message.
  2668. *
  2669. * @param size is the length of the message(Unit: Byte).
  2670. *
  2671. * @param timeout is a timeout period (unit: an OS tick).
  2672. *
  2673. * @return Return the operation status. When the return value is RT_EOK, the
  2674. * operation is successful. If the return value is any other values,
  2675. * it means that the messagequeue detach failed.
  2676. *
  2677. * @warning This function can be called in interrupt context and thread
  2678. * context.
  2679. */
  2680. static rt_err_t _rt_mq_send_wait(rt_mq_t mq,
  2681. const void *buffer,
  2682. rt_size_t size,
  2683. rt_int32_t timeout,
  2684. int suspend_flag)
  2685. {
  2686. rt_base_t level;
  2687. struct rt_mq_message *msg;
  2688. rt_uint32_t tick_delta;
  2689. struct rt_thread *thread;
  2690. rt_err_t ret;
  2691. /* parameter check */
  2692. RT_ASSERT(mq != RT_NULL);
  2693. RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
  2694. RT_ASSERT(buffer != RT_NULL);
  2695. RT_ASSERT(size != 0);
  2696. /* current context checking */
  2697. RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
  2698. /* greater than one message size */
  2699. if (size > mq->msg_size)
  2700. return -RT_ERROR;
  2701. /* initialize delta tick */
  2702. tick_delta = 0;
  2703. /* get current thread */
  2704. thread = rt_thread_self();
  2705. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent)));
  2706. /* disable interrupt */
  2707. level = rt_hw_interrupt_disable();
  2708. /* get a free list, there must be an empty item */
  2709. msg = (struct rt_mq_message *)mq->msg_queue_free;
  2710. /* for non-blocking call */
  2711. if (msg == RT_NULL && timeout == 0)
  2712. {
  2713. /* enable interrupt */
  2714. rt_hw_interrupt_enable(level);
  2715. return -RT_EFULL;
  2716. }
  2717. /* message queue is full */
  2718. while ((msg = (struct rt_mq_message *)mq->msg_queue_free) == RT_NULL)
  2719. {
  2720. /* reset error number in thread */
  2721. thread->error = -RT_EINTR;
  2722. /* no waiting, return timeout */
  2723. if (timeout == 0)
  2724. {
  2725. /* enable interrupt */
  2726. rt_hw_interrupt_enable(level);
  2727. return -RT_EFULL;
  2728. }
  2729. /* suspend current thread */
  2730. ret = _ipc_list_suspend(&(mq->suspend_sender_thread),
  2731. thread,
  2732. mq->parent.parent.flag,
  2733. suspend_flag);
  2734. if (ret != RT_EOK)
  2735. {
  2736. rt_hw_interrupt_enable(level);
  2737. return ret;
  2738. }
  2739. /* has waiting time, start thread timer */
  2740. if (timeout > 0)
  2741. {
  2742. /* get the start tick of timer */
  2743. tick_delta = rt_tick_get();
  2744. RT_DEBUG_LOG(RT_DEBUG_IPC, ("mq_send_wait: start timer of thread:%s\n",
  2745. thread->name));
  2746. /* reset the timeout of thread timer and start it */
  2747. rt_timer_control(&(thread->thread_timer),
  2748. RT_TIMER_CTRL_SET_TIME,
  2749. &timeout);
  2750. rt_timer_start(&(thread->thread_timer));
  2751. }
  2752. /* enable interrupt */
  2753. rt_hw_interrupt_enable(level);
  2754. /* re-schedule */
  2755. rt_schedule();
  2756. /* resume from suspend state */
  2757. if (thread->error != RT_EOK)
  2758. {
  2759. /* return error */
  2760. return thread->error;
  2761. }
  2762. /* disable interrupt */
  2763. level = rt_hw_interrupt_disable();
  2764. /* if it's not waiting forever and then re-calculate timeout tick */
  2765. if (timeout > 0)
  2766. {
  2767. tick_delta = rt_tick_get() - tick_delta;
  2768. timeout -= tick_delta;
  2769. if (timeout < 0)
  2770. timeout = 0;
  2771. }
  2772. }
  2773. /* move free list pointer */
  2774. mq->msg_queue_free = msg->next;
  2775. /* enable interrupt */
  2776. rt_hw_interrupt_enable(level);
  2777. /* the msg is the new tailer of list, the next shall be NULL */
  2778. msg->next = RT_NULL;
  2779. /* copy buffer */
  2780. rt_memcpy(msg + 1, buffer, size);
  2781. /* disable interrupt */
  2782. level = rt_hw_interrupt_disable();
  2783. /* link msg to message queue */
  2784. if (mq->msg_queue_tail != RT_NULL)
  2785. {
  2786. /* if the tail exists, */
  2787. ((struct rt_mq_message *)mq->msg_queue_tail)->next = msg;
  2788. }
  2789. /* set new tail */
  2790. mq->msg_queue_tail = msg;
  2791. /* if the head is empty, set head */
  2792. if (mq->msg_queue_head == RT_NULL)
  2793. mq->msg_queue_head = msg;
  2794. if(mq->entry < RT_MQ_ENTRY_MAX)
  2795. {
  2796. /* increase message entry */
  2797. mq->entry ++;
  2798. }
  2799. else
  2800. {
  2801. rt_hw_interrupt_enable(level); /* enable interrupt */
  2802. return -RT_EFULL; /* value overflowed */
  2803. }
  2804. /* resume suspended thread */
  2805. if (!rt_list_isempty(&mq->parent.suspend_thread))
  2806. {
  2807. _ipc_list_resume(&(mq->parent.suspend_thread));
  2808. /* enable interrupt */
  2809. rt_hw_interrupt_enable(level);
  2810. rt_schedule();
  2811. return RT_EOK;
  2812. }
  2813. /* enable interrupt */
  2814. rt_hw_interrupt_enable(level);
  2815. return RT_EOK;
  2816. }
  2817. rt_err_t rt_mq_send_wait(rt_mq_t mq,
  2818. const void *buffer,
  2819. rt_size_t size,
  2820. rt_int32_t timeout)
  2821. {
  2822. return _rt_mq_send_wait(mq, buffer, size, timeout, RT_UNINTERRUPTIBLE);
  2823. }
  2824. RTM_EXPORT(rt_mq_send_wait)
  2825. rt_err_t rt_mq_send_wait_interruptible(rt_mq_t mq,
  2826. const void *buffer,
  2827. rt_size_t size,
  2828. rt_int32_t timeout)
  2829. {
  2830. return _rt_mq_send_wait(mq, buffer, size, timeout, RT_INTERRUPTIBLE);
  2831. }
  2832. RTM_EXPORT(rt_mq_send_wait_interruptible)
  2833. rt_err_t rt_mq_send_wait_killable(rt_mq_t mq,
  2834. const void *buffer,
  2835. rt_size_t size,
  2836. rt_int32_t timeout)
  2837. {
  2838. return _rt_mq_send_wait(mq, buffer, size, timeout, RT_KILLABLE);
  2839. }
  2840. RTM_EXPORT(rt_mq_send_wait_killable)
  2841. /**
  2842. * @brief This function will send a message to the messagequeue object.
  2843. * If there is a thread suspended on the messagequeue, the thread will be resumed.
  2844. *
  2845. * @note When using this function to send a message, if the messagequeue is fully used,
  2846. * the current thread will wait for a timeout.
  2847. * By contrast, when the messagequeue is fully used, the rt_mq_send_wait() function will
  2848. * return an error code immediately without waiting.
  2849. *
  2850. * @see rt_mq_send_wait()
  2851. *
  2852. * @param mq is a pointer to the messagequeue object to be sent.
  2853. *
  2854. * @param buffer is the content of the message.
  2855. *
  2856. * @param size is the length of the message(Unit: Byte).
  2857. *
  2858. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2859. * If the return value is any other values, it means that the messagequeue detach failed.
  2860. *
  2861. * @warning This function can be called in interrupt context and thread context.
  2862. */
  2863. rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size)
  2864. {
  2865. return rt_mq_send_wait(mq, buffer, size, 0);
  2866. }
  2867. RTM_EXPORT(rt_mq_send);
  2868. rt_err_t rt_mq_send_interrupt(rt_mq_t mq, const void *buffer, rt_size_t size)
  2869. {
  2870. return rt_mq_send_wait_interruptible(mq, buffer, size, 0);
  2871. }
  2872. RTM_EXPORT(rt_mq_send_interrupt);
  2873. rt_err_t rt_mq_send_killable(rt_mq_t mq, const void *buffer, rt_size_t size)
  2874. {
  2875. return rt_mq_send_wait_killable(mq, buffer, size, 0);
  2876. }
  2877. RTM_EXPORT(rt_mq_send_killable);
  2878. /**
  2879. * @brief This function will send an urgent message to the messagequeue object.
  2880. *
  2881. * @note This function is almost the same as the rt_mq_send() function. The only difference is that
  2882. * when sending an urgent message, the message is placed at the head of the messagequeue so that
  2883. * the recipient can receive the urgent message first.
  2884. *
  2885. * @see rt_mq_send()
  2886. *
  2887. * @param mq is a pointer to the messagequeue object to be sent.
  2888. *
  2889. * @param buffer is the content of the message.
  2890. *
  2891. * @param size is the length of the message(Unit: Byte).
  2892. *
  2893. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2894. * If the return value is any other values, it means that the mailbox detach failed.
  2895. */
  2896. rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size)
  2897. {
  2898. rt_base_t level;
  2899. struct rt_mq_message *msg;
  2900. /* parameter check */
  2901. RT_ASSERT(mq != RT_NULL);
  2902. RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
  2903. RT_ASSERT(buffer != RT_NULL);
  2904. RT_ASSERT(size != 0);
  2905. /* greater than one message size */
  2906. if (size > mq->msg_size)
  2907. return -RT_ERROR;
  2908. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent)));
  2909. /* disable interrupt */
  2910. level = rt_hw_interrupt_disable();
  2911. /* get a free list, there must be an empty item */
  2912. msg = (struct rt_mq_message *)mq->msg_queue_free;
  2913. /* message queue is full */
  2914. if (msg == RT_NULL)
  2915. {
  2916. /* enable interrupt */
  2917. rt_hw_interrupt_enable(level);
  2918. return -RT_EFULL;
  2919. }
  2920. /* move free list pointer */
  2921. mq->msg_queue_free = msg->next;
  2922. /* enable interrupt */
  2923. rt_hw_interrupt_enable(level);
  2924. /* copy buffer */
  2925. rt_memcpy(msg + 1, buffer, size);
  2926. /* disable interrupt */
  2927. level = rt_hw_interrupt_disable();
  2928. /* link msg to the beginning of message queue */
  2929. msg->next = (struct rt_mq_message *)mq->msg_queue_head;
  2930. mq->msg_queue_head = msg;
  2931. /* if there is no tail */
  2932. if (mq->msg_queue_tail == RT_NULL)
  2933. mq->msg_queue_tail = msg;
  2934. if(mq->entry < RT_MQ_ENTRY_MAX)
  2935. {
  2936. /* increase message entry */
  2937. mq->entry ++;
  2938. }
  2939. else
  2940. {
  2941. rt_hw_interrupt_enable(level); /* enable interrupt */
  2942. return -RT_EFULL; /* value overflowed */
  2943. }
  2944. /* resume suspended thread */
  2945. if (!rt_list_isempty(&mq->parent.suspend_thread))
  2946. {
  2947. _ipc_list_resume(&(mq->parent.suspend_thread));
  2948. /* enable interrupt */
  2949. rt_hw_interrupt_enable(level);
  2950. rt_schedule();
  2951. return RT_EOK;
  2952. }
  2953. /* enable interrupt */
  2954. rt_hw_interrupt_enable(level);
  2955. return RT_EOK;
  2956. }
  2957. RTM_EXPORT(rt_mq_urgent);
  2958. /**
  2959. * @brief This function will receive a message from message queue object,
  2960. * if there is no message in messagequeue object, the thread shall wait for a specified time.
  2961. *
  2962. * @note Only when there is mail in the mailbox, the receiving thread can get the mail immediately and return RT_EOK,
  2963. * otherwise the receiving thread will be suspended until timeout.
  2964. * If the mail is not received within the specified time, it will return -RT_ETIMEOUT.
  2965. *
  2966. * @param mq is a pointer to the messagequeue object to be received.
  2967. *
  2968. * @param buffer is the content of the message.
  2969. *
  2970. * @param size is the length of the message(Unit: Byte).
  2971. *
  2972. * @param timeout is a timeout period (unit: an OS tick). If the message is unavailable, the thread will wait for
  2973. * the message in the queue up to the amount of time specified by this parameter.
  2974. *
  2975. * NOTE:
  2976. * If use Macro RT_WAITING_FOREVER to set this parameter, which means that when the
  2977. * message is unavailable in the queue, the thread will be waiting forever.
  2978. * If use macro RT_WAITING_NO to set this parameter, which means that this
  2979. * function is non-blocking and will return immediately.
  2980. *
  2981. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  2982. * If the return value is any other values, it means that the mailbox release failed.
  2983. */
  2984. static rt_err_t _rt_mq_recv(rt_mq_t mq,
  2985. void *buffer,
  2986. rt_size_t size,
  2987. rt_int32_t timeout,
  2988. int suspend_flag)
  2989. {
  2990. struct rt_thread *thread;
  2991. rt_base_t level;
  2992. struct rt_mq_message *msg;
  2993. rt_uint32_t tick_delta;
  2994. rt_err_t ret;
  2995. /* parameter check */
  2996. RT_ASSERT(mq != RT_NULL);
  2997. RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
  2998. RT_ASSERT(buffer != RT_NULL);
  2999. RT_ASSERT(size != 0);
  3000. /* current context checking */
  3001. RT_DEBUG_SCHEDULER_AVAILABLE(timeout != 0);
  3002. /* initialize delta tick */
  3003. tick_delta = 0;
  3004. /* get current thread */
  3005. thread = rt_thread_self();
  3006. RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mq->parent.parent)));
  3007. /* disable interrupt */
  3008. level = rt_hw_interrupt_disable();
  3009. /* for non-blocking call */
  3010. if (mq->entry == 0 && timeout == 0)
  3011. {
  3012. rt_hw_interrupt_enable(level);
  3013. return -RT_ETIMEOUT;
  3014. }
  3015. /* message queue is empty */
  3016. while (mq->entry == 0)
  3017. {
  3018. /* reset error number in thread */
  3019. thread->error = -RT_EINTR;
  3020. /* no waiting, return timeout */
  3021. if (timeout == 0)
  3022. {
  3023. /* enable interrupt */
  3024. rt_hw_interrupt_enable(level);
  3025. thread->error = -RT_ETIMEOUT;
  3026. return -RT_ETIMEOUT;
  3027. }
  3028. /* suspend current thread */
  3029. ret = _ipc_list_suspend(&(mq->parent.suspend_thread),
  3030. thread,
  3031. mq->parent.parent.flag,
  3032. suspend_flag);
  3033. if (ret != RT_EOK)
  3034. {
  3035. rt_hw_interrupt_enable(level);
  3036. return ret;
  3037. }
  3038. /* has waiting time, start thread timer */
  3039. if (timeout > 0)
  3040. {
  3041. /* get the start tick of timer */
  3042. tick_delta = rt_tick_get();
  3043. RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
  3044. thread->name));
  3045. /* reset the timeout of thread timer and start it */
  3046. rt_timer_control(&(thread->thread_timer),
  3047. RT_TIMER_CTRL_SET_TIME,
  3048. &timeout);
  3049. rt_timer_start(&(thread->thread_timer));
  3050. }
  3051. /* enable interrupt */
  3052. rt_hw_interrupt_enable(level);
  3053. /* re-schedule */
  3054. rt_schedule();
  3055. /* recv message */
  3056. if (thread->error != RT_EOK)
  3057. {
  3058. /* return error */
  3059. return thread->error;
  3060. }
  3061. /* disable interrupt */
  3062. level = rt_hw_interrupt_disable();
  3063. /* if it's not waiting forever and then re-calculate timeout tick */
  3064. if (timeout > 0)
  3065. {
  3066. tick_delta = rt_tick_get() - tick_delta;
  3067. timeout -= tick_delta;
  3068. if (timeout < 0)
  3069. timeout = 0;
  3070. }
  3071. }
  3072. /* get message from queue */
  3073. msg = (struct rt_mq_message *)mq->msg_queue_head;
  3074. /* move message queue head */
  3075. mq->msg_queue_head = msg->next;
  3076. /* reach queue tail, set to NULL */
  3077. if (mq->msg_queue_tail == msg)
  3078. mq->msg_queue_tail = RT_NULL;
  3079. /* decrease message entry */
  3080. if(mq->entry > 0)
  3081. {
  3082. mq->entry --;
  3083. }
  3084. /* enable interrupt */
  3085. rt_hw_interrupt_enable(level);
  3086. /* copy message */
  3087. rt_memcpy(buffer, msg + 1, size > mq->msg_size ? mq->msg_size : size);
  3088. /* disable interrupt */
  3089. level = rt_hw_interrupt_disable();
  3090. /* put message to free list */
  3091. msg->next = (struct rt_mq_message *)mq->msg_queue_free;
  3092. mq->msg_queue_free = msg;
  3093. /* resume suspended thread */
  3094. if (!rt_list_isempty(&(mq->suspend_sender_thread)))
  3095. {
  3096. _ipc_list_resume(&(mq->suspend_sender_thread));
  3097. /* enable interrupt */
  3098. rt_hw_interrupt_enable(level);
  3099. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent)));
  3100. rt_schedule();
  3101. return RT_EOK;
  3102. }
  3103. /* enable interrupt */
  3104. rt_hw_interrupt_enable(level);
  3105. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent)));
  3106. return RT_EOK;
  3107. }
  3108. rt_err_t rt_mq_recv(rt_mq_t mq,
  3109. void *buffer,
  3110. rt_size_t size,
  3111. rt_int32_t timeout)
  3112. {
  3113. return _rt_mq_recv(mq, buffer, size, timeout, RT_UNINTERRUPTIBLE);
  3114. }
  3115. RTM_EXPORT(rt_mq_recv);
  3116. rt_err_t rt_mq_recv_interruptible(rt_mq_t mq,
  3117. void *buffer,
  3118. rt_size_t size,
  3119. rt_int32_t timeout)
  3120. {
  3121. return _rt_mq_recv(mq, buffer, size, timeout, RT_INTERRUPTIBLE);
  3122. }
  3123. RTM_EXPORT(rt_mq_recv_interruptible);
  3124. rt_err_t rt_mq_recv_killable(rt_mq_t mq,
  3125. void *buffer,
  3126. rt_size_t size,
  3127. rt_int32_t timeout)
  3128. {
  3129. return _rt_mq_recv(mq, buffer, size, timeout, RT_KILLABLE);
  3130. }
  3131. RTM_EXPORT(rt_mq_recv_killable);
  3132. /**
  3133. * @brief This function will set some extra attributions of a messagequeue object.
  3134. *
  3135. * @note Currently this function only supports the RT_IPC_CMD_RESET command to reset the messagequeue.
  3136. *
  3137. * @param mq is a pointer to a messagequeue object.
  3138. *
  3139. * @param cmd is a command used to configure some attributions of the messagequeue.
  3140. *
  3141. * @param arg is the argument of the function to execute the command.
  3142. *
  3143. * @return Return the operation status. When the return value is RT_EOK, the operation is successful.
  3144. * If the return value is any other values, it means that this function failed to execute.
  3145. */
  3146. rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg)
  3147. {
  3148. rt_base_t level;
  3149. struct rt_mq_message *msg;
  3150. /* parameter check */
  3151. RT_ASSERT(mq != RT_NULL);
  3152. RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue);
  3153. if (cmd == RT_IPC_CMD_RESET)
  3154. {
  3155. /* disable interrupt */
  3156. level = rt_hw_interrupt_disable();
  3157. /* resume all waiting thread */
  3158. _ipc_list_resume_all(&mq->parent.suspend_thread);
  3159. /* also resume all message queue private suspended thread */
  3160. _ipc_list_resume_all(&(mq->suspend_sender_thread));
  3161. /* release all message in the queue */
  3162. while (mq->msg_queue_head != RT_NULL)
  3163. {
  3164. /* get message from queue */
  3165. msg = (struct rt_mq_message *)mq->msg_queue_head;
  3166. /* move message queue head */
  3167. mq->msg_queue_head = msg->next;
  3168. /* reach queue tail, set to NULL */
  3169. if (mq->msg_queue_tail == msg)
  3170. mq->msg_queue_tail = RT_NULL;
  3171. /* put message to free list */
  3172. msg->next = (struct rt_mq_message *)mq->msg_queue_free;
  3173. mq->msg_queue_free = msg;
  3174. }
  3175. /* clean entry */
  3176. mq->entry = 0;
  3177. /* enable interrupt */
  3178. rt_hw_interrupt_enable(level);
  3179. rt_schedule();
  3180. return RT_EOK;
  3181. }
  3182. return -RT_ERROR;
  3183. }
  3184. RTM_EXPORT(rt_mq_control);
  3185. /**@}*/
  3186. #endif /* RT_USING_MESSAGEQUEUE */
  3187. /**@}*/