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

桃源谷

心靈的旅行

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

W2K信號(hào)(Signals)的設(shè)備驅(qū)動(dòng)

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

 


W2K信號(hào)(Signals)的設(shè)備驅(qū)動(dòng)

     Unix下的信號(hào)提供了一個(gè)簡(jiǎn)單的IPC機(jī)制,也就是當(dāng)進(jìn)程收到一個(gè)信號(hào)后會(huì)異步(asynchronous) 地調(diào)用你的信號(hào)處理函數(shù)(也叫做句柄),不管你的代碼是否已經(jīng)處在執(zhí)行的過程之中。 而在Windows 2000(譯者注:版本高于W2kWindows平臺(tái))下就需要用到一個(gè)設(shè)備驅(qū)動(dòng),以便你能使用異步過程調(diào)用(asynchronous procedure calls , 簡(jiǎn)稱APCs或者APC) 來達(dá)成同樣的效果.

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

翻譯:Lymons (lymons@gmail.com)

 


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

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

1.            信號(hào)和基本機(jī)制

2.           庫(kù)和驅(qū)動(dòng)的設(shè)計(jì)與實(shí)現(xiàn)

3.           該機(jī)制下的性能測(cè)量

4.           面向程序員的API

5.           以及相關(guān)的擴(kuò)展和可能用法。

信號(hào)的概述

       信號(hào)是把異步事件通知給進(jìn)程的一個(gè)機(jī)制。它的基本思想是為每一個(gè)獨(dú)特的信號(hào)關(guān)聯(lián)上一個(gè)整數(shù)代碼,并且任何進(jìn)程都能給任何一個(gè)信號(hào)注冊(cè)一個(gè)處理函數(shù)(回調(diào)函數(shù))(通過指定該信號(hào)的整數(shù)代碼). 當(dāng)一個(gè)進(jìn)程發(fā)送一個(gè)特定的信號(hào)給其他的進(jìn)程(該進(jìn)程已經(jīng)為這個(gè)信號(hào)注冊(cè)了信號(hào)處理函數(shù))的時(shí)候,這個(gè)目標(biāo)進(jìn)程當(dāng)前正在做的操作將會(huì)被中斷,轉(zhuǎn)而去執(zhí)行這個(gè)被注冊(cè)的信號(hào)處理函數(shù)。

       信號(hào)機(jī)制有點(diǎn)兒類似于,在一個(gè)信號(hào)中斷中進(jìn)行一個(gè)中斷處理,不管目標(biāo)進(jìn)程是否正在執(zhí)行某一段代碼。跟中斷處理函數(shù)一樣,信號(hào)處理函數(shù)需要認(rèn)真仔細(xì)地編碼 --- 普通的代碼一定不能訪問和信號(hào)處理函數(shù)中一樣的數(shù)據(jù),除非它們都是用同步原語(yǔ)(synchronization primitives)來避免相互之間的破壞。信號(hào)提供了簡(jiǎn)單和方便的進(jìn)程間通信。通常傳統(tǒng)的應(yīng)用在下面的情況:

1.           通知一個(gè)服務(wù)它將輪轉(zhuǎn)(rotate)它的日志文件;

2.           通知一個(gè)父進(jìn)程子進(jìn)程已經(jīng)完成初始化并已經(jīng)準(zhǔn)備開始實(shí)行下面的工作;

3.           通知一個(gè)進(jìn)程它將暫時(shí)暫停自己的操作;

4.           通知一個(gè)進(jìn)程它將在關(guān)機(jī)時(shí)盡可能快地執(zhí)行清除操作

5.           等等。

      每個(gè)信號(hào)都被關(guān)連上一個(gè)將被執(zhí)行的動(dòng)作,通過內(nèi)核調(diào)度來使接收到這個(gè)信號(hào)的進(jìn)程來執(zhí)行它的行為。對(duì)于大多數(shù)的信號(hào),缺省的動(dòng)作時(shí)終止進(jìn)程的運(yùn)行,盡管一個(gè)進(jìn)程能被要求執(zhí)行一些來自系統(tǒng)選擇的動(dòng)作。這些可能的可選動(dòng)作無(wú)非就是:

