os_sem.c
上传用户:jingkewang
上传日期:2013-04-11
资源大小:917k
文件大小:23k
源码类别:

uCOS

开发平台:

Visual C++

  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. #ifndef  OS_MASTER_FILE
  16. #include <ucos_ii.h>
  17. #endif
  18. #if OS_SEM_EN > 0
  19. /*
  20. *********************************************************************************************************
  21. *                                           ACCEPT SEMAPHORE
  22. *
  23. * Description: This function checks the semaphore to see if a resource is available or, if an event
  24. *              occurred.  Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
  25. *              resource is not available or the event did not occur.
  26. *
  27. * Arguments  : pevent     is a pointer to the event control block
  28. *
  29. * Returns    : >  0       if the resource is available or the event did not occur the semaphore is
  30. *                         decremented to obtain the resource.
  31. *              == 0       if the resource is not available or the event did not occur or,
  32. *                         if 'pevent' is a NULL pointer or,
  33. *                         if you didn't pass a pointer to a semaphore
  34. *********************************************************************************************************
  35. */
  36. #if OS_SEM_ACCEPT_EN > 0
  37. INT16U  OSSemAccept (OS_EVENT *pevent)
  38. {
  39.     INT16U     cnt;
  40. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  41.     OS_CPU_SR  cpu_sr = 0;
  42. #endif
  43. #if OS_ARG_CHK_EN > 0
  44.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  45.         return (0);
  46.     }
  47. #endif
  48.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
  49.         return (0);
  50.     }
  51.     OS_ENTER_CRITICAL();
  52.     cnt = pevent->OSEventCnt;
  53.     if (cnt > 0) {                                    /* See if resource is available                  */
  54.         pevent->OSEventCnt--;                         /* Yes, decrement semaphore and notify caller    */
  55.     }
  56.     OS_EXIT_CRITICAL();
  57.     return (cnt);                                     /* Return semaphore count                        */
  58. }
  59. #endif
  60. /*$PAGE*/
  61. /*
  62. *********************************************************************************************************
  63. *                                           CREATE A SEMAPHORE
  64. *
  65. * Description: This function creates a semaphore.
  66. *
  67. * Arguments  : cnt           is the initial value for the semaphore.  If the value is 0, no resource is
  68. *                            available (or no event has occurred).  You initialize the semaphore to a
  69. *                            non-zero value to specify how many resources are available (e.g. if you have
  70. *                            10 resources, you would initialize the semaphore to 10).
  71. *
  72. * Returns    : != (void *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  73. *                            created semaphore
  74. *              == (void *)0  if no event control blocks were available
  75. *********************************************************************************************************
  76. */
  77. OS_EVENT  *OSSemCreate (INT16U cnt)
  78. {
  79.     OS_EVENT  *pevent;
  80. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  81.     OS_CPU_SR  cpu_sr = 0;
  82. #endif
  83.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  84.         return ((OS_EVENT *)0);                            /* ... can't CREATE from an ISR             */
  85.     }
  86.     OS_ENTER_CRITICAL();
  87.     pevent = OSEventFreeList;                              /* Get next free event control block        */
  88.     if (OSEventFreeList != (OS_EVENT *)0) {                /* See if pool of free ECB pool was empty   */
  89.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  90.     }
  91.     OS_EXIT_CRITICAL();
  92.     if (pevent != (OS_EVENT *)0) {                         /* Get an event control block               */
  93.         pevent->OSEventType    = OS_EVENT_TYPE_SEM;
  94.         pevent->OSEventCnt     = cnt;                      /* Set semaphore value                      */
  95.         pevent->OSEventPtr     = (void *)0;                /* Unlink from ECB free list                */
  96. #if OS_EVENT_NAME_SIZE > 1
  97.         pevent->OSEventName[0] = '?';                      /* Unknown name                             */
  98.         pevent->OSEventName[1] = OS_ASCII_NUL;
  99. #endif
  100.         OS_EventWaitListInit(pevent);                      /* Initialize to 'nobody waiting' on sem.   */
  101.     }
  102.     return (pevent);
  103. }
  104. /*$PAGE*/
  105. /*
  106. *********************************************************************************************************
  107. *                                         DELETE A SEMAPHORE
  108. *
  109. * Description: This function deletes a semaphore and readies all tasks pending on the semaphore.
  110. *
  111. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  112. *                            semaphore.
  113. *
  114. *              opt           determines delete options as follows:
  115. *                            opt == OS_DEL_NO_PEND   Delete semaphore ONLY if no task pending
  116. *                            opt == OS_DEL_ALWAYS    Deletes the semaphore even if tasks are waiting.
  117. *                                                    In this case, all the tasks pending will be readied.
  118. *
  119. *              err           is a pointer to an error code that can contain one of the following values:
  120. *                            OS_NO_ERR               The call was successful and the semaphore was deleted
  121. *                            OS_ERR_DEL_ISR          If you attempted to delete the semaphore from an ISR
  122. *                            OS_ERR_INVALID_OPT      An invalid option was specified
  123. *                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the semaphore
  124. *                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a semaphore
  125. *                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
  126. *
  127. * Returns    : pevent        upon error
  128. *              (OS_EVENT *)0 if the semaphore was successfully deleted.
  129. *
  130. * Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
  131. *                 the semaphore MUST check the return code of OSSemPend().
  132. *              2) OSSemAccept() callers will not know that the intended semaphore has been deleted unless
  133. *                 they check 'pevent' to see that it's a NULL pointer.
  134. *              3) This call can potentially disable interrupts for a long time.  The interrupt disable
  135. *                 time is directly proportional to the number of tasks waiting on the semaphore.
  136. *              4) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in
  137. *                 applications where the semaphore is used for mutual exclusion because the resource(s)
  138. *                 will no longer be guarded by the semaphore.
  139. *********************************************************************************************************
  140. */
  141. #if OS_SEM_DEL_EN > 0
  142. OS_EVENT  *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  143. {
  144.     BOOLEAN    tasks_waiting;
  145.     OS_EVENT  *pevent_return;
  146. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  147.     OS_CPU_SR  cpu_sr = 0;
  148. #endif
  149. #if OS_ARG_CHK_EN > 0
  150.     if (err == (INT8U *)0) {                               /* Validate 'err'                           */
  151.         return (pevent);
  152.     }
  153.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  154.         *err = OS_ERR_PEVENT_NULL;
  155.         return (pevent);
  156.     }
  157. #endif
  158.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  159.         *err = OS_ERR_EVENT_TYPE;
  160.         return (pevent);
  161.     }
  162.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  163.         *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
  164.         return (pevent);
  165.     }
  166.     OS_ENTER_CRITICAL();
  167.     if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on semaphore    */
  168.         tasks_waiting = TRUE;                              /* Yes                                      */
  169.     } else {
  170.         tasks_waiting = FALSE;                             /* No                                       */
  171.     }
  172.     switch (opt) {
  173.         case OS_DEL_NO_PEND:                               /* Delete semaphore only if no task waiting */
  174.              if (tasks_waiting == FALSE) {
  175. #if OS_EVENT_NAME_SIZE > 1
  176.                  pevent->OSEventName[0] = '?';             /* Unknown name                             */
  177.                  pevent->OSEventName[1] = OS_ASCII_NUL;
  178. #endif
  179.                  pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
  180.                  pevent->OSEventPtr     = OSEventFreeList; /* Return Event Control Block to free list  */
  181.                  pevent->OSEventCnt     = 0;
  182.                  OSEventFreeList        = pevent;          /* Get next free event control block        */
  183.                  OS_EXIT_CRITICAL();
  184.                  *err                   = OS_NO_ERR;
  185.                  pevent_return          = (OS_EVENT *)0;   /* Semaphore has been deleted               */
  186.              } else {
  187.                  OS_EXIT_CRITICAL();
  188.                  *err                   = OS_ERR_TASK_WAITING;
  189.                  pevent_return          = pevent;
  190.              }
  191.              break;
  192.         case OS_DEL_ALWAYS:                                /* Always delete the semaphore              */
  193.              while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for semaphore    */
  194.                  (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);
  195.              }
  196. #if OS_EVENT_NAME_SIZE > 1
  197.              pevent->OSEventName[0] = '?';                 /* Unknown name                             */
  198.              pevent->OSEventName[1] = OS_ASCII_NUL;
  199. #endif
  200.              pevent->OSEventType    = OS_EVENT_TYPE_UNUSED;
  201.              pevent->OSEventPtr     = OSEventFreeList;     /* Return Event Control Block to free list  */
  202.              pevent->OSEventCnt     = 0;
  203.              OSEventFreeList        = pevent;              /* Get next free event control block        */
  204.              OS_EXIT_CRITICAL();
  205.              if (tasks_waiting == TRUE) {                  /* Reschedule only if task(s) were waiting  */
  206.                  OS_Sched();                               /* Find highest priority task ready to run  */
  207.              }
  208.              *err                   = OS_NO_ERR;
  209.              pevent_return          = (OS_EVENT *)0;       /* Semaphore has been deleted               */
  210.              break;
  211.         default:
  212.              OS_EXIT_CRITICAL();
  213.              *err                   = OS_ERR_INVALID_OPT;
  214.              pevent_return          = pevent;
  215.              break;
  216.     }
  217.     return (pevent_return);
  218. }
  219. #endif
  220. /*$PAGE*/
  221. /*
  222. *********************************************************************************************************
  223. *                                           PEND ON SEMAPHORE
  224. *
  225. * Description: This function waits for a semaphore.
  226. *
  227. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  228. *                            semaphore.
  229. *
  230. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  231. *                            wait for the resource up to the amount of time specified by this argument.
  232. *                            If you specify 0, however, your task will wait forever at the specified
  233. *                            semaphore or, until the resource becomes available (or the event occurs).
  234. *
  235. *              err           is a pointer to where an error message will be deposited.  Possible error
  236. *                            messages are:
  237. *
  238. *                            OS_NO_ERR           The call was successful and your task owns the resource
  239. *                                                or, the event you are waiting for occurred.
  240. *                            OS_TIMEOUT          The semaphore was not received within the specified
  241. *                                                timeout.
  242. *                            OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore.
  243. *                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
  244. *                                                would lead to a suspension.
  245. *                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
  246. *
  247. * Returns    : none
  248. *********************************************************************************************************
  249. */
  250. void  OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  251. {
  252. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  253.     OS_CPU_SR  cpu_sr = 0;
  254. #endif
  255. #if OS_ARG_CHK_EN > 0
  256.     if (err == (INT8U *)0) {                          /* Validate 'err'                                */
  257.         return;
  258.     }
  259.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  260.         *err = OS_ERR_PEVENT_NULL;
  261.         return;
  262.     }
  263. #endif
  264.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
  265.         *err = OS_ERR_EVENT_TYPE;
  266.         return;
  267.     }
  268.     if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
  269.         *err = OS_ERR_PEND_ISR;                       /* ... can't PEND from an ISR                    */
  270.         return;
  271.     }
  272.     OS_ENTER_CRITICAL();
  273.     if (pevent->OSEventCnt > 0) {                     /* If sem. is positive, resource available ...   */
  274.         pevent->OSEventCnt--;                         /* ... decrement semaphore only if positive.     */
  275.         OS_EXIT_CRITICAL();
  276.         *err = OS_NO_ERR;
  277.         return;
  278.     }
  279.                                                       /* Otherwise, must wait until event occurs       */
  280.     OSTCBCur->OSTCBStat   |= OS_STAT_SEM;             /* Resource not available, pend on semaphore     */
  281.     OSTCBCur->OSTCBPendTO  = FALSE;
  282.     OSTCBCur->OSTCBDly     = timeout;                 /* Store pend timeout in TCB                     */
  283.     OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
  284.     OS_EXIT_CRITICAL();
  285.     OS_Sched();                                       /* Find next highest priority task ready         */
  286.     OS_ENTER_CRITICAL();
  287.     if (OSTCBCur->OSTCBPendTO == TRUE) {              /* See if we timedout                            */
  288.         OS_EventTO(pevent);
  289.         OS_EXIT_CRITICAL();
  290.         *err = OS_TIMEOUT;                            /* Indicate that didn't get event within TO      */
  291.         return;
  292.     }
  293.     OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  294.     OS_EXIT_CRITICAL();
  295.     *err = OS_NO_ERR;
  296. }
  297. /*$PAGE*/
  298. /*
  299. *********************************************************************************************************
  300. *                                         POST TO A SEMAPHORE
  301. *
  302. * Description: This function signals a semaphore
  303. *
  304. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  305. *                            semaphore.
  306. *
  307. * Returns    : OS_NO_ERR           The call was successful and the semaphore was signaled.
  308. *              OS_SEM_OVF          If the semaphore count exceeded its limit.  In other words, you have
  309. *                                  signalled the semaphore more often than you waited on it with either
  310. *                                  OSSemAccept() or OSSemPend().
  311. *              OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore
  312. *              OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
  313. *********************************************************************************************************
  314. */
  315. INT8U  OSSemPost (OS_EVENT *pevent)
  316. {
  317. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  318.     OS_CPU_SR  cpu_sr = 0;
  319. #endif
  320. #if OS_ARG_CHK_EN > 0
  321.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  322.         return (OS_ERR_PEVENT_NULL);
  323.     }
  324. #endif
  325.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  326.         return (OS_ERR_EVENT_TYPE);
  327.     }
  328.     OS_ENTER_CRITICAL();
  329.     if (pevent->OSEventGrp != 0) {                             /* See if any task waiting for semaphore*/
  330.         (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready HPT waiting on event           */
  331.         OS_EXIT_CRITICAL();
  332.         OS_Sched();                                            /* Find HPT ready to run                */
  333.         return (OS_NO_ERR);
  334.     }
  335.     if (pevent->OSEventCnt < 65535u) {                /* Make sure semaphore will not overflow         */
  336.         pevent->OSEventCnt++;                         /* Increment semaphore count to register event   */
  337.         OS_EXIT_CRITICAL();
  338.         return (OS_NO_ERR);
  339.     }
  340.     OS_EXIT_CRITICAL();                               /* Semaphore value has reached its maximum       */
  341.     return (OS_SEM_OVF);
  342. }
  343. /*$PAGE*/
  344. /*
  345. *********************************************************************************************************
  346. *                                          QUERY A SEMAPHORE
  347. *
  348. * Description: This function obtains information about a semaphore
  349. *
  350. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  351. *                            semaphore
  352. *
  353. *              p_sem_data    is a pointer to a structure that will contain information about the
  354. *                            semaphore.
  355. *
  356. * Returns    : OS_NO_ERR           The call was successful and the message was sent
  357. *              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non semaphore.
  358. *              OS_ERR_PEVENT_NULL  If 'pevent'     is a NULL pointer.
  359. *              OS_ERR_PDATA_NULL   If 'p_sem_data' is a NULL pointer
  360. *********************************************************************************************************
  361. */
  362. #if OS_SEM_QUERY_EN > 0
  363. INT8U  OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *p_sem_data)
  364. {
  365. #if OS_LOWEST_PRIO <= 63
  366.     INT8U     *psrc;
  367.     INT8U     *pdest;
  368. #else
  369.     INT16U    *psrc;
  370.     INT16U    *pdest;
  371. #endif
  372.     INT8U      i;
  373. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  374.     OS_CPU_SR  cpu_sr = 0;
  375. #endif
  376. #if OS_ARG_CHK_EN > 0
  377.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  378.         return (OS_ERR_PEVENT_NULL);
  379.     }
  380.     if (p_sem_data == (OS_SEM_DATA *)0) {                  /* Validate 'p_sem_data'                    */
  381.         return (OS_ERR_PDATA_NULL);
  382.     }
  383. #endif
  384.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  385.         return (OS_ERR_EVENT_TYPE);
  386.     }
  387.     OS_ENTER_CRITICAL();
  388.     p_sem_data->OSEventGrp = pevent->OSEventGrp;           /* Copy message mailbox wait list           */
  389.     psrc                   = &pevent->OSEventTbl[0];
  390.     pdest                  = &p_sem_data->OSEventTbl[0];
  391.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  392.         *pdest++ = *psrc++;
  393.     }
  394.     p_sem_data->OSCnt = pevent->OSEventCnt;                /* Get semaphore count                      */
  395.     OS_EXIT_CRITICAL();
  396.     return (OS_NO_ERR);
  397. }
  398. #endif                                                     /* OS_SEM_QUERY_EN                          */
  399. /*$PAGE*/
  400. /*
  401. *********************************************************************************************************
  402. *                                              SET SEMAPHORE
  403. *
  404. * Description: This function sets the semaphore count to the value specified as an argument.  Typically,
  405. *              this value would be 0.
  406. *
  407. *              You would typically use this function when a semaphore is used as a signaling mechanism
  408. *              and, you want to reset the count value.
  409. *
  410. * Arguments  : pevent     is a pointer to the event control block
  411. *
  412. *              cnt        is the new value for the semaphore count.  You would pass 0 to reset the
  413. *                         semaphore count.
  414. *
  415. *              err        is a pointer to an error code returned by the function as follows:
  416. *
  417. *                            OS_NO_ERR            The call was successful and the semaphore value was set.
  418. *                            OS_ERR_EVENT_TYPE    If you didn't pass a pointer to a semaphore.
  419. *                            OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer.
  420. *                            OS_ERR_TASK_WAITING  If tasks are waiting on the semaphore.
  421. *********************************************************************************************************
  422. */
  423. #if OS_SEM_SET_EN > 0
  424. void  OSSemSet (OS_EVENT *pevent, INT16U cnt, INT8U *err)
  425. {
  426. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  427.     OS_CPU_SR  cpu_sr = 0;
  428. #endif
  429. #if OS_ARG_CHK_EN > 0
  430.     if (err == (INT8U *)0) {                          /* Validate 'err'                                */
  431.         return;
  432.     }
  433.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  434.         *err = OS_ERR_PEVENT_NULL;
  435.         return;
  436.     }
  437. #endif
  438.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
  439.         *err = OS_ERR_EVENT_TYPE;
  440.         return;
  441.     }
  442.     OS_ENTER_CRITICAL();
  443.     *err = OS_NO_ERR;
  444.     if (pevent->OSEventCnt > 0) {                     /* See if semaphore already has a count          */
  445.         pevent->OSEventCnt = cnt;                     /* Yes, set it to the new value specified.       */
  446.     } else {                                          /* No                                            */
  447.         if (pevent->OSEventGrp == 0) {                /*      See if task(s) waiting?                  */
  448.             pevent->OSEventCnt = cnt;                 /*      No, OK to set the value                  */
  449.         } else {
  450.             *err               = OS_ERR_TASK_WAITING;
  451.         }
  452.     }
  453.     OS_EXIT_CRITICAL();
  454. }
  455. #endif
  456. #endif                                                /* OS_SEM_EN                                     */