青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

桃源谷

心靈的旅行

人生就是一場旅行,不在乎旅行的目的地,在乎的是沿途的風景和看風景的心情 !
posts - 32, comments - 42, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

W2K信號(Signals)的設備驅動

Posted on 2010-04-13 10:29 lymons 閱讀(2340) 評論(0)  編輯 收藏 引用 所屬分類: C++CUnix/Linux
 

 


W2K信號(Signals)的設備驅動

     Unix下的信號提供了一個簡單的IPC機制,也就是當進程收到一個信號后會異步(asynchronous) 地調用你的信號處理函數(也叫做句柄),不管你的代碼是否已經處在執行的過程之中。 而在Windows 2000(譯者注:版本高于W2kWindows平臺)下就需要用到一個設備驅動,以便你能使用異步過程調用(asynchronous procedure calls , 簡稱APCs或者APC) 來達成同樣的效果.

By Panagiotis E.
August 01, 2001
URL:http://www.ddj.com/windows/184416344

翻譯:Lymons (lymons@gmail.com)

 


      在Windows和基于Unix的操作系統之間的一個重要的不同就是對程序員自定義的信號處理函數的支持。盡管標準C庫已經為信號處理[2]提供了基本的支持,但這些函數對于那些想主要依靠信號來實現進程間通信(IPC)的程序員來講還不夠。 實際上,在Windows的上下文中缺乏這樣的一個機制,導致了進程(線程)間的異步通信的實現困難,另外還需要運用一些特殊的數據結構,如事件,而且還需要創建一個進程,專門用于不斷地去輪巡一些條件[6],查看其狀態是否發生改變。 在本文中,我將向大家介紹SignalsLib庫,它被用于在Win32平臺下進行信號處理。這個庫的核心是一個設備驅動,該驅動提供了一個給目標進程發送信號并讓其異步執行信號處理函數的機制,即使是目標進程并不處在消息等待的狀態。

      跟大多文章一樣,本文為信號處理提供了一份概要性的說明,

1.            信號和基本機制

2.           庫和驅動的設計與實現

3.           該機制下的性能測量

4.           面向程序員的API

5.           以及相關的擴展和可能用法。

信號的概述

       信號是把異步事件通知給進程的一個機制。它的基本思想是為每一個獨特的信號關聯上一個整數代碼,并且任何進程都能給任何一個信號注冊一個處理函數(回調函數)(通過指定該信號的整數代碼). 當一個進程發送一個特定的信號給其他的進程(該進程已經為這個信號注冊了信號處理函數)的時候,這個目標進程當前正在做的操作將會被中斷,轉而去執行這個被注冊的信號處理函數。

       信號機制有點兒類似于,在一個信號中斷中進行一個中斷處理,不管目標進程是否正在執行某一段代碼。跟中斷處理函數一樣,信號處理函數需要認真仔細地編碼 --- 普通的代碼一定不能訪問和信號處理函數中一樣的數據,除非它們都是用同步原語(synchronization primitives)來避免相互之間的破壞。信號提供了簡單和方便的進程間通信。通常傳統的應用在下面的情況:

1.           通知一個服務它將輪轉(rotate)它的日志文件;

2.           通知一個父進程子進程已經完成初始化并已經準備開始實行下面的工作;

3.           通知一個進程它將暫時暫停自己的操作;

4.           通知一個進程它將在關機時盡可能快地執行清除操作

5.           等等。

      每個信號都被關連上一個將被執行的動作,通過內核調度來使接收到這個信號的進程來執行它的行為。對于大多數的信號,缺省的動作時終止進程的運行,盡管一個進程能被要求執行一些來自系統選擇的動作。這些可能的可選動作無非就是:

1. 忽略這個信號。 在這種情況下,進程將不會接收到這個信號的通知。

2. 恢復缺省的信號動作。

3. 執行一個指定的信號處理函數。這種場合下,當希望一個指定的信號到達時,想要某個進程去執行一些定制動作,就可以去注冊這個定制函數。當關聯的信號發生時就可以異步地調用它了。在這個信號處理函數返回之后,將在被中斷的代碼的地方繼續執行原來的操作。

Windows支持信號

        Win32為信號支持提供了一個十分特殊的函數 SetConsoleCtrlHandler(). 這個函數讓一個控制臺的程序能捕獲很多的系統自身的信號(如,用戶按下了Ctrl-C, 用戶注銷, ) 但它沒有提供任何的程序員自定義的信號,也沒有提供任何的進程間通信 這就很嚴格的意味著操作系統只能把很少的一些特定事件通知給一個進程。

        Windwos提供的僅有的與信號機制類似的是異常處理這種機制。然而,標準C要求給著名的signal()/raise() Unix 函數以及一些受約束的信號[2]提供支持. signal()給指定的信號設定被調用的信號處理函數raise() 是給當前的進程發送特定的信號,調用為這個信號注冊的處理函數,或者與該信號關聯的缺省動作。 另外,這些信號是不可擴展的,并且它們只能在給定的進程內部進行傳播。 (標準C并沒有為向其他進程發送信號而定義標準函數)

        作為信號的替代品,Windows支持異步過程調用,簡稱為APCs (Asynchronous Procedure Calls). 一個APC 就是一個內核定義的控制對象,代表著一個過程/函數可以被異步的調用. APCs 有著下列的幾個特征[7]:

