PageRenderTime 494ms CodeModel.GetById 188ms app.highlight 75ms RepoModel.GetById 116ms app.codeStats 0ms

/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
 16#ifndef  OS_MASTER_FILE

 17#include <ucos_ii.h>

 18#endif

 19
 20#if OS_MBOX_EN > 0

 21/*
 22*********************************************************************************************************
 23*                                     ACCEPT MESSAGE FROM MAILBOX
 24*
 25* Description: This function checks the mailbox to see if a message is available.  Unlike OSMboxPend(),
 26*              OSMboxAccept() does not suspend the calling task if a message is not available.
 27*
 28* Arguments  : pevent        is a pointer to the event control block
 29*
 30* Returns    : != (void *)0  is the message in the mailbox if one is available.  The mailbox is cleared
 31*                            so the next time OSMboxAccept() is called, the mailbox will be empty.
 32*              == (void *)0  if the mailbox is empty or,
 33*                            if 'pevent' is a NULL pointer or,
 34*                            if you didn't pass the proper event pointer.
 35*********************************************************************************************************
 36*/
 37
 38#if OS_MBOX_ACCEPT_EN > 0

 39void  *OSMboxAccept (OS_EVENT *pevent)
 40{
 41    void      *msg;
 42#if OS_CRITICAL_METHOD == 3                               /* Allocate storage for CPU status register  */

 43    OS_CPU_SR  cpu_sr = 0;
 44#endif

 45
 46
 47
 48#if OS_ARG_CHK_EN > 0

 49    if (pevent == (OS_EVENT *)0) {                        /* Validate 'pevent'                         */
 50        return ((void *)0);
 51    }
 52#endif

 53    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {      /* Validate event block type                 */
 54        return ((void *)0);
 55    }
 56    OS_ENTER_CRITICAL();
 57    msg                = pevent->OSEventPtr;
 58    pevent->OSEventPtr = (void *)0;                       /* Clear the mailbox                         */
 59    OS_EXIT_CRITICAL();
 60    return (msg);                                         /* Return the message received (or NULL)     */
 61}
 62#endif

 63/*$PAGE*/
 64/*
 65*********************************************************************************************************
 66*                                        CREATE A MESSAGE MAILBOX
 67*
 68* Description: This function creates a message mailbox if free event control blocks are available.
 69*
 70* Arguments  : msg           is a pointer to a message that you wish to deposit in the mailbox.  If
 71*                            you set this value to the NULL pointer (i.e. (void *)0) then the mailbox
 72*                            will be considered empty.
 73*
 74* Returns    : != (OS_EVENT *)0  is a pointer to the event control clock (OS_EVENT) associated with the
 75*                                created mailbox
 76*              == (OS_EVENT *)0  if no event control blocks were available
 77*********************************************************************************************************
 78*/
 79
 80OS_EVENT  *OSMboxCreate (void *msg)
 81{
 82    OS_EVENT  *pevent;
 83#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */

 84    OS_CPU_SR  cpu_sr = 0;
 85#endif

 86
 87
 88
 89    if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
 90        return ((OS_EVENT *)0);                  /* ... can't CREATE from an ISR                       */
 91    }
 92    OS_ENTER_CRITICAL();
 93    pevent = OSEventFreeList;                    /* Get next free event control block                  */
 94    if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
 95        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
 96    }
 97    OS_EXIT_CRITICAL();
 98    if (pevent != (OS_EVENT *)0) {
 99        pevent->OSEventType    = OS_EVENT_TYPE_MBOX;
100        pevent->OSEventCnt     = 0;
101        pevent->OSEventPtr     = msg;            /* Deposit message in event control block             */
102#if OS_EVENT_NAME_SIZE > 1

103        pevent->OSEventName[0] = '?';
104        pevent->OSEventName[1] = OS_ASCII_NUL;
105#endif

106        OS_EventWaitListInit(pevent);
107    }
108    return (pevent);                             /* Return pointer to event control block              */
109}
110/*$PAGE*/
111/*
112*********************************************************************************************************
113*                                         DELETE A MAIBOX
114*
115* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
116*
117* Arguments  : pevent        is a pointer to the event control block associated with the desired
118*                            mailbox.
119*
120*              opt           determines delete options as follows:
121*                            opt == OS_DEL_NO_PEND   Delete the mailbox ONLY if no task pending
122*                            opt == OS_DEL_ALWAYS    Deletes the mailbox even if tasks are waiting.
123*                                                    In this case, all the tasks pending will be readied.
124*
125*              err           is a pointer to an error code that can contain one of the following values:
126*                            OS_NO_ERR               The call was successful and the mailbox was deleted
127*                            OS_ERR_DEL_ISR          If you attempted to delete the mailbox from an ISR
128*                            OS_ERR_INVALID_OPT      An invalid option was specified
129*                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the mailbox
130*                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a mailbox
131*                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
132*
133* Returns    : pevent        upon error
134*              (OS_EVENT *)0 if the mailbox was successfully deleted.
135*
136* Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
137*                 the mailbox MUST check the return code of OSMboxPend().
138*              2) OSMboxAccept() callers will not know that the intended mailbox has been deleted!
139*              3) This call can potentially disable interrupts for a long time.  The interrupt disable
140*                 time is directly proportional to the number of tasks waiting on the mailbox.
141*              4) Because ALL tasks pending on the mailbox will be readied, you MUST be careful in
142*                 applications where the mailbox is used for mutual exclusion because the resource(s)
143*                 will no longer be guarded by the mailbox.
144*********************************************************************************************************
145*/
146
147#if OS_MBOX_DEL_EN > 0

