⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_mutex.c

📁 ucos_ii在S3C2410上的移植
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
*********************************************************************************************************
*                                                uC/OS-II 实时内核
*                                                 信号量管理
*
*                            (c) 版权 1992-2002, 所有版权归Jean J. Labrosse, Weston, FL 所有
*                                         
*
* 文件名称 :          OS_MUTEX.C
* 程序作者 :          Jean J. Labrosse 
*********************************************************************************************************
*/

#ifndef  OS_MASTER_FILE
#include "includes.h"
#endif

/*
*********************************************************************************************************
*                                            局部 变量
*********************************************************************************************************
*/

#define  OS_MUTEX_KEEP_LOWER_8   0x00FF
#define  OS_MUTEX_KEEP_UPPER_8   0xFF00

#define  OS_MUTEX_AVAILABLE      0x00FF


#if OS_MUTEX_EN > 0
/*
*********************************************************************************************************
*                                   获得互斥型信号量
*
* 函数描述: 该函数检查互斥型信号量看资源是否有效。假如资源无效或事件未发生,不象OSMutexPend()函数,
*           OSMutexAccept() 不会挂起调用的任务。
*
* 输入函数: pevent     指向ECB的指针
*
*           err        返回到应用程序的出错代码指针:
*                      OS_NO_ERR          调用成功
*                      OS_ERR_EVENT_TYPE   'pevent' 不是一个指向 mutex 的指针
*                      OS_ERR_PEVENT_NULL 'pevent' 是一个空指针
*                      OS_ERR_PEND_ISR     如果调用来自ISR
*
* 返回值:    == 1       如果资源有效,得到互斥型信号量
*            == 0       a) 如果信号量无效的返回值
*                       b) 没有传递一个互斥型信号量的返回值
*                       c) 从ISR中调用该函数的返回值
*
* 警告:    因为互斥型信号量仅为任务所用,所以该函数不能从ISR 中调用。
*********************************************************************************************************
*/

#if OS_MUTEX_ACCEPT_EN > 0
INT8U  OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                             /* 为CPU状态寄存器分配存储变量 */
    OS_CPU_SR  cpu_sr;
#endif    
    
    
    if (OSIntNesting > 0) 
    {                                                                         /* 确信没有从 ISR 中调用 */
        *err = OS_ERR_PEND_ISR;
        return (0);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0)
     {                                                                             /* 无效的 'pevent'  */
        *err = OS_ERR_PEVENT_NULL;
        return (0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) 
    {                                                                            /* 无效的事件控制块型 */
        *err = OS_ERR_EVENT_TYPE;
        return (0);
    }
#endif                                                     
    OS_ENTER_CRITICAL();							                         /* 得到互斥型的值(0或1) */
    if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) 
    {     
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;               /*      屏蔽低字节 (得到互斥值)     */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;                  /*      在低字节中保存任务优先级   */
        pevent->OSEventPtr  = (void *)OSTCBCur;                  /*      链接占有互斥值的任务的TCB     */
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
        return (1);
    }
    OS_EXIT_CRITICAL();
    *err = OS_NO_ERR;
    return (0);
}
#endif                                                     

/*$PAGE*/
/*
*********************************************************************************************************
*                                  建立一个互斥型信号量
*
* 函数描述:  该函数建立一个互斥型信号量
*
* 输入参数 : prio          访问互斥型信号量时使用的优先级。换句话说,当信号量被使用时,一个更高的优先级
*                          任务想得到该信号量,那么,占有该信号量的任务被提升到该优先级。它在数值上应是
*                          所有竞争此互斥型信号量的任务当中,值最小的,也就是优先级最高的。
*                          
*            err           返回到应用程序的出错代码的指针:
*                               OS_NO_ERR           如果调用成功
*                               OS_ERR_CREATE_ISR   如果从ISR中创建一个互斥型信号量
*                               OS_PRIO_EXIST       如果PIP 的任务级已经存在。
*                               OS_ERR_PEVENT_NULL  没有可用的ECB
*                               OS_PRIO_INVALID     如果指定的优先级高于最大允许值。(例如 > OS_LOWEST_PRIO)
*
* 返回值 :  != (void *)0  指向带有已建好的互斥型信号量的ECB的指针。
*           == (void *)0  如果错误被删除
*
* 注释   :  1) '.OSEventCnt' 的低8位用于保存占有互斥型信号量任务的优先级号,或者没有任务占有时保存0XFF。
*           2) '.OSEventCnt' 的高8位用于保存降解优先级反转的优先级号。
*********************************************************************************************************
*/

OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                /* 为CPU状态寄存器分配存储变量 */
    OS_CPU_SR  cpu_sr;
#endif    
    OS_EVENT  *pevent;


    if (OSIntNesting > 0) 
    {                                                      /* 看是否从 ISR中调用? ...               */
        *err = OS_ERR_CREATE_ISR;                          /* ... 从ISR中不能建立一个互斥型信号量       */
        return ((OS_EVENT *)0);
    }
#if OS_ARG_CHK_EN > 0
    if (prio >= OS_LOWEST_PRIO) 
    {                                                      /* 无效的 PIP                             */
        *err = OS_PRIO_INVALID;
        return ((OS_EVENT *)0);
    }
#endif
    OS_ENTER_CRITICAL();
    if (OSTCBPrioTbl[prio] != (OS_TCB *)0) 
    {                                                      /* 互斥型信号量的优先级不能已经存在    */
        OS_EXIT_CRITICAL();                                /* 任务的优先级已经存在 ...       */
        *err = OS_PRIO_EXIST;                              /* ... 继承优先级                 */
        return ((OS_EVENT *)0);                            
    }
    OSTCBPrioTbl[prio] = (OS_TCB *)1;                      /* 保留优先级                 */
    pevent             = OSEventFreeList;                  /* 得到ECB        */
    if (pevent == (OS_EVENT *)0) 
    {                                                      /* 看ECB是否有效?             */
        OSTCBPrioTbl[prio] = (OS_TCB *)0;                  /* 无效, 释放优先级              */
        OS_EXIT_CRITICAL();
        *err               = OS_ERR_PEVENT_NULL;           /* 没有空余的ECB             */
        return (pevent);
    }
    OSEventFreeList     = (OS_EVENT *)OSEventFreeList->OSEventPtr;   /* 调整空余事件链表指针          */
    OS_EXIT_CRITICAL();
    pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
    pevent->OSEventCnt  = (prio << 8) | OS_MUTEX_AVAILABLE;/* 资源有效                   */
    pevent->OSEventPtr  = (void *)0;                       /* 没有任务占用互斥型信号量                 */
    OS_EventWaitListInit(pevent);
    *err                = OS_NO_ERR;
    return (pevent);
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                          删除一个互斥型信号量
*
* 函数描述: 该函数删除一个互斥型信号量以及就绪所有挂起的任务。
*
* 输入参数  : pevent        指向带有期望的互斥型信号量的ECB的指针。
*
*              opt           决定删除的选择项:
*                            opt == OS_DEL_NO_PEND   没有任务挂起时,才删除互斥型信号量。
*                            opt == OS_DEL_ALWAYS    即使任务在等待,也要删除互斥型信号量。
*                                                    该种情形下,所有挂起的任务都将就绪。
*
*              err           包含指向下列值之一的出错代码的指针:
*                            OS_NO_ERR               调用成功,互斥型信号量被删除
*                            OS_ERR_DEL_ISR          试图从 ISR 中删除互斥型信号量
*                            OS_ERR_INVALID_OPT      指定的为无效选项
*                            OS_ERR_TASK_WAITING     一个或更多的任务正在等待互斥型信号量
*                            OS_ERR_EVENT_TYPE       没有传递一个指向互斥型信号量的指针
*                            OS_ERR_PEVENT_NULL      'pevent'是空指针
*
* 返回值    : pevent        以上出错代码
*              (OS_EVENT *)0 如果互斥型信号量被成功删除
*
* 注释    :  1) 该函数一定要小心使用. 期望信号量的任务一定要检查OSMutexPend()的返回值。
*            2) 这种调用潜在地关闭中断很长时间。中断关闭时间直接正比于等待互斥型信号量的任务的数量。
*            3) 由于所有等待互斥型信号量的任务将被就绪,所以必须谨慎,因为资源不在被互斥型信号量保护。
*********************************************************************************************************
*/

#if OS_MUTEX_DEL_EN
OS_EVENT  *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                            /* 为CPU状态寄存器分配存储变量  */
    OS_CPU_SR  cpu_sr;
#endif    
    BOOLEAN    tasks_waiting;
    INT8U      pip;


    if (OSIntNesting > 0) 
    {                                                              /* 看是否从 ISR中调用? ...         */
        *err = OS_ERR_DEL_ISR;                             /* ... 从ISR中不能删除一个互斥型信号量      */
        return (pevent);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) 
    {                                                                            /* 无效的 'pevent'    */
        *err = OS_ERR_PEVENT_NULL;
        return ((OS_EVENT *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) 
    {                                                                              /* 无效的ECB型     */
        *err = OS_ERR_EVENT_TYPE;
        return (pevent);
    }
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) 
    {                                                               /* 看是否有任务等待互斥型信号量? */
        tasks_waiting = TRUE;                              /* 是                                      */
    } 
    else 
    {
        tasks_waiting = FALSE;                             /* 没有                                    */
    }
    switch (opt) 
    {
        case OS_DEL_NO_PEND:                              /* 只在没有等待的任务时,才删除互斥型信号量 */
             if (tasks_waiting == FALSE) 
             {
                 pip                 = (INT8U)(pevent->OSEventCnt >> 8);
                 OSTCBPrioTbl[pip]   = (OS_TCB *)0;                 /* 置空PIP                        */
                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr  = OSEventFreeList;                       /* 把ECB返回到空余链表  */
                 OSEventFreeList     = pevent;
                 OS_EXIT_CRITICAL();
                 *err = OS_NO_ERR;
                 return ((OS_EVENT *)0);                                       /* 互斥型信号量被删除  */
             } 
             else 
             {
                 OS_EXIT_CRITICAL();
                 *err = OS_ERR_TASK_WAITING;
                 return (pevent);
             }

        case OS_DEL_ALWAYS:                                 /* 即使任务正在等待,也要删除互斥型信号量  */
             while (pevent->OSEventGrp != 0x00)               /* 就绪所有等待互斥型信号量的任务        */
              {         
                 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
             }
             pip                 = (INT8U)(pevent->OSEventCnt >> 8);
             OSTCBPrioTbl[pip]   = (OS_TCB *)0;                                            /* 置空PIP  */
             pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr  = OSEventFreeList;                            /* 把ECB返回到空余链表  */
             OSEventFreeList     = pevent;                 
             OS_EXIT_CRITICAL();
             if (tasks_waiting == TRUE) 
             {                                                              /* 只有任务等待时才可调度  */
                 OS_Sched();                                                /* 寻找最高优先级就绪运行  */
             }
             *err = OS_NO_ERR;
             return ((OS_EVENT *)0);                                        /* 互斥型信号量被删除      */

        default:
             OS_EXIT_CRITICAL();
             *err = OS_ERR_INVALID_OPT;
             return (pevent);
    }
}
#endif

/*$PAGE*/
/*
*********************************************************************************************************
*                                  挂起互斥型信号量

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -