os_mutex.c
上传用户:tkwrx3909
上传日期:2015-10-06
资源大小:3310k
文件大小:35k
源码类别:

uCOS

开发平台:

Visual C++

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