148OS_EVENT  *OSMboxDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
149{
150    BOOLEAN    tasks_waiting;
151    OS_EVENT  *pevent_return;
152#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */

153    OS_CPU_SR  cpu_sr = 0;
154#endif

155
156
157
158#if OS_ARG_CHK_EN > 0

159    if (err == (INT8U *)0) {                               /* Validate 'err'                           */
160        return (pevent);
161    }
162    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
163        *err = OS_ERR_PEVENT_NULL;
164        return (pevent);
165    }
166#endif

167    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {       /* Validate event block type                */
168        *err = OS_ERR_EVENT_TYPE;
169        return (pevent);
170    }
171    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
172        *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
173        return (pevent);
174    }
175    OS_ENTER_CRITICAL();
176    if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on mailbox      */
177        tasks_waiting = TRUE;                              /* Yes                                      */
178    } else {
179        tasks_waiting = FALSE;                             /* No                                       */
180    }
181    switch (opt) {
182        case OS_DEL_NO_PEND:                               /* Delete mailbox only if no task waiting   */
183             if (tasks_waiting == FALSE) {
184#if OS_EVENT_NAME_SIZE > 1

185                 pevent->OSEventName[0] = '?';             /* Unknown name                             */
186                 pevent->OSEventName[1] = OS_ASCII_NUL;
187#endif

188                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
189                 pevent->OSEventPtr  = OSEventFreeList;    /* Return Event Control Block to free list  */
190                 pevent->OSEventCnt  = 0;
191                 OSEventFreeList     = pevent;             /* Get next free event control block        */
192                 OS_EXIT_CRITICAL();
193                 *err                = OS_NO_ERR;
194                 pevent_return       = (OS_EVENT *)0;      /* Mailbox has been deleted                 */
195             } else {
196                 OS_EXIT_CRITICAL();
197                 *err                = OS_ERR_TASK_WAITING;
198                 pevent_return       = pevent;
199             }
200             break;
201
202        case OS_DEL_ALWAYS:                                /* Always delete the mailbox                */
203             while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for mailbox      */
204                 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX);
205             }
206#if OS_EVENT_NAME_SIZE > 1

207             pevent->OSEventName[0] = '?';                 /* Unknown name                             */
208             pevent->OSEventName[1] = OS_ASCII_NUL;
209#endif

210             pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
211             pevent->OSEventPtr     = OSEventFreeList;     /* Return Event Control Block to free list  */
212             pevent->OSEventCnt     = 0;
213             OSEventFreeList        = pevent;              /* Get next free event control block        */
214             OS_EXIT_CRITICAL();
215             if (tasks_waiting == TRUE) {                  /* Reschedule only if task(s) were waiting  */
216                 OS_Sched();                               /* Find highest priority task ready to run  */
217             }
218             *err          = OS_NO_ERR;
219             pevent_return = (OS_EVENT *)0;                /* Mailbox has been deleted                 */
220             break;
221
222        default:
223             OS_EXIT_CRITICAL();
224             *err          = OS_ERR_INVALID_OPT;
225             pevent_return = pevent;
226             break;
227    }
228    return (pevent_return);
229}
230#endif

231
232/*$PAGE*/
233/*
234*********************************************************************************************************
235*                                      PEND ON MAILBOX FOR A MESSAGE
236*
237* Description: This function waits for a message to be sent to a mailbox
238*
239* Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
240*
241*              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
242*                            wait for a message to arrive at the mailbox up to the amount of time
243*                            specified by this argument.  If you specify 0, however, your task will wait
244*                            forever at the specified mailbox or, until a message arrives.
245*
246*              err           is a pointer to where an error message will be deposited.  Possible error
247*                            messages are:
248*
249*                            OS_NO_ERR           The call was successful and your task received a
250*                                                message.
251*                            OS_TIMEOUT          A message was not received within the specified timeout
252*                            OS_ERR_EVENT_TYPE   Invalid event type
253*                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
254*                                                would lead to a suspension.
255*                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
256*
257* Returns    : != (void *)0  is a pointer to the message received
258*              == (void *)0  if no message was received or,
259*                            if 'pevent' is a NULL pointer or,
260*                            if you didn't pass the proper pointer to the event control block.
261*********************************************************************************************************
262*/
263
264void  *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
265{
266    void      *msg;
267#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */

268    OS_CPU_SR  cpu_sr = 0;
269#endif

270
271
272
273#if OS_ARG_CHK_EN > 0

274    if (err == (INT8U *)0) {                          /* Validate 'err'                                */
275        return ((void *)0);
276    }
277    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
278        *err = OS_ERR_PEVENT_NULL;
279        return ((void *)0);
280    }
281#endif

