PageRenderTime 47ms CodeModel.GetById 19ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ftk.googlecode.com/
C | 493 lines | 285 code | 37 blank | 171 comment | 70 complexity | fec2d060c56ad9b8f9a9b33dfd7a5593 MD5 | raw file
  1/*
  2*********************************************************************************************************
  3*                                                uC/OS-II
  4*                                          The Real-Time Kernel
  5*                                          SEMAPHORE MANAGEMENT
  6*
  7*                          (c) Copyright 1992-2005, Jean J. Labrosse, Weston, FL
  8*                                           All Rights Reserved
  9*
 10* File    : OS_SEM.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_SEM_EN > 0

 21/*
 22*********************************************************************************************************
 23*                                           ACCEPT SEMAPHORE
 24*
 25* Description: This function checks the semaphore to see if a resource is available or, if an event
 26*              occurred.  Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
 27*              resource is not available or the event did not occur.
 28*
 29* Arguments  : pevent     is a pointer to the event control block
 30*
 31* Returns    : >  0       if the resource is available or the event did not occur the semaphore is
 32*                         decremented to obtain the resource.
 33*              == 0       if the resource is not available or the event did not occur or,
 34*                         if 'pevent' is a NULL pointer or,
 35*                         if you didn't pass a pointer to a semaphore
 36*********************************************************************************************************
 37*/
 38
 39#if OS_SEM_ACCEPT_EN > 0

 40INT16U  OSSemAccept (OS_EVENT *pevent)
 41{
 42    INT16U     cnt;
 43#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */

 44    OS_CPU_SR  cpu_sr = 0;
 45#endif

 46
 47
 48
 49#if OS_ARG_CHK_EN > 0

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

 54    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
 55        return (0);
 56    }
 57    OS_ENTER_CRITICAL();
 58    cnt = pevent->OSEventCnt;
 59    if (cnt > 0) {                                    /* See if resource is available                  */
 60        pevent->OSEventCnt--;                         /* Yes, decrement semaphore and notify caller    */
 61    }
 62    OS_EXIT_CRITICAL();
 63    return (cnt);                                     /* Return semaphore count                        */
 64}
 65#endif

 66
 67/*$PAGE*/
 68/*
 69*********************************************************************************************************
 70*                                           CREATE A SEMAPHORE
 71*
 72* Description: This function creates a semaphore.
 73*
 74* Arguments  : cnt           is the initial value for the semaphore.  If the value is 0, no resource is
 75*                            available (or no event has occurred).  You initialize the semaphore to a
 76*                            non-zero value to specify how many resources are available (e.g. if you have
 77*                            10 resources, you would initialize the semaphore to 10).
 78*
 79* Returns    : != (void *)0  is a pointer to the event control clock (OS_EVENT) associated with the
 80*                            created semaphore
 81*              == (void *)0  if no event control blocks were available
 82*********************************************************************************************************
 83*/
 84
 85OS_EVENT  *OSSemCreate (INT16U cnt)
 86{
 87    OS_EVENT  *pevent;
 88#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */

 89    OS_CPU_SR  cpu_sr = 0;
 90#endif

 91
 92
 93
 94    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
 95        return ((OS_EVENT *)0);                            /* ... can't CREATE from an ISR             */
 96    }
 97    OS_ENTER_CRITICAL();
 98    pevent = OSEventFreeList;                              /* Get next free event control block        */
 99    if (OSEventFreeList != (OS_EVENT *)0) {                /* See if pool of free ECB pool was empty   */
100        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
101    }
102    OS_EXIT_CRITICAL();
103    if (pevent != (OS_EVENT *)0) {                         /* Get an event control block               */
104        pevent->OSEventType    = OS_EVENT_TYPE_SEM;
105        pevent->OSEventCnt     = cnt;                      /* Set semaphore value                      */
106        pevent->OSEventPtr     = (void *)0;                /* Unlink from ECB free list                */
107#if OS_EVENT_NAME_SIZE > 1

108        pevent->OSEventName[0] = '?';                      /* Unknown name                             */
109        pevent->OSEventName[1] = OS_ASCII_NUL;
110#endif

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

155OS_EVENT  *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
156{
157    BOOLEAN    tasks_waiting;
158    OS_EVENT  *pevent_return;
159#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */

160    OS_CPU_SR  cpu_sr = 0;
161#endif

162
163
164
165#if OS_ARG_CHK_EN > 0

166    if (err == (INT8U *)0) {                               /* Validate 'err'                           */
167        return (pevent);
168    }
169    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
170        *err = OS_ERR_PEVENT_NULL;
171        return (pevent);
172    }
173#endif

174    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
175        *err = OS_ERR_EVENT_TYPE;
176        return (pevent);
177    }
178    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
179        *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
180        return (pevent);
181    }
182    OS_ENTER_CRITICAL();
183    if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on semaphore    */
184        tasks_waiting = TRUE;                              /* Yes                                      */
185    } else {
186        tasks_waiting = FALSE;                             /* No                                       */
187    }
188    switch (opt) {
189        case OS_DEL_NO_PEND:                               /* Delete semaphore only if no task waiting */
190             if (tasks_waiting == FALSE) {
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                 *err                   = OS_NO_ERR;
201                 pevent_return          = (OS_EVENT *)0;   /* Semaphore has been deleted               */
202             } else {
203                 OS_EXIT_CRITICAL();
204                 *err                   = OS_ERR_TASK_WAITING;
205                 pevent_return          = pevent;
206             }
207             break;
208
209        case OS_DEL_ALWAYS:                                /* Always delete the semaphore              */
210             while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for semaphore    */
211                 (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);
212             }
213#if OS_EVENT_NAME_SIZE > 1

