OS_SEM.C
上传用户:ssllxx2007
上传日期:2022-06-12
资源大小:784k
文件大小:19k
源码类别:

uCOS

开发平台:

C/C++

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