282    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
283        *err = OS_ERR_EVENT_TYPE;
284        return ((void *)0);
285    }
286    if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
287        *err = OS_ERR_PEND_ISR;                       /* ... can't PEND from an ISR                    */
288        return ((void *)0);
289    }
290    OS_ENTER_CRITICAL();
291    msg = pevent->OSEventPtr;
292    if (msg != (void *)0) {                           /* See if there is already a message             */
293        pevent->OSEventPtr = (void *)0;               /* Clear the mailbox                             */
294        OS_EXIT_CRITICAL();
295        *err = OS_NO_ERR;
296        return (msg);                                 /* Return the message received (or NULL)         */
297    }
298    OSTCBCur->OSTCBStat  |= OS_STAT_MBOX;             /* Message not available, task will pend         */
299    OSTCBCur->OSTCBPendTO = FALSE;
300    OSTCBCur->OSTCBDly    = timeout;                  /* Load timeout in TCB                           */
301    OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
302    OS_EXIT_CRITICAL();
303    OS_Sched();                                       /* Find next highest priority task ready to run  */
304    OS_ENTER_CRITICAL();
305    if (OSTCBCur->OSTCBPendTO == TRUE) {              /* See if we were given the message              */
306        OS_EventTO(pevent);                           /* Timed out, Make task ready                    */
307        OS_EXIT_CRITICAL();
308        *err = OS_TIMEOUT;                            /* Indicate that a timeout occured               */
309        return ((void *)0);                           /* Return a NULL message                         */
310    }
311    msg                     = OSTCBCur->OSTCBMsg;
312    OSTCBCur->OSTCBMsg      = (void *)0;              /* Yes, clear message received                   */
313    OSTCBCur->OSTCBStat     = OS_STAT_RDY;
314    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;          /* No longer waiting for event                   */
315    OS_EXIT_CRITICAL();
316    *err                    = OS_NO_ERR;
317    return (msg);                                     /* Return the message received                   */
318}
319/*$PAGE*/
320/*
321*********************************************************************************************************
322*                                       POST MESSAGE TO A MAILBOX
323*
324* Description: This function sends a message to a mailbox
325*
326* Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
327*
328*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
329*
330* Returns    : OS_NO_ERR            The call was successful and the message was sent
331*              OS_MBOX_FULL         If the mailbox already contains a message.  You can can only send one
332*                                   message at a time and thus, the message MUST be consumed before you
333*                                   are allowed to send another one.
334*              OS_ERR_EVENT_TYPE    If you are attempting to post to a non mailbox.
335*              OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer
336*              OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
337*
338* Note(s)    : 1) HPT means Highest Priority Task
339*********************************************************************************************************
340*/
341
342#if OS_MBOX_POST_EN > 0

343INT8U  OSMboxPost (OS_EVENT *pevent, void *msg)
344{
345#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */

346    OS_CPU_SR  cpu_sr = 0;
347#endif

348
349
350
351#if OS_ARG_CHK_EN > 0

352    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
353        return (OS_ERR_PEVENT_NULL);
354    }
355    if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
356        return (OS_ERR_POST_NULL_PTR);
357    }
358#endif

359    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
360        return (OS_ERR_EVENT_TYPE);
361    }
362    OS_ENTER_CRITICAL();
363    if (pevent->OSEventGrp != 0) {                        /* See if any task pending on mailbox        */
364        (void)OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX); /* Ready HPT waiting on event                */
365        OS_EXIT_CRITICAL();
366        OS_Sched();                                   /* Find highest priority task ready to run       */
367        return (OS_NO_ERR);
368    }
369    if (pevent->OSEventPtr != (void *)0) {            /* Make sure mailbox doesn't already have a msg  */
370        OS_EXIT_CRITICAL();
371        return (OS_MBOX_FULL);
372    }
373    pevent->OSEventPtr = msg;                         /* Place message in mailbox                      */
374    OS_EXIT_CRITICAL();
375    return (OS_NO_ERR);
376}
377#endif