214             pevent->OSEventName[0] = '?';                 /* Unknown name                             */
215             pevent->OSEventName[1] = OS_ASCII_NUL;
216#endif

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

238
239/*$PAGE*/
240/*
241*********************************************************************************************************
242*                                           PEND ON SEMAPHORE
243*
244* Description: This function waits for a semaphore.
245*
246* Arguments  : pevent        is a pointer to the event control block associated with the desired
247*                            semaphore.
248*
249*              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
250*                            wait for the resource up to the amount of time specified by this argument.
251*                            If you specify 0, however, your task will wait forever at the specified
252*                            semaphore or, until the resource becomes available (or the event occurs).
253*
254*              err           is a pointer to where an error message will be deposited.  Possible error
255*                            messages are:
256*
257*                            OS_NO_ERR           The call was successful and your task owns the resource
258*                                                or, the event you are waiting for occurred.
259*                            OS_TIMEOUT          The semaphore was not received within the specified
260*                                                timeout.
261*                            OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore.
262*                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
263*                                                would lead to a suspension.
264*                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
265*
266* Returns    : none
267*********************************************************************************************************
268*/
269
270void  OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
271{
272#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */

273    OS_CPU_SR  cpu_sr = 0;
274#endif

275
276
277
278#if OS_ARG_CHK_EN > 0

279    if (err == (INT8U *)0) {                          /* Validate 'err'                                */
280        return;
281    }
282    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
283        *err = OS_ERR_PEVENT_NULL;
284        return;
285    }
286#endif

287    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
288        *err = OS_ERR_EVENT_TYPE;
289        return;
290    }
291    if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
292        *err = OS_ERR_PEND_ISR;                       /* ... can't PEND from an ISR                    */
293        return;
294    }
295    OS_ENTER_CRITICAL();
296    if (pevent->OSEventCnt > 0) {                     /* If sem. is positive, resource available ...   */
297        pevent->OSEventCnt--;                         /* ... decrement semaphore only if positive.     */
298        OS_EXIT_CRITICAL();
299        *err = OS_NO_ERR;
300        return;
301    }
302                                                      /* Otherwise, must wait until event occurs       */
303    OSTCBCur->OSTCBStat   |= OS_STAT_SEM;             /* Resource not available, pend on semaphore     */
304    OSTCBCur->OSTCBPendTO  = FALSE;
305    OSTCBCur->OSTCBDly     = timeout;                 /* Store pend timeout in TCB                     */
306    OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
307    OS_EXIT_CRITICAL();
308    OS_Sched();                                       /* Find next highest priority task ready         */
309    OS_ENTER_CRITICAL();
310    if (OSTCBCur->OSTCBPendTO == TRUE) {              /* See if we timedout                            */
311        OS_EventTO(pevent);
312        OS_EXIT_CRITICAL();
313        *err = OS_TIMEOUT;                            /* Indicate that didn't get event within TO      */
314        return;
315    }
316    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
317    OS_EXIT_CRITICAL();
318    *err = OS_NO_ERR;
319}
320/*$PAGE*/
321/*
322*********************************************************************************************************
323*                                         POST TO A SEMAPHORE
324*
325* Description: This function signals a semaphore
326*
327* Arguments  : pevent        is a pointer to the event control block associated with the desired
328*                            semaphore.
329*
330* Returns    : OS_NO_ERR           The call was successful and the semaphore was signaled.
331*              OS_SEM_OVF          If the semaphore count exceeded its limit.  In other words, you have
332*                                  signalled the semaphore more often than you waited on it with either
333*                                  OSSemAccept() or OSSemPend().
334*              OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore
335*              OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
336*********************************************************************************************************
337*/
338
339INT8U  OSSemPost (OS_EVENT *pevent)
340{
341#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */

342    OS_CPU_SR  cpu_sr = 0;
343#endif

344
345
346
347#if OS_ARG_CHK_EN > 0

348    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
349        return (OS_ERR_PEVENT_NULL);
350    }
351#endif