1. 忽略這個(gè)信號(hào)。 在這種情況下,進(jìn)程將不會(huì)接收到這個(gè)信號(hào)的通知。

2. 恢復(fù)缺省的信號(hào)動(dòng)作。

3. 執(zhí)行一個(gè)指定的信號(hào)處理函數(shù)。這種場(chǎng)合下,當(dāng)希望一個(gè)指定的信號(hào)到達(dá)時(shí),想要某個(gè)進(jìn)程去執(zhí)行一些定制動(dòng)作,就可以去注冊(cè)這個(gè)定制函數(shù)。當(dāng)關(guān)聯(lián)的信號(hào)發(fā)生時(shí)就可以異步地調(diào)用它了。在這個(gè)信號(hào)處理函數(shù)返回之后,將在被中斷的代碼的地方繼續(xù)執(zhí)行原來的操作。

Windows支持信號(hào)

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

        Windwos提供的僅有的與信號(hào)機(jī)制類似的是異常處理這種機(jī)制。然而,標(biāo)準(zhǔn)C要求給著名的signal()/raise() Unix 函數(shù)以及一些受約束的信號(hào)[2]提供支持. signal()給指定的信號(hào)設(shè)定被調(diào)用的信號(hào)處理函數(shù)raise() 是給當(dāng)前的進(jìn)程發(fā)送特定的信號(hào),調(diào)用為這個(gè)信號(hào)注冊(cè)的處理函數(shù),或者與該信號(hào)關(guān)聯(lián)的缺省動(dòng)作。 另外,這些信號(hào)是不可擴(kuò)展的,并且它們只能在給定的進(jìn)程內(nèi)部進(jìn)行傳播。 (標(biāo)準(zhǔn)C并沒有為向其他進(jìn)程發(fā)送信號(hào)而定義標(biāo)準(zhǔn)函數(shù))

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

1. 一個(gè) APC 總是運(yùn)行在一個(gè)指定的線程的上下文中.

2. 一個(gè) APC 運(yùn)行在 OS 的預(yù)設(shè)時(shí)間內(nèi).

3. APCs 能夠搶占當(dāng)前正在運(yùn)行的線程.

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

      在內(nèi)核中APCs 有三個(gè)不同的類型[2,3]:

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

1. 當(dāng)一個(gè)應(yīng)用調(diào)用等待服務(wù)(wait service)并且觸發(fā)了告警發(fā)生機(jī)制的時(shí)候;

2. 或者調(diào)用告警測(cè)試服務(wù)(test-alert service)的時(shí)候.

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

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

       Win32 API [4] 提供了 QueueUserAPC()這個(gè)函數(shù), 它允許一個(gè)應(yīng)用把線程的APC對(duì)象放置到隊(duì)列中。正在排隊(duì)中的APC是讓一個(gè)指定的線程去調(diào)用APC函數(shù)的請(qǐng)求。當(dāng)用戶模式的APC被放到隊(duì)列中時(shí),線程則不能直接去調(diào)用這個(gè)APC函數(shù),除非它是處在一個(gè)告警使能的狀態(tài)。 不幸的是,一個(gè)線程只能使用下列的 Win32 API函數(shù)的之一才能使自己進(jìn)入到告警使能的狀態(tài): SleepEx(), SignalObjectAndWait(), WaitForSingleObjectEx(), WaitForMultipleObjectEx(), MsgWaitForMultipleObjectsEx().

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

SignalsLib 函數(shù)庫(kù)的接口

       這個(gè)函數(shù)庫(kù)給支持信號(hào)處理提供了適宜的接口,必要的數(shù)據(jù)結(jié)構(gòu)和機(jī)制。在構(gòu)建過程的期間,用戶能夠給每個(gè)線程定義選項(xiàng)以及全局信號(hào)處理函數(shù)表的用途。

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

