OS_SEM.C
上传用户:zfj3589
上传日期:2022-07-13
资源大小:635k
文件大小:19k
源码类别:

微处理器开发

开发平台:

C/C++

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