os_mutex.c
上传用户:dongxin
上传日期:2022-06-22
资源大小:370k
文件大小:37k
源码类别:

uCOS

开发平台:

Others

  1. /*
  2. *********************************************************************************************************
  3. *                                                uC/OS-II
  4. *                                          The Real-Time Kernel
  5. *                                  MUTUAL EXCLUSION SEMAPHORE MANAGEMENT
  6. *
  7. *                              (c) Copyright 1992-2007, Micrium, Weston, FL
  8. *                                           All Rights Reserved
  9. *
  10. * File    : OS_MUTEX.C
  11. * By      : Jean J. Labrosse
  12. * Version : V2.86
  13. *
  14. * LICENSING TERMS:
  15. * ---------------
  16. *   uC/OS-II is provided in source form for FREE evaluation, for educational use or for peaceful research.  
  17. * If you plan on using  uC/OS-II  in a commercial product you need to contact Micri祄 to properly license 
  18. * its use in your product. We provide ALL the source code for your convenience and to help you experience 
  19. * uC/OS-II.   The fact that the  source is provided does  NOT  mean that you can use it without  paying a 
  20. * licensing fee.
  21. *********************************************************************************************************
  22. */
  23. #ifndef  OS_MASTER_FILE
  24. #include <ucos_ii.h>
  25. #endif
  26. #if OS_MUTEX_EN > 0
  27. /*
  28. *********************************************************************************************************
  29. *                                            LOCAL CONSTANTS
  30. *********************************************************************************************************
  31. */
  32. #define  OS_MUTEX_KEEP_LOWER_8   ((INT16U)0x00FFu)
  33. #define  OS_MUTEX_KEEP_UPPER_8   ((INT16U)0xFF00u)
  34. #define  OS_MUTEX_AVAILABLE      ((INT16U)0x00FFu)
  35. /*
  36. *********************************************************************************************************
  37. *                                            LOCAL CONSTANTS
  38. *********************************************************************************************************
  39. */
  40. static  void  OSMutex_RdyAtPrio(OS_TCB *ptcb, INT8U prio);
  41. /*$PAGE*/
  42. /*
  43. *********************************************************************************************************
  44. *                                   ACCEPT MUTUAL EXCLUSION SEMAPHORE
  45. *
  46. * Description: This  function checks the mutual exclusion semaphore to see if a resource is available.
  47. *              Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is
  48. *              not available or the event did not occur.
  49. *
  50. * Arguments  : pevent     is a pointer to the event control block
  51. *
  52. *              perr       is a pointer to an error code which will be returned to your application:
  53. *                            OS_ERR_NONE         if the call was successful.
  54. *                            OS_ERR_EVENT_TYPE   if 'pevent' is not a pointer to a mutex
  55. *                            OS_ERR_PEVENT_NULL  'pevent' is a NULL pointer
  56. *                            OS_ERR_PEND_ISR     if you called this function from an ISR
  57. *                            OS_ERR_PIP_LOWER    If the priority of the task that owns the Mutex is
  58. *                                                HIGHER (i.e. a lower number) than the PIP.  This error
  59. *                                                indicates that you did not set the PIP higher (lower
  60. *                                                number) than ALL the tasks that compete for the Mutex.
  61. *                                                Unfortunately, this is something that could not be
  62. *                                                detected when the Mutex is created because we don't know
  63. *                                                what tasks will be using the Mutex.
  64. *
  65. * Returns    : == OS_TRUE    if the resource is available, the mutual exclusion semaphore is acquired
  66. *              == OS_FALSE   a) if the resource is not available
  67. *                            b) you didn't pass a pointer to a mutual exclusion semaphore
  68. *                            c) you called this function from an ISR
  69. *
  70. * Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are
  71. *              intended to be used by tasks only.
  72. *********************************************************************************************************
  73. */
  74. #if OS_MUTEX_ACCEPT_EN > 0
  75. BOOLEAN  OSMutexAccept (OS_EVENT *pevent, INT8U *perr)
  76. {
  77.     INT8U      pip;                                    /* Priority Inheritance Priority (PIP)          */
  78. #if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
  79.     OS_CPU_SR  cpu_sr = 0;
  80. #endif
  81. #if OS_ARG_CHK_EN > 0
  82.     if (perr == (INT8U *)0) {                          /* Validate 'perr'                              */
  83.         return (OS_FALSE);
  84.     }
  85.     if (pevent == (OS_EVENT *)0) {                     /* Validate 'pevent'                            */
  86.         *perr = OS_ERR_PEVENT_NULL;
  87.         return (OS_FALSE);
  88.     }
  89. #endif
  90.     if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {  /* Validate event block type                    */
  91.         *perr = OS_ERR_EVENT_TYPE;
  92.         return (OS_FALSE);
  93.     }
  94.     if (OSIntNesting > 0) {                            /* Make sure it's not called from an ISR        */
  95.         *perr = OS_ERR_PEND_ISR;
  96.         return (OS_FALSE);
  97.     }
  98.     OS_ENTER_CRITICAL();                               /* Get value (0 or 1) of Mutex                  */
  99.     pip = (INT8U)(pevent->OSEventCnt >> 8);            /* Get PIP from mutex                           */
  100.     if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
  101.         pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;   /*      Mask off LSByte (Acquire Mutex)         */
  102.         pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;     /*      Save current task priority in LSByte    */
  103.         pevent->OSEventPtr  = (void *)OSTCBCur;        /*      Link TCB of task owning Mutex           */
  104.         if (OSTCBCur->OSTCBPrio <= pip) {              /*      PIP 'must' have a SMALLER prio ...      */
  105.             OS_EXIT_CRITICAL();                        /*      ... than current task!                  */
  106.             *perr = OS_ERR_PIP_LOWER;
  107.         } else {
  108.             OS_EXIT_CRITICAL();
  109.             *perr = OS_ERR_NONE;
  110.         }
  111.         return (OS_TRUE);
  112.     }
  113.     OS_EXIT_CRITICAL();
  114.     *perr = OS_ERR_NONE;
  115.     return (OS_FALSE);
  116. }
  117. #endif
  118. /*$PAGE*/
  119. /*
  120. *********************************************************************************************************
  121. *                                  CREATE A MUTUAL EXCLUSION SEMAPHORE
  122. *
  123. * Description: This function creates a mutual exclusion semaphore.
  124. *
  125. * Arguments  : prio          is the priority to use when accessing the mutual exclusion semaphore.  In
  126. *                            other words, when the semaphore is acquired and a higher priority task
  127. *                            attempts to obtain the semaphore then the priority of the task owning the
  128. *                            semaphore is raised to this priority.  It is assumed that you will specify
  129. *                            a priority that is LOWER in value than ANY of the tasks competing for the
  130. *                            mutex.
  131. *
  132. *              perr          is a pointer to an error code which will be returned to your application:
  133. *                               OS_ERR_NONE         if the call was successful.
  134. *                               OS_ERR_CREATE_ISR   if you attempted to create a MUTEX from an ISR
  135. *                               OS_ERR_PRIO_EXIST   if a task at the priority inheritance priority
  136. *                                                   already exist.
  137. *                               OS_ERR_PEVENT_NULL  No more event control blocks available.
  138. *                               OS_ERR_PRIO_INVALID if the priority you specify is higher that the
  139. *                                                   maximum allowed (i.e. > OS_LOWEST_PRIO)
  140. *
  141. * Returns    : != (void *)0  is a pointer to the event control clock (OS_EVENT) associated with the
  142. *                            created mutex.
  143. *              == (void *)0  if an error is detected.
  144. *
  145. * Note(s)    : 1) The LEAST significant 8 bits of '.OSEventCnt' are used to hold the priority number
  146. *                 of the task owning the mutex or 0xFF if no task owns the mutex.
  147. *
  148. *              2) The MOST  significant 8 bits of '.OSEventCnt' are used to hold the priority number
  149. *                 to use to reduce priority inversion.
  150. *********************************************************************************************************
  151. */
  152. OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *perr)
  153. {
  154.     OS_EVENT  *pevent;
  155. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  156.     OS_CPU_SR  cpu_sr = 0;
  157. #endif
  158. #if OS_ARG_CHK_EN > 0
  159.     if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */
  160.         return ((OS_EVENT *)0);
  161.     }
  162.     if (prio >= OS_LOWEST_PRIO) {                          /* Validate PIP                             */
  163.         *perr = OS_ERR_PRIO_INVALID;
  164.         return ((OS_EVENT *)0);
  165.     }
  166. #endif
  167.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  168.         *perr = OS_ERR_CREATE_ISR;                         /* ... can't CREATE mutex from an ISR       */
  169.         return ((OS_EVENT *)0);
  170.     }
  171.     OS_ENTER_CRITICAL();
  172.     if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {               /* Mutex priority must not already exist    */
  173.         OS_EXIT_CRITICAL();                                /* Task already exist at priority ...       */
  174.         *perr = OS_ERR_PRIO_EXIST;                         /* ... inheritance priority                 */
  175.         return ((OS_EVENT *)0);
  176.     }
  177.     OSTCBPrioTbl[prio] = OS_TCB_RESERVED;                  /* Reserve the table entry                  */
  178.     pevent             = OSEventFreeList;                  /* Get next free event control block        */
  179.     if (pevent == (OS_EVENT *)0) {                         /* See if an ECB was available              */
  180.         OSTCBPrioTbl[prio] = (OS_TCB *)0;                  /* No, Release the table entry              */
  181.         OS_EXIT_CRITICAL();
  182.         *perr              = OS_ERR_PEVENT_NULL;           /* No more event control blocks             */
  183.         return (pevent);
  184.     }
  185.     OSEventFreeList        = (OS_EVENT *)OSEventFreeList->OSEventPtr;   /* Adjust the free list        */
  186.     OS_EXIT_CRITICAL();
  187.     pevent->OSEventType    = OS_EVENT_TYPE_MUTEX;
  188.     pevent->OSEventCnt     = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE; /* Resource is avail.   */
  189.     pevent->OSEventPtr     = (void *)0;                                 /* No task owning the mutex    */
  190. #if OS_EVENT_NAME_SIZE > 1
  191.     pevent->OSEventName[0] = '?';
  192.     pevent->OSEventName[1] = OS_ASCII_NUL;
  193. #endif
  194.     OS_EventWaitListInit(pevent);
  195.     *perr                  = OS_ERR_NONE;
  196.     return (pevent);
  197. }
  198. /*$PAGE*/
  199. /*
  200. *********************************************************************************************************
  201. *                                          DELETE A MUTEX
  202. *
  203. * Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it.
  204. *
  205. * Arguments  : pevent        is a pointer to the event control block associated with the desired mutex.
  206. *
  207. *              opt           determines delete options as follows:
  208. *                            opt == OS_DEL_NO_PEND   Delete mutex ONLY if no task pending
  209. *                            opt == OS_DEL_ALWAYS    Deletes the mutex even if tasks are waiting.
  210. *                                                    In this case, all the tasks pending will be readied.
  211. *
  212. *              perr          is a pointer to an error code that can contain one of the following values:
  213. *                            OS_ERR_NONE             The call was successful and the mutex was deleted
  214. *                            OS_ERR_DEL_ISR          If you attempted to delete the MUTEX from an ISR
  215. *                            OS_ERR_INVALID_OPT      An invalid option was specified
  216. *                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the mutex
  217. *                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a mutex
  218. *                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
  219. *
  220. * Returns    : pevent        upon error
  221. *              (OS_EVENT *)0 if the mutex was successfully deleted.
  222. *
  223. * Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
  224. *                 the mutex MUST check the return code of OSMutexPend().
  225. *
  226. *              2) This call can potentially disable interrupts for a long time.  The interrupt disable
  227. *                 time is directly proportional to the number of tasks waiting on the mutex.
  228. *
  229. *              3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the
  230. *                 resource(s) will no longer be guarded by the mutex.
  231. *
  232. *              4) IMPORTANT: In the 'OS_DEL_ALWAYS' case, we assume that the owner of the Mutex (if there
  233. *                            is one) is ready-to-run and is thus NOT pending on another kernel object or
  234. *                            has delayed itself.  In other words, if a task owns the mutex being deleted,
  235. *                            that task will be made ready-to-run at its original priority.
  236. *********************************************************************************************************
  237. */
  238. #if OS_MUTEX_DEL_EN
  239. OS_EVENT  *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *perr)
  240. {
  241.     BOOLEAN    tasks_waiting;
  242.     OS_EVENT  *pevent_return;
  243.     INT8U      pip;                                        /* Priority inheritance priority            */
  244.     INT8U      prio;
  245.     OS_TCB    *ptcb;
  246. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  247.     OS_CPU_SR  cpu_sr = 0;
  248. #endif
  249. #if OS_ARG_CHK_EN > 0
  250.     if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */
  251.         return (pevent);
  252.     }
  253.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  254.         *perr = OS_ERR_PEVENT_NULL;
  255.         return (pevent);
  256.     }
  257. #endif
  258.     if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
  259.         *perr = OS_ERR_EVENT_TYPE;
  260.         return (pevent);
  261.     }
  262.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  263.         *perr = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
  264.         return (pevent);
  265.     }
  266.     OS_ENTER_CRITICAL();
  267.     if (pevent->OSEventGrp != 0) {                         /* See if any tasks waiting on mutex        */
  268.         tasks_waiting = OS_TRUE;                           /* Yes                                      */
  269.     } else {
  270.         tasks_waiting = OS_FALSE;                          /* No                                       */
  271.     }
  272.     switch (opt) {
  273.         case OS_DEL_NO_PEND:                               /* DELETE MUTEX ONLY IF NO TASK WAITING --- */
  274.              if (tasks_waiting == OS_FALSE) {
  275. #if OS_EVENT_NAME_SIZE > 1
  276.                  pevent->OSEventName[0] = '?';             /* Unknown name                             */
  277.                  pevent->OSEventName[1] = OS_ASCII_NUL;
  278. #endif
  279.                  pip                 = (INT8U)(pevent->OSEventCnt >> 8);
  280.                  OSTCBPrioTbl[pip]   = (OS_TCB *)0;        /* Free up the PIP                          */
  281.                  pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  282.                  pevent->OSEventPtr  = OSEventFreeList;    /* Return Event Control Block to free list  */
  283.                  pevent->OSEventCnt  = 0;
  284.                  OSEventFreeList     = pevent;
  285.                  OS_EXIT_CRITICAL();
  286.                  *perr               = OS_ERR_NONE;
  287.                  pevent_return       = (OS_EVENT *)0;      /* Mutex has been deleted                   */
  288.              } else {
  289.                  OS_EXIT_CRITICAL();
  290.                  *perr               = OS_ERR_TASK_WAITING;
  291.                  pevent_return       = pevent;
  292.              }
  293.              break;
  294.         case OS_DEL_ALWAYS:                                /* ALWAYS DELETE THE MUTEX ---------------- */
  295.              pip  = (INT8U)(pevent->OSEventCnt >> 8);                     /* Get PIP of mutex          */
  296.              prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  /* Get owner's original prio */
  297.              ptcb = (OS_TCB *)pevent->OSEventPtr;
  298.              if (ptcb != (OS_TCB *)0) {                    /* See if any task owns the mutex           */
  299.                  if (ptcb->OSTCBPrio == pip) {             /* See if original prio was changed         */
  300.                      OSMutex_RdyAtPrio(ptcb, prio);        /* Yes, Restore the task's original prio    */
  301.                  }
  302.              }
  303.              while (pevent->OSEventGrp != 0) {             /* Ready ALL tasks waiting for mutex        */
  304.                  (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
  305.              }
  306. #if OS_EVENT_NAME_SIZE > 1
  307.              pevent->OSEventName[0] = '?';                 /* Unknown name                             */
  308.              pevent->OSEventName[1] = OS_ASCII_NUL;
  309. #endif
  310.              pip                 = (INT8U)(pevent->OSEventCnt >> 8);
  311.              OSTCBPrioTbl[pip]   = (OS_TCB *)0;            /* Free up the PIP                          */
  312.              pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  313.              pevent->OSEventPtr  = OSEventFreeList;        /* Return Event Control Block to free list  */
  314.              pevent->OSEventCnt  = 0;
  315.              OSEventFreeList     = pevent;                 /* Get next free event control block        */
  316.              OS_EXIT_CRITICAL();
  317.              if (tasks_waiting == OS_TRUE) {               /* Reschedule only if task(s) were waiting  */
  318.                  OS_Sched();                               /* Find highest priority task ready to run  */
  319.              }
  320.              *perr         = OS_ERR_NONE;
  321.              pevent_return = (OS_EVENT *)0;                /* Mutex has been deleted                   */
  322.              break;
  323.         default:
  324.              OS_EXIT_CRITICAL();
  325.              *perr         = OS_ERR_INVALID_OPT;
  326.              pevent_return = pevent;
  327.              break;
  328.     }
  329.     return (pevent_return);
  330. }
  331. #endif
  332. /*$PAGE*/
  333. /*
  334. *********************************************************************************************************
  335. *                                  PEND ON MUTUAL EXCLUSION SEMAPHORE
  336. *
  337. * Description: This function waits for a mutual exclusion semaphore.
  338. *
  339. * Arguments  : pevent        is a pointer to the event control block associated with the desired
  340. *                            mutex.
  341. *
  342. *              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
  343. *                            wait for the resource up to the amount of time specified by this argument.
  344. *                            If you specify 0, however, your task will wait forever at the specified
  345. *                            mutex or, until the resource becomes available.
  346. *
  347. *              perr          is a pointer to where an error message will be deposited.  Possible error
  348. *                            messages are:
  349. *                               OS_ERR_NONE        The call was successful and your task owns the mutex
  350. *                               OS_ERR_TIMEOUT     The mutex was not available within the specified 'timeout'.
  351. *                               OS_ERR_PEND_ABORT  The wait on the mutex was aborted.
  352. *                               OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a mutex
  353. *                               OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
  354. *                               OS_ERR_PEND_ISR    If you called this function from an ISR and the result
  355. *                                                  would lead to a suspension.
  356. *                               OS_ERR_PIP_LOWER   If the priority of the task that owns the Mutex is
  357. *                                                  HIGHER (i.e. a lower number) than the PIP.  This error
  358. *                                                  indicates that you did not set the PIP higher (lower
  359. *                                                  number) than ALL the tasks that compete for the Mutex.
  360. *                                                  Unfortunately, this is something that could not be
  361. *                                                  detected when the Mutex is created because we don't know
  362. *                                                  what tasks will be using the Mutex.
  363. *                               OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
  364. *
  365. * Returns    : none
  366. *
  367. * Note(s)    : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex.
  368. *
  369. *              2) You MUST NOT change the priority of the task that owns the mutex
  370. *********************************************************************************************************
  371. */
  372. void  OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
  373. {
  374.     INT8U      pip;                                        /* Priority Inheritance Priority (PIP)      */
  375.     INT8U      mprio;                                      /* Mutex owner priority                     */
  376.     BOOLEAN    rdy;                                        /* Flag indicating task was ready           */
  377.     OS_TCB    *ptcb;
  378.     OS_EVENT  *pevent2;
  379.     INT8U      y;
  380. #if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
  381.     OS_CPU_SR  cpu_sr = 0;
  382. #endif
  383. #if OS_ARG_CHK_EN > 0
  384.     if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */
  385.         return;
  386.     }
  387.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  388.         *perr = OS_ERR_PEVENT_NULL;
  389.         return;
  390.     }
  391. #endif
  392.     if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
  393.         *perr = OS_ERR_EVENT_TYPE;
  394.         return;
  395.     }
  396.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  397.         *perr = OS_ERR_PEND_ISR;                           /* ... can't PEND from an ISR               */
  398.         return;
  399.     }
  400.     if (OSLockNesting > 0) {                               /* See if called with scheduler locked ...  */
  401.         *perr = OS_ERR_PEND_LOCKED;                        /* ... can't PEND when locked               */
  402.         return;
  403.     }
  404. /*$PAGE*/
  405.     OS_ENTER_CRITICAL();
  406.     pip = (INT8U)(pevent->OSEventCnt >> 8);                /* Get PIP from mutex                       */
  407.                                                            /* Is Mutex available?                      */
  408.     if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
  409.         pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;       /* Yes, Acquire the resource                */
  410.         pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;         /*      Save priority of owning task        */
  411.         pevent->OSEventPtr  = (void *)OSTCBCur;            /*      Point to owning task's OS_TCB       */
  412.         if (OSTCBCur->OSTCBPrio <= pip) {                  /*      PIP 'must' have a SMALLER prio ...  */
  413.             OS_EXIT_CRITICAL();                            /*      ... than current task!              */
  414.             *perr = OS_ERR_PIP_LOWER;
  415.         } else {
  416.             OS_EXIT_CRITICAL();
  417.             *perr = OS_ERR_NONE;
  418.         }
  419.         return;
  420.     }
  421.     mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  /* No, Get priority of mutex owner   */
  422.     ptcb  = (OS_TCB *)(pevent->OSEventPtr);                       /*     Point to TCB of mutex owner   */
  423.     if (ptcb->OSTCBPrio > pip) {                                  /*     Need to promote prio of owner?*/
  424.         if (mprio > OSTCBCur->OSTCBPrio) {
  425.             y = ptcb->OSTCBY;
  426.             if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0) {           /*     See if mutex owner is ready   */
  427.                 OSRdyTbl[y] &= ~ptcb->OSTCBBitX;                  /*     Yes, Remove owner from Rdy ...*/
  428.                 if (OSRdyTbl[y] == 0) {                           /*          ... list at current prio */
  429.                     OSRdyGrp &= ~ptcb->OSTCBBitY;
  430.                 }
  431.                 rdy = OS_TRUE;
  432.             } else {
  433.                 pevent2 = ptcb->OSTCBEventPtr;
  434.                 if (pevent2 != (OS_EVENT *)0) {                   /* Remove from event wait list       */
  435.                     if ((pevent2->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
  436.                         pevent2->OSEventGrp &= ~ptcb->OSTCBBitY;
  437.                     }
  438.                 }
  439.                 rdy = OS_FALSE;                            /* No                                       */
  440.             }
  441.             ptcb->OSTCBPrio = pip;                         /* Change owner task prio to PIP            */
  442. #if OS_LOWEST_PRIO <= 63
  443.             ptcb->OSTCBY    = (INT8U)( ptcb->OSTCBPrio >> 3);
  444.             ptcb->OSTCBX    = (INT8U)( ptcb->OSTCBPrio & 0x07);
  445.             ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
  446.             ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);
  447. #else
  448.             ptcb->OSTCBY    = (INT8U)((ptcb->OSTCBPrio >> 4) & 0xFF);
  449.             ptcb->OSTCBX    = (INT8U)( ptcb->OSTCBPrio & 0x0F);
  450.             ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY);
  451.             ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX);
  452. #endif
  453.             if (rdy == OS_TRUE) {                          /* If task was ready at owner's priority ...*/
  454.                 OSRdyGrp               |= ptcb->OSTCBBitY; /* ... make it ready at new priority.       */
  455.                 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  456.             } else {
  457.                 pevent2 = ptcb->OSTCBEventPtr;
  458.                 if (pevent2 != (OS_EVENT *)0) {            /* Add to event wait list                   */
  459.                     pevent2->OSEventGrp               |= ptcb->OSTCBBitY;
  460.                     pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  461.                 }
  462.             }
  463.             OSTCBPrioTbl[pip] = ptcb;
  464.         }
  465.     }
  466.     OSTCBCur->OSTCBStat     |= OS_STAT_MUTEX;         /* Mutex not available, pend current task        */
  467.     OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
  468.     OSTCBCur->OSTCBDly       = timeout;               /* Store timeout in current task's TCB           */
  469.     OS_EventTaskWait(pevent);                         /* Suspend task until event or timeout occurs    */
  470.     OS_EXIT_CRITICAL();
  471.     OS_Sched();                                       /* Find next highest priority task ready         */
  472.     OS_ENTER_CRITICAL();
  473.     switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
  474.         case OS_STAT_PEND_OK:
  475.              *perr = OS_ERR_NONE;
  476.              break;
  477.         case OS_STAT_PEND_ABORT:
  478.              *perr = OS_ERR_PEND_ABORT;               /* Indicate that we aborted getting mutex        */
  479.              break;
  480.              
  481.         case OS_STAT_PEND_TO:
  482.         default:
  483.              OS_EventTaskRemove(OSTCBCur, pevent);
  484.              *perr = OS_ERR_TIMEOUT;                  /* Indicate that we didn't get mutex within TO   */
  485.              break;
  486.     }
  487.     OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */
  488.     OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */
  489.     OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */
  490. #if (OS_EVENT_MULTI_EN > 0)
  491.     OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
  492. #endif
  493.     OS_EXIT_CRITICAL();
  494. }
  495. /*$PAGE*/
  496. /*
  497. *********************************************************************************************************
  498. *                                  POST TO A MUTUAL EXCLUSION SEMAPHORE
  499. *
  500. * Description: This function signals a mutual exclusion semaphore
  501. *
  502. * Arguments  : pevent              is a pointer to the event control block associated with the desired
  503. *                                  mutex.
  504. *
  505. * Returns    : OS_ERR_NONE             The call was successful and the mutex was signaled.
  506. *              OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a mutex
  507. *              OS_ERR_PEVENT_NULL      'pevent' is a NULL pointer
  508. *              OS_ERR_POST_ISR         Attempted to post from an ISR (not valid for MUTEXes)
  509. *              OS_ERR_NOT_MUTEX_OWNER  The task that did the post is NOT the owner of the MUTEX.
  510. *              OS_ERR_PIP_LOWER        If the priority of the new task that owns the Mutex is
  511. *                                      HIGHER (i.e. a lower number) than the PIP.  This error
  512. *                                      indicates that you did not set the PIP higher (lower
  513. *                                      number) than ALL the tasks that compete for the Mutex.
  514. *                                      Unfortunately, this is something that could not be
  515. *                                      detected when the Mutex is created because we don't know
  516. *                                      what tasks will be using the Mutex.
  517. *********************************************************************************************************
  518. */
  519. INT8U  OSMutexPost (OS_EVENT *pevent)
  520. {
  521.     INT8U      pip;                                   /* Priority inheritance priority                 */
  522.     INT8U      prio;
  523. #if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
  524.     OS_CPU_SR  cpu_sr = 0;
  525. #endif
  526.     if (OSIntNesting > 0) {                           /* See if called from ISR ...                    */
  527.         return (OS_ERR_POST_ISR);                     /* ... can't POST mutex from an ISR              */
  528.     }
  529. #if OS_ARG_CHK_EN > 0
  530.     if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
  531.         return (OS_ERR_PEVENT_NULL);
  532.     }
  533. #endif
  534.     if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type                     */
  535.         return (OS_ERR_EVENT_TYPE);
  536.     }
  537.     OS_ENTER_CRITICAL();
  538.     pip  = (INT8U)(pevent->OSEventCnt >> 8);          /* Get priority inheritance priority of mutex    */
  539.     prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  /* Get owner's original priority      */
  540.     if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) {   /* See if posting task owns the MUTEX            */
  541.         OS_EXIT_CRITICAL();
  542.         return (OS_ERR_NOT_MUTEX_OWNER);
  543.     }
  544.     if (OSTCBCur->OSTCBPrio == pip) {                 /* Did we have to raise current task's priority? */
  545.         OSMutex_RdyAtPrio(OSTCBCur, prio);            /* Restore the task's original priority          */
  546.     }
  547.     OSTCBPrioTbl[pip] = OS_TCB_RESERVED;              /* Reserve table entry                           */
  548.     if (pevent->OSEventGrp != 0) {                    /* Any task waiting for the mutex?               */
  549.                                                       /* Yes, Make HPT waiting for mutex ready         */
  550.         prio                = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
  551.         pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;  /*      Save priority of mutex's new owner       */
  552.         pevent->OSEventCnt |= prio;
  553.         pevent->OSEventPtr  = OSTCBPrioTbl[prio];     /*      Link to new mutex owner's OS_TCB         */
  554.         if (prio <= pip) {                            /*      PIP 'must' have a SMALLER prio ...       */
  555.             OS_EXIT_CRITICAL();                       /*      ... than current task!                   */
  556.             OS_Sched();                               /*      Find highest priority task ready to run  */
  557.             return (OS_ERR_PIP_LOWER);
  558.         } else {
  559.             OS_EXIT_CRITICAL();
  560.             OS_Sched();                               /*      Find highest priority task ready to run  */
  561.             return (OS_ERR_NONE);
  562.         }
  563.     }
  564.     pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;         /* No,  Mutex is now available                   */
  565.     pevent->OSEventPtr  = (void *)0;
  566.     OS_EXIT_CRITICAL();
  567.     return (OS_ERR_NONE);
  568. }
  569. /*$PAGE*/
  570. /*
  571. *********************************************************************************************************
  572. *                                     QUERY A MUTUAL EXCLUSION SEMAPHORE
  573. *
  574. * Description: This function obtains information about a mutex
  575. *
  576. * Arguments  : pevent          is a pointer to the event control block associated with the desired mutex
  577. *
  578. *              p_mutex_data    is a pointer to a structure that will contain information about the mutex
  579. *
  580. * Returns    : OS_ERR_NONE          The call was successful and the message was sent
  581. *              OS_ERR_QUERY_ISR     If you called this function from an ISR
  582. *              OS_ERR_PEVENT_NULL   If 'pevent'       is a NULL pointer
  583. *              OS_ERR_PDATA_NULL    If 'p_mutex_data' is a NULL pointer
  584. *              OS_ERR_EVENT_TYPE    If you are attempting to obtain data from a non mutex.
  585. *********************************************************************************************************
  586. */
  587. #if OS_MUTEX_QUERY_EN > 0
  588. INT8U  OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data)
  589. {
  590.     INT8U      i;
  591. #if OS_LOWEST_PRIO <= 63
  592.     INT8U     *psrc;
  593.     INT8U     *pdest;
  594. #else
  595.     INT16U    *psrc;
  596.     INT16U    *pdest;
  597. #endif
  598. #if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
  599.     OS_CPU_SR  cpu_sr = 0;
  600. #endif
  601.     if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
  602.         return (OS_ERR_QUERY_ISR);                         /* ... can't QUERY mutex from an ISR        */
  603.     }
  604. #if OS_ARG_CHK_EN > 0
  605.     if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
  606.         return (OS_ERR_PEVENT_NULL);
  607.     }
  608.     if (p_mutex_data == (OS_MUTEX_DATA *)0) {              /* Validate 'p_mutex_data'                  */
  609.         return (OS_ERR_PDATA_NULL);
  610.     }
  611. #endif
  612.     if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type                */
  613.         return (OS_ERR_EVENT_TYPE);
  614.     }
  615.     OS_ENTER_CRITICAL();
  616.     p_mutex_data->OSMutexPIP  = (INT8U)(pevent->OSEventCnt >> 8);
  617.     p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
  618.     if (p_mutex_data->OSOwnerPrio == 0xFF) {
  619.         p_mutex_data->OSValue = OS_TRUE;
  620.     } else {
  621.         p_mutex_data->OSValue = OS_FALSE;
  622.     }
  623.     p_mutex_data->OSEventGrp  = pevent->OSEventGrp;        /* Copy wait list                           */
  624.     psrc                      = &pevent->OSEventTbl[0];
  625.     pdest                     = &p_mutex_data->OSEventTbl[0];
  626.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  627.         *pdest++ = *psrc++;
  628.     }
  629.     OS_EXIT_CRITICAL();
  630.     return (OS_ERR_NONE);
  631. }
  632. #endif                                                     /* OS_MUTEX_QUERY_EN                        */
  633. /*$PAGE*/
  634. /*
  635. *********************************************************************************************************
  636. *                                RESTORE A TASK BACK TO ITS ORIGINAL PRIORITY
  637. *
  638. * Description: This function makes a task ready at the specified priority
  639. *
  640. * Arguments  : ptcb            is a pointer to OS_TCB of the task to make ready
  641. *
  642. *              prio            is the desired priority
  643. *
  644. * Returns    : none
  645. *********************************************************************************************************
  646. */
  647. static  void  OSMutex_RdyAtPrio (OS_TCB *ptcb, INT8U prio)
  648. {
  649.     INT8U   y;
  650.     y            =  ptcb->OSTCBY;                          /* Remove owner from ready list at 'pip'    */
  651.     OSRdyTbl[y] &= ~ptcb->OSTCBBitX;
  652.     if (OSRdyTbl[y] == 0) {
  653.         OSRdyGrp &= ~ptcb->OSTCBBitY;
  654.     }
  655.     ptcb->OSTCBPrio         = prio;
  656. #if OS_LOWEST_PRIO <= 63
  657.     ptcb->OSTCBY            = (INT8U)((prio >> (INT8U)3) & (INT8U)0x07);
  658.     ptcb->OSTCBX            = (INT8U) (prio & (INT8U)0x07);
  659.     ptcb->OSTCBBitY         = (INT8U)(1 << ptcb->OSTCBY);
  660.     ptcb->OSTCBBitX         = (INT8U)(1 << ptcb->OSTCBX);
  661. #else
  662.     ptcb->OSTCBY            = (INT8U)((prio >> (INT8U)4) & (INT8U)0x0F);
  663.     ptcb->OSTCBX            = (INT8U) (prio & (INT8U)0x0F);
  664.     ptcb->OSTCBBitY         = (INT16U)(1 << ptcb->OSTCBY);
  665.     ptcb->OSTCBBitX         = (INT16U)(1 << ptcb->OSTCBX);
  666. #endif
  667.     OSRdyGrp               |= ptcb->OSTCBBitY;             /* Make task ready at original priority     */
  668.     OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
  669.     OSTCBPrioTbl[prio]      = ptcb;
  670. }
  671. #endif                                                     /* OS_MUTEX_EN                              */