1. 一個 APC 總是運行在一個指定的線程的上下文中.

2. 一個 APC 運行在 OS 的預設時間內.

3. APCs 能夠搶占當前正在運行的線程.

4. APC 例程也能被他們自己搶占.

      在內核中APCs 有三個不同的類型[2,3]:

     用戶模式(User-mode) APCs. 用戶模式 APCs 默認是被禁止的; 也就是對于用戶模式的線程它們雖然被放置到隊列進行排隊,但它們并不會被執行,除了在程序中一些明確定義的點上。具體的就是,它們能夠在下面兩種情況被執行:

1. 當一個應用調用等待服務(wait service)并且觸發了告警發生機制的時候;

2. 或者調用告警測試服務(test-alert service)的時候.

      常態內核模式(Normal kernel-mode) APCs. 除了默認情況下是可以被執行的之外,其他的它們更像用戶模式的APCs。也就是,當線程已經開始執行一個內核模式的APC,或者駐留在一個臨界區代碼之中時,是不能被執行的。除此之外,它們都是可以被執行的。

      特殊內核模式(Special kernel-mode) APCs. 它們是不能被阻塞的, 除了線程運行在IRQL (interrupt request level)喚起的狀態下。 特殊內核模式的APCs 在內核態中能在IRQL APC_LEVEL級別下運行。它們被用來強制讓一個線程在它的上下文中去執行一個過程。 特殊內核模式的APC 能夠搶占常態內核模式APC的執行。

       Win32 API [4] 提供了 QueueUserAPC()這個函數, 它允許一個應用把線程的APC對象放置到隊列中。正在排隊中的APC是讓一個指定的線程去調用APC函數的請求。當用戶模式的APC被放到隊列中時,線程則不能直接去調用這個APC函數,除非它是處在一個告警使能的狀態。 不幸的是,一個線程只能使用下列的 Win32 API函數的之一才能使自己進入到告警使能的狀態: SleepEx(), SignalObjectAndWait(), WaitForSingleObjectEx(), WaitForMultipleObjectEx(), MsgWaitForMultipleObjectsEx().

    在內核態[1], 程序員可以使用KeInitializeApc()來初始化一個APC對象, 定義目標線程,以及一個內核態和用戶態的回調函數, 以及APC (內核 或者 用戶)類型, 最后是傳遞給這兩個函數的參數。接著, 這個目標線程的 APC 被排隊(KeInsertQueueApc()) 到隊列中,并且在線程沒有進入到告警使能的狀態時也能夠被執行。

SignalsLib 函數庫的接口

       這個函數庫給支持信號處理提供了適宜的接口,必要的數據結構和機制。在構建過程的期間,用戶能夠給每個線程定義選項以及全局信號處理函數表的用途。

        signals.h (Listing 1) 定義了可用的信號,信號的整形代碼是從零開始直到MAX_SIGNALS-1. 在這個頭文件中為信號函數庫中的兩個如下的函數聲明了接口。

1. SetSignalHandler() 給指定的信號設置一個函數(handler). 該函數如果執行失敗則返回0 成功則返回非零值。

2. SendSignalToThread() 給指定的線程發送一個信號. 你必須給想接收這個信號的線程指定該線程的句柄,以及想要發送的信號(整形代碼)。該函數成功則返回0,否則返回非零。

        testapp.c (Listing 2) 描述了如何去使用這個信號函數庫。 這個應用創建了一個設定信號和對應的信號處理函數的線程,以及發送這個信號給子線程的主線程,最終導致這個已經安裝的信號處理函數被執行。當然,這個驅動必須事先被安裝到系統里并且已被裝載到內存中,否則當函數庫的DLLMain()函數被執行的時候,會輸出相應的錯誤消息。