378
379/*$PAGE*/
380/*
381*********************************************************************************************************
382*                                       POST MESSAGE TO A MAILBOX
383*
384* Description: This function sends a message to a mailbox
385*
386* Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
387*
388*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
389*
390*              opt           determines the type of POST performed:
391*                            OS_POST_OPT_NONE         POST to a single waiting task
392*                                                     (Identical to OSMboxPost())
393*                            OS_POST_OPT_BROADCAST    POST to ALL tasks that are waiting on the mailbox
394*
395* Returns    : OS_NO_ERR            The call was successful and the message was sent
396*              OS_MBOX_FULL         If the mailbox already contains a message.  You can can only send one
397*                                   message at a time and thus, the message MUST be consumed before you
398*                                   are allowed to send another one.
399*              OS_ERR_EVENT_TYPE    If you are attempting to post to a non mailbox.
400*              OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer
401*              OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
402*
403* Note(s)    : 1) HPT means Highest Priority Task
404*
405* Warning    : Interrupts can be disabled for a long time if you do a 'broadcast'.  In fact, the
406*              interrupt disable time is proportional to the number of tasks waiting on the mailbox.
407*********************************************************************************************************
408*/
409
410#if OS_MBOX_POST_OPT_EN > 0

411INT8U  OSMboxPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
412{
413#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */

414    OS_CPU_SR  cpu_sr = 0;
415#endif

416
417
418
419#if OS_ARG_CHK_EN > 0

420    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
421        return (OS_ERR_PEVENT_NULL);
422    }
423    if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
424        return (OS_ERR_POST_NULL_PTR);
425    }
426#endif

427    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
428        return (OS_ERR_EVENT_TYPE);
429    }
430    OS_ENTER_CRITICAL();
431    if (pevent->OSEventGrp != 0) {                    /* See if any task pending on mailbox            */
432        if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* Do we need to post msg to ALL waiting tasks ? */
433            while (pevent->OSEventGrp != 0) {         /* Yes, Post to ALL tasks waiting on mailbox     */
434                (void)OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);
435            }
436        } else {
437            (void)OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);  /* No,  Post to HPT waiting on mbox     */
438        }
439        OS_EXIT_CRITICAL();
440        OS_Sched();                                            /* Find HPT ready to run                */
441        return (OS_NO_ERR);
442    }
443    if (pevent->OSEventPtr != (void *)0) {            /* Make sure mailbox doesn't already have a msg  */
444        OS_EXIT_CRITICAL();
445        return (OS_MBOX_FULL);
446    }
447    pevent->OSEventPtr = msg;                         /* Place message in mailbox                      */
448    OS_EXIT_CRITICAL();
449    return (OS_NO_ERR);
450}
451#endif

452
453/*$PAGE*/
454/*
455*********************************************************************************************************
456*                                        QUERY A MESSAGE MAILBOX
457*
458* Description: This function obtains information about a message mailbox.
459*
460* Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
461*
462*              p_mbox_data   is a pointer to a structure that will contain information about the message
463*                            mailbox.
464*
465* Returns    : OS_NO_ERR           The call was successful and the message was sent
466*              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non mailbox.
467*              OS_ERR_PEVENT_NULL  If 'pevent'      is a NULL pointer
468*              OS_ERR_PDATA_NULL   If 'p_mbox_data' is a NULL pointer
469*********************************************************************************************************
470*/
471
472#if OS_MBOX_QUERY_EN > 0

473INT8U  OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *p_mbox_data)
474{
475    INT8U      i;
476#if OS_LOWEST_PRIO <= 63

477    INT8U     *psrc;
478    INT8U     *pdest;
479#else

480    INT16U    *psrc;
481    INT16U    *pdest;
482#endif

483#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */

484    OS_CPU_SR  cpu_sr = 0;
485#endif

486
487
488
489#if OS_ARG_CHK_EN > 0

490    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
491        return (OS_ERR_PEVENT_NULL);
492    }
493    if (p_mbox_data == (OS_MBOX_DATA *)0) {                /* Validate 'p_mbox_data'                   */
494        return (OS_ERR_PDATA_NULL);
495    }
496#endif

497    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {       /* Validate event block type                */
498        return (OS_ERR_EVENT_TYPE);
499    }
500    OS_ENTER_CRITICAL();
501    p_mbox_data->OSEventGrp = pevent->OSEventGrp;          /* Copy message mailbox wait list           */
502    psrc                    = &pevent->OSEventTbl[0];
503    pdest                   = &p_mbox_data->OSEventTbl[0];
504    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
505        *pdest++ = *psrc++;
506    }
507    p_mbox_data->OSMsg = pevent->OSEventPtr;               /* Get message from mailbox                 */
508    OS_EXIT_CRITICAL();
509    return (OS_NO_ERR);
510}
511#endif                                                     /* OS_MBOX_QUERY_EN                         */

512#endif                                                     /* OS_MBOX_EN                               */