os_sem.c
上传用户:yyyd609
上传日期:2022-07-18
资源大小:183k
文件大小:23k
源码类别:

微处理器开发

开发平台:

C/C++

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