352    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
353        return (OS_ERR_EVENT_TYPE);
354    }
355    OS_ENTER_CRITICAL();
356    if (pevent->OSEventGrp != 0) {                             /* See if any task waiting for semaphore*/
357        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready HPT waiting on event           */
358        OS_EXIT_CRITICAL();
359        OS_Sched();                                            /* Find HPT ready to run                */
360        return (OS_NO_ERR);
361    }
362    if (pevent->OSEventCnt < 65535u) {                /* Make sure semaphore will not overflow         */
363        pevent->OSEventCnt++;                         /* Increment semaphore count to register event   */
364        OS_EXIT_CRITICAL();
365        return (OS_NO_ERR);
366    }
367    OS_EXIT_CRITICAL();                               /* Semaphore value has reached its maximum       */
368    return (OS_SEM_OVF);
369}
370/*$PAGE*/
371/*
372*********************************************************************************************************
373*                                          QUERY A SEMAPHORE
374*
375* Description: This function obtains information about a semaphore
376*
377* Arguments  : pevent        is a pointer to the event control block associated with the desired
378*                            semaphore
379*
380*              p_sem_data    is a pointer to a structure that will contain information about the
381*                            semaphore.
382*
383* Returns    : OS_NO_ERR           The call was successful and the message was sent
384*              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non semaphore.
385*              OS_ERR_PEVENT_NULL  If 'pevent'     is a NULL pointer.
386*              OS_ERR_PDATA_NULL   If 'p_sem_data' is a NULL pointer
387*********************************************************************************************************
388*/
389
390#if OS_SEM_QUERY_EN > 0

391INT8U  OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *p_sem_data)
392{
393#if OS_LOWEST_PRIO <= 63

394    INT8U     *psrc;
395    INT8U     *pdest;
396#else

397    INT16U    *psrc;
398    INT16U    *pdest;
399#endif

400    INT8U      i;
401#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */

402    OS_CPU_SR  cpu_sr = 0;
403#endif

404
405
406
407#if OS_ARG_CHK_EN > 0

408    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
409        return (OS_ERR_PEVENT_NULL);
410    }
411    if (p_sem_data == (OS_SEM_DATA *)0) {                  /* Validate 'p_sem_data'                    */
412        return (OS_ERR_PDATA_NULL);
413    }
414#endif

415    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
416        return (OS_ERR_EVENT_TYPE);
417    }
418    OS_ENTER_CRITICAL();
419    p_sem_data->OSEventGrp = pevent->OSEventGrp;           /* Copy message mailbox wait list           */
420    psrc                   = &pevent->OSEventTbl[0];
421    pdest                  = &p_sem_data->OSEventTbl[0];
422    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
423        *pdest++ = *psrc++;
424    }
425    p_sem_data->OSCnt = pevent->OSEventCnt;                /* Get semaphore count                      */
426    OS_EXIT_CRITICAL();
427    return (OS_NO_ERR);
428}
429#endif                                                     /* OS_SEM_QUERY_EN                          */

430
431/*$PAGE*/
432/*
433*********************************************************************************************************
434*                                              SET SEMAPHORE
435*
436* Description: This function sets the semaphore count to the value specified as an argument.  Typically,
437*              this value would be 0.
438*
439*              You would typically use this function when a semaphore is used as a signaling mechanism
440*              and, you want to reset the count value.
441*
442* Arguments  : pevent     is a pointer to the event control block
443*
444*              cnt        is the new value for the semaphore count.  You would pass 0 to reset the
445*                         semaphore count.
446*
447*              err        is a pointer to an error code returned by the function as follows:
448*
449*                            OS_NO_ERR            The call was successful and the semaphore value was set.
450*                            OS_ERR_EVENT_TYPE    If you didn't pass a pointer to a semaphore.
451*                            OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer.
452*                            OS_ERR_TASK_WAITING  If tasks are waiting on the semaphore.
453*********************************************************************************************************
454*/
455
456#if OS_SEM_SET_EN > 0

457void  OSSemSet (OS_EVENT *pevent, INT16U cnt, INT8U *err)
458{
459#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */

460    OS_CPU_SR  cpu_sr = 0;
461#endif

462
463
464
465#if OS_ARG_CHK_EN > 0

466    if (err == (INT8U *)0) {                          /* Validate 'err'                                */
467        return;
468    }
469    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
470        *err = OS_ERR_PEVENT_NULL;
471        return;
472    }
473#endif

474    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
475        *err = OS_ERR_EVENT_TYPE;
476        return;
477    }
478    OS_ENTER_CRITICAL();
479    *err = OS_NO_ERR;
480    if (pevent->OSEventCnt > 0) {                     /* See if semaphore already has a count          */
481        pevent->OSEventCnt = cnt;                     /* Yes, set it to the new value specified.       */
482    } else {                                          /* No                                            */
483        if (pevent->OSEventGrp == 0) {                /*      See if task(s) waiting?                  */
484            pevent->OSEventCnt = cnt;                 /*      No, OK to set the value                  */
485        } else {
486            *err               = OS_ERR_TASK_WAITING;
487        }
488    }
489    OS_EXIT_CRITICAL();
490}
491#endif

492
493#endif                                                /* OS_SEM_EN                                     */