kernel timer objects and synchronization
I won开发者_如何转开发dered if anyone can tell me simply (I know this is not a simple subject) how kernel timer objects are used to synchronize access to data structures in the kernel?
EDIT:
A kernel timer object is part of the kernel's dispatcher objects, which are the kernel's group of synchronization objects. I wanted to also know if the timer object is the thing that a thread has to wait to get a handle on before being able to continue, or is it the callback that is triggered when the timer expires that a thread waits to get a handle on?
I hope this makes sense. Kernels are a new subject to me.
Short answer: timer objects are not used to synchronize access to data structures in the kernel. For that the NT kernel has things like the fast mutex, guarded mutex, push lock, mutex object, etc. I don't quite understand your question - what data structures are you talking about? Nevertheless I will continue on the assumption that you want to know how timer objects can be used.
There are two ways you can use timer objects. The first is that they are signaled after a specified due time. So a thread might wait on a timer object using KeWaitForSingleObject, and it will only wake up after the due time has arrived. You can also use periodic signaling for the timer - you might want it to reset to a non-signaled state each time a thread gets woken up by it, and get signaled every few seconds.
The second (less common) use is that timer objects can insert APCs into the thread which set the timer. In case you don't know what an APC is - it's an Asynchronous Procedure Call. If a thread performs an alertable wait, an inserted APC will interrupt the wait and begin executing. Of course APCs are tricky to use, which is why people like to register timer objects with the threadpool and it takes care of handling callbacks (but that's another topic).
It's one method to synchronize by avoiding simultaneous access. Access is controlled essentially by serialization which occurs in a single handler function which is called through a callback, in this case a timer callback. See this.
The point of managing access is to prevent two threads from simultaneously accessing (either reading or writing) an object at the same time. There are several mechanisms for accomplishing this:
- Only one thread: contention is not possible because there's only one actor.
- Mutex: an operating system mechanism is combined with coding techniques to formalize access so that each time a thread says I want control of the mutex. When control is granted, it means no one else can access the associated object until the owner of the mutex releases it.
- Serialization: this is similar to only one thread. A typical scheme allows requests to be queued. Once higher priority requests are complete, then your request is processed. No other requests for the object are processed until yours is complete.
You have to view it in this way: when you're waiting on a timer you're synchronizing on the expiry of the timer. Your thread will not run until the timer's specified duetime has elapsed (subject to the granularity of system time, which is typically 15.6 ms).
In general, calling the timer a "synchronization object" has more to do with the family of APIs you use to find out about its duetime on a thread than the actual function of the object itself.
More often than not in kernel mode, timer expiry is actually consumed using a DPC callback (see the DPC parameter to KeSetTimer). This is just an asynchronous call which occurs in some arbitrary thread context in the kernel where you can have your code run (but it can't block, take locks, access pageable memory, etc). The latter restrictions aren't really a problem for device drivers, which mostly want to just touch their devices periodically.
精彩评论