windows内核原理分析之DPC函数的执行(2)

windows内核原理分析之DPC函数的执行(2)

需要执行DPC函数时,就通过KeInsertQueueDpc()提出DPC请求,就是把具体的KDPC结构挂入PRCB中的DPC请求队列,这常常是由中断服务程序完成的。

BOOLEAN NTAPI  
KeInsertQueueDpc(IN PKDPC Dpc,  
                 IN PVOID SystemArgument1, IN PVOID SystemArgument2)  
{  
    ......  
    ASSERT_DPC(Dpc);  

    /* Check IRQL and Raise it to HIGH_LEVEL */  
    KeRaiseIrql(HIGH_LEVEL, &OldIrql);  
    CurrentPrcb = KeGetCurrentPrcb();    //获取当前所在CPU的PRCB  
    /* Check if the DPC has more then the maximum number of CPUs */  
    if (Dpc->Number >= MAXIMUM_PROCESSORS)  
    {  
        /* Then substract the maximum and get that PRCB. */  
        Cpu = Dpc->Number - MAXIMUM_PROCESSORS;  
        Prcb = KiProcessorBlock[Cpu];  
    }  
    else  
    {  
        /* Use the current one */  
        Prcb = CurrentPrcb;  
        Cpu = Prcb->Number;  
    }  

    /* ROS Sanity Check */  
    ASSERT(Prcb == CurrentPrcb);  
    /* Check if this is a threaded DPC and threaded DPCs are enabled */  
    if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))  
    {  
        /* Then use the threaded data */  
        DpcData = &Prcb->DpcData[DPC_THREADED];  
    }  
    else  
    {  
        /* Otherwise, use the regular data */  
        DpcData = &Prcb->DpcData[DPC_NORMAL];  
    }  
    /* Acquire the DPC lock */  
    KiAcquireSpinLock(&DpcData->DpcLock);  
    /* Get the DPC Data */  
    if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))  
    {  
        /* Now we can play with the DPC safely */  
        Dpc->SystemArgument1SystemArgument1 = SystemArgument1;  
        Dpc->SystemArgument2SystemArgument2 = SystemArgument2;  
        DpcData->DpcQueueDepth++;  
        DpcData->DpcCount++;  
        DpcConfigured = TRUE;  
        /* Check if this is a high importance DPC */  
        if (Dpc->Importance == HighImportance)  
        {  
            /* Pre-empty other DPCs */  
            InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);  
        }  
        else  
        {  
            /* Add it at the end */  
            InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);  
        }  
        /* Check if this is the DPC on the threaded list */  
        if (&Prcb->DpcData[DPC_THREADED] == DpcData)  
        {  
            /* Make sure a threaded DPC isn't already active */  
            if (!(Prcb->DpcThreadActive) && !(Prcb->DpcThreadRequested))  
            {  
                /* FIXME: Setup Threaded DPC */  
                DPRINT1("Threaded DPC not supported\n");  
                while (TRUE);  
            }  
        }  //end if (&Prcb->DpcData[DPC_THREADED] == DpcData)  
        else  
        {  
            /* Make sure a DPC isn't executing already */  
            if (!(Prcb->DpcRoutineActive) && !(Prcb->
                 DpcInterruptRequested))  
            {  
                /* Check if this is the same CPU */  
                if (Prcb != CurrentPrcb)  
                {  
                    /* Check if the DPC is of high importance or above the  
                     * maximum depth. If it is, then make sure that the CPU  
                     * isn't idle, or that it's sleeping. */  
                    if (((Dpc->Importance == HighImportance) ||  
                        (DpcData->DpcQueueDepth >= 
                          Prcb->MaximumDpcQueueDepth))   
                        && (!(AFFINITY_MASK(Cpu) & KiIdleSummary)  
                        || (Prcb->Sleeping)))  
                    {  
                        /* Set interrupt requested */  
                        Prcb->DpcInterruptRequested = TRUE;  
                        /* Set DPC inserted */  
                        DpcInserted = TRUE;  
                    }  
                }  //end if (Prcb != CurrentPrcb)  
                else  
                {  
                    /* Check if the DPC is of anything but
                       low importance */  
                    if ((Dpc->Importance != LowImportance) ||  
                        (DpcData->DpcQueueDepth >= 
                         Prcb->MaximumDpcQueueDepth)  
                        || (Prcb->DpcRequestRate 
                            < Prcb->MinimumDpcRate))  
                    {  
                        /* Set interrupt requested */  
                        Prcb->DpcInterruptRequested = TRUE;  
                        /* Set DPC inserted */  
                        DpcInserted = TRUE;  
                    }  
                }  
            }  //end if (!(Prcb->DpcRoutineActive) 
&& !(Prcb->DpcInterrupt Requested))  
        }  //end if (&Prcb->DpcData[DPC_THREADED] == DpcData) else   
    }  //end if (!InterlockedCompareExchangePointer(
&Dpc->DpcData, DpcData, NULL))  
    /* Release the lock */  
    KiReleaseSpinLock(&DpcData->DpcLock);  
    /* Check if the DPC was inserted */  
    if (DpcInserted)  
    {  
        /* Check if this was SMP */  
        if (Prcb != CurrentPrcb)  
        {  
            /* It was, request and IPI */  
            KiIpiSendRequest(AFFINITY_MASK(Cpu), IPI_DPC);  
        }  
        else  
        {  
            /* It wasn't, request an interrupt from HAL 
             */  //要求扫描DPC请求队列  
            HalRequestSoftwareInterrupt(DISPATCH_LEVEL);  //调用HalRequestSoftwareInterrupt函数
        }  
    }  
    /* Lower IRQL */  
    KeLowerIrql(OldIrql);  //降低到原来的Irql
    return DpcConfigured;  
} 

这段代码是支持SMP多处理器结构的,所以不同的CPU有不同的PRCB数据结构,但是单CPU的系统只有一个PRCB。

如果将DPC请求挂入了队列,就通过HalRequestSoftwareInterrupt()将PCR中的相应标志位设置成TRUE,表示要求扫描DPC请求队列:

[KeInsertQueueDpc() > HalRequestSoftwareInterrupt()]  

VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Request)  
{  
  switch (Request)  
  {  
    case APC_LEVEL:  
      ((PKIPCR)KeGetPcr())->HalReserved[HAL_APC_REQUEST] = TRUE;  
      break;  
    case DISPATCH_LEVEL:  
      ((PKIPCR)KeGetPcr())->HalReserved[HAL_DPC_REQUEST] = TRUE;  
      break;  
    default:  
      KEBUGCHECK(0);  
  }  
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值