1. SetSignalHandler() 給指定的信號(hào)設(shè)置一個(gè)函數(shù)(handler). 該函數(shù)如果執(zhí)行失敗則返回0, 成功則返回非零值。

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

        testapp.c (Listing 2) 描述了如何去使用這個(gè)信號(hào)函數(shù)庫(kù)。 這個(gè)應(yīng)用創(chuàng)建了一個(gè)設(shè)定信號(hào)和對(duì)應(yīng)的信號(hào)處理函數(shù)的線程,以及發(fā)送這個(gè)信號(hào)給子線程的主線程,最終導(dǎo)致這個(gè)已經(jīng)安裝的信號(hào)處理函數(shù)被執(zhí)行。當(dāng)然,這個(gè)驅(qū)動(dòng)必須事先被安裝到系統(tǒng)里并且已被裝載到內(nèi)存中,否則當(dāng)函數(shù)庫(kù)的DLLMain()函數(shù)被執(zhí)行的時(shí)候,會(huì)輸出相應(yīng)的錯(cuò)誤消息。

設(shè)計(jì)和實(shí)現(xiàn)

      SignalsLib 庫(kù)由DLL文件和內(nèi)核態(tài)的設(shè)備驅(qū)動(dòng)組成。這個(gè) DLL 給應(yīng)用程序提供了一個(gè)用戶態(tài)的接口, 當(dāng)我們想要讓目標(biāo)線程排隊(duì)一個(gè)內(nèi)核模式的APC并去調(diào)用關(guān)聯(lián)的內(nèi)核態(tài)的函數(shù)的時(shí)候,就需要用到這個(gè)設(shè)備驅(qū)動(dòng)。應(yīng)用程序僅僅是簡(jiǎn)單的調(diào)用SetSignalHandler() SendSignalToThread()這兩個(gè)函數(shù)就可以, 然而這個(gè) DLL 隱藏了所有的與設(shè)備驅(qū)動(dòng)進(jìn)行通信的細(xì)節(jié)。

       SetSignalHandler() 函數(shù)很簡(jiǎn)單它僅僅是存儲(chǔ)了在信號(hào)處理函數(shù)的全局?jǐn)?shù)組中的相應(yīng)位置,也就是一個(gè)函數(shù)指針。 當(dāng)一個(gè)信號(hào)確實(shí)是被觸發(fā)的時(shí)候,內(nèi)部函數(shù)SignalsDriverRoutine()將會(huì)被調(diào)用,并且訪問這個(gè)全局?jǐn)?shù)組來決定調(diào)用哪個(gè)信號(hào)處理函數(shù)。這兩個(gè)函數(shù)在signals.c (Listing 3)有定義.

       SendSignalToThread() 函數(shù)是DLL與設(shè)備驅(qū)動(dòng)進(jìn)行通信的地方。 DllMain() DLL第一次被載入的時(shí)候會(huì)獲得一個(gè)設(shè)備驅(qū)動(dòng)的句柄, 并且在DLL被卸載的時(shí)候會(huì)釋放這個(gè)句柄。 SendSignalToThread() 函數(shù)在調(diào)用DeviceIoControl()函數(shù)(該函數(shù)是傳遞一個(gè)SIGINFO結(jié)構(gòu)體給這個(gè)設(shè)備驅(qū)動(dòng))的時(shí)候會(huì)使用這個(gè)句柄:

 

typedef struct _SIGINFO

