os_sem.c
上传用户:zbk8730
上传日期:2017-08-10
资源大小:12168k
文件大小:23k
源码类别:

uCOS

开发平台:

C/C++

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                          SEMAPHORE MANAGEMENT
  6. *
  7. *                          (c) Copyright 1992-2006, Jean J. Labrosse, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File    : OS_SEM.C
  11. * By      : Jean J. Labrosse
  12. * Version : V2.83
  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 = OS_TRUE;                           /* Yes                                      */
  169.     } else {
  170.         tasks_waiting = OS_FALSE;                          /* No                                       */
  171.     }
  172.     switch (opt) {
  173.         case OS_DEL_NO_PEND:                               /* Delete semaphore only if no task waiting */
  174.              if (tasks_waiting == OS_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 == OS_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.     if (OSLockNesting > 0) {                          /* See if called with scheduler locked ...       */
  273.         *err = OS_ERR_PEND_LOCKED;                    /* ... can't PEND when locked                    */
  274.         return;
  275.     }
  276.     OS_ENTER_CRITICAL();
  277.     if (pevent->OSEventCnt > 0) {                     /* If sem. is positive, resource available ...   */
  278.         pevent->OSEventCnt--;                         /* ... decrement semaphore only if positive.     */
  279.         OS_EXIT_CRITICAL();
  280.         *err = OS_NO_ERR;
  281.         return;
  282.     }
  283.                                                       /* Otherwise, must wait until event occurs       */
  284.     OSTCBCur->OSTCBStat   |= OS_STAT_SEM;             /* Resource not available, pend on semaphore     */
  285.     OSTCBCur->OSTCBPendTO  = OS_FALSE;
  286.     OSTCBCur->OSTCBDly     = timeout;                 /* Store pend timeout in TCB                     */
  287.     OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
  288.     OS_EXIT_CRITICAL();
  289.     OS_Sched();                                       /* Find next highest priority task ready         */
  290.     OS_ENTER_CRITICAL();
  291.     if (OSTCBCur->OSTCBPendTO == OS_TRUE) {           /* See if we timedout                            */
  292.         OS_EventTO(pevent);
  293.         OS_EXIT_CRITICAL();
  294.         *err = OS_TIMEOUT;                            /* Indicate that didn't get event within TO      */
  295.         return;
  296.     }
  297.     OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  298.     OS_EXIT_CRITICAL();
  299.     *err = OS_NO_ERR;
  300. }
  301. /*$PAGE*/
  302. /*
  303. *********************************************************************************************************
  304. *                                         POST TO A SEMAPHORE
  305. *
  306. * Description: This function signals a semaphore
  307. *
  308. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  309. *                            semaphore.
  310. *
  311. * Returns    : OS_NO_ERR           The call was successful and the semaphore was signaled.
  312. *              OS_SEM_OVF          If the semaphore count exceeded its limit.  In other words, you have
  313. *                                  signalled the semaphore more often than you waited on it with either
  314. *                                  OSSemAccept() or OSSemPend().
  315. *              OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore
  316. *              OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
  317. *********************************************************************************************************
  318. */
  319. INT8U  OSSemPost (OS_EVENT *pevent)
  320. {
  321. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  322.     OS_CPU_SR  cpu_sr = 0;
  323. #endif
  324. #if OS_ARG_CHK_EN > 0
  325.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  326.         return (OS_ERR_PEVENT_NULL);
  327.     }
  328. #endif
  329.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  330.         return (OS_ERR_EVENT_TYPE);
  331.     }
  332.     OS_ENTER_CRITICAL();
  333.     if (pevent->OSEventGrp != 0) {                             /* See if any task waiting for semaphore*/
  334.         (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready HPT waiting on event           */
  335.         OS_EXIT_CRITICAL();
  336.         OS_Sched();                                            /* Find HPT ready to run                */
  337.         return (OS_NO_ERR);
  338.     }
  339.     if (pevent->OSEventCnt < 65535u) {                /* Make sure semaphore will not overflow         */
  340.         pevent->OSEventCnt++;                         /* Increment semaphore count to register event   */
  341.         OS_EXIT_CRITICAL();
  342.         return (OS_NO_ERR);
  343.     }
  344.     OS_EXIT_CRITICAL();                               /* Semaphore value has reached its maximum       */
  345.     return (OS_SEM_OVF);
  346. }
  347. /*$PAGE*/
  348. /*
  349. *********************************************************************************************************
  350. *                                          QUERY A SEMAPHORE
  351. *
  352. * Description: This function obtains information about a semaphore
  353. *
  354. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  355. *                            semaphore
  356. *
  357. *              p_sem_data    is a pointer to a structure that will contain information about the
  358. *                            semaphore.
  359. *
  360. * Returns    : OS_NO_ERR           The call was successful and the message was sent
  361. *              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non semaphore.
  362. *              OS_ERR_PEVENT_NULL  If 'pevent'     is a NULL pointer.
  363. *              OS_ERR_PDATA_NULL   If 'p_sem_data' is a NULL pointer
  364. *********************************************************************************************************
  365. */
  366. #if OS_SEM_QUERY_EN > 0
  367. INT8U  OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *p_sem_data)
  368. {
  369. #if OS_LOWEST_PRIO <= 63
  370.     INT8U     *psrc;
  371.     INT8U     *pdest;
  372. #else
  373.     INT16U    *psrc;
  374.     INT16U    *pdest;
  375. #endif
  376.     INT8U      i;
  377. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  378.     OS_CPU_SR  cpu_sr = 0;
  379. #endif
  380. #if OS_ARG_CHK_EN > 0
  381.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  382.         return (OS_ERR_PEVENT_NULL);
  383.     }
  384.     if (p_sem_data == (OS_SEM_DATA *)0) {                  /* Validate 'p_sem_data'                    */
  385.         return (OS_ERR_PDATA_NULL);
  386.     }
  387. #endif
  388.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {        /* Validate event block type                */
  389.         return (OS_ERR_EVENT_TYPE);
  390.     }
  391.     OS_ENTER_CRITICAL();
  392.     p_sem_data->OSEventGrp = pevent->OSEventGrp;           /* Copy message mailbox wait list           */
  393.     psrc                   = &pevent->OSEventTbl[0];
  394.     pdest                  = &p_sem_data->OSEventTbl[0];
  395.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  396.         *pdest++ = *psrc++;
  397.     }
  398.     p_sem_data->OSCnt = pevent->OSEventCnt;                /* Get semaphore count                      */
  399.     OS_EXIT_CRITICAL();
  400.     return (OS_NO_ERR);
  401. }
  402. #endif                                                     /* OS_SEM_QUERY_EN                          */
  403. /*$PAGE*/
  404. /*
  405. *********************************************************************************************************
  406. *                                              SET SEMAPHORE
  407. *
  408. * Description: This function sets the semaphore count to the value specified as an argument.  Typically,
  409. *              this value would be 0.
  410. *
  411. *              You would typically use this function when a semaphore is used as a signaling mechanism
  412. *              and, you want to reset the count value.
  413. *
  414. * Arguments  : pevent     is a pointer to the event control block
  415. *
  416. *              cnt        is the new value for the semaphore count.  You would pass 0 to reset the
  417. *                         semaphore count.
  418. *
  419. *              err        is a pointer to an error code returned by the function as follows:
  420. *
  421. *                            OS_NO_ERR            The call was successful and the semaphore value was set.
  422. *                            OS_ERR_EVENT_TYPE    If you didn't pass a pointer to a semaphore.
  423. *                            OS_ERR_PEVENT_NULL   If 'pevent' is a NULL pointer.
  424. *                            OS_ERR_TASK_WAITING  If tasks are waiting on the semaphore.
  425. *********************************************************************************************************
  426. */
  427. #if OS_SEM_SET_EN > 0
  428. void  OSSemSet (OS_EVENT *pevent, INT16U cnt, INT8U *err)
  429. {
  430. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  431.     OS_CPU_SR  cpu_sr = 0;
  432. #endif
  433. #if OS_ARG_CHK_EN > 0
  434.     if (err == (INT8U *)0) {                          /* Validate 'err'                                */
  435.         return;
  436.     }
  437.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  438.         *err = OS_ERR_PEVENT_NULL;
  439.         return;
  440.     }
  441. #endif
  442.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   /* Validate event block type                     */
  443.         *err = OS_ERR_EVENT_TYPE;
  444.         return;
  445.     }
  446.     OS_ENTER_CRITICAL();
  447.     *err = OS_NO_ERR;
  448.     if (pevent->OSEventCnt > 0) {                     /* See if semaphore already has a count          */
  449.         pevent->OSEventCnt = cnt;                     /* Yes, set it to the new value specified.       */
  450.     } else {                                          /* No                                            */
  451.         if (pevent->OSEventGrp == 0) {                /*      See if task(s) waiting?                  */
  452.             pevent->OSEventCnt = cnt;                 /*      No, OK to set the value                  */
  453.         } else {
  454.             *err               = OS_ERR_TASK_WAITING;
  455.         }
  456.     }
  457.     OS_EXIT_CRITICAL();
  458. }
  459. #endif
  460. #endif                                                /* OS_SEM_EN                                     */