設計和實現

      SignalsLib 庫由DLL文件和內核態的設備驅動組成。這個 DLL 給應用程序提供了一個用戶態的接口, 當我們想要讓目標線程排隊一個內核模式的APC并去調用關聯的內核態的函數的時候,就需要用到這個設備驅動。應用程序僅僅是簡單的調用SetSignalHandler() SendSignalToThread()這兩個函數就可以, 然而這個 DLL 隱藏了所有的與設備驅動進行通信的細節。

       SetSignalHandler() 函數很簡單它僅僅是存儲了在信號處理函數的全局數組中的相應位置,也就是一個函數指針。 當一個信號確實是被觸發的時候,內部函數SignalsDriverRoutine()將會被調用,并且訪問這個全局數組來決定調用哪個信號處理函數。這兩個函數在signals.c (Listing 3)有定義.

       SendSignalToThread() 函數是DLL與設備驅動進行通信的地方。 DllMain() DLL第一次被載入的時候會獲得一個設備驅動的句柄, 并且在DLL被卸載的時候會釋放這個句柄。 SendSignalToThread() 函數在調用DeviceIoControl()函數(該函數是傳遞一個SIGINFO結構體給這個設備驅動)的時候會使用這個句柄:

 

typedef struct _SIGINFO

{

   HANDLE   hThread;   
/* target thread */

   ULONG    SigNo;     
/* signal number */

   ULONG    SigFunc;   
/* address of DriverRoutine */

}
 SIGINFO, *PSIGINFO;

 

        注意這個 SigFunc 不是一個單獨信號處理函數的地址,而是SignalsDriverRoutine()函數的地址,該函數的功能是查詢和調用DLL中的正確的信號處理函數。

        當SendSignalToThread() 函數傳遞這個信息給DeviceIoControl()的時候, 它將導致這個驅動的中斷服務程序被調用。該驅動的主要源代碼都在sigdrv.c (Listing 4)文件里面. 然后驅動中斷服務例程會調用SigDriverSendTheSignal()函數來負責為目標線程來排隊一個相應的內核模式的APC. SigDriverSendTheSignal() 中有一個指向這個目標線程的ETHREAD 的數據結構體 [2]的指針. 然后調用 KeInitializeApc() 函數去初始化一個內核模式的APC并且調用KeInsertQueueApc() 來把目標線程的 APC 插入到隊列中。

         這個被放入到隊列中的 APC 包含一個指向sigdrv.c (Listing 4)文件中的一個函數UserApcCallBack()的指針. 這個函數將會在用戶態中被調用并且傳遞SIGINFO 結構體. UserApcCallBack() 使用 SIGINFO 中的信息來調用DLL 函數 SignalsDriverRoutine(), 而它就是那個查詢且調用與指定信號關聯的信號處理函數的函數。

性能評估

        編程時到底是選擇常態還是特殊內核模式的APC,是跟你所期望的功能有關,而跟性能無關。 如果你認為你的信號處理函數能被其他的被觸發的信號所搶占是一件重要的事情的話,那么你應該選擇使用特殊內核模式的APC而不是常態內核模式APCs.

        這個APC 機制執行的相當棒;一旦目標線程被調度后這個信號處理函數就會很快的被調用,一般情況下就是幾微秒之間的事兒。其中值得注意的一個重要的事情就是,內核模式APC能立刻完成信號的傳送,這與系統載入的(或者說在系統中運行的)線程數量無關。他是通過改變線程的優先級來減少這個響應時間。例如, SendSignalToThread() 函數能夠提升目標線程的優先級。

結論

       主要是為了在Win32應用中能夠使能相同線程內部或者不同線程間的異步通信,我實現了這個用戶自定義信號的基本機制。與Unix系統調用signal() kill() 相似的,最終的,通過DLL和設備驅動協同工作也能提供這兩個重要的信號處理的接口,并且也支持了相似的SIGUSR1 SIGUSR2這兩個信號.

       作為這個庫的擴展將來很可能會實現一些其他的Unix信號,如SIGSTOP, SIGCONT, SIGTERM, 并且支持POSIX 標準。 也愿意把這個機制集成到標準C庫中去。這個庫也協助實現了POSIX函數pthread_kill() ,這就使得應用程序在用戶模式下(或者是從內核到用戶模式)POSIX線程間需要通知機制時,就讓開發工作變的很容易, 僅僅是讓設備驅動知道驅動例程的函數地址即可。 盡管這個POSIX 標準為應用程序的所有的線程定義了全局信號處理函數,這個庫也能容易的為每個線程提供信號處理的支持,通過使用線程的局部存儲數據;為了簡單,在當前這個版本中沒有這么做。

       為了發表這篇文章我盡量讓代碼編寫的簡潔, 代碼的實現是假設所有參與進來的進程都共享同一個signals.dll的實例(也就是它們之間是父子進程的關系). 更明確的說, SendSignalToThread() 函數總是傳遞SignalsDriverRoutine() 的函數地址(調用進程的上下文中)給設備驅動,但是設備驅動則會嘗試使用目標進程(很可能是另外一個進程)上下文中的那個地址. 如果目標進程已經把signals.dll 載入到了一個不同的地址而不是調用進程載入進來的地址,這將會導致一個災難發生。如果一個特別的進程不能把signals.dll 載入到一個缺省的地址,你可以選擇另外一個地址,直到你找到與已經載入的DLL地址沒有沖突的另外一個地址。 你能更優雅地解決這個問題通過修訂這個接口以便讓設備驅動能夠有足夠的信息來定位指定線程中的正確的回調函數的地址。

      最后,另外一個基于用戶模式APC的實現在這里沒有描述。不過SendSignalToThread() 可以調用 Win32 QueueUserAPC() 函數然后通過內核模式的設備驅動,來設置目標線程成告警使能狀態。 你可以對與ETHREAD數據結構[2]的基地址相偏移0x4a 個字節的一個內存地址進行設定來實現的。