{

   HANDLE   hThread;   
/* target thread */

   ULONG    SigNo;     
/* signal number */

   ULONG    SigFunc;   
/* address of DriverRoutine */

}
 SIGINFO, *PSIGINFO;

 

        注意這個(gè) SigFunc 不是一個(gè)單獨(dú)信號(hào)處理函數(shù)的地址,而是SignalsDriverRoutine()函數(shù)的地址,該函數(shù)的功能是查詢和調(diào)用DLL中的正確的信號(hào)處理函數(shù)。

        當(dāng)SendSignalToThread() 函數(shù)傳遞這個(gè)信息給DeviceIoControl()的時(shí)候, 它將導(dǎo)致這個(gè)驅(qū)動(dòng)的中斷服務(wù)程序被調(diào)用。該驅(qū)動(dòng)的主要源代碼都在sigdrv.c (Listing 4)文件里面. 然后驅(qū)動(dòng)中斷服務(wù)例程會(huì)調(diào)用SigDriverSendTheSignal()函數(shù)來負(fù)責(zé)為目標(biāo)線程來排隊(duì)一個(gè)相應(yīng)的內(nèi)核模式的APC. SigDriverSendTheSignal() 中有一個(gè)指向這個(gè)目標(biāo)線程的ETHREAD 的數(shù)據(jù)結(jié)構(gòu)體 [2]的指針. 然后調(diào)用 KeInitializeApc() 函數(shù)去初始化一個(gè)內(nèi)核模式的APC并且調(diào)用KeInsertQueueApc() 來把目標(biāo)線程的 APC 插入到隊(duì)列中。

         這個(gè)被放入到隊(duì)列中的 APC 包含一個(gè)指向sigdrv.c (Listing 4)文件中的一個(gè)函數(shù)UserApcCallBack()的指針. 這個(gè)函數(shù)將會(huì)在用戶態(tài)中被調(diào)用并且傳遞SIGINFO 結(jié)構(gòu)體. UserApcCallBack() 使用 SIGINFO 中的信息來調(diào)用DLL 函數(shù) SignalsDriverRoutine(), 而它就是那個(gè)查詢且調(diào)用與指定信號(hào)關(guān)聯(lián)的信號(hào)處理函數(shù)的函數(shù)。

性能評(píng)估

        編程時(shí)到底是選擇常態(tài)還是特殊內(nèi)核模式的APC,是跟你所期望的功能有關(guān),而跟性能無(wú)關(guān)。 如果你認(rèn)為你的信號(hào)處理函數(shù)能被其他的被觸發(fā)的信號(hào)所搶占是一件重要的事情的話,那么你應(yīng)該選擇使用特殊內(nèi)核模式的APC而不是常態(tài)內(nèi)核模式APCs.

        這個(gè)APC 機(jī)制執(zhí)行的相當(dāng)棒;一旦目標(biāo)線程被調(diào)度后這個(gè)信號(hào)處理函數(shù)就會(huì)很快的被調(diào)用,一般情況下就是幾微秒之間的事兒。其中值得注意的一個(gè)重要的事情就是,內(nèi)核模式APC能立刻完成信號(hào)的傳送,這與系統(tǒng)載入的(或者說在系統(tǒng)中運(yùn)行的)線程數(shù)量無(wú)關(guān)。他是通過改變線程的優(yōu)先級(jí)來減少這個(gè)響應(yīng)時(shí)間。例如, SendSignalToThread() 函數(shù)能夠提升目標(biāo)線程的優(yōu)先級(jí)。

