Running a timer

I have two different cases that require two different timer layouts which I am trying to configure. First I am trying to figure out how to get a timer to run once at a specified interval and then if a certain case is true I need to be able to cancel that timer and run a new one at a different time interval. The second case is being able to run a timer at the same set interval for a set amount of loops. Both of these timers need to have context to my WDFDEVICE and a custom struct that the timer will use. I also need to be able to cancel a timer when needed (based on input from IOCTL).

Anyways I am fairly sure this is what I am looking for which seems to set the interval for a single timer pass. But before I could use it I had to first initialize the PKTIMER struct and then set the time. As of now its just set at a static 1ms relative time (I will multiply it by a multiplier later to be able to set a time thats a multiple of 1ms). That being said I am confused about the PKDPC / custom DPC part which seems to be the call back function which will actually get called when the time expires. Lastly, just to make sure this is all ran on the same kernel thread?

    PKTIMER timer;
    KeInitializeTimer(&timer);

    if (timer == NULL) {
        DebugMessage("Timer is null! \n");
        return STATUS_CANCELLED;
    }

    LARGE_INTEGER expiration; 
    expiration.QuadPart = -10000; // As of now this time is 10,000nano * 100nano = 1ms  

    KDEFERRED_ROUTINE KdeferredRoutine;
    KdeferredRoutine();

    PRKDPC dpc;
    KeInitializeDpc(&dpc, ); // Initialize this first and replace NULL in KeSetTimer

    if (!KeSetTimer(timer, expiration, NULL)) {
        DebugMessage("Set Timer Failed! \n");
        return STATUS_CANCELLED;
    }

Why not use a WDFTIMER to keep it simple?

KeSetTimer only does one-shot timers. To get it to recur, you need to call KeSetTimer again in the callback.

KeSetTimerEx has the ability to set up a repeating periodic timer.

No one guarantees that the DPCs will be called on a single thread.

@Doron_Holan said:
Why not use a WDFTIMER to keep it simple?

I was not aware of that but thanks for mentioning it how does it differ from Ke timers?

@Doron_Holan said:
Why not use a WDFTIMER to keep it simple?

Alright I have done the following with WdfTimer but I have a few questions firstly is this all synchronous with the main driver thread? Secondly, is there a way to cancel a timer from running? Thirdly, is there a way I can modify the call back function to pass in a custom struct? If its not possible and if its synchronous I can just make the struct a global variable instead. Lastly, does the timer only run once because if so I assume I will need to schedule another one from inside the cleanup function (which I have not added yet).

    WDF_TIMER_CONFIG  timerConfig;
    WDF_OBJECT_ATTRIBUTES  timerAttributes;
    WDFTIMER  timerHandle;
    NTSTATUS  status;

    WDF_TIMER_CONFIG_INIT(&timerConfig, EvtWdfTimer);

    timerConfig.AutomaticSerialization = TRUE;

    WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
    timerAttributes.ParentObject = hDevice; // <-- WdfDevice

    if (!NT_SUCCESS(status = WdfTimerCreate(&timerConfig, &timerAttributes, &timerHandle))) {
        DebugMessage("WdfTimer could not be created \n");
        return STATUS_CANCELLED;
    }

    // Time is denoted in 100nano second intervals. Negative value just means its relative to the systems time
    if (!WdfTimerStart(timerHandle, -10000)) { // Time is 10,000nano * 100nano = 1ms
        return STATUS_CANCELLED;
    }
    return STATUS_SUCCESS;
}

void EvtWdfTimer(WDFTIMER timer)
{
    
}

The first question about timers should be how frequently you need one to fire (order of magnitude) and how much tolerance for jitter. Remember that unlike analog systems, digital systems do not jitter equally in all directions - they can only skew towards longer times

instead of changing between two timers, could you have both active all the time and simply decide in the callback which one should do work and which one should exit immediately?