• <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>
            面對現實,超越自己
            逆水行舟,不進則退
            posts - 269,comments - 32,trackbacks - 0
            很多時候程序的 Debug 版本運行沒有任何問題,但是一旦發布 Release 版本后,運行就出錯,著實讓人郁悶。大家知道,VC++ 中 Release 版本是對無法對源代碼進行調試的。一般的做法是在懷疑有錯誤的代碼前后插入MessageBox 函數,在函數中顯示可能導致錯誤的變量的值。或者插入寫文件的語句,輸出可能導致錯誤的變量的值到一個記錄文件。其實,除了上面講的這個辦法之外,還有其它的途徑來調試 Release 版本的。下面就結合自己的經驗和網上查找的一些資料給出調試 Release 版本的兩個方法:

            方法一、利用 *.PDB 符號文件調試 Release 版本
            在 VCKBASE 的在線雜志中有一篇參考文章:符號文件——Windows 應用程序調試必備(http://www.vckbase.com/document/viewdoc/?id=1710),文章談到了如何產生 Release 版本二進制文件對應的 PDB 文件的問題。有了 PDB 文件后,就可以調試 Release 了,方法是:
            1、在Project Settings里選Settings For為All Configurations。 
            2、在C/C++標簽中,Debug info 選 Program Database。 
            3、在Link 標簽中,Category選 Debug,選中Debug info 復選框和Microsoft format。 
            進行了上述設置后,我們就可以像在調試版本中那樣設置斷點進行測試了,由于代碼優化,有些變量觀察不到,行的運行順序可能也會不同。 
            有一點需要注意:ASSERT宏在 Release 版本中不起作用,在 Release 版本中應該使用 VERIFY 來代替 ASSERT 進行調試。如果發行版本運行有問題,可以先禁止所有代碼優化再進行調試。

            方法二、在需要加斷點的地方添加如下匯編語句: 
                __asm int 3 

            不過調試的時候無法顯示C程序,只有asm代碼。 
                 
            此處 int 3 是專門用來設置斷點的,是 CPU 定義的,Windows 和 DOS 下的大多數調試器都采用這種方法。

            本貼不斷更新中,希望大家跟貼貢獻出更好的調試方法。以便受益者少走彎路......

            本文轉自:http://www.shnenglu.com/mzty/archive/2006/11/19/15439.html
            posted @ 2013-11-28 10:20 王海光 閱讀(694) | 評論 (0)編輯 收藏


            FTP
             Wanderer - FTP Client using WININET

            Sample Image

            Description

            This article presents a fully functional implementation of a FTP client. FTP Wanderer is a multithreaded FTP client with the look-and-feel of Windows Explorer, and makes moving files between the Internet and your computer as simple as local file manipulation. This application uses WININET API's to handle the FTP protocol, and while it's not the most elegant way to connect to a FTP server it does the job pretty well.

            Features list

            • All file transfer requests are handled in the background, so you don't have to wait while files copy to continue browsing the current server. You can even connect to a different server, while file transfers on another server are still in progress.
            • The Transfer Manager shows all file transfers currently in progress plus the ones that are in the queue. You can configure how many transfers are processed simultaneously, so you don't run out of resources.
            • FTP Wanderer uses the Windows 9x/NT/XP style list boxes for displaying the contents of remote servers. With all familiar system icons and context menus.
            • You can specify the number of times it should try to connect, and the time delay between connection attempts.
            • Full Drag and Drop support. Simply drag one or more files or even complete folders onto FTP Wanderer's file view area to transfer them to the location of the server that is currently connected.
            • Easily configure FTP site settings, like username, password, port, initial remote folder, number of retries and default download folder.

            Here's a brief description of some of the important classes of the application:

            CMainFrame

            CMainFrame contains most of the code for managing the FTP connection. It takes care of connecting to the server; initiate up/downloads and handling other FTP related actions.

            CFTPListView

            This is just a CListView derived class that takes care of displaying the files and enabling you to sort them. When the application is busy downloading or sorting a directory listing it can display an animation, just like explorer does.

            CConnectDlg

            This class (= Site Manager) enables the user to manage FTP sites. You can add/change and delete sites and configure properties such as hostname, port, username and password. The settings of each site are save to disk using serializing.

            CTransferManagerDlg

            CTransferManagerDlg (= Transfer manager) takes care of queuing the file transfers. It shows all file transfers currently in progress plus the ones that are in the queue. You can configure how many transfers are processed simultaneously, so you don't run out of resources. Each up/download in handled in a separate thread by initiating aCDownloadThread or CUploadThread thread.

            CDownloadThread

            Each download is handled in the background using a separate thread. CDownloadThread creates a new connection with the FTP server and displays a progress dialog that tells you the status of the file transfer. When the download is completed (or aborted) it notifies the transfer manager so the UI can be updated.

            CUploadThread

            Each upload is handled in the background using a separate thread. CUploadThread creates a new connection with the FTP server and displays a progress dialog that tells you the status of the file transfer. When the upload is completed (or aborted) it notifies the transfer manager so the UI can be updated.

            To do list:

            While this application has most of the features you might expect in a FTP client, there are a few things left to do:

            • Drag and drop support out of the file view area to Explorer. I think this one is not that easy, because this would probably 'block' explorer until the file transfer is completed (any suggestions?).
            • Progress indication in the transfer manager. This is not really that hard to do, so this will probably be in the next release.
            • Better asynchrony handling of getting directory listing. The UI now does not respond when downloading a huge directory listing.

            Contacting the Author

            Please send any comments or bug reports to me via email. For any updates to this article, check my site here.

            Revision history

            • 31st July 2002 - Initial revision.

            License

            This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

            A list of licenses authors might use can be found here

            原文
            地址:http://www.codeproject.com/Articles/2665/FTP-Wanderer-FTP-Client-using-WININET

            posted @ 2013-11-19 08:54 王海光 閱讀(712) | 評論 (0)編輯 收藏
            在Window平臺上開發任何稍微底層一點的東西,基本上都是Hook滿天飛, 普通應用程序如此,安全軟件更是如此, 這里簡單記錄一些常用的Hook技術。
            SetWindowsHookEx
            基本上做Windows開發都知道這個API, 它給我們提供了一個攔截系統事件和消息的機會, 并且它可以將我們的DLL注入到其他進程。
            但是隨著64位時代的到來和Vista之后的UAC機制開啟,這個API很多時候不能正常工作了:
            首先,32位DLL沒法直接注入到64位的應用程序里面, 因為他們的地址空間完全不一樣的。當然盡管沒法直接注入,但是在權限范圍內,系統會盡量以消息的方式讓你能收到64位程序的消息事件。
            其次,UAC打開的情況下低權限程序沒法Hook高權限程序, 實際上低權限程序以高權限程序窗口為Owner創建窗口也會失敗, 低權限程序在高權限程序窗口上模擬鼠標鍵盤也會失敗。
            有人說我們可以關閉UAC, Win7下你確實可以,但是Win8下微軟已經不支持真正關閉UAC, 從這里我們也可以看到微軟技術過渡的方式, 中間會提供一個選項來讓你慢慢適應,最后再把這個選項關掉, UAC和Aero模式都是如此。
            那么我們如何解決這些問題?
            對于64位問題 , 解決方法是提供2個DLL,分別可以Hook32和64位程序。
            對于權限問題, 解決方法是提升權限, 通過注冊系統服務, 由服務程序創建我們的工作進程。這里為什么要創建一個其他進程而不直接在服務進程里干活? 因為Vista后我們有了Session隔離機制,服務程序運行在Session 0,我們的其他程序運行在Session 1, Session 2等, 如果我們直接在服務程序里干活,我們就只能在Session 0里工作。通過創建進程,我們可以在DuplicateTokenEx后將Token的SessionID設置成目標Session,并且在CreateProcessAsUser時指定目標WinStation和Desktop, 這樣我們就既獲得了System權限,并且也可以和當前桌面進程交互了。
            SetWinEventHook
            很多人可能都不知道這個API, 但是這個API其實挺重要的, 看名字就知道它是Hook事件(Event)的, 具體哪些事件可以看這里.
            為什么說這個API重要, 因為這個API大部分時候沒有SetWindowsHookEx的權限問題, 也就是說這個API可以讓你Hook到高權限程序的事件, 它同時支持進程內(WINEVENT_INCONTEXT)和進程外(WINEVENT_OUTOFCONTEXT)2種Hook方式, 你可以以進程外的方式Hook到64位程序的事件。
            為什么這個API沒有權限問題, 因為它是給Accessibility用的, 也就是它是給自動測試和殘障工具用的, 所以它要保證有效。
            我曾經看到這樣一個程序,當任何程序(無論權限高低)有窗口拖動(拖標題欄改變位置或是拖邊框改變大小), 程序都能捕獲到, 當時很好奇它是怎么做到的?
            Spy了下窗口消息, 知道有這樣2個消息:WM_ENTERSIZEMOVE和WM_EXITSIZEMOVE表示進入和退出這個事件, 但是那也只能獲得自己的消息,其他程序的消息它是如何捕獲到的?當時懷疑用的是Hook, 卻發現沒有DLL注入。查遍了Windows API 也沒有發現有API可以查詢一個窗口是否在這個拖動狀態。最后發現用的是SetWinEventHookEVENT_SYSTEM_MOVESIZESTART和EVENT_SYSTEM_MOVESIZEEND。

            API Hook
            常見的API Hook包括2種, 一種是基于PE文件的導入表(IAT), 還有一種是修改前5個字節直接JMP的inline Hook.

            對于基于IAT的方式, 原理是PE文件里有個導入表, 代表該模塊調用了哪些外部API,模塊被加載到內存后, PE加載器會修改該表,地址改成外部API重定位后的真實地址, 我們只要直接把里面的地址改成我們新函數的地址, 就可以完成對相應API的Hook。《Windows核心編程》里第22章有個封裝挺好的CAPIHook類,我們可以直接拿來用。
            我曾經用API Hook來實現自動測試,見這里 API Hook在TA中的應用

            對于基于Jmp方式的inline hook, 原理是修改目標函數的前5個字節, 直接Jmp到我們的新函數。雖然原理挺簡單, 但是因為用到了平臺相關的匯編代碼, 一般人很難寫穩定。真正在項目中用還是要求穩定, 所以我們一般用微軟封裝好的Detours, 對于Detours的原理,這里有篇不錯的文章 微軟研究院Detour開發包之API攔截技術

            比較一下2種方式: 
            IAT的方式比較安全簡單, 但是只適用于Hook導入函數方式的API。
            Inline Hook相對來說復雜點, 但是它能Hook到任何函數(API和內部函數),但是它要求目標函數大于5字節, 同時把握好修改時機或是Freeze其他線程, 因為多線程中改寫可能會引起沖突。

            還有一種是Hook被調用模塊的導出表(EAT), 但是感覺一般用得用的不多。原理是調用模塊里IAT中的函數地址是通過被調用模塊的EAT獲取的, 所以你只要修改了被調用模塊的EAT中的函數地址,對方的調用就自然被你Hook了。但是這里有個時機問題, 就是你替換EAT表要足夠早,要在IAT使用它之前才行。但是感覺這個行為是由PE加載器決定的, 一般人很難干涉, 不知道大家有什么好方法? 

            我們一般可以將IAT Hook和EAT Hook結合起來使用, 先枚舉所有模塊Hook IAT,這樣當前已有模塊的API都被你Hook了,然后再Hook EAT, 這樣后續的模塊也被你Hook了(因為要通過EAT獲取函數地址)。 

            如果你只用Hook IAT而不Hook EAT, 當有新模塊加載時,你要Hook它的IAT, 所以你就要Hook LoadLibrary(Ex)和GetProcAddress來攔截新模塊的加載。所以理論上感覺 Hook EAT不是很有必要, 因為單用Hook IAT已經可以解決我們所有的問題了, HOOK IAT還有一種優勢是我們可以過濾某個模塊不Hook,而一旦hook EAT, 它就會影響我們所有調用該函數的模塊。

            COM Hook
            Window上因為有很多開發包是以COM方式提供的(比如DirectX), 所以我們就有了攔截COM調用的COM Hook。
            因為COM里面很關鍵的是它的接口是C++里虛表的形式提供的, 所以COM的Hook很多是時候其實就是虛表(vtable)的Hook。
            關于C++ 對象模型和虛表可以看我這篇 探索C++對象模型

            對于COMHook,考慮下面2種case:

            一種是我們Hook程序先運行,然后啟動某個游戲程序(DirectX 9), 我們想Hook游戲的繪畫內容。

            這種方式下, 我們可以先Hook API Direct3DCreate9, 然后我們繼承于IDirect3D9, 自己實現一個COM對象返回回去, 這樣我們就可以攔截到所有對該對象的操作,為所欲為了, 當然我們自己現實的COM對象內部會調用真正的Direct3DCreate9,封裝真正的IDirect3D9。

            當然有時我們可能不用替代整個COM組件,我們只需要修改其中一個或幾個COM函數, 這種情況下我們可以創建真正的IDirect3D9對象后直接修改它的虛表, 把其中某些函數改成我們自己的函數地址就可以了。

            其實ATL就是用接口替代的方式來調試和記錄COM接口引用計數的次數, 具體可以看我這篇 理解ATL中的一些匯編代碼

            還有一種case是游戲程序已經在運行了, 然后才啟動我們的Hook進程, 我們怎么樣才能Hook到里面的內容?

            這種情況下我們首先要對程序內存有比較詳細的認識, 才能思考創建出來的D3D對象的虛表位置, 從而進行Hook, 關于程序內存布局,可見我這篇 理解程序內存

            理論上說COM對象如果是以C++接口的方式實現, 虛表會位于PE文件的只讀數據節(.rdata), 并且所有該類型的對象都共享該虛表, 所以我們只要創建一個該類型對象,我們就可以獲得其他人創建的該類型對象的虛表位置,我們就可以改寫該虛表實現Hook(實際操作時需要通過VirtualProtect修改頁面的只讀屬性才能寫入)。

            但是實際上COM的虛表只是一塊內存, 它并不一定是以C++實現, 所以它可以存在于任何內存的任何地方。另外對象的虛表也不一定是所有同類型的對象共享同一虛表, 我們完全可以每個對象都有自己的一份虛表。比如我發現IDirect3D9是大家共享同一虛表的(存在D3D9.dll), 但是IDirect3DDevice9就是每個對象都有自己的虛表了(存在于堆heap)。所以如果你要Hook IDirect3DDevice9接口,通過修改虛表實際上沒法實現。

            但是盡管有時每個對象的虛表不一樣,同類型對象虛表里的函數地址卻都是一樣的, 所以這種情況下我們可以通過inline Hook直接修改函數代碼。當然有些情況下如果是靜態鏈接庫,即使函數代碼也是每個模塊都有自己的一份, 這種情況下就只能反匯編獲取虛表和函數的地址了。

            最后,總結一下, 上面主要探討了Windows上的各種Hook技術,通過將這些Hook技術組起來, 可以實現很多意想不到的功能, 比如我們完全可以通過Hook D3D實現Win7任務欄那種Thumbnail預覽的效果(當然該效果可以直接由DWM API實現, 但是如果我們可以通過HOOK以動畫的方式實現是不是更有趣 )

            本文轉自:
            http://www.shnenglu.com/weiym/archive/2013/10/30/203991.html
            posted @ 2013-11-08 08:15 王海光 閱讀(691) | 評論 (0)編輯 收藏

                談到"C#代碼反編譯",大家可能都會想到 Reflector代碼反編譯工具,對其應該也不會太陌生;做C#開發,它算得上是一個不可或缺的實用工具。通過它我們可以很方便的查看一個程序集的源代碼(這是其最基本的使用,也是大家常用的),還可以方便破解軟件...,而我這篇文章要跟大家分享的是:用Reflector將C#的開發的軟件[項目](此文中所說的是winForm項目,對于.net項目可以借鑒或參考)的項目代碼還原——反編譯得到可運行項目源碼。 我所做的反編譯,并不是'破解',其使用的前提或情況是:公司原來請人開發的'配餐軟件(幼兒園版)',現有客戶咨詢想買,并且軟件中存在一些問題需改,——不是本人開發的,該軟件也無源碼,想修改只能想辦法得到軟件的源碼。具體的'破解'方法記錄在下,方便自己以后查看!(ps: '破解'的方法,自己之前就摸索過。但困于反編譯之后的error比較多,沒有耐心,有的問題感覺比較離奇,試了幾次不行就放棄了  ——這就間接的說明:真正的黑客,應該都是比較有耐心的,呵呵..., 但做軟件開發,又何嘗不需要這樣?!)

                 a.使用到的工具:Reflector,具體的說是:Reflector插件File disassembler(具體是什么和how to use,直接上網查)。

                 b. 打開Reflector,選擇要'破解'的軟件(.exe)主程序,再選擇并點擊 如圖:, 在右側出現的 程序集(輸出)類型選擇界面 選擇類型'windows Appliction' (因為是winForm應用程序,如果是選擇的其它 如'class ...'類庫,則需要在之后的步驟中,改變項目屬性中的 輸出類型,不建議這樣操作),如圖:

             點擊 生成 即可 得到此主程序集的源碼,其它的相關程序集再如此操作即可! ——不要以為大功告成,這只是第一步,麻煩的在后面!

                c.將生成的源碼 在Vs中打開(項目), 先試著運行下,(一般)會報錯,排除'xxx程序集不存在'這類的錯誤,我所遇到的如下:

            using System;
            using System.Collections.Generic;
            using System.Runtime.CompilerServices;
            using System.Runtime.InteropServices;

            [CompilerGenerated]
            internalclass<PrivateImplementationDetails>{1FF4F699-35E0-4117-BDBC-9E44A1B0F9F5}
            {
            internalstatic Dictionary<stringint> $$method0x600012e-1;
            internalstatic Dictionary<stringint> $$method0x6000137-1;
            internalstatic Dictionary<stringint> $$method0x6000137-2;
            internalstatic Dictionary<stringint> $$method0x600014a-1;
            internalstatic Dictionary<stringint> $$method0x6000169-1;
            internalstatic Dictionary<stringint> $$method0x60001b6-1;
            internalstatic __StaticArrayInitTypeSize=20 $$method0x6000213-1; // data size: 20 bytes
            internalstatic __StaticArrayInitTypeSize=20 $$method0x6000213-2; // data size: 20 bytes
            internalstatic __StaticArrayInitTypeSize=20 $$method0x6000213-3; // data size: 20 bytes
            internalstatic __StaticArrayInitTypeSize=20 $$method0x6000213-4; // data size: 20 bytes

            [StructLayout(LayoutKind.Explicit, Size=20, Pack=1)]
            privatestruct __StaticArrayInitTypeSize=20
            {
            }
            }

             源碼文件中會出現一個 _PrivateImplementationDetails_{1FF4F699-35E0-4117-BDBC-9E44A1B0F9F5}.cs 文件名很長 內容如上的 亂碼類,對此解決辦法時:注釋此類 或直接刪除。【程序相關的文件,如圖片、數據庫等要記得放到項目關聯位置,一般在bin/debug/文件夾下】

                d. 添加相關程序集的引用,設置啟動對象。到這兒,差不多程序就可以 跑起來了,但是還沒有完 ——因為 反編譯后的代碼,文件夾的位置和界面與資源引用之間的關聯,基本上都亂了.所以現在要解決的關鍵問題是:恢復文件間的關聯和引用(其它的問題,通過調試就差不多可以解決)。如圖:

            窗體的.cs和.resx(資源)文件不在同一個文件夾中,對應窗體的.resx文件都加上了項目或解決方案名前綴(zhiyiSystem.) ——This is point!  這就是我們要解決問題的關鍵:恢復窗體的.cs和.resx文件間的關聯,操作大致有以下兩步:1.將窗體的.cs和.resx文件放在同一個文件中——即同一目錄。2.去掉窗體的.resx文件的前綴 ——即修改文件名,如果是一個個文件去修改,窗體比較多的話,是一件非常重復而無聊的事,于是 就上網找 "批量修改文件名"的工具,下載了一兩個感覺都不好用,找不到,只能自己搞了,再說這東西簡單,說白了就是 遍歷文件夾中文件并'重命名'(代碼就不貼出了,文章后 附有 自己寫的 "批量修改文件名"工具)。

                   到此,程序就可以真正跑起來了。別看我寫出來,似乎'破解'就是一會兒的事,但我做的時候,卻幾經折騰 好幾次都感覺"算了,又卡住了...",有些或大或小問題,在這里因為時間的原因 及有些步驟一時半會也想不起來了,但主要的方法應該都沒有落下,如果有不明白的朋友,可以留言交流,再做解答;也希望在'破解'方法有經驗的,能多提些意見,分享下你的‘破解’經驗!

                 后附:
                           批量修改文件名工具.rar

            本文轉自:http://www.cnblogs.com/know/archive/2011/03/15/1985026.html
            相關
            連接:http://www.cnblogs.com/verygis/archive/2008/12/02/1346072.html

            posted @ 2013-10-23 10:23 王海光 閱讀(942) | 評論 (0)編輯 收藏


             看了《深入理解linux內核》的中斷與異常,簡單總結了下,如果有錯誤,望指正!

            一 什么是中斷和異常

              異常又叫同步中斷,是當指令執行時由cpu控制單元產生的,之所以稱之為異常,是因為只有在一條指令結束之后才發出中斷(程序執行異常或者系統調用)。

              中斷又叫異步中斷,是由其他硬件設備依照cpu時鐘信號隨機產生的。

            二 高級可編程中斷控制器

            APIC

              每個CPU都有一個本地的APIC,通過IIC bus鏈接到一個I/O APIC,這個I/O APIC負責處理外部IRQS,分發IRQS給本地APIC。

            三 中斷與異常處理程序嵌套執行

              中斷處理程序允許被另一個中斷處理程序”中斷“,從而引起內核控制路徑嵌套執行。但是中斷處理程序是不允許發生阻塞,即任務切換的

              中斷可以搶占異常處理程序,但異常處理程序不會搶占中斷。因為中斷處理程序必定處于內核態,如果發生異常,那只能是BUG了,也就是說內核控制路徑中異常處理程序不會超過一個。

            四 Linux中斷描述符

              Intel把中斷描述符分三類:任務門、中斷門、陷阱門,而Linux則分成五類:

            1. 中斷門:Intel的中斷門,DPL = 0,描述中斷處理程序,通過set_intr_gate宏設置
            2. 系統門:Intel的陷阱門,DPL = 3,用于系統調用,通過set_system_gate宏設置
            3. 系統中斷門:Intel的中斷門,DPL = 3,用于向量3的異常處理,通過set_system_intr_gate宏設置
            4. 陷阱門:Intel陷阱門,DPL = 0,大部分的異常處理,通過set_trap_gate宏設置
            5. 任務門:Intel任務門,DPL = 0,對”Double fault“異常處理,通過set_task_gate宏設置

            五 異常處理

              當cpu產生異常時,會自動根據產生的異常編號在IDT中找對應的異常處理程序,異常處理程序保存大多數寄存器的值,調用異常處理的高級C函數處理該異常,然后通過調用ret_from_exception從異常處理程序退出。

            六 中斷處理

              I/O中斷處理程序執行的四個基本過程:

            1. 在內核態堆棧中保存IRQ的值和寄存器的內容
            2. 給正在為IRQ線服務的PIC發送一個應答,這將允許該PIC進一步發中斷
            3. 執行共享該IRQ的所有設備的中斷服務例程(ISR)

            七 IRQ數據結構

            IRQ數據結構

              hw_irq_controller是對PIC進程控制的一些函數,包括應答PIC什么的。action指向的是一個irqaction鏈,每個irqaction描述一個設備的服務例程。irq_desc_t中的state字段保證了同一時刻只有一個設備會擁有該IRQ,正在處理該IRQ的CPU會禁用這條IRQ(本地),其它cpu還是可以接受該IRQ的請求,不過由于此時state的狀態為IRQ_INPROGRESS,所以新的IRQ請求會在其它的CPU上應答,但不會處理,也就是該新的IRQ處理會被延遲到處理同一個IRQ的前面一個CPU上執行。能這樣做是因為IRQ的數據結構是所有CPU所共享的

             

            八 多種類型的內核棧

              如果編譯內核設置內核棧為8k,那么進程的內核棧被用于所有類型的內核控制路徑。如果內核棧為4k,則內核使用3種類型的內核棧:異常棧,用于處理異常,每個進程一個;硬中斷棧,用于處理中斷,每個cpu一個;軟中斷棧,用于出來延遲函數,每個cpu一個

            九 軟中斷

            1 為什么要引進軟中斷機制,用前面的中斷機制不就可以了嗎(老版本的linux就沒有軟中斷機制)?

              從前面的中斷處理中可以看出,一個中斷處理程序的幾個中斷服務例程(每個設備一個)是串行執行的,如果某個處理例程執行的時間比較長,而后面的例程又很緊急,那么會導致這個緊急的例程匯編延遲比較久的時間。所以如果能把一些服務例程中不是很緊急但又花費比較長的操作延遲到執行完該IRQ上所有中斷服務例程之后執行,那么一些緊急的,花費時間短(一般緊急的操作所需的時間都是比較短的)的例程就可以得到快速的響應。還有就是對于某個設備的中斷服務例程,如果它的服務例程服務時間過長,cpu在執行該服務例程時是會中斷本地cpu對該設備的中斷或者整個本地中斷,這樣會導致很多中斷會得不到快速的響應。

            2 軟中斷使用的關鍵數據結構

              softirq_vec數組,每個數組元素類型為softirq_action,該數組總共有32個元素,目前只用了前面六個。softirq_action數據結構包含兩個字段:指向軟中斷處理函數的action指針和指向軟中斷函數需要的通用數據結構的data指針,這是cpu共享的

              每個進程描述的thread_info字段中的preempt_count字段,該字段被編碼來表示三個不同的計數器和一個標志。0-7位表示是否允許搶占內核,8-15表示是否正在處理軟中斷,16-27表示硬件中斷控制路徑嵌套數,28為是PREEMPT_ACTIVE標志。每個進程有一個

              另一個是每個cpu都有的32位掩碼,存放在irq_cpustat_t數據結構中的__softirq_pending字段,32位,每一位表示softirq_vec數組中的對應的軟中斷函數是否已激活。irq_cpustat_t存放在irq_stat數組中,每個cpu對于數組中的一個irq_cpustat_t。每個cpu一個

             

            3 軟中斷可延遲函數的四個操作

            • 初始化,定義一個新的可延遲函數,并加入到softirq_vec數組中,所有cpu共享該softirq_vec
            • 激活,標記一個可延遲函數為”掛起“,通過前面描述的__softirq_pending字段。
            • 屏蔽,有選擇地屏蔽一個可延遲函數,即使它被激活。它是通過前面的preempt_count字段或者關閉本地中斷(延遲函數一般是通過中斷處理程序激活的,如果沒有中斷處理程序執行,自然也就不會有延遲函數的激活)來實現的。
            • 執行,執行一個掛起的可延遲函數和同類型的其它掛起的可延遲函數。通過do_softirq實現。

              激活和執行可延遲函數必須要在同一個cpu上,從前面激活和執行可以看出這一點。因為__softirq_pending是每個cpu一個,所有在特定cpu激活的延遲函數,只有在該cpu上的__softirq_pending標記激活,而其它cpu是不知道該函數被激活的,也就不會去執行該函數了

            4 linux現有的六種軟中斷

              處理高級優先級的tasklet軟中斷HI_SOFTIRQ,在softirq_vec數組的下標為0;和時鐘中斷關聯的tasklet軟中斷TIMER_SOFTIRQ,在softirq_vec數組的下標為1;把數據包傳送到網卡軟中斷NET_TX_SOFTIRQ,在softirq_vec數組的下標為2;從網卡接收數據包的軟中斷NET_RX_SOFTIRQ,在softirq_vec數組的下標為3;SCSI命令的后天中斷處理的軟中斷SCSI_SOFTIRQ,在softirq_vec數組的下標為4;處理常規tasklet軟中斷TASKLET_SOFTIRQ,在softirq_vec數組的下標為5;它們的優先級是從高到低的。

            5 檢查是否有軟中斷掛起(也叫激活)的時機

            • 內核調用local_bh_enable激活本地軟中斷
            • smp_apic_timer_interrupt處理完本地定時中斷
            • cpu處理CALL_FUNCTION_VECTOR中斷處理
            • 當一個特殊的ksoftirq/n內核線程被喚醒。

              ksoftirq/n內核線程是專門用來處理激活的軟中斷的,每個cpu有一個

            十 tasklet

              tasklet是在軟中斷的基礎上實現的。正如前面說的linux現有的六種軟中斷,其中HI_SOFTIRQ和TASKLET_SOFTIRQ軟中斷就是tasklet。

              對于每種tasklet(HI_SOFTIRQ和TASKLET_SOFTIRQ),每個cpu都有一個tasklet_head類型來描述這種tasklet。tasklet_head類型指向了一個由tasklet類型組成的鏈表,而每個tasklet類型描述了該tasklet要執行的函數和函數需要的數據以及tasklet的狀態(狀態表示同類型的tasklet是否在運行等)。

              當do_softirq處理軟中斷時,如果相應的HI_SOFTIRQ和TASKLET_SOFTIRQ軟中斷被激活,就會調用對應的軟中斷函數tasklet_hi_action和tasklet_action。而這兩個函數處理的數據正是HI_SOFTIRQ和TASKLET_SOFTIRQ類型tasklet所對應的tasklet_head類型指向的tasklett鏈表。

              為了能夠寫自己的tasklet函數并加入到對應tasklet類型的tasklet_head指向的鏈表中,需要調用tasklet_init來初始化新的tasklet和調用tasklet_schedule或tasklet_hi_schedule來把我們自定義的tasklet加入到對應的tasklet_head指向的鏈表中并激活該tasklet類型所對應的軟中斷。

              所以說tasklet是在軟中斷的基礎上實現的,但不同的是軟中斷時靜態分配的(linux分配了6個軟中斷),而tasklet是可以動態加入和刪除tasklet的。

            十一 工作隊列

              每個工作隊列,在每個cpu上都有一個cpu_workqueue_struct結構來描述,即對于同一個工作隊列,每個cpu都有該隊列的一個拷貝。cpu_workqueue_struct中的worklist成員指向了由work_struct結構組成的鏈表,這個鏈表描述的是該工作隊列被掛起的函數,等待工作者線程去執行。

              通過調用create_workqueue創建工作隊列。如果是smp,則每個cpu都會創建一個工作隊列和為該工作隊列工作的工作者線程。該工作者線程一直阻塞,直到有函數被加入到工作隊列中去,工作者線程執行了函數之后就把函數從工作隊列中刪除。

              可以通過queue_work函數把一個函數加入到工作隊列中去。

              由于僅僅為了一個函數就創建一個工作隊列開銷太大,所以內核預定義了一個叫events的工作隊列,為該隊列工作的工作者線程叫events/n,每個cpu一個。還有就是專門為塊設備使用的kblocked工作隊列。

            十二 軟中斷與工作隊列的區別

              從上面可以看出,軟中斷和工作隊列十分的相似,都是對服務例程中某些耗時的操延后處理。主要區別在于,軟中斷的可延遲函數是在中斷上下文中執行的,而工作者隊列的函數則是在進程上下文中執行的,也就是說軟中斷的延遲函數執行期間不允許內核被搶占,而工作隊列則是可以的。

            本文轉自:http://www.cnblogs.com/chengxuyuancc/p/3380922.html

            posted @ 2013-10-22 08:32 王海光 閱讀(575) | 評論 (0)編輯 收藏
            示例代碼:
            long begin,end;
            double time;
            begin = clock();
            {
                 //查看代碼
            }
            end  = clock();
            time = (double)(end - begin) / CLOCKS_PER_SEC;
            Logger->Info( "%f seconds\n", time );

            其他參考:
            #include<iostream> 
            include<windows.h> 
            using namespace std;
            int main() 

                DWORD start_time=GetTickCount(); 
                { 
                   //此處為被測試代碼
                 } 
                DWORD end_time=GetTickCount(); 
                cout<<"The run time is:"<<(end_time-start_time)<<"ms!"<<endl;//輸出運行時間
                return 0; 
            }  

            #include<iostream> 
            #include<time.h> 
            using namespace std;
            int main()

               clock_t start_time=clock(); 
               { 
                  //被測試代碼 
                } 
               clock_t end_time=clock();
               cout<< "Running time is: "<<static_cast<double>(end_time- start_time)/CLOCKS_PER_SEC*1000<<"ms"<<endl;//輸出運行時間 
               return 0
            posted @ 2013-10-22 08:20 王海光 閱讀(838) | 評論 (0)編輯 收藏
                  STL中的容器按存儲方式分為兩類:一類是按以數組形式存儲的容器(如:vector,deque);另一類是以不連續的節點形式存儲的容器(如:list,map,set)。
                  在使用erase方法刪除元素時,迭代器有時候會失效。在Effective STL,條款9,找到了erase容器中元素的原則。

                     1. 對于關聯容器(如map, set, multimap,multiset),刪除當前的iterator,僅僅會使當前的iterator失效,只要在erase時,遞增當前iterator即可。這是因為map之類的容器,使用了紅黑樹來實現,插入、刪除一個結點不會對其他結點造成影響。
            錯誤的使用方法

                std::map<stringstring> mapTest;
                std::map<stringstring>::iterator iter; 
                
            for ( iter = mapTest.begin();iter != mapTest.end(); iter ++ ) 
                { 
                    
            if ( iter->second == "test" ) 
                    { 
                        mapTest.erase( iter ); 
                    } 
                } 

            正確的使用方法1:
                std::map<stringstring> mapTest;
                std::map<stringstring>::iterator iter; 
                
            for ( iter = mapTest.begin();iter != mapTest.end();) 
                { 
                    
            if ( iter->second == "test" ) 
                    { 
                        mapTest.erase( iter++ ); 
                    } 
                    
            else
                    {
                        iter++// Use Pre Increment for efficiency. 
                    }
                } 
                  因為iter傳給erase方法的是一個副本,iter++會指向下一個元素。
             
            正確的使用方法2:
                std::map<stringstring> mapTest;
                std::map<stringstring>::iterator iter; 
                 for ( iter = mapTest.begin();iter != mapTest.end();) 
                { 
                    if ( iter->second == "test" ) 
                    { 
                        iter = mapTest.erase( iter ); 
                    } 
                    else
                    {
                           ++iter; // Use Pre Increment for efficiency. 
                    }
                } 

                     2. 對于序列式容器(如vector,deque),刪除當前的iterator會使后面所有元素的iterator都失效。這是因為vetor,deque使用了連續分配的內存,刪除一個元素導致后面所有的元素會向前移動一個位置。還好erase方法可以返回下一個有效的iterator
                   3. 對于list來說,它使用了不連續分配的內存,并且它的erase方法也會返回下一個有效的iterator,因此上面兩種正確的方法都可以使用。
                  
            其他鏈接:http://www.shnenglu.com/Herbert/archive/2009/01/08/70479.html
            其他
            鏈接:http://blog.csdn.net/kay226/article/details/6126515
            其他鏈接
            http://www.shnenglu.com/humanchao/archive/2013/04/22/199630.html
            posted @ 2013-10-14 18:22 王海光 閱讀(1004) | 評論 (0)編輯 收藏

            在MFC開發過程中使用ComboBox,有時會根據需求要求只能輸入數字,并且要求數字在一定的范圍內,例如一個用于選擇小時的ComboBox,時間范圍為00到23,那么該如何實現?

            代碼如下:

            在Dialog.h中: 
            …… 
            CComboBox m_cbHour;// 聲明CComboBox類型作為CDialog類的成員變量 
            …… 
            afx_msg void OnCbnEditchangeCbHour(); 
            afx_msg void OnCbnEditupdateCbHour();

            在Dialog.cpp中: 
            …… 
            DDX_Control(pDX, IDC_CB_HOUR, m_cbHour);// 數據交換 
            …… 
            ON_CBN_EDITCHANGE(IDC_CB_HOUR, &CDialog::OnCbnEditchangeCbHour)//添加消息映射,用于CComboBox內容改變中 
            ON_CBN_EDITUPDATE(IDC_CB_HOUR, &CCDialog::OnCbnEditupdateCbHour)//添加消息映射,用于CComboBox內容更新 
            …… 
            下面來具體實現函數: 
            image 
            循環遍歷CComboBox中已經輸入的字符如果發現含有非數字則,置為“00”,使用循環的目的是為了防止用戶跳著輸(大概只有測試人員才會跳著輸)。
            將for循環改為for (int i = 0; i < (strTmp.GetLength()); i++)遇到非數字字符就設置為00;

            image 
            當CComboBox更新數據時判斷數字范圍,如果超過邊界,則設置值為最近邊界值,至此一個只接受可控范圍數字的CComboBox就完成了,但是在WinCE開發中卻有一個問題,就是所有的漢字都輸不進去,但是“頭”這個漢字卻能輸入,不知道這是不是一個BUG,如果在代碼中對“頭”做特別判斷,那這段程序也太奇怪了!

            本文轉自:
            http://blog.csdn.net/wyunteng/article/details/6370882

            posted @ 2013-09-25 17:39 王海光 閱讀(3446) | 評論 (1)編輯 收藏
            在用SetWindowText設置控件內容時,有時候會出字體重疊問題,調用次數越多,重疊越嚴重。以下為解決方法。

            方法一:RedrawWindow()
            1 GetDlgItem(IDC_STATIC)->SetWindowText("your string");   
            2 GetDlgItem(IDC_STATIC)->GetParent()->RedrawWindow(); 

            缺點:窗口刷新太頻繁,一閃一閃,效果不太好。

            方法二:局部刷新
            1 void YourDlg::RefreshControl(UINT uCtlID)   
            2 {      
            3     CRect   rc;      
            4     GetDlgItem(uCtlID)->GetWindowRect(&rc);    
            5     ScreenToClient(&rc);      
            6     InvalidateRect(rc);      
            7 }     

            方法三:隱藏和顯示
            1 GetDlgItem(IDC_STATIC)->ShowWindow(SW_HIDE);
            2 GetDlgItem(IDC_STATIC)->ShowWindow(SW_SHOW);

            posted @ 2013-09-24 10:31 王海光 閱讀(3719) | 評論 (0)編輯 收藏
            方法一:

            CFile類的成員變量:

            m_hFile:表示一個打開文件的操作系統文件句柄。通過對m_hFile  CFile::hFileNull的比較來判斷該文件是否已經打開。

            示例代碼:

             1     CString strFilename = _T("D:\\大學語文.docx");
             2     CFile file;
             3     file.Open(strFilename,CFile::modeReadWrite);//
             4     
             6     if (file.m_hFile != CFile::hFileNull)
             7     {
             8         file.Close();
             9     }
            10     else
            11     {
            12         printf("File Already Close \n");
            13     }

            方法二:

            利用file.GetFileName().IsEmpty()來判斷

            示例代碼:

             1     CString strFilename = _T("D:\\大學語文.docx");
             2     CFile file;
             3     file.Open(strFilename,CFile::modeReadWrite);//
             4     
             5     if (!file.GetFileName().IsEmpty())
             6     {
             7         file.Close();
             8     }
             9     else
            10     {
            11         printf("File Already Close \n");
            12     }

            方法三:

            通過設置成員變量來記錄文件是否被打開。如BOOL bIsFileOpen;默認是FALSE,

            打開成功,把它置為TRUE;否則置為FALSE;

            然后在程序里面判斷就可以了。關閉后置bIsFileOpenFALSE,

             

            posted @ 2013-09-23 16:46 王海光 閱讀(10032) | 評論 (0)編輯 收藏
            僅列出標題
            共27頁: 1 2 3 4 5 6 7 8 9 Last 
            欧美精品一本久久男人的天堂| 欧美精品九九99久久在观看| 国产精品久久久久免费a∨| 国产成人精品久久亚洲高清不卡| 久久综合88熟人妻| 久久99精品国产自在现线小黄鸭| 久久精品国产亚洲αv忘忧草| 一级a性色生活片久久无| 久久国产AVJUST麻豆| 久久人与动人物a级毛片| 国产精品亚洲综合久久| 久久九九精品99国产精品| 精品熟女少妇a∨免费久久| 99国产欧美精品久久久蜜芽| 久久九九亚洲精品| 久久久久国产精品嫩草影院| 伊人久久五月天| 亚洲国产精品久久久久婷婷软件| 亚洲AV乱码久久精品蜜桃| 欧洲国产伦久久久久久久| 国产精品久久久久久五月尺| 久久精品中文无码资源站| 色综合久久无码中文字幕| 国产成人精品白浆久久69| 91精品国产91久久久久久蜜臀| 色偷偷888欧美精品久久久| 久久精品国产一区二区三区| 精品久久久久久无码不卡| 久久久久久亚洲AV无码专区| 国产精品日韩欧美久久综合| 伊人久久综合无码成人网| 久久电影网一区| 国产精品99久久久久久宅男小说| 亚洲∧v久久久无码精品| 狠狠色伊人久久精品综合网 | 亚洲国产天堂久久综合| 性做久久久久久久| 久久久久久一区国产精品| 97热久久免费频精品99| 久久99国产精品久久99小说| 久久精品九九亚洲精品天堂|