結(jié)論

       主要是為了在Win32應(yīng)用中能夠使能相同線程內(nèi)部或者不同線程間的異步通信,我實(shí)現(xiàn)了這個(gè)用戶自定義信號(hào)的基本機(jī)制。與Unix系統(tǒng)調(diào)用signal() kill() 相似的,最終的,通過DLL和設(shè)備驅(qū)動(dòng)協(xié)同工作也能提供這兩個(gè)重要的信號(hào)處理的接口,并且也支持了相似的SIGUSR1 SIGUSR2這兩個(gè)信號(hào).

       作為這個(gè)庫(kù)的擴(kuò)展將來很可能會(huì)實(shí)現(xiàn)一些其他的Unix信號(hào),如SIGSTOP, SIGCONT, SIGTERM, 并且支持POSIX 標(biāo)準(zhǔn)。 也愿意把這個(gè)機(jī)制集成到標(biāo)準(zhǔn)C庫(kù)中去。這個(gè)庫(kù)也協(xié)助實(shí)現(xiàn)了POSIX函數(shù)pthread_kill() ,這就使得應(yīng)用程序在用戶模式下(或者是從內(nèi)核到用戶模式)POSIX線程間需要通知機(jī)制時(shí),就讓開發(fā)工作變的很容易, 僅僅是讓設(shè)備驅(qū)動(dòng)知道驅(qū)動(dòng)例程的函數(shù)地址即可。 盡管這個(gè)POSIX 標(biāo)準(zhǔn)為應(yīng)用程序的所有的線程定義了全局信號(hào)處理函數(shù),這個(gè)庫(kù)也能容易的為每個(gè)線程提供信號(hào)處理的支持,通過使用線程的局部存儲(chǔ)數(shù)據(jù);為了簡(jiǎn)單,在當(dāng)前這個(gè)版本中沒有這么做。

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

      最后,另外一個(gè)基于用戶模式APC的實(shí)現(xiàn)在這里沒有描述。不過SendSignalToThread() 可以調(diào)用 Win32 QueueUserAPC() 函數(shù)然后通過內(nèi)核模式的設(shè)備驅(qū)動(dòng),來設(shè)置目標(biāo)線程成告警使能狀態(tài)。 你可以對(duì)與ETHREAD數(shù)據(jù)結(jié)構(gòu)[2]的基地址相偏移0x4a 個(gè)字節(jié)的一個(gè)內(nèi)存地址進(jìn)行設(shè)定來實(shí)現(xiàn)的。

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 */

 

