Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV
Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


WDFWORKITEM / WDFTIMER info

msrmsr Member Posts: 354

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

Comments

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,313

    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

    Peter Viscarola
    OSR
    @OSRDrivers

  • msrmsr Member Posts: 354

    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**);
      
  • msrmsr Member Posts: 354

    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);
    
  • MBond2MBond2 Member Posts: 277

    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

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Writing WDF Drivers 7 Dec 2020 LIVE ONLINE
Internals & Software Drivers 25 Jan 2021 LIVE ONLINE
Developing Minifilters 8 March 2021 LIVE ONLINE