OS_SEM.c
上传用户:jinguanrq
上传日期:2022-06-04
资源大小:724k
文件大小:11k
源码类别:

uCOS

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                          SEMAPHORE MANAGEMENT
  6. *
  7. *                        (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
  8. *                                           All Rights Reserved
  9. *
  10. *                                                  V2.00
  11. *
  12. * File : OS_SEM.C
  13. * By   : Jean J. Labrosse
  14. *********************************************************************************************************
  15. */
  16. #ifndef  OS_MASTER_FILE
  17. #include "includes.h"
  18. #endif
  19. #if OS_SEM_EN
  20. /*
  21. *********************************************************************************************************
  22. *                                           ACCEPT SEMAPHORE
  23. *
  24. * Description: This function checks the semaphore to see if a resource is available or, if an event
  25. *              occurred.  Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
  26. *              resource is not available or the event did not occur.
  27. *
  28. * Arguments  : pevent     is a pointer to the event control block
  29. *
  30. * Returns    : >  0       if the resource is available or the event did not occur the semaphore is
  31. *                         decremented to obtain the resource.
  32. *              == 0       if the resource is not available or the event did not occur or,
  33. *                         you didn't pass a pointer to a semaphore
  34. *********************************************************************************************************
  35. */
  36. INT16U OSSemAccept (OS_EVENT *pevent)
  37. {
  38.     INT16U cnt;
  39.     OS_ENTER_CRITICAL();
  40.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
  41.         OS_EXIT_CRITICAL();
  42.         return (0);
  43.     }
  44.     cnt = pevent->OSEventCnt;
  45.     if (cnt > 0) {                                    /* See if resource is available                  */
  46.         pevent->OSEventCnt--;                         /* Yes, decrement semaphore and notify caller    */
  47.     }
  48.     OS_EXIT_CRITICAL();
  49.     return (cnt);                                     /* Return semaphore count                        */
  50. }
  51. /*$PAGE*/
  52. /*
  53. *********************************************************************************************************
  54. *                                           CREATE A SEMAPHORE
  55. *
  56. * Description: This function creates a semaphore.
  57. *
  58. * Arguments  : cnt           is the initial value for the semaphore.  If the value is 0, no resource is
  59. *                            available (or no event has occurred).  You initialize the semaphore to a 
  60. *                            non-zero value to specify how many resources are available (e.g. if you have
  61. *                            10 resources, you would initialize the semaphore to 10).
  62. *
  63. * Returns    : != (void *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  64. *                            created semaphore
  65. *              == (void *)0  if no event control blocks were available
  66. *********************************************************************************************************
  67. */
  68. OS_EVENT *OSSemCreate (INT16U cnt)
  69. {
  70.     OS_EVENT *pevent;
  71.     OS_ENTER_CRITICAL();
  72.     pevent = OSEventFreeList;                              /* Get next free event control block        */
  73.     if (OSEventFreeList != (OS_EVENT *)0) {                /* See if pool of free ECB pool was empty   */
  74.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  75.     }
  76.     OS_EXIT_CRITICAL();
  77.     if (pevent != (OS_EVENT *)0) {                         /* Get an event control block               */
  78.         pevent->OSEventType = OS_EVENT_TYPE_SEM;
  79.         pevent->OSEventCnt  = cnt;                         /* Set semaphore value                      */
  80.         OSEventWaitListInit(pevent);
  81.     }
  82.     return (pevent);
  83. }
  84. /*$PAGE*/
  85. /*
  86. *********************************************************************************************************
  87. *                                           PEND ON SEMAPHORE
  88. *
  89. * Description: This function waits for a semaphore.
  90. *
  91. * Arguments  : pevent        is a pointer to the event control block associated with the desired 
  92. *                            semaphore.
  93. *
  94. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  95. *                            wait for the resource up to the amount of time specified by this argument.  
  96. *                            If you specify 0, however, your task will wait forever at the specified 
  97. *                            semaphore or, until the resource becomes available (or the event occurs).
  98. *
  99. *              err           is a pointer to where an error message will be deposited.  Possible error
  100. *                            messages are:
  101. *
  102. *                            OS_NO_ERR          The call was successful and your task owns the resource 
  103. *                                               or, the event you are waiting for occurred.
  104. *                            OS_TIMEOUT         The semaphore was not received within the specified 
  105. *                                               timeout.
  106. *                            OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a semaphore.
  107. *                            OS_ERR_PEND_ISR    If you called this function from an ISR and the result
  108. *                                               would lead to a suspension.
  109. *
  110. * Returns    : none
  111. *********************************************************************************************************
  112. */
  113. void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  114. {
  115.     OS_ENTER_CRITICAL();
  116.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
  117.         OS_EXIT_CRITICAL();
  118.         *err = OS_ERR_EVENT_TYPE;
  119.     }
  120.     if (pevent->OSEventCnt > 0) {                     /* If sem. is positive, resource available ...   */
  121.         pevent->OSEventCnt--;                         /* ... decrement semaphore only if positive.     */
  122.         OS_EXIT_CRITICAL();
  123.         *err = OS_NO_ERR;
  124.     } else if (OSIntNesting > 0) {                    /* See if called from ISR ...                    */
  125.         OS_EXIT_CRITICAL();                           /* ... can't PEND from an ISR                    */
  126.         *err = OS_ERR_PEND_ISR;
  127.     } else {                                          /* Otherwise, must wait until event occurs       */
  128.         OSTCBCur->OSTCBStat    |= OS_STAT_SEM;        /* Resource not available, pend on semaphore     */
  129.         OSTCBCur->OSTCBDly      = timeout;            /* Store pend timeout in TCB                     */
  130.         OSEventTaskWait(pevent);                      /* Suspend task until event or timeout occurs    */
  131.         OS_EXIT_CRITICAL();
  132.         OSSched();                                    /* Find next highest priority task ready         */
  133.         OS_ENTER_CRITICAL();
  134.         if (OSTCBCur->OSTCBStat & OS_STAT_SEM) {      /* Must have timed out if still waiting for event*/
  135.             OSEventTO(pevent);
  136.             OS_EXIT_CRITICAL();
  137.             *err = OS_TIMEOUT;                        /* Indicate that didn't get event within TO      */
  138.         } else {
  139.             OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  140.             OS_EXIT_CRITICAL();
  141.             *err = OS_NO_ERR;
  142.         }
  143.     }
  144. }
  145. /*$PAGE*/
  146. /*
  147. *********************************************************************************************************
  148. *                                         POST TO A SEMAPHORE
  149. *
  150. * Description: This function signals a semaphore
  151. *
  152. * Arguments  : pevent        is a pointer to the event control block associated with the desired 
  153. *                            semaphore.
  154. *
  155. * Returns    : OS_NO_ERR          The call was successful and the semaphore was signaled.
  156. *              OS_SEM_OVF         If the semaphore count exceeded its limit.  In other words, you have 
  157. *                                 signalled the semaphore more often than you waited on it with either
  158. *                                 OSSemAccept() or OSSemPend().
  159. *              OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a semaphore
  160. *********************************************************************************************************
  161. */
  162. INT8U OSSemPost (OS_EVENT *pevent)
  163. {
  164.     OS_ENTER_CRITICAL();
  165.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  166.         OS_EXIT_CRITICAL();
  167.         return (OS_ERR_EVENT_TYPE);
  168.     }
  169.     if (pevent->OSEventGrp) {                              /* See if any task waiting for semaphore    */
  170.         OSEventTaskRdy(pevent, (void *)0, OS_STAT_SEM);    /* Ready highest prio task waiting on event */
  171.         OS_EXIT_CRITICAL();
  172.         OSSched();                                    /* Find highest priority task ready to run       */
  173.         return (OS_NO_ERR);
  174.     } else {
  175.         if (pevent->OSEventCnt < 65535) {             /* Make sure semaphore will not overflow         */
  176.             pevent->OSEventCnt++;                     /* Increment semaphore count to register event   */
  177.             OS_EXIT_CRITICAL();
  178.             return (OS_NO_ERR);
  179.         } else {                                      /* Semaphore value has reached its maximum       */
  180.             OS_EXIT_CRITICAL();
  181.             return (OS_SEM_OVF);
  182.         }
  183.     }
  184. }
  185. /*
  186. *********************************************************************************************************
  187. *                                          QUERY A SEMAPHORE
  188. *
  189. * Description: This function obtains information about a semaphore
  190. *
  191. * Arguments  : pevent        is a pointer to the event control block associated with the desired 
  192. *                            semaphore
  193. *
  194. *              pdata         is a pointer to a structure that will contain information about the 
  195. *                            semaphore.
  196. *
  197. * Returns    : OS_NO_ERR          The call was successful and the message was sent
  198. *              OS_ERR_EVENT_TYPE  If you are attempting to obtain data from a non semaphore.
  199. *********************************************************************************************************
  200. */
  201. INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)
  202. {
  203.     INT8U  i;
  204.     INT8U *psrc;
  205.     INT8U *pdest;
  206.     
  207.     
  208.     OS_ENTER_CRITICAL();
  209.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  210.         OS_EXIT_CRITICAL();
  211.         return (OS_ERR_EVENT_TYPE);
  212.     }
  213.     pdata->OSEventGrp = pevent->OSEventGrp;                /* Copy message mailbox wait list           */
  214.     psrc              = &pevent->OSEventTbl[0];
  215.     pdest             = &pdata->OSEventTbl[0];
  216.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  217.         *pdest++ = *psrc++;   
  218.     }
  219.     pdata->OSCnt      = pevent->OSEventCnt;                /* Get semaphore count                      */
  220.     OS_EXIT_CRITICAL();
  221.     return (OS_NO_ERR);
  222. }
  223. #endif