【问题标题】:Difference between GetWorkLoop()->runAction and GetCommandGate()->runAction?GetWorkLoop()->runAction 和 GetCommandGate()->runAction 的区别?
【发布时间】:2016-03-07 09:05:21
【问题描述】:

这让我困惑了很长时间。 在我的 IOkit 驱动程序中,我将中断事件源、定时器事件源注册到工作循环。我使用 GetWorkLoop()->runAction(pAction) 进行硬件访问。 因此,来自中断处理程序和计时器处理程序以及我的 pAction 的所有硬件访问都是序列化的。 但是,我从 IOCommandGate 找到了另一个 runAction。我想知道这两个 runAction 的区别。 我查看了一些 iokit 内核文档。没有得到明确的答案。

在 xnu 源中:

IOReturn IOWorkLoop::runAction(Action inAction, OSObject *target,
                                  void *arg0, void *arg1,
                                  void *arg2, void *arg3)
{
    IOReturn res;

    // closeGate is recursive so don't worry if we already hold the lock.
    closeGate();
    res = (*inAction)(target, arg0, arg1, arg2, arg3);
    openGate();
    return res;
}

我的意思是当我调用 GetWorkLoop()->runAction(inAction) 时。 inAction 在我的线程上下文中运行,而不是在工作循环线程上下文中运行。它是否正确?

IOReturn IOCommandGate::runAction(Action inAction,
                                  void *arg0, void *arg1,
                                  void *arg2, void *arg3)
{
    if (!inAction)
        return kIOReturnBadArgument;

    // closeGate is recursive needn't worry if we already hold the lock.
    closeGate();

    // If the command gate is disabled and we aren't on the workloop thread
    // itself then sleep until we get enabled.
    IOReturn res;
    if (!workLoop->onThread()) {
    while (!enabled) {
        uintptr_t *sleepersP = (uintptr_t *) &reserved;

        *sleepersP += 2;
        IOReturn res = sleepGate(&enabled, THREAD_ABORTSAFE);
        *sleepersP -= 2;

        bool wakeupTearDown = (*sleepersP & 1);
        if (res || wakeupTearDown) {
        openGate();

         if (wakeupTearDown)
             commandWakeup(sleepersP);  // No further resources used

        return kIOReturnAborted;
        }
    }
    }

    bool trace = ( gIOKitTrace & kIOTraceCommandGates ) ? true : false;

    if (trace)
        IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION),
                     VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner);

    IOStatisticsActionCall();

    // Must be gated and on the work loop or enabled
    res = (*inAction)(owner, arg0, arg1, arg2, arg3);

    if (trace)
        IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION),
                       VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner);

    openGate();
    return res;
}

代码似乎 GetCommandGate()->runAction 也在我的线程上下文中运行。不是工作循环线程?

【问题讨论】:

    标签: macos synchronization iokit kernel-extension xnu


    【解决方案1】:

    您是对的,在这两种情况下,您的操作都将在当前线程的上下文中运行,而不是 IOWorkLoop 线程。但是,当您的操作正在运行时,可以保证 IOWorkLoop 不会在其线程上运行任何操作(辅助中断处理程序等)。

    如您所见,两者之间的区别在于,可以禁用和重新启用 IOCommandGate 以暂停操作的运行。我在实践中不需要这个,但有时它可能会派上用场。

    要在IOWorkLoop 线程本身上运行操作,IOEventSource 子类必须覆盖checkForWork() 虚方法,并通过IOEventSourcesignalWorkAvailable() 方法通知IOWorkLoop 有新工作。

    我不知道您可以使用一个通用事件源,它允许您将任意作业排队以在 IOWorkLoop 线程上运行,而不是 IOCommandQueue,它已被弃用多年。 (所以你不应该使用它)

    【讨论】:

    • 所以,它们几乎是一样的。很高兴听到这个消息,有时我使用 IOTimerEventSource 来实现对工作循环线程的延迟调用。注册一个func到一个IOTimerEventSource实例,添加EventSource到workloop,并设置一个超时值,
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    相关资源
    最近更新 更多