我的個(gè)人簡(jiǎn)歷第一頁(yè) 我的個(gè)人簡(jiǎn)歷第二頁(yè)
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久精品五月| 亚洲国产天堂久久综合网| 国产精品亚洲视频| 久久riav二区三区| 亚洲综合999| 亚洲精品影视在线观看| 免费欧美日韩国产三级电影| 性色av一区二区三区| 亚洲精品日韩激情在线电影 | 国产精品亚洲视频| 欧美大片91| 欧美日韩伊人| 国产精品美女视频网站| 欧美午夜视频一区二区| 欧美视频精品一区| 久久一二三区| 亚洲自拍偷拍色片视频| 亚洲欧美日韩中文视频| 亚洲精品精选| 制服丝袜亚洲播放| 欧美在线视频播放| 亚洲高清在线精品| 亚洲激情国产| 欧美一级免费视频| 欧美区一区二| 伊人精品成人久久综合软件| 亚洲美女黄色片| 久久福利精品| 亚洲国产一区视频| 亚洲一区二区三区中文字幕| 久久九九免费| 国产精品国产馆在线真实露脸| 欧美日韩亚洲一区三区 | 欧美国产视频在线观看| 亚洲黄色成人网| 欧美中文在线视频| 欧美日韩在线视频观看| 欧美精品激情在线| 一区免费视频| 久久综合九色欧美综合狠狠| 亚洲视频在线观看一区| 欧美激情在线播放| 亚洲电影网站| 日韩手机在线导航| 亚洲第一精品在线| 久久久精品久久久久| 国产亚洲精品久久飘花| 久久久久久久欧美精品| 久久三级视频| 销魂美女一区二区三区视频在线| 免费亚洲电影在线| 欧美福利一区二区| 亚洲激情欧美激情| 亚洲乱码国产乱码精品精98午夜| 久久综合久久久久88| 亚洲国产欧美另类丝袜| 欧美成人dvd在线视频| 欧美国产日韩一二三区| 99日韩精品| 亚洲欧美视频一区| 激情综合色综合久久综合| 91久久精品国产91久久| 国产精品电影网站| 欧美激情一区二区三区四区| 国产精品久久97| 亚洲国产一区二区三区a毛片 | 欧美专区亚洲专区| 欧美v日韩v国产v| 亚洲在线免费观看| 久久麻豆一区二区| 亚洲欧美视频在线观看| 麻豆九一精品爱看视频在线观看免费| 在线观看一区| 亚洲人成在线观看网站高清| 欧美精品成人91久久久久久久| 亚洲国产精品成人精品| 久久综合久久久久88| 欧美在线观看网站| 一区二区免费在线播放| 久久久www成人免费无遮挡大片| 亚洲人成网站色ww在线| 亚洲网友自拍| 夜夜嗨av一区二区三区| 久久久久综合网| 久久天天躁狠狠躁夜夜爽蜜月| 好吊日精品视频| 在线一区二区三区做爰视频网站 | 国产精品美女在线| 亚洲成人在线视频网站| 亚洲欧美日韩电影| 卡一卡二国产精品| 国产日本精品| 久久er99精品| 日韩一区二区免费看| 久久在线免费| 免费成人你懂的| 亚洲成色999久久网站| 久久久久久穴| 亚洲日韩视频| 激情欧美国产欧美| 美脚丝袜一区二区三区在线观看 | 最近中文字幕日韩精品| 亚洲精品一区二区三区四区高清| 亚洲自拍三区| 久久久久国产免费免费| 欧美不卡视频一区| 亚洲精品中文字幕在线| 国产精品一区在线播放| 亚洲一级网站| 久久在精品线影院精品国产| 加勒比av一区二区| 欧美日韩1080p| 欧美国产日韩在线| 亚洲午夜电影网| 欧美顶级少妇做爰| 欧美福利专区| 亚洲午夜羞羞片| 欧美成人午夜影院| 欧美在线综合| 久久乐国产精品| 先锋影音久久| 一区二区免费在线播放| 激情六月婷婷综合| 国产精品福利影院| 欧美精品激情blacked18| 亚洲午夜在线观看| 久久只精品国产| 在线亚洲欧美专区二区| 亚洲欧洲在线一区| 欧美午夜大胆人体| 欧美日本精品一区二区三区| 久久国产毛片| 欧美制服丝袜| 亚洲免费高清| 欧美激情亚洲精品| 欧美国产成人精品| 亚洲国内自拍| 亚洲精品三级| 日韩视频一区二区在线观看 | 亚洲区一区二| 亚洲一区二区三区视频播放| 亚洲国产成人精品视频| 好吊一区二区三区| 亚洲高清久久网| 亚洲精品自在久久| 国产精品初高中精品久久| 国模私拍一区二区三区| 狠狠色综合色综合网络| 永久域名在线精品| 99热这里只有成人精品国产| 国产色视频一区| 亚洲免费不卡| 久久久99精品免费观看不卡| 亚洲精品网站在线播放gif| 国产视频精品网| 亚洲午夜一区二区三区| 亚洲美女黄色片| 欧美午夜视频在线观看| 亚洲国产精品一区二区第一页 | 久久嫩草精品久久久精品一| 欧美视频中文字幕在线| 亚洲国产一区二区三区a毛片| 尤妮丝一区二区裸体视频| 亚洲精品乱码视频| 久久av一区二区三区| 欧美日韩在线看| 亚洲欧美在线aaa| 久久99伊人| 亚洲精品1区2区| 亚洲美女福利视频网站| 最新日韩在线视频| 欧美激情视频在线播放 | 久热精品视频在线观看| 噜噜噜91成人网| 亚洲美女视频| 欧美午夜精彩| 久久视频这里只有精品| 亚洲国产精品久久精品怡红院| 一区二区三区蜜桃网| 欧美日韩精品久久| 久久久av毛片精品| 亚洲精品在线观| 久久躁狠狠躁夜夜爽| 亚洲第一精品电影| 国产精品私房写真福利视频| 西西裸体人体做爰大胆久久久| 欧美激情一区二区三区在线视频观看 | 欧美国产日本| 欧美一区二区日韩| 在线观看亚洲精品| 国产精品国产a| 久久精品国产综合| 亚洲字幕在线观看| 在线观看视频亚洲| 久久综合激情| 小嫩嫩精品导航| 亚洲激情在线激情| 久久精品中文字幕一区| 亚洲日产国产精品| 欧美美女bbbb|