References

[1] E. N. Dekker and J. M. Newcomer. Developing Windows NT Device Drivers: A Programmer’s Handbook (Addison-Wesley, 1999).

[2] Microsoft Corporation. Microsoft Developer Network Library, msdn.microsoft.com/library.

[3] D. A. Solomon. Inside Windows NT, Second Edition (Microsoft Press, 1998).

[4] J. Ritcher. Advanced Windows: The Professional Developer’s Guide to the Win32 API for Windows NT 4.0 and Windows 95 (Microsoft Press, 1995).

[5] www.cmkrnl.com/arc-userapc.html

[6] www.microsoft.com/msj/0799/nerd/nerd0709.html

[7] www.osr.com/insider/1998/apc.html

[8] Microsoft Visual Studio\VC98\CRT\SRC\WINSIG.C

Panagiotis Hadjidoukas is a postgraduate student at High Performance Information Systems Laboratory, Department of Computer Engineering & Informatics, at the University of Patras in Greece. You can reach him by email at peh@hpclab.ceid.upatras.gr or at the web page of his laboratory at http://www.hpclab.ceid.upatras.gr.

Listing 1: signals.h — Interface to signal library

/* Number of supported signals */

#define MAX_SIGNALS     4

 

/* Signal names */

#define SIGNAL0 0

#define SIGNAL1 1

#define SIGNAL2 2

#define SIGNAL3 3

 

#ifndef SIGNALSLIBAPI

#define SIGNALSLIBAPI __declspec(dllimport)

#endif

 

/* Set a signal handler */

SIGNALSLIBAPI DWORD SetSignalHandler(DWORD, PVOID);

 

/* Send a signal to a thread */

SIGNALSLIBAPI DWORD SendSignalToThread(HANDLE, DWORD);

/* End of File */


Listing 2: testapp.c — Source for signal demonstration program

 

#define STRICT 1

#include 
<windows.h>

#include 
<stdio.h>

#include 
<string.h>

#include 
<stdlib.h>

 

#include 
"..\dll\signals.h"

 

/* Global variables to avoid any optimization by the compiler */

long sum1 = 0, sum2 = 0;

 

volatile unsigned long WaitFlag = 0;

 

VOID __stdcall fSignal0(VOID)

