GetWorkLoop()->runAction 和 GetCommandGate()->runAction 之间的区别?
Difference between GetWorkLoop()->runAction and GetCommandGate()->runAction?
这让我困惑了很久。
在我的 IOkit 驱动程序中,我将中断事件源、定时器事件源注册到工作循环。我使用 GetWorkLoop()->运行Action(pAction) 进行硬件访问。
因此,来自中断处理程序和定时器处理程序以及我的 pAction 的所有硬件访问都是序列化的。
但是,我从 IOCommandGate 找到了另一个 运行Action。我想知道这两个 运行Action 之间的区别。
我调查了一些 iokit 内核 docs.didn 没有得到明确的答案。
在 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()->运行Action(inAction) 时。 inAction 在我的线程上下文中是 运行,而不是在 workloop 线程上下文中。这个对吗?
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()->运行Action。不是工作循环线程?
你是对的,在这两种情况下,你的操作将是 运行 在当前线程的上下文中, 而不是 IOWorkLoop 线程。保证 IOWorkLoop 不会 运行 在其线程上执行任何操作(辅助中断处理程序等),而您的操作是 运行 宁。
如您所见,两者的区别在于可以禁用和重新启用 IOCommandGate 以暂停 运行 操作。我在实践中不需要这个,但有时它可能会有用。
为了运行在IOWorkLoop
线程本身上的动作,IOEventSource
子类必须覆盖checkForWork()
虚方法,并通知IOWorkLoop
新的通过 IOEventSource
的 signalWorkAvailable()
方法工作。
我不知道您可以使用通用事件源,它允许您将任意作业排队到 IOWorkLoop 线程上的 运行,但 IOCommandQueue
已被弃用很多年。 (所以你不应该使用它)
这让我困惑了很久。 在我的 IOkit 驱动程序中,我将中断事件源、定时器事件源注册到工作循环。我使用 GetWorkLoop()->运行Action(pAction) 进行硬件访问。 因此,来自中断处理程序和定时器处理程序以及我的 pAction 的所有硬件访问都是序列化的。 但是,我从 IOCommandGate 找到了另一个 运行Action。我想知道这两个 运行Action 之间的区别。 我调查了一些 iokit 内核 docs.didn 没有得到明确的答案。
在 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()->运行Action(inAction) 时。 inAction 在我的线程上下文中是 运行,而不是在 workloop 线程上下文中。这个对吗?
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()->运行Action。不是工作循环线程?
你是对的,在这两种情况下,你的操作将是 运行 在当前线程的上下文中, 而不是 IOWorkLoop 线程。保证 IOWorkLoop 不会 运行 在其线程上执行任何操作(辅助中断处理程序等),而您的操作是 运行 宁。
如您所见,两者的区别在于可以禁用和重新启用 IOCommandGate 以暂停 运行 操作。我在实践中不需要这个,但有时它可能会有用。
为了运行在IOWorkLoop
线程本身上的动作,IOEventSource
子类必须覆盖checkForWork()
虚方法,并通知IOWorkLoop
新的通过 IOEventSource
的 signalWorkAvailable()
方法工作。
我不知道您可以使用通用事件源,它允许您将任意作业排队到 IOWorkLoop 线程上的 运行,但 IOCommandQueue
已被弃用很多年。 (所以你不应该使用它)