WDFWORKITEM / WDFTIMER info

Hi

I have 1.27 KMDF.
I reuse WDFWORKITEM and WDFTIMER(passive-level, non-periodic, not no-wake, not high-resolution) objects.

  • WDF_WORKITEM_CONFIG.parent is a distinct WDFQUEUE, AutoSerial=1
  • WDF_TIMER_CONFIG.AutoSerial=1, WDF_OBJECT_ATTRIBUTES.parent = distinct WDFQUEUE, WdfExecutionLevelPassive
  1. If I do WdfWorkItemEnqueue for the same WDFWORKITEM from its EvtWorkItem(), can the EvtWotkItem() run before current EvtWorkItem() finishes?
    (I have seen this happening between different WDFWORKITEMs’)

  2. If I use WdfStartTimer(0), I assume the EvtTimerFunc runs between 0 and 15.6ms? (or it could be between 15-30ms?)

  3. Does below imply that Passive-level timers can’t be high-resolution (can make sense)?

Instead, it calls the callback function once, after the WdfTimerStart method’s DueTime has elapsed. (The time period must be zero if WdfTimerCreate sets the execution level to WdfExecutionLevelPassive.)

To create a high resolution timer, set the UseHighResolutionTimer member of WDF_TIMER_CONFIG to WdfTrue, and then adjust the Period value to the desired resolution.

Thanks

First of all, using SyncScope and auto serialization is definitely not considered a best practice. I would strongly recommend you consider implementing your own locks, and just forgetting that SyncScope and AutoSerial exist. This will save you from having to wonder about many corner cases, such as the one you’ve raised.

In question #1, you ask if two WDFWORKITEMs (presumably) from the same synchronization domain and that have had sync scope extended using AutomaticSerialization = TRUE. If you’ve configured things right, the answer is no. There’s a lot at the “top” object of your domain (the Queue or the Device). That lock (spinlock or mutex) is acquired before any of the related callbacks are invoked. So, only one item in the synchronization domain will run at a time. But be careful: Actually getting all these things configured right so that you HAVE SyncScope and an extended SyncScope domain via AutomaticSerialization can be tricky.

Just do the locking yourself and stop wondering.

So, next… passive level timer handling is “weird” – I believe if you actually want passive-level handling for the timer, you’ll need to explicitly specify this in your OBJECT_ATTRIBUTES… and “InheritFromParent” isn’t enough. See here.

I don’t see any code that would prevent you from having a passive level, high precision, timer. Having SAID that, I’m not sure what you think this will get you. Your passive level timer callback fire with “high precision” which will then result in scheduling a work item. Won’t the latency of scheduling the work item effectively destroy the precision you’re hoping to gain?

Hmmmm… does WdfStartTimer(0) even WORK if you have a high resolution timer? I wouldn’t think so, because you’re required to pass in a delta time (which is negative).

If you’re having trouble verifying what’s going on, you might want to enable WDF Verifier, enable verbose logging, and check the log for various operations.

Peter

Thanks Peter.

I am porting Linux code (tasklet, work, delayed-work, I use passive-level-timer for delayed-work()). Code does scheduling like

  • same delayed-work(0 ms) from same delayed-work-func().
  • same work-item from the same work().
    Code already has inside stack synchronization mechanisms in place w.r.t to Linux semantics
  • Tasklet won’t run in parallel with itself.
  • Work / delayed-work can run in parallel with itself

I was trying to preserve above as much as possible, without adding windows extras inside business code. That’s fine will remove any SyncScope/AutoSerial and adapt the port.

Won’t the latency of scheduling the work item effectively destroy the precision you’re hoping to gain?
I was seeing if I should use high-res passive-level-timer for linux schedule-delayed-work(0 ms)
True, With passive level timer precision is lost. I could just use a work-item instead.

does WdfStartTimer(0) even WORK if you have a high resolution timer?
For passive-level non-high-resolution timer this worked. Will DV with passive-level high-resolution timer.

  1. For Timer, using below

WDF_TIMER_CONFIG_INIT(&Config, Func);
Config.UseHighResolutionTimer = FALSE;

//use distinct parent (WDFQUEUE), so to NOT serialize against other timers'
//Further AutomaticSerialization=TRUE, so this timer is serialized against itself
//WDF_TIMER_CONFIG.AutomaticSerialization=TRUE has no effect if the parent's synchronization scope is WdfSynchronizationScopeNone.
NT_ASSERT(Config.AutomaticSerialization == TRUE && !Config.Period && !Config.TolerableDelay);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, CONTEXT);

** Attributes.ExecutionLevel = WdfExecutionLevelPassive;**
//Set the parent object to be WDFQUEUE (parent(queue) = device(and device(ExecutionLevel) = WdfExecutionLevelDispatch))
Attributes.ParentObject = CreateQueue(manuai_dispatch, powermanaged=false, WdfSynchronizationScopeQueue, WdfExecutionLevelPassive);

For DPC, was using below

WDF_DPC_CONFIG_INIT(&Config, func);

    // Each DPC has distinct parent (WDFQUEUE), so they are NOT serialized against other DPC'
    NT_ASSERT(dpcConfig.AutomaticSerialization == TRUE);
    Config.AutomaticSerialization = FALSE;

     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CONTEXT);
    // Set the parent object to distinct *WDFQUEUE* - parent(queue) is device(and device(ExecutionLevel) is WdfExecutionLevelDispatch))
    attributes.ParentObject = CreateQueue(manuai_dispatch, powermanaged=false, WdfSynchronizationScopeQueue,WdfExecutionLevelDispatch);

when porting drivers from *nix to windows or vice versa, it is usually best to evaluate the overall design first and not to look for drop in replacements from one OS to the other.

the IO systems are significantly different as well as thread scheduling. Good design on *NIX is often poor on windows and vice versa.

i don’t understand what your driver is supposed to do based on the info so far, so it is hard to offer anything more concrete