其他分享
首页 > 其他分享> > SylixOS里的互斥信号量实现原理详解

SylixOS里的互斥信号量实现原理详解

作者:互联网

实现原理

相比于二进制信号量的实现,互斥信号量增加了优先级天花板算法和优先级继承算法的支持。

实现源码

/*********************************************************************************************************
** 函数名称: API_SemaphoreMCreate
** 功能描述: 互斥信号量建立
** 输 入  : 
**           pcName             事件名缓冲区
**           ucCeilingPriority  如果使用天花板优先级机制,此参数为天花板优先级
**           ulOption           事件选项        推荐使用 PRIORITY 队列和 DELELTE SAFE 选项
**           pulId              事件ID指针
** 输 出  : 事件句柄
*********************************************************************************************************/ 
LW_OBJECT_HANDLE  API_SemaphoreMCreate (CPCHAR             pcName,
                                        UINT8              ucCeilingPriority,
                                        ULONG              ulOption,
                                        LW_OBJECT_ID      *pulId)
{
    REGISTER PLW_CLASS_EVENT       pevent;
    REGISTER ULONG                 ulI;
             PLW_CLASS_WAITQUEUE   pwqTemp[2];
    REGISTER ULONG                 ulIdTemp;
    

    __KERNEL_MODE_PROC(
        pevent = _Allocate_Event_Object();                              /*  获得一个事件控制块          */
    );
    
    if (!pevent) {
        return  (LW_OBJECT_HANDLE_INVALID);
    }
    
    if (pcName) {                                                       /*  拷贝名字                    */
        lib_strcpy(pevent->EVENT_cEventName, pcName);
    } else {
        pevent->EVENT_cEventName[0] = PX_EOS;                           /*  清空名字                    */
    }
                                                                        /*  开始初始化                  */
    pevent->EVENT_ucType            = LW_TYPE_EVENT_MUTEX;
    pevent->EVENT_ulCounter         = (ULONG)LW_TRUE;                   /*  初始化为有效                */
    pevent->EVENT_ulMaxCounter      = LW_PRIO_LOWEST;                   /*  被用作保存线程优先级        */
    pevent->EVENT_ucCeilingPriority = ucCeilingPriority;                /*  天花板优先级                */
    pevent->EVENT_ulOption          = ulOption;
    pevent->EVENT_pvPtr             = LW_NULL;
    pevent->EVENT_pvTcbOwn          = LW_NULL;
    
    pwqTemp[0] = &pevent->EVENT_wqWaitQ[0];
    pwqTemp[1] = &pevent->EVENT_wqWaitQ[1];
    pwqTemp[0]->WQ_usNum = 0;                                           /*  没有线程                    */
    pwqTemp[1]->WQ_usNum = 0;
    
    for (ulI = 0; ulI < __EVENT_Q_SIZE; ulI++) {
        pwqTemp[0]->WQ_wlQ.WL_pringPrio[ulI] = LW_NULL;
        pwqTemp[1]->WQ_wlQ.WL_pringPrio[ulI] = LW_NULL;
    }
    
    ulIdTemp = _MakeObjectId(_OBJECT_SEM_M, 
                             LW_CFG_PROCESSOR_NUMBER, 
                             pevent->EVENT_usIndex);                    /*  构建对象 id                 */

    if (pulId) {
        *pulId = ulIdTemp;
    }
    
    return  (ulIdTemp);
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreMPend
** 功能描述: 等待互斥信号量            由于 mutext post 操作不能在中断中进行,可大大缩短关中断时间
** 输 入  : 
**           ulId            事件句柄
**           ulTimeout       等待时间
** 输 出  : 
*********************************************************************************************************/  
ULONG  API_SemaphoreMPend (LW_OBJECT_HANDLE  ulId, ULONG  ulTimeout)
{
             INTREG                iregInterLevel;
             
             PLW_CLASS_TCB         ptcbCur;
    REGISTER UINT16                usIndex;
    REGISTER PLW_CLASS_EVENT       pevent;
    REGISTER UINT8                 ucPriorityIndex;
    REGISTER PLW_LIST_RING        *ppringList;
             ULONG                 ulTimeSave;                          /*  系统事件记录                */
             INT                   iSchedRet;
             
             ULONG                 ulEventOption;                       /*  事件创建选项                */
             
    usIndex = _ObjectGetIndex(ulId);
    
    LW_TCB_GET_CUR_SAFE(ptcbCur);                                       /*  当前任务控制块              */
    
    pevent = &_K_eventBuffer[usIndex];
    
    __KERNEL_ENTER();                                                   /*  进入内核                    */
    //获取信号量成功
    if (pevent->EVENT_ulCounter) {                                      /*  事件有效                    */
        pevent->EVENT_ulCounter    = LW_FALSE;
        pevent->EVENT_ulMaxCounter = (ULONG)ptcbCur->TCB_ucPriority;    /*  保存占用资源线程优先级      */
        pevent->EVENT_pvTcbOwn     = (PVOID)ptcbCur;                    /*  保存占用资源线程信息        */
        LW_THREAD_SAFE_INKERN(ptcbCur);
        __KERNEL_EXIT();                                                /*  退出内核                    */
        return  (ERROR_NONE);
    }
    //获取信号量失败
    //处理递归调用
    if (!(pevent->EVENT_ulOption & LW_OPTION_NORMAL)) {                 /*  需要递归支持或递归检查      */
        if (pevent->EVENT_pvTcbOwn == (PVOID)ptcbCur) {                 /*  是否是自己连续调用          */
            if (pevent->EVENT_ulOption & LW_OPTION_ERRORCHECK) {
                __KERNEL_EXIT();                                        /*  退出内核                    */
                return  (EDEADLK);
            }
                                                                        /*  临时计数器++                */
            pevent->EVENT_pvPtr = (PVOID)((ULONG)pevent->EVENT_pvPtr + 1);
            __KERNEL_EXIT();                                            /*  退出内核                    */
            return  (ERROR_NONE);
        }
    }
    //是否需要超时
    if (ulTimeout == LW_OPTION_NOT_WAIT) {                              /*  不等待                      */
        __KERNEL_EXIT();                                                /*  退出内核                    */
        return  (ERROR_THREAD_WAIT_TIMEOUT);
    }

    _EventPrioTryBoost(pevent, ptcbCur);                                /*  尝试提升所属任务优先级      */
    
    iregInterLevel = KN_INT_DISABLE();                                  /*  关闭中断                    */
    
    ptcbCur->TCB_iPendQ         = EVENT_SEM_Q;
    ptcbCur->TCB_usStatus      |= LW_THREAD_STATUS_SEM;                 /*  写状态位,开始等待          */
    ptcbCur->TCB_ucWaitTimeout  = LW_WAIT_TIME_CLEAR;                   /*  清空等待时间                */
    
    if (ulTimeout == LW_OPTION_WAIT_INFINITE) {                         /*  是否是无穷等待              */
        ptcbCur->TCB_ulDelay = 0ul;
    } else {
        ptcbCur->TCB_ulDelay = ulTimeout;                               /*  设置超时时间                */
    }
    __KERNEL_TIME_GET_NO_SPINLOCK(ulTimeSave, ULONG);                   /*  记录系统时间                */
    
    if (pevent->EVENT_ulOption & LW_OPTION_WAIT_PRIORITY) {             /*  按优先级等待                */
        _EVENT_INDEX_Q_PRIORITY(ptcbCur->TCB_ucPriority, ucPriorityIndex);
        _EVENT_PRIORITY_Q_PTR(EVENT_SEM_Q, ppringList, ucPriorityIndex);
        ptcbCur->TCB_ppringPriorityQueue = ppringList;                  /*  记录等待队列位置            */
        _EventWaitPriority(pevent, ppringList);                         /*  加入优先级等待表            */
        
    } else {                                                            /*  按 FIFO 等待                */
        _EVENT_FIFO_Q_PTR(EVENT_SEM_Q, ppringList);                     /*  确定 FIFO 队列的位置        */
        _EventWaitFifo(pevent, ppringList);                             /*  加入 FIFO 等待表            */
    }
    
    KN_INT_ENABLE(iregInterLevel);                                      /*  使能中断                    */

    ulEventOption = pevent->EVENT_ulOption;
    
    __KERNEL_EXIT();                                                    /*  调度器解锁                  */
    
    if (ptcbCur->TCB_ucWaitTimeout == LW_WAIT_TIME_OUT) {               /*  等待超时                    */
        return  (ERROR_THREAD_WAIT_TIMEOUT);
    } else {
        if (ptcbCur->TCB_ucIsEventDelete == LW_EVENT_EXIST) {           /*  事件是否存在                */
            return  (ERROR_NONE);                                       /*  释放操作已将此任务设为安全  */
        } else {
            return  (ERROR_EVENT_WAS_DELETED);
        }
    }
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreMPost
** 功能描述: 释放互斥信号量, 不可在中断中操作
** 输 入  : 
**           ulId                   事件句柄
** 输 出  : 
*********************************************************************************************************/
ULONG  API_SemaphoreMPost (LW_OBJECT_HANDLE  ulId)
{
             INTREG                iregInterLevel;
             
             PLW_CLASS_TCB         ptcbCur;
    REGISTER UINT16                usIndex;
    REGISTER PLW_CLASS_EVENT       pevent;
    REGISTER PLW_CLASS_TCB         ptcb;
    REGISTER PLW_LIST_RING        *ppringList;                          /*  等待队列地址                */
    
    usIndex = _ObjectGetIndex(ulId);
    
    LW_TCB_GET_CUR_SAFE(ptcbCur);                                       /*  当前任务控制块              */
    
    pevent = &_K_eventBuffer[usIndex];
    
    __KERNEL_ENTER();                                                   /*  进入内核                    */
    
    if (pevent->EVENT_pvPtr) {                                          /*  检测是否进行了递归调用      */
        pevent->EVENT_pvPtr = (PVOID)((ULONG)pevent->EVENT_pvPtr - 1);  /*  临时计数器--                */
        __KERNEL_EXIT();                                                /*  退出内核                    */
        return  (ERROR_NONE);
    }
    
    iregInterLevel = KN_INT_DISABLE();
    
    if (_EventWaitNum(EVENT_SEM_Q, pevent)) {
        if (pevent->EVENT_ulOption & LW_OPTION_WAIT_PRIORITY) {         /*  优先级等待队列              */
            _EVENT_DEL_Q_PRIORITY(EVENT_SEM_Q, ppringList);             /*  激活优先级等待线程          */
            ptcb = _EventReadyPriorityLowLevel(pevent, LW_NULL, ppringList);
        
        } else {
            _EVENT_DEL_Q_FIFO(EVENT_SEM_Q, ppringList);                 /*  激活FIFO等待线程            */
            ptcb = _EventReadyFifoLowLevel(pevent, LW_NULL, ppringList);
        }
        
        KN_INT_ENABLE(iregInterLevel);
        
        _EventPrioTryResume(pevent, ptcbCur);                           /*  尝试返回之前的优先级        */
        
        pevent->EVENT_ulMaxCounter = (ULONG)ptcb->TCB_ucPriority;
        pevent->EVENT_pvTcbOwn     = (PVOID)ptcb;                       /*  保存线程信息                */

        _EventReadyHighLevel(ptcb, LW_THREAD_STATUS_SEM);               /*  处理 TCB                    */
        
        if (pevent->EVENT_ulOption & LW_OPTION_DELETE_SAFE) {
            LW_THREAD_SAFE_INKERN(ptcb);                                /*  将激活任务设置为安全        */
        }
        
        __KERNEL_EXIT();                                                /*  退出内核                    */
        
        if (pevent->EVENT_ulOption & LW_OPTION_DELETE_SAFE) {           /*  本任务退出安全模式          */
            LW_THREAD_UNSAFE();
        }
        return  (ERROR_NONE);
    
    } else {                                                            /*  没有线程等待                */
        KN_INT_ENABLE(iregInterLevel);
        
        if (pevent->EVENT_ulCounter == LW_FALSE) {                      /*  检查是否还有空间加          */
            pevent->EVENT_ulCounter = (ULONG)LW_TRUE;
            
            pevent->EVENT_ulMaxCounter = LW_PRIO_LOWEST;                /*  清空保存信息                */
            pevent->EVENT_pvTcbOwn     = LW_NULL;
            
            __KERNEL_EXIT();                                            /*  退出内核                    */
            
            if (pevent->EVENT_ulOption & LW_OPTION_DELETE_SAFE) {       /*  本任务退出安全模式          */
                LW_THREAD_UNSAFE();
            }
            return  (ERROR_NONE);
        
        } else {                                                        /*  已经满了                    */
            __KERNEL_EXIT();                                            /*  退出内核                    */
            _ErrorHandle(ERROR_EVENT_FULL);
            return  (ERROR_EVENT_FULL);
        }
    }
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreMDelete
** 功能描述: 互斥信号量删除, 因为MUTEX的所有操作函数均不能在中断中运行,所以这里不用关中断
** 输 入  : 
**           pulId            事件句柄指针
** 输 出  : 
*********************************************************************************************************/ 
ULONG  API_SemaphoreMDelete (LW_OBJECT_HANDLE  *pulId)
{
             INTREG                iregInterLevel;
    REGISTER ULONG                 ulOptionTemp;
    REGISTER UINT16                usIndex;
    REGISTER UINT8                 ucPriority;
    REGISTER PLW_CLASS_EVENT       pevent;
    REGISTER PLW_CLASS_TCB         ptcb;
    REGISTER PLW_LIST_RING        *ppringList;                          /*  等待队列地址                */
    
    REGISTER LW_OBJECT_HANDLE      ulId;
    
    ulId = *pulId;
    
    usIndex = _ObjectGetIndex(ulId);
    pevent = &_K_eventBuffer[usIndex];
    
    iregInterLevel = __KERNEL_ENTER_IRQ();                              /*  进入内核                    */

    _ObjectCloseId(pulId);                                              /*  清除句柄                    */
    
    pevent->EVENT_ucType = LW_TYPE_EVENT_UNUSED;                        /*  事件类型为空                */
    
    while (_EventWaitNum(EVENT_SEM_Q, pevent)) {                        /*  是否存在正在等待的任务      */
        if (pevent->EVENT_ulOption & LW_OPTION_WAIT_PRIORITY) {         /*  优先级等待队列              */
            _EVENT_DEL_Q_PRIORITY(EVENT_SEM_Q, ppringList);             /*  激活优先级等待线程          */
            ptcb = _EventReadyPriorityLowLevel(pevent, LW_NULL, ppringList);
        
        } else {
            _EVENT_DEL_Q_FIFO(EVENT_SEM_Q, ppringList);                 /*  激活FIFO等待线程            */
            ptcb = _EventReadyFifoLowLevel(pevent, LW_NULL, ppringList);
        }

        KN_INT_ENABLE(iregInterLevel);
        ptcb->TCB_ucIsEventDelete = LW_EVENT_DELETE;                    /*  事件已经被删除              */
        _EventReadyHighLevel(ptcb, LW_THREAD_STATUS_SEM);               /*  处理 TCB                    */
        iregInterLevel = KN_INT_DISABLE();
    }
    
    KN_INT_ENABLE(iregInterLevel);                                      /*  允许当前 CPU 中断           */
    
    ptcb = (PLW_CLASS_TCB)pevent->EVENT_pvTcbOwn;                       /*  获得拥有者 TCB              */
    pevent->EVENT_pvTcbOwn = LW_NULL;
    
    if (ptcb) {
        ucPriority = (UINT8)pevent->EVENT_ulMaxCounter;                 /*  获得原线程优先级            */
        if (!LW_PRIO_IS_EQU(ucPriority, ptcb->TCB_ucPriority)) {        /*  拥有者优先级发生了变化      */
            _SchedSetPrio(ptcb, ucPriority);                            /*  还原 优先级                 */
        }
    }
    
    _Free_Event_Object(pevent);                                         /*  交还控制块                  */
    ulOptionTemp = pevent->EVENT_ulOption;                              /*  暂存选项                    */
    
    __KERNEL_EXIT();                                                    /*  退出内核                    */
    
    if (ptcb) {
        if (ulOptionTemp & LW_OPTION_DELETE_SAFE) {                     /*  退出安全模式                */
            LW_THREAD_UNSAFE_EX(ptcb);
        }
    }
    
    return  (ERROR_NONE);
}

标签:SylixOS,优先级,LW,ptcbCur,pevent,信号量,互斥,TCB,EVENT
来源: https://blog.csdn.net/ScilogyHunter/article/details/112106550