{

   printf(
"Thread (%ld):Inside the handler \

of signal SIGNAL0
!!!\n", GetCurrentThreadId());

   
return;

}


 

DWORD WINAPI ThreadRoutine(LPVOID Param)

{

   
long i;

 

   
/* Set a hanndler for SIGNAL0 */

   SetSignalHandler(SIGNAL0, fSignal0);

 

   
/* Do some stuff*/

   
for (i = 0; i < 10000000; i++) sum1++;

 

   
/* Wait until the main thread sets the flag */

   
while (WaitFlag == 0);

   
return 0;

}


 

HANDLE hThread;

DWORD ThreadId;

 

int main()

{

   ULONG   i 
= 0;

   DWORD   Data 
= 1;   /* Not actually used */

 

   
/* Create the target thread */

   hThread 
= CreateThread(NULL,0,ThreadRoutine,&Data,0,&ThreadId);

 

   
/* Let the target thread to run for a while */

   Sleep(
1000);

 

   
/* Send a signal to the target thread */

   printf(
"Thread (%ld): Sends a signal to the \

target thread\n
", GetCurrentThreadId());

   SendSignalToThread(hThread, SIGNAL0);

 

   
/* Do some stuff and wait for a while */

   
for (i = 0; i < 10000000; i++) sum2++;

   Sleep(
1000); 

 

   
/* Set the flag. The handler must have been executed by now */

   WaitFlag 
= 1;

 

   
/* Wait for the thread's termination */

  WaitForSingleObject(hThread, INFINITE);

 

   
return 0;

}


/* End of File */


Listing 3: signals.c — Source for signal DLL

 

#define STRICT 1

#include 
<windows.h>

#include 
<stdio.h>

#include 
<winioctl.h>

#include 
<string.h>

#include 
<stdlib.h>

 

#include 
"..\driver\sigdrv.h"

#define SIGNALSLIBAPI __declspec(dllexport)

#include 
"signals.h"

 

/* Global array of signal handler */

VOID (__stdcall 
*functable[MAX_SIGNALS])(VOID);

 

/* Handle to the device driver */

HANDLE hDevice;

 

/* Set a signal thread */

DWORD SetSignalHandler(DWORD SignalNumber, PVOID f)

{

   
if (SignalNumber < MAX_SIGNALS)

   
{

      functable[SignalNumber] 
= f;

      
return 0;

   }


   
return 1;

}


 

/* Call the appropriate signal handler */

DWORD WINAPI SignalsDriverRoutine(DWORD SignalNumber)

{

   
if (functable[SignalNumber] != NULL)

      (functable[SignalNumber])();

   
else

      printf(
"NULL signal function!\n");

 

   
return 0;

}


 

 

/* this information is sent to the device driver */

typedef 
struct _SIGINFO

{

   HANDLE   hThread;   
/* target thread */

   ULONG    SigNo;     
/* signal number */

   ULONG    SigFunc;   
/* address of DriverRoutine */

}
 SIGINFO, *PSIGINFO;

 

SIGINFO     siginfo;

 

/* Send a signal to the targer thread */

DWORD SendSignalToThread(HANDLE hThread, DWORD SignalNumber)

{

   DWORD   cbReturned;

 

   
/* Initialize a SIGINFO structure */

   siginfo.hThread 
= hThread;

   siginfo.SigNo 
= SignalNumber;

   siginfo.SigFunc 
= (unsigned long)SignalsDriverRoutine;

 

   
/* Send the information to the driver */

   
if (!DeviceIoControl (hDevice,

                         (DWORD)IOCTL_SIGDRV_SEND_SIGNAL,

                         (PSIGINFO) 
&siginfo,

                         
sizeof(SIGINFO),

                         NULL,

                         
0,

                         
&cbReturned,

                         
0

                         ) )

   
{

      
return 1;

   }


    
return 0;

}


 

BOOL WINAPI DllMain(HINSTANCE hDllInst, DWORD fdwReason,

                    LPVOID lpvReserved)

{

   
switch (fdwReason)

   
{

      
case DLL_PROCESS_ATTACH:

         
if ((hDevice =

                CreateFile(

                  
"\\\\.\\Global\\SIGDRV",

                  GENERIC_READ 
| GENERIC_WRITE,

                  FILE_SHARE_READ 
| FILE_SHARE_WRITE,

                  NULL,

                  OPEN_EXISTING,

                  FILE_ATTRIBUTE_NORMAL,

                  NULL

             )) 
== INVALID_HANDLE_VALUE)

         
{

             printf (
"Can't get a handle to the driver\n");

             
return FALSE;

         }


 

         
break;

      
case DLL_PROCESS_DETACH:

           CloseHandle(hDevice);

         
break;

      
case DLL_THREAD_ATTACH:

         
break;

      
case DLL_THREAD_DETACH:

         
break;

   }


   
return TRUE;

}


 

/* End of File */


Listing 4: sigdrv.c — Kernel-mode driver for signal library

 

#define STRICT 1

#include 
"ntddk.h"

#include 
"string.h"

#include 
"sigdrv.h"

 

#define SIGDRV_DEVICE_NAME_U     L"\\Device\\Sigdrv"

#define SIGDRV_DOS_DEVICE_NAME_U L"\\DosDevices\\SIGDRV"

 

// Debugging macros

#ifdef DBG

#define SigDrvKdPrint(_x_) \

                DbgPrint(
"SigDrv.sys: ");\

                DbgPrint _x_;

#else

#define SigDrvKdPrint(_x_)

#endif

 

NTSTATUS DriverEntry(

   IN PDRIVER_OBJECT DriverObject,

   IN PUNICODE_STRING registryPath);

 

VOID SigDrvUnload(

   IN PDRIVER_OBJECT DriverObject);

 

NTSTATUS SigDrvDispatch(

   IN PDEVICE_OBJECT DeviceObject,

   IN PIRP Irp);

 

NTSTATUS SigDrvSendTheSignal(

   IN PDEVICE_OBJECT DeviceObject,

   IN OUT PVOID ioBuffer,

   IN ULONG inputBufferLength,

   IN ULONG outputBufferLength);

 

void KeInitializeApc(

   PKAPC Apc,

   PKTHREAD Thread,

 

   CCHAR ApcStateIndex,

   PKKERNEL_ROUTINE KernelRoutine,

   PKRUNDOWN_ROUTINE RundownRoutine,

   PKNORMAL_ROUTINE NormalRoutine,

   KPROCESSOR_MODE ApcMode,

   PVOID NormalContext);

 

 

void KeInsertQueueApc(

   PKAPC Apc,

   PVOID SystemArgument1,

   PVOID SystemArgument2,

   UCHAR unknown);

 

// Information the driver receives from user mode

typedef 
struct _SIGINFO

{

   HANDLE   hThread;   
// handle of targer thread

   ULONG    SigNo;     
// which signal

   ULONG    SigFunc;   
// signals' driver-routine of the dll

}
 SIGINFO, *PSIGINFO;

 

void KernelApcCallBack(

   PKAPC Apc,

   PKNORMAL_ROUTINE NormalRoutine,

   PVOID NormalContext,

   PVOID SystemArgument1,

   PVOID SystemArgument2)

{

   ExFreePool(Apc);    
// just free the kernel memory

   
return;

}


 

void UserApcCallBack(PVOID arg1, PVOID arg2, PVOID arg3)

{

   PSIGINFO psiginfo 
= (PSIGINFO) arg3;

   ULONG (
*SignalDriverRoutine)(ULONG);

 

   
// take the user mode address of the function

   SignalDriverRoutine 
= (unsigned long (__stdcall *)

        (unsigned 
long)) psiginfo->SigFunc;

 

   
// call the driver-routine

   SignalDriverRoutine(psiginfo
->SigNo);

 

   
return;

}


 

NTSTATUS DriverEntry(

   IN PDRIVER_OBJECT DriverObject,

   IN PUNICODE_STRING RegistryPath)

{

   PDEVICE_OBJECT deviceObject
=NULL;

   NTSTATUS       ntStatus;

   WCHAR          deviceNameBuffer[]
=SIGDRV_DEVICE_NAME_U;

   UNICODE_STRING deviceNameUnicodeString;

   WCHAR          deviceLinkBuffer[]
=SIGDRV_DOS_DEVICE_NAME_U;

   UNICODE_STRING deviceLinkUnicodeString;

 

   RtlInitUnicodeString (
&deviceNameUnicodeString,

                         deviceNameBuffer);

   ntStatus 
= IoCreateDevice (

                      DriverObject,
0,&deviceNameUnicodeString,

                      FILE_DEVICE_SIGDRV,
0,FALSE,&deviceObject);

   
if (!NT_SUCCESS(ntStatus))

   
{

       SigDrvKdPrint((
"IoCreateDevice failed:%x\n", ntStatus));

       
return ntStatus;

   }


 

   DriverObject
->MajorFunction[IRP_MJ_CREATE] =

   DriverObject
->MajorFunction[IRP_MJ_DEVICE_CONTROL] =

   DriverObject
->MajorFunction[IRP_MJ_CLOSE] = SigDrvDispatch;

 

   DriverObject
->DriverUnload = SigDrvUnload;

 

   RtlInitUnicodeString (
&deviceLinkUnicodeString,

                         deviceLinkBuffer);

 

   ntStatus 
= IoCreateSymbolicLink (&deviceLinkUnicodeString,

                                    
&deviceNameUnicodeString);

   
if (!NT_SUCCESS(ntStatus))

   
{

      SigDrvKdPrint ((
"IoCreateSymbolicLink failed\n"));

      IoDeleteDevice (deviceObject);

   }


 

   
return ntStatus;

}


 

NTSTATUS SigDrvDispatch(

   IN PDEVICE_OBJECT DeviceObject,

   IN PIRP Irp)

{

   PIO_STACK_LOCATION irpStack;

   PVOID              ioBuffer;

   ULONG              inputBufferLength;

   ULONG              outputBufferLength;

   ULONG              ioControlCode;

   NTSTATUS           ntStatus;

 

   Irp
->IoStatus.Status      = STATUS_SUCCESS;

   Irp
->IoStatus.Information = 0;

 

   irpStack 
= IoGetCurrentIrpStackLocation(Irp);

 

   ioBuffer           
= Irp->AssociatedIrp.SystemBuffer;

   inputBufferLength 
=

      irpStack
->Parameters.DeviceIoControl.InputBufferLength;

   outputBufferLength 
=

      irpStack
->Parameters.DeviceIoControl.OutputBufferLength;

 

   
switch (irpStack->MajorFunction)

   
{

      
case IRP_MJ_CREATE:

         SigDrvKdPrint ((
"IRP_MJ_CREATE\n"));

         
break;

 

      
case IRP_MJ_CLOSE:

         SigDrvKdPrint ((
"IRP_MJ_CLOSE\n"));

         
break;

 

      
case IRP_MJ_DEVICE_CONTROL:

         ioControlCode 
=

           irpStack
->Parameters.DeviceIoControl.IoControlCode;

 

         
switch (ioControlCode)

         
{

            
case IOCTL_SIGDRV_SEND_SIGNAL:

               Irp
->IoStatus.Status = SigDrvSendTheSignal(

                                          DeviceObject,

                                          ioBuffer,

                                          inputBufferLength,

                                          outputBufferLength);

 

               
if (NT_SUCCESS(Irp->IoStatus.Status))

               
{

                  Irp
->IoStatus.Information = sizeof(PVOID);

                  SigDrvKdPrint((
"Signal was sent\n"));

               }


               
else

               
{

                  Irp
->IoStatus.Status = STATUS_INVALID_PARAMETER;

                  SigDrvKdPrint((
"Signal failed to be sent\n"));

               }


               
break;

            
default:

               SigDrvKdPrint ((
"unknown IRP_MJ_DEVICE_CONTROL\n"));

               Irp
->IoStatus.Status = STATUS_INVALID_PARAMETER;

               
break;

         }


         
break;

   }


 

   ntStatus 
= Irp->IoStatus.Status;

   IoCompleteRequest(Irp, IO_NO_INCREMENT);

   
return ntStatus;

}


 

VOID SigDrvUnload(IN PDRIVER_OBJECT DriverObject)

{

   WCHAR deviceLinkBuffer[] 
= SIGDRV_DOS_DEVICE_NAME_U;

   UNICODE_STRING deviceLinkUnicodeString;

 

   RtlInitUnicodeString (
&deviceLinkUnicodeString,

                             deviceLinkBuffer);

   IoDeleteSymbolicLink (
&deviceLinkUnicodeString);

   IoDeleteDevice (DriverObject
->DeviceObject);

 

   
return;

}


 

NTSTATUS SigDrvSendTheSignal(

 IN PDEVICE_OBJECT DeviceObject,

 IN OUT PVOID      IoBuffer,

 IN ULONG          InputBufferLength,

 IN ULONG          OutputBufferLength)

{

   NTSTATUS   ntStatus 
= STATUS_SUCCESS;

   PVOID      virtualAddress;

   SIGINFO    
*psiginfo = (PSIGINFO) IoBuffer;

   PETHREAD   uThread 
= NULL;

   PKAPC      kApc;

 

   
// take a pointer to the kernel thread structure

   ntStatus 
= ObReferenceObjectByHandle(

                psiginfo
->hThread, THREAD_ALL_ACCESS,

                NULL, KernelMode, 
&uThread, NULL);

   
if (NT_ERROR(ntStatus)) {

      SigDrvKdPrint ((
"ObReferenceObjectByHandle Failed\n"));

      
return ntStatus;

   }


 

   
// Allocate an KAPC structure from NonPagedPool

   kApc 
= ExAllocatePool(NonPagedPool, sizeof(KAPC));

 

   KeInitializeApc(kApc,

                   (PKTHREAD) uThread, 
0,

                   (PKKERNEL_ROUTINE) 
&KernelApcCallBack, 0,

                   (PKNORMAL_ROUTINE) 
&UserApcCallBack,

                   KernelMode, (PVOID) 
0);

   KeInsertQueueApc (kApc, (PVOID) (ULONG) 
10, (PVOID) psiginfo, 0);

 

   ObDereferenceObject((PVOID) uThread);

   
return ntStatus;

}


/* End of File */

 

我的個人簡歷第一頁 我的個人簡歷第二頁
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            91久久精品国产91久久| 欧美一区二区三区四区在线观看地址| 国产精品视频最多的网站| 麻豆国产精品va在线观看不卡| 亚洲四色影视在线观看| 亚洲国产高清aⅴ视频| 久久九九精品99国产精品| 9久re热视频在线精品| 亚洲大胆视频| 国产综合自拍| 国产伦精品一区二区三区照片91 | 一区电影在线观看| 亚洲电影观看| 国语自产精品视频在线看| 国产精品久久久免费| 欧美日韩国产一中文字不卡| 免费成人激情视频| 久久人人爽爽爽人久久久| 欧美在线视频不卡| 欧美一区二区视频在线| 亚洲男人的天堂在线aⅴ视频| 亚洲伦伦在线| 亚洲另类在线一区| 日韩视频免费观看高清在线视频| 欧美激情精品久久久久久蜜臀| 久久人人超碰| 久久这里只有精品视频首页| 久久久国产亚洲精品| 久久久久国产精品厨房| 欧美一区在线直播| 欧美在线一区二区三区| 香蕉av777xxx色综合一区| 亚洲欧美日韩在线不卡| 亚洲色诱最新| 亚洲免费视频观看| 午夜伦理片一区| 久久国产精品黑丝| 久久久久久久久久久成人| 久久在线观看视频| 欧美成人蜜桃| 91久久精品日日躁夜夜躁国产| 亚洲区一区二| 一区二区三区日韩欧美| 亚洲少妇自拍| 午夜精品久久久久久久99黑人| 午夜一区二区三区不卡视频| 久久精品理论片| 欧美aa在线视频| 欧美日韩亚洲精品内裤| 国产精品久久久久久久久| 国产日韩欧美精品| 伊人久久大香线| 日韩视频免费观看| 亚洲综合视频一区| 久久精品国亚洲| 亚洲福利国产精品| 一区二区三区四区精品| 亚洲欧美精品中文字幕在线| 久久久精品动漫| 欧美激情一区二区三区不卡| 国产精品久线观看视频| 狠狠爱综合网| 一本色道久久88亚洲综合88| 欧美一区二区大片| 欧美国产日韩二区| 亚洲夜间福利| 免费不卡在线观看av| 欧美系列一区| 亚洲成色777777女色窝| 亚洲天堂免费观看| 久久夜色精品一区| 999在线观看精品免费不卡网站| 亚洲欧美制服中文字幕| 免费亚洲一区| 国产色综合网| 一区二区三区久久精品| 久久综合网络一区二区| 99v久久综合狠狠综合久久| 欧美一二三视频| 欧美久色视频| 精品动漫3d一区二区三区| 一本色道久久88精品综合| 久久久久久久激情视频| 日韩视频在线你懂得| 久久久久久综合| 国产精品欧美日韩一区二区| 亚洲精品美女在线观看| 久久久久国产一区二区三区四区 | 亚洲一区激情| 欧美寡妇偷汉性猛交| 国产欧美一区二区色老头| 99国内精品| 欧美国产日韩一区二区| 性色一区二区三区| 国产精品扒开腿做爽爽爽视频| 亚洲国产你懂的| 久久久久久久91| 亚洲影音一区| 欧美日韩成人一区二区| 精品动漫3d一区二区三区免费版| 亚洲欧美日韩一区在线| 日韩性生活视频| 麻豆精品视频在线观看| 黄色成人免费网站| 欧美一区二区三区播放老司机| 亚洲乱码国产乱码精品精可以看 | 亚洲人成网站777色婷婷| 久久久免费精品视频| 亚洲欧美日本精品| 欧美日韩网址| 一区二区三区日韩在线观看| 亚洲电影有码| 欧美a级在线| 亚洲高清在线观看一区| 噜噜噜久久亚洲精品国产品小说| 亚洲综合电影| 国产精品久久久久久久9999| 亚洲香蕉成视频在线观看| 亚洲精品国产精品乱码不99| 欧美成人蜜桃| 亚洲免费观看高清完整版在线观看熊| 欧美成人国产一区二区| 久久久亚洲成人| 在线精品亚洲一区二区| 免费视频亚洲| 久久男人av资源网站| 伊人成年综合电影网| 久久综合色88| 久久一二三国产| 亚洲国产精品999| 欧美成人第一页| 欧美freesex交免费视频| 亚洲伦理久久| 亚洲看片网站| 国产精品久久久久aaaa| 小黄鸭精品aⅴ导航网站入口| 亚洲在线播放电影| 国产欧美日韩一区二区三区在线观看| 欧美影院一区| 久久久久久国产精品mv| 亚洲二区在线视频| 最新亚洲一区| 欧美亚洲不卡| 欧美在线亚洲在线| 久久精品国产999大香线蕉| 原创国产精品91| 亚洲三级视频在线观看| 国产精品久久国产三级国电话系列| 欧美一级久久久| 久久精品99无色码中文字幕| 亚洲国产乱码最新视频| 亚洲日本视频| 国产老女人精品毛片久久| 久久久欧美精品sm网站| 男女精品网站| 亚洲一二三区精品| 香蕉亚洲视频| 亚洲美女毛片| 亚洲欧美卡通另类91av| 亚洲高清一二三区| 一区二区三区.www| 国产一区高清视频| 亚洲欧洲在线视频| 国产精品一区免费视频| 美女免费视频一区| 欧美日韩在线视频一区二区| 久久久一区二区三区| 欧美猛交免费看| 久久久久久久久久久成人| 欧美极品aⅴ影院| 久久成人免费电影| 欧美成人中文| 久久国产精品久久久久久| 欧美成ee人免费视频| 欧美一区二区日韩| 欧美顶级少妇做爰| 久久国产精品色婷婷| 欧美劲爆第一页| 久久精品国产一区二区三区免费看| 欧美韩国一区| 久久在线免费观看| 欧美视频在线观看视频极品| 蜜臀av性久久久久蜜臀aⅴ| 欧美午夜在线一二页| 欧美激情免费在线| 国产日韩一区在线| 日韩一级精品| 亚洲激情一区二区三区| 欧美亚洲一区在线| 一本久久综合亚洲鲁鲁五月天| 久久精品国产清自在天天线| 亚洲欧美日韩在线一区| 免费国产一区二区| 久久久噜噜噜久久久| 国产精品日韩欧美一区| 亚洲精品精选| 亚洲国产成人午夜在线一区| 欧美一区视频| 午夜综合激情| 国产精品二区三区四区|