2011年3月3日 星期四

[ Windows DDP ] 計時器 : 計時器實作方式一

前言 : 
在驅動程式中, 一般有兩種方式使用計時器, 一種方法是使用 I/O 計時器常式, 另一種方法是使用 DPC 常式. 這裡將介紹如何使用 I/O 計時器常式. 

I/O 計時器 : 
I/O 計時器是 DDK 提供的一種計時器. 使用這種計時器, 每間隔 1s 鐘系統會呼叫一次 I/O 計時器常式. 設計師可以對這種計時器稍加改進, 在計時器常式中記錄某一個計數, 初始值設置為 N. 每次進入計時器的時候計數減一, 當計數歸零時, 執行某項操作, 並將計數還原為 N. 這樣間隔 1s 的計時器就變化為間隔 N s的計時器. 
I/O 計時器可以間隔 Ns 做定時, 但如果要實作對 ms 層級間隔甚至更小單位, 則需要用到另一種計時機制 (下一節介紹的 DPC 計時器). 在使用 I/O 計時器前需要先進行初始化, 初始化 I/O 計時器使用內核函式 IoInitializeTimer, 其宣告如下 : 

- Syntax :
  1. NTSTATUS IoInitializeTimer(  
  2.   __in      PDEVICE_OBJECT DeviceObject,  
  3.   __in      PIO_TIMER_ROUTINE TimerRoutine,  
  4.   __in_opt  PVOID Context  
  5. );  

- 參數說明 :
* 參數 DeviceObject : 這個參數是 I/O 計時器關聯的裝置物件指標
* 參數 TimerRoutine : 這個參數是 I/O 計時器關聯的計時器常式
* 參數 Context : 這個參數是傳進計時器常式的參數.

在初始化 I/O 計時器後, 可以開啟與停止 I/O 計時器. 開啟計時器後, 每隔一秒, 系統呼叫一次計時器常式. 在停止計時器後, 系統就不會進入計時器常式. 開啟計時器的內核函式是IoStartTimer, 停止 I/O 計時器的內核函式是 IoStopTimer. 
需要指出的是, I/O 計時器常式執行在 DISPATCH_LEVEL 層級, 因此在這個常式中不能使用分頁記憶體, 否則會引起頁故障而導致系統崩潰. 另外 I/O 計時器是執行在任意執行緒的, 不一定是 IRP 發起的執行緒中, 因此不能直接使用應用程式的記憶體. 

示例程式碼 : 
下面的例子演示了如何在驅動程式中使用 I/O 計時器. 這個例子每隔一秒進入 I/O 計時器常式, 每隔 3 秒輸出一行除錯資訊. 首先在 DriverEntry 中對 I/O 計時器進行初始化 : 
  1. ...  
  2. IoInitializeTimer(pDeviceObj, OnTimer, NULL);  
  3. ...  
然後在裝置擴充中, 加入一個計數變數, 這個變數負責記錄間隔的秒數 : 
  1. typedef struct _DEVICE_EXTENSION {  
  2. ...  
  3.     LONG lTimerCount;    // 計數變數  
  4. ...  
  5. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;  
然後定義兩個 IOCTL 碼, 分別是 IOCTL_START_TIMER 和 IOCTL_STOP. 當應用程式發起這兩個 IOCTL 請求後, 分別開啟與關閉計時器 : 
- Driver.cpp (函式 HelloDDKDeviceIOControl) :
  1. #pragma PAGEDCODE  
  2. NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,  
  3.                                  IN PIRP pIrp)  
  4. {  
  5.     NTSTATUS status = STATUS_SUCCESS;  
  6.     KdPrint(("Enter HelloDDKDeviceIOControl\n"));  
  7.   
  8.     //得到當前堆疊  
  9.     PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);  
  10.     //得到輸入緩衝區大小  
  11.     ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;  
  12.     //得到輸出緩衝區大小  
  13.     ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;  
  14.     //得到IOCTL碼  
  15.     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;  
  16.   
  17.     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)  
  18.         pDevObj->DeviceExtension;  
  19.   
  20.     ULONG info = 0;  
  21.   
  22.     switch (code)  
  23.     {                       // process request  
  24.         case IOCTL_START_TIMER:  
  25.         {  
  26.             KdPrint(("IOCTL_START_TIMER\n"));  
  27.             pDevExt->lTimerCount = TIMER_OUT;  
  28.             IoStartTimer(pDevObj);  
  29.             break;  
  30.         }  
  31.         case IOCTL_STOP:  
  32.         {  
  33.             KdPrint(("IOCTL_STOP\n"));  
  34.             IoStopTimer(pDevObj);  
  35.             break;  
  36.         }  
  37.         default:  
  38.             status = STATUS_INVALID_VARIANT;  
  39.     }  
  40.   
  41.     // 完成IRP  
  42.     pIrp->IoStatus.Status = status;  
  43.     pIrp->IoStatus.Information = info;   // bytes xfered  
  44.     IoCompleteRequest( pIrp, IO_NO_INCREMENT );  
  45.   
  46.     KdPrint(("Leave HelloDDKDeviceIOControl\n"));  
  47.   
  48.     return status;  
  49. }  

下面編寫計時常式, 這個常式是執行在 DISPATCH_LEVEL 的 IRQL 層級. 首先注意這個常式中不能使用分頁計憶體, 另外在函式首部要使用 #pragma LOCKEDCODE. 為了證明該執行緒可以執行在任意執行緒 Context, 在這個常式的最後, 我們得到當前執行緒的名稱, 並用 log 資訊將其輸出 : 
- Driver.cpp (函式 OnTimer) :
  1. #pragma LOCKEDCODE  
  2. VOID OnTimer(  
  3.     IN PDEVICE_OBJECT DeviceObject,  
  4.     IN PVOID Context)  
  5. {  
  6.     PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)  
  7.         DeviceObject->DeviceExtension;  
  8.     KdPrint(("Enter OnTimer!\n"));  
  9.   
  10.     //將計數器自鎖減一  
  11.     InterlockedDecrement(&pDevExt->lTimerCount);  
  12.       
  13.     //如果計數器減到0,重新程式設計TIMER_OUT,整個過程是互鎖運算  
  14.     LONG previousCount = InterlockedCompareExchange(&pDevExt->lTimerCount,TIMER_OUT,0);  
  15.   
  16.     //每隔三秒,計數器一個迴圈,輸出以下log  
  17.     if (previousCount==0)  
  18.     {  
  19.         KdPrint(("%d seconds time out!\n",TIMER_OUT));  
  20.     }  
  21.   
  22.     //證明該執行緒運行在任意執行緒context的  
  23.     PEPROCESS pEProcess = IoGetCurrentProcess();  
  24.      
  25.     PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);//即可得到使用者處理程序  
  26.   
  27.     KdPrint(("The current process is %s\n",ProcessName));  
  28. }  

接著在 User mode 程序發起 IOCTL 呼叫 : 
- main.cpp : 發出 IOCTL:IOCTL_START_TIMER 呼叫, 並於 5秒後再次發出 IOCTL:IOCTL_STOP 呼叫
  1. #include   
  2. #include   
  3. //使用CTL_CODE必須加入winioctl.h  
  4. #include   
  5. #include "..\NT_Driver\Ioctls.h"  
  6.   
  7. int main()  
  8. {  
  9.     HANDLE hDevice =   
  10.         CreateFile("\\\\.\\HelloDDK",  
  11.                     GENERIC_READ | GENERIC_WRITE,  
  12.                     0,      // share mode none  
  13.                     NULL,   // no security  
  14.                     OPEN_EXISTING,  
  15.                     FILE_ATTRIBUTE_NORMAL,  
  16.                     NULL );     // no template  
  17.   
  18.     if (hDevice == INVALID_HANDLE_VALUE)  
  19.     {  
  20.         printf("Failed to obtain file handle to device: "  
  21.             "%s with Win32 error code: %d\n",  
  22.             "MyWDMDevice", GetLastError() );  
  23.         return 1;  
  24.     }  
  25.   
  26.     DWORD dwOutput;  
  27.   
  28.     DeviceIoControl(hDevice, IOCTL_START_TIMER, NULL, 0, NULL, 0, &dwOutput, NULL);  
  29.   
  30.     Sleep(5000);  
  31.   
  32.     DeviceIoControl(hDevice, IOCTL_STOP, NULL, 0, NULL, 0, &dwOutput, NULL);  
  33.   
  34.     CloseHandle(hDevice);  
  35.   
  36.     return 0;  
  37. }  

下圖為執行後 log 輸出結果, 每個 1s 進入一次 I/O 計時器常式, 另外實做了每隔 3s 輸出一行除錯資訊. I/O 計時器常式還列出當前的處理程序名, 可以發現呼叫函式 OnTimer 的並不是發起 IOCTL 請求的處理程序. 
Idle 處理程序和系統處理程序一樣, 都是一種特殊處理程序, 他沒有對應的 exe 檔與之對應, 在 Windows 啟動後這兩個程序就存在於系統中了. 

2011年3月2日 星期三

[ Data Structures with Java ] Section 15.4 : Priority Queues


Preface :
A queue is a data structure that provides FIFO ordering of elements. Access is limited only to the first of "oldest" element in the queue and a deletion operation removes this element. Applications sometimes require a modified version of a queue in which access is given to the element with a priority ranking instead of chronological order. This structure, called a priority queue, removes the element of highest priority. The ranking of the elements in a priority queue is determined by some external criterion. For instance, suppose a business provides a centralized office pool to handle a variety of jobs for the staff. Company policy judges job requests by the president to be of highest priority (Priority 3), followed by requests from directors (Priority 2), from managers (Priority 1), and finally from clerks (Priority 0). A person's rank in the company becomes a criterion that measures the relative importance of a job. Instead of handling jobs on a first-come/first-served basic, the office pool uses a priority queue to handle jobs in the order of their assigned importance. For instance, below figure shows jobs 1-4 in the priority queue. The office pool processes the jobs in the order #2, #1, #4 and #3 so that the president is handled first and the clerk is handled last.


The "bucket" display in upper figure is a good abstract model for a priority queue. There is no assumption on how elements enter the priority queue but only a criterion for their exit. Think of a priority queue as a collection of elements loosely tossed into a bucket. Removing an element involves reaching around in the bucket and pulling out the one with the highest priority.
In a maximum priority queue, the highest-priority item has the largest value. The secretarial pool example illustrate a maximum priority queue. In a minimum priority queue, the highest-priority item has the smallest value. As an example of a minimum priority queue, an operating system can insert print jobs into a priority queue on the basic of the number of pages. In this situation, the higher-priority jobs are those with the lower page count. It is reasonable to print 2-,7- and 10- pages before a 100-page job.

A Simple Priority Queue Implementation :
Below is a simple example of using OrderedList to be the underlying data structure of the Priority queue. So the elements in the Priority queue should implements the Comparable interface for further operations.
The collection OrderedPQueue implements the PQueue interface which uses the same method names found in the Stack and Queue interfaces. So each time you add element into the OrderedPQueue, the new element will be insert into correct location to make sure the underlying data structure is in order. So we pop the element will have the highest priority among elements in the data structure (Bucket) :
- OrderedPQueue.java : Simple implementation of Priority Queue
  1. package DSwJ.S15;  
  2.   
  3. import DSwJ.S12.OrderedList;  
  4.   
  5. public class OrderedPQueue extends Comparablesuper T>> implements PQueue{  
  6.     private OrderedList orderList=null;  
  7.       
  8.     public OrderedPQueue(){orderList = new OrderedList(OrderedList.DESCENDING);}  
  9.   
  10.     @Override  
  11.     public boolean isEmpty() {  
  12.         return orderList.isEmpty();  
  13.     }  
  14.   
  15.     @Override  
  16.     public T peek() {  
  17.         return orderList.peek();  
  18.     }  
  19.   
  20.     @Override  
  21.     public T pop() {  
  22.         return orderList.removeFirst();  
  23.     }  
  24.   
  25.     @Override  
  26.     public void push(T item) {  
  27.         orderList.add(item);          
  28.     }  
  29.   
  30.     @Override  
  31.     public int size() {  
  32.         return orderList.size();  
  33.     }  
  34.       
  35.     public static void main(String args[]){  
  36.         HeapPQueue pq = new HeapPQueue();  
  37.         pq.push("green");  
  38.         pq.push("red");  
  39.         pq.push("blue");  
  40.         System.out.println(pq.size()+" "+pq.peek());  
  41.         while(!pq.isEmpty()) System.out.print(pq.pop()+" ");  
  42.     }  
  43. }  

Output:
3 red
red green blue
This message was edited 1 time. Last update was at 11/10/2010 17:18:55

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...