/src/compiler/ucos-vs2008/UCOS_SIM/src/ucosii/os_mbox.c

http://ftk.googlecode.com/ · C · 512 lines · 300 code · 35 blank · 177 comment · 77 complexity · aeaf9824f0bc2bb6d5a8d3100a8d2fde MD5 · raw file

  1. /*
  2. *********************************************************************************************************
  3. * uC/OS-II
  4. * The Real-Time Kernel
  5. * MESSAGE MAILBOX MANAGEMENT
  6. *
  7. * (c) Copyright 1992-2005, Jean J. Labrosse, Weston, FL
  8. * All Rights Reserved
  9. *
  10. * File : OS_MBOX.C
  11. * By : Jean J. Labrosse
  12. * Version : V2.80
  13. *********************************************************************************************************
  14. */
  15. #ifndef OS_MASTER_FILE
  16. #include <ucos_ii.h>
  17. #endif
  18. #if OS_MBOX_EN > 0
  19. /*
  20. *********************************************************************************************************
  21. * ACCEPT MESSAGE FROM MAILBOX
  22. *
  23. * Description: This function checks the mailbox to see if a message is available. Unlike OSMboxPend(),
  24. * OSMboxAccept() does not suspend the calling task if a message is not available.
  25. *
  26. * Arguments : pevent is a pointer to the event control block
  27. *
  28. * Returns : != (void *)0 is the message in the mailbox if one is available. The mailbox is cleared
  29. * so the next time OSMboxAccept() is called, the mailbox will be empty.
  30. * == (void *)0 if the mailbox is empty or,
  31. * if 'pevent' is a NULL pointer or,
  32. * if you didn't pass the proper event pointer.
  33. *********************************************************************************************************
  34. */
  35. #if OS_MBOX_ACCEPT_EN > 0
  36. void *OSMboxAccept (OS_EVENT *pevent)
  37. {
  38. void *msg;
  39. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  40. OS_CPU_SR cpu_sr = 0;
  41. #endif
  42. #if OS_ARG_CHK_EN > 0
  43. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  44. return ((void *)0);
  45. }
  46. #endif
  47. if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
  48. return ((void *)0);
  49. }
  50. OS_ENTER_CRITICAL();
  51. msg = pevent->OSEventPtr;
  52. pevent->OSEventPtr = (void *)0; /* Clear the mailbox */
  53. OS_EXIT_CRITICAL();
  54. return (msg); /* Return the message received (or NULL) */
  55. }
  56. #endif
  57. /*$PAGE*/
  58. /*
  59. *********************************************************************************************************
  60. * CREATE A MESSAGE MAILBOX
  61. *
  62. * Description: This function creates a message mailbox if free event control blocks are available.
  63. *
  64. * Arguments : msg is a pointer to a message that you wish to deposit in the mailbox. If
  65. * you set this value to the NULL pointer (i.e. (void *)0) then the mailbox
  66. * will be considered empty.
  67. *
  68. * Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the
  69. * created mailbox
  70. * == (OS_EVENT *)0 if no event control blocks were available
  71. *********************************************************************************************************
  72. */
  73. OS_EVENT *OSMboxCreate (void *msg)
  74. {
  75. OS_EVENT *pevent;
  76. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  77. OS_CPU_SR cpu_sr = 0;
  78. #endif
  79. if (OSIntNesting > 0) { /* See if called from ISR ... */
  80. return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
  81. }
  82. OS_ENTER_CRITICAL();
  83. pevent = OSEventFreeList; /* Get next free event control block */
  84. if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
  85. OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  86. }
  87. OS_EXIT_CRITICAL();
  88. if (pevent != (OS_EVENT *)0) {
  89. pevent->OSEventType = OS_EVENT_TYPE_MBOX;
  90. pevent->OSEventCnt = 0;
  91. pevent->OSEventPtr = msg; /* Deposit message in event control block */
  92. #if OS_EVENT_NAME_SIZE > 1
  93. pevent->OSEventName[0] = '?';
  94. pevent->OSEventName[1] = OS_ASCII_NUL;
  95. #endif
  96. OS_EventWaitListInit(pevent);
  97. }
  98. return (pevent); /* Return pointer to event control block */
  99. }
  100. /*$PAGE*/
  101. /*
  102. *********************************************************************************************************
  103. * DELETE A MAIBOX
  104. *
  105. * Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
  106. *
  107. * Arguments : pevent is a pointer to the event control block associated with the desired
  108. * mailbox.
  109. *
  110. * opt determines delete options as follows:
  111. * opt == OS_DEL_NO_PEND Delete the mailbox ONLY if no task pending
  112. * opt == OS_DEL_ALWAYS Deletes the mailbox even if tasks are waiting.
  113. * In this case, all the tasks pending will be readied.
  114. *
  115. * err is a pointer to an error code that can contain one of the following values:
  116. * OS_NO_ERR The call was successful and the mailbox was deleted
  117. * OS_ERR_DEL_ISR If you attempted to delete the mailbox from an ISR
  118. * OS_ERR_INVALID_OPT An invalid option was specified
  119. * OS_ERR_TASK_WAITING One or more tasks were waiting on the mailbox
  120. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox
  121. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  122. *
  123. * Returns : pevent upon error
  124. * (OS_EVENT *)0 if the mailbox was successfully deleted.
  125. *
  126. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  127. * the mailbox MUST check the return code of OSMboxPend().
  128. * 2) OSMboxAccept() callers will not know that the intended mailbox has been deleted!
  129. * 3) This call can potentially disable interrupts for a long time. The interrupt disable
  130. * time is directly proportional to the number of tasks waiting on the mailbox.
  131. * 4) Because ALL tasks pending on the mailbox will be readied, you MUST be careful in
  132. * applications where the mailbox is used for mutual exclusion because the resource(s)
  133. * will no longer be guarded by the mailbox.
  134. *********************************************************************************************************
  135. */
  136. #if OS_MBOX_DEL_EN > 0
  137. OS_EVENT *OSMboxDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  138. {
  139. BOOLEAN tasks_waiting;
  140. OS_EVENT *pevent_return;
  141. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  142. OS_CPU_SR cpu_sr = 0;
  143. #endif
  144. #if OS_ARG_CHK_EN > 0
  145. if (err == (INT8U *)0) { /* Validate 'err' */
  146. return (pevent);
  147. }
  148. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  149. *err = OS_ERR_PEVENT_NULL;
  150. return (pevent);
  151. }
  152. #endif
  153. if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
  154. *err = OS_ERR_EVENT_TYPE;
  155. return (pevent);
  156. }
  157. if (OSIntNesting > 0) { /* See if called from ISR ... */
  158. *err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  159. return (pevent);
  160. }
  161. OS_ENTER_CRITICAL();
  162. if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on mailbox */
  163. tasks_waiting = TRUE; /* Yes */
  164. } else {
  165. tasks_waiting = FALSE; /* No */
  166. }
  167. switch (opt) {
  168. case OS_DEL_NO_PEND: /* Delete mailbox only if no task waiting */
  169. if (tasks_waiting == FALSE) {
  170. #if OS_EVENT_NAME_SIZE > 1
  171. pevent->OSEventName[0] = '?'; /* Unknown name */
  172. pevent->OSEventName[1] = OS_ASCII_NUL;
  173. #endif
  174. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  175. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  176. pevent->OSEventCnt = 0;
  177. OSEventFreeList = pevent; /* Get next free event control block */
  178. OS_EXIT_CRITICAL();
  179. *err = OS_NO_ERR;
  180. pevent_return = (OS_EVENT *)0; /* Mailbox has been deleted */
  181. } else {
  182. OS_EXIT_CRITICAL();
  183. *err = OS_ERR_TASK_WAITING;
  184. pevent_return = pevent;
  185. }
  186. break;
  187. case OS_DEL_ALWAYS: /* Always delete the mailbox */
  188. while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for mailbox */
  189. (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX);
  190. }
  191. #if OS_EVENT_NAME_SIZE > 1
  192. pevent->OSEventName[0] = '?'; /* Unknown name */
  193. pevent->OSEventName[1] = OS_ASCII_NUL;
  194. #endif
  195. pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  196. pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  197. pevent->OSEventCnt = 0;
  198. OSEventFreeList = pevent; /* Get next free event control block */
  199. OS_EXIT_CRITICAL();
  200. if (tasks_waiting == TRUE) { /* Reschedule only if task(s) were waiting */
  201. OS_Sched(); /* Find highest priority task ready to run */
  202. }
  203. *err = OS_NO_ERR;
  204. pevent_return = (OS_EVENT *)0; /* Mailbox has been deleted */
  205. break;
  206. default:
  207. OS_EXIT_CRITICAL();
  208. *err = OS_ERR_INVALID_OPT;
  209. pevent_return = pevent;
  210. break;
  211. }
  212. return (pevent_return);
  213. }
  214. #endif
  215. /*$PAGE*/
  216. /*
  217. *********************************************************************************************************
  218. * PEND ON MAILBOX FOR A MESSAGE
  219. *
  220. * Description: This function waits for a message to be sent to a mailbox
  221. *
  222. * Arguments : pevent is a pointer to the event control block associated with the desired mailbox
  223. *
  224. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  225. * wait for a message to arrive at the mailbox up to the amount of time
  226. * specified by this argument. If you specify 0, however, your task will wait
  227. * forever at the specified mailbox or, until a message arrives.
  228. *
  229. * err is a pointer to where an error message will be deposited. Possible error
  230. * messages are:
  231. *
  232. * OS_NO_ERR The call was successful and your task received a
  233. * message.
  234. * OS_TIMEOUT A message was not received within the specified timeout
  235. * OS_ERR_EVENT_TYPE Invalid event type
  236. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  237. * would lead to a suspension.
  238. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  239. *
  240. * Returns : != (void *)0 is a pointer to the message received
  241. * == (void *)0 if no message was received or,
  242. * if 'pevent' is a NULL pointer or,
  243. * if you didn't pass the proper pointer to the event control block.
  244. *********************************************************************************************************
  245. */
  246. void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  247. {
  248. void *msg;
  249. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  250. OS_CPU_SR cpu_sr = 0;
  251. #endif
  252. #if OS_ARG_CHK_EN > 0
  253. if (err == (INT8U *)0) { /* Validate 'err' */
  254. return ((void *)0);
  255. }
  256. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  257. *err = OS_ERR_PEVENT_NULL;
  258. return ((void *)0);
  259. }
  260. #endif
  261. if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
  262. *err = OS_ERR_EVENT_TYPE;
  263. return ((void *)0);
  264. }
  265. if (OSIntNesting > 0) { /* See if called from ISR ... */
  266. *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  267. return ((void *)0);
  268. }
  269. OS_ENTER_CRITICAL();
  270. msg = pevent->OSEventPtr;
  271. if (msg != (void *)0) { /* See if there is already a message */
  272. pevent->OSEventPtr = (void *)0; /* Clear the mailbox */
  273. OS_EXIT_CRITICAL();
  274. *err = OS_NO_ERR;
  275. return (msg); /* Return the message received (or NULL) */
  276. }
  277. OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */
  278. OSTCBCur->OSTCBPendTO = FALSE;
  279. OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */
  280. OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  281. OS_EXIT_CRITICAL();
  282. OS_Sched(); /* Find next highest priority task ready to run */
  283. OS_ENTER_CRITICAL();
  284. if (OSTCBCur->OSTCBPendTO == TRUE) { /* See if we were given the message */
  285. OS_EventTO(pevent); /* Timed out, Make task ready */
  286. OS_EXIT_CRITICAL();
  287. *err = OS_TIMEOUT; /* Indicate that a timeout occured */
  288. return ((void *)0); /* Return a NULL message */
  289. }
  290. msg = OSTCBCur->OSTCBMsg;
  291. OSTCBCur->OSTCBMsg = (void *)0; /* Yes, clear message received */
  292. OSTCBCur->OSTCBStat = OS_STAT_RDY;
  293. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */
  294. OS_EXIT_CRITICAL();
  295. *err = OS_NO_ERR;
  296. return (msg); /* Return the message received */
  297. }
  298. /*$PAGE*/
  299. /*
  300. *********************************************************************************************************
  301. * POST MESSAGE TO A MAILBOX
  302. *
  303. * Description: This function sends a message to a mailbox
  304. *
  305. * Arguments : pevent is a pointer to the event control block associated with the desired mailbox
  306. *
  307. * msg is a pointer to the message to send. You MUST NOT send a NULL pointer.
  308. *
  309. * Returns : OS_NO_ERR The call was successful and the message was sent
  310. * OS_MBOX_FULL If the mailbox already contains a message. You can can only send one
  311. * message at a time and thus, the message MUST be consumed before you
  312. * are allowed to send another one.
  313. * OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox.
  314. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  315. * OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
  316. *
  317. * Note(s) : 1) HPT means Highest Priority Task
  318. *********************************************************************************************************
  319. */
  320. #if OS_MBOX_POST_EN > 0
  321. INT8U OSMboxPost (OS_EVENT *pevent, void *msg)
  322. {
  323. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  324. OS_CPU_SR cpu_sr = 0;
  325. #endif
  326. #if OS_ARG_CHK_EN > 0
  327. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  328. return (OS_ERR_PEVENT_NULL);
  329. }
  330. if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */
  331. return (OS_ERR_POST_NULL_PTR);
  332. }
  333. #endif
  334. if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
  335. return (OS_ERR_EVENT_TYPE);
  336. }
  337. OS_ENTER_CRITICAL();
  338. if (pevent->OSEventGrp != 0) { /* See if any task pending on mailbox */
  339. (void)OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX); /* Ready HPT waiting on event */
  340. OS_EXIT_CRITICAL();
  341. OS_Sched(); /* Find highest priority task ready to run */
  342. return (OS_NO_ERR);
  343. }
  344. if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */
  345. OS_EXIT_CRITICAL();
  346. return (OS_MBOX_FULL);
  347. }
  348. pevent->OSEventPtr = msg; /* Place message in mailbox */
  349. OS_EXIT_CRITICAL();
  350. return (OS_NO_ERR);
  351. }
  352. #endif
  353. /*$PAGE*/
  354. /*
  355. *********************************************************************************************************
  356. * POST MESSAGE TO A MAILBOX
  357. *
  358. * Description: This function sends a message to a mailbox
  359. *
  360. * Arguments : pevent is a pointer to the event control block associated with the desired mailbox
  361. *
  362. * msg is a pointer to the message to send. You MUST NOT send a NULL pointer.
  363. *
  364. * opt determines the type of POST performed:
  365. * OS_POST_OPT_NONE POST to a single waiting task
  366. * (Identical to OSMboxPost())
  367. * OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the mailbox
  368. *
  369. * Returns : OS_NO_ERR The call was successful and the message was sent
  370. * OS_MBOX_FULL If the mailbox already contains a message. You can can only send one
  371. * message at a time and thus, the message MUST be consumed before you
  372. * are allowed to send another one.
  373. * OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox.
  374. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  375. * OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
  376. *
  377. * Note(s) : 1) HPT means Highest Priority Task
  378. *
  379. * Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the
  380. * interrupt disable time is proportional to the number of tasks waiting on the mailbox.
  381. *********************************************************************************************************
  382. */
  383. #if OS_MBOX_POST_OPT_EN > 0
  384. INT8U OSMboxPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
  385. {
  386. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  387. OS_CPU_SR cpu_sr = 0;
  388. #endif
  389. #if OS_ARG_CHK_EN > 0
  390. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  391. return (OS_ERR_PEVENT_NULL);
  392. }
  393. if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */
  394. return (OS_ERR_POST_NULL_PTR);
  395. }
  396. #endif
  397. if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
  398. return (OS_ERR_EVENT_TYPE);
  399. }
  400. OS_ENTER_CRITICAL();
  401. if (pevent->OSEventGrp != 0) { /* See if any task pending on mailbox */
  402. if ((opt & OS_POST_OPT_BROADCAST) != 0x00) { /* Do we need to post msg to ALL waiting tasks ? */
  403. while (pevent->OSEventGrp != 0) { /* Yes, Post to ALL tasks waiting on mailbox */
  404. (void)OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);
  405. }
  406. } else {
  407. (void)OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX); /* No, Post to HPT waiting on mbox */
  408. }
  409. OS_EXIT_CRITICAL();
  410. OS_Sched(); /* Find HPT ready to run */
  411. return (OS_NO_ERR);
  412. }
  413. if (pevent->OSEventPtr != (void *)0) { /* Make sure mailbox doesn't already have a msg */
  414. OS_EXIT_CRITICAL();
  415. return (OS_MBOX_FULL);
  416. }
  417. pevent->OSEventPtr = msg; /* Place message in mailbox */
  418. OS_EXIT_CRITICAL();
  419. return (OS_NO_ERR);
  420. }
  421. #endif
  422. /*$PAGE*/
  423. /*
  424. *********************************************************************************************************
  425. * QUERY A MESSAGE MAILBOX
  426. *
  427. * Description: This function obtains information about a message mailbox.
  428. *
  429. * Arguments : pevent is a pointer to the event control block associated with the desired mailbox
  430. *
  431. * p_mbox_data is a pointer to a structure that will contain information about the message
  432. * mailbox.
  433. *
  434. * Returns : OS_NO_ERR The call was successful and the message was sent
  435. * OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mailbox.
  436. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
  437. * OS_ERR_PDATA_NULL If 'p_mbox_data' is a NULL pointer
  438. *********************************************************************************************************
  439. */
  440. #if OS_MBOX_QUERY_EN > 0
  441. INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *p_mbox_data)
  442. {
  443. INT8U i;
  444. #if OS_LOWEST_PRIO <= 63
  445. INT8U *psrc;
  446. INT8U *pdest;
  447. #else
  448. INT16U *psrc;
  449. INT16U *pdest;
  450. #endif
  451. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  452. OS_CPU_SR cpu_sr = 0;
  453. #endif
  454. #if OS_ARG_CHK_EN > 0
  455. if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  456. return (OS_ERR_PEVENT_NULL);
  457. }
  458. if (p_mbox_data == (OS_MBOX_DATA *)0) { /* Validate 'p_mbox_data' */
  459. return (OS_ERR_PDATA_NULL);
  460. }
  461. #endif
  462. if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */
  463. return (OS_ERR_EVENT_TYPE);
  464. }
  465. OS_ENTER_CRITICAL();
  466. p_mbox_data->OSEventGrp = pevent->OSEventGrp; /* Copy message mailbox wait list */
  467. psrc = &pevent->OSEventTbl[0];
  468. pdest = &p_mbox_data->OSEventTbl[0];
  469. for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  470. *pdest++ = *psrc++;
  471. }
  472. p_mbox_data->OSMsg = pevent->OSEventPtr; /* Get message from mailbox */
  473. OS_EXIT_CRITICAL();
  474. return (OS_NO_ERR);
  475. }
  476. #endif /* OS_MBOX_QUERY_EN */
  477. #endif /* OS_MBOX_EN */