亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

??

?? 兼容內核漫談 適合想將Windows上的程序移植到其它平臺上的朋友研究查看
??
?? 第 1 頁 / 共 5 頁
字號:
        if(PreviousCount) {
            _SEH_TRY . . . . . ._SEH_END;
        }
    }
    /* Return Status */
    return Status;
}[/code]
    此類函數都是先調用ObReferenceObjectByHandle(),以取得指向目標對象數據結構的指針,然后就對此數據結構執行具體對象類型的具體操作,在這里是KeReleaseSemaphore()。
    常規的V操作只使信號量加1,可以理解為只提供一張通行證,而KeReleaseSemaphore()則對此作了推廣,可以使信號量加N,即同時提供好幾張通行證,參數ReleaseCount就是這個增量,而PreviousCount則用來返回原來(V操作之前)的信號量數值。這里的常數IO_NO_INCREMENT定義為0,表示不需要提高被喚醒進程的調度優先級。

[code][NtReleaseSemaphore() > KeReleaseSemaphore()]

LONG  STDCALL
KeReleaseSemaphore(PKSEMAPHORE Semaphore,
                   KPRIORITY Increment,
                   LONG Adjustment,
                   BOOLEAN Wait)

{
    ULONG InitialState;
    KIRQL OldIrql;
    PKTHREAD CurrentThread;

    . . . . . .
    /* Lock the Dispatcher Database */
    OldIrql = KeAcquireDispatcherDatabaseLock();

    /* Save the Old State */
    InitialState = Semaphore->Header.SignalState;
    /* Check if the Limit was exceeded */
    if (Semaphore->Limit < (LONG) InitialState + Adjustment ||
                                        InitialState > InitialState + Adjustment) {
        /* Raise an error if it was exceeded */
        KeReleaseDispatcherDatabaseLock(OldIrql);
        ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
    }

    /* Now set the new state */
    Semaphore->Header.SignalState += Adjustment;
    /* Check if we should wake it */
    if (InitialState == 0 && !IsListEmpty(&Semaphore->Header.WaitListHead)) {
        /* Wake the Semaphore */
        KiWaitTest(&Semaphore->Header, Increment);
    }

    /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
    if (Wait == FALSE) {
        /* Release the Lock */
        KeReleaseDispatcherDatabaseLock(OldIrql);
    } else {
        /* Set a wait */
        CurrentThread = KeGetCurrentThread();
        CurrentThread->WaitNext = TRUE;
        CurrentThread->WaitIrql = OldIrql;
    }
    /* Return the previous state */
    return InitialState;
}[/code]
    參數Adjustment就是信號量數值的增量,另一個參數Increment如為非0則表示要為被喚醒的線程暫時增加一些調度優先級,使其盡快得到運行的機會。還有個參數Wait的作用下面就會講到。
    程序中KeAcquireDispatcherDatabaseLock()的作用是提升程序的運行級別(稱為IRQL,以后在別的漫談中會講到這個問題),以禁止線程調度,直至執行與之配對的函數KeReleaseDispatcherDatabaseLock()為止。這樣,在這兩個函數調用之間就形成了一個“調度禁區”。可是我們從代碼中看到,KeReleaseDispatcherDatabaseLock()之是否執行實際上取決于參數Wait。這是為什么呢?我在上一篇漫談中講到,在Windows中,當一個線程要在某個或某幾個對象上等待某些事態的發生時,有兩個系統調用可資調用,一個是NtWaitForSingleObject(),另一個是NtWaitForMultipleObjects()??墒瞧鋵嵾€有一個,就是NtSignalAndWaitForSingleObject(),只是這個系統調用有些特殊。正如其函數名所示,這個系統調用一方面是“Signal”一個對象,就是對其執行類似于KeReleaseSemaphore()這樣的操作;另一方面自己又立即在另一個對象上等待,類似于執行NtWaitForSingleObject();而且這二者應該是一氣呵成的。這樣就來了問題,如果在KeReleaseSemaphore()一類的函數中一律調用KeReleaseDispatcherDatabaseLock(),然后在NtWaitForSingleObject()中又調用KeAcquireDispatcherDatabaseLock(),那么在此二者之間就有個間隙,在此間隙中是可以發生線程調度的。再說,從程序效率的角度,那樣不必要地(且不說有害)來回折騰,也是不可取的,理應加以優化。像現在這樣有條件地執行KeReleaseDispatcherDatabaseLock(),就避免了這個問題。
    對信號量本身的操作倒很簡單,就是改變Semaphore->Header.SignalState的數值。同時,如果有線程在睡眠等待(隊列非空),并且此前信號量的數值是0,那么既然現在退還了若干張通行證(增加了信號量的數值),就可以放幾個正在等待的進程進入臨界區了,所以通過KiWaitTest()喚醒等待中的進程。至于KiWaitTest(),讀者在上一篇漫談中已經看過它的代碼了。注意這里對于睡眠/喚醒的處理與傳統的P/V操作略有些不同。在傳統的P操作中,每執行一次P操作、不管能否進入臨界區、都使信號量的值遞減,所以信號量可以有負值,而且此時其絕對值就是正在睡眠等待的進程的數量。另一方面,當事進程之能否進入臨界區也是按遞減了以后的信號量數值判定的。而在NtWaitForSingleObject()、KiIsObjectSignaled()、KiSatisfyObjectWait()、以及KiWaitTest()的代碼中,則當事進程只有在信號量大于0時才能獲準進入臨界區,這樣的P操作才使信號量的值遞減,否則當事進程就被掛入等待隊列并進入睡眠,因此信號量不會有負值。所以,NtWaitForSingleObject()是變了形的P操作。
    如前所述,信號量既可以用來實現臨界區,也可以使進程(線程)之間形成供應者/消費者的關系和互動。所以,雖然從表面上看信號量操作本身并不攜帶數據,但是它為高效的進程間通信提供了同步手段。另一方面,進程間同步也蘊含著信息的交換,也屬于進程間通信的范疇,所以信號量同時又是一種進程間通信機制。

3. 互斥門(Mutant)
    互斥門(Mutant,又稱Mutex,實現于內核中稱Mutant,實現于用戶空間稱Mutex)是“信號量”的一個特例和變種。在信號量機制中,如果把信號量的最大值和初始值都設置成1,就成了互斥門。把信號量的最大值和初始值都設置成1,就相當于一共只有一張通行證,自然就只能有一個線程可以進入臨界區;在它退出臨界區之前,別的線程想要進入臨界區就只好在大門口睡眠等候。所謂“互斥”,就是因此而來。我的朋友胡希明老師曾把這樣的臨界區比作列車上的廁所(當時他常坐火車出差,想必屢屢為此所苦),二十多年過去了,當年的學生聚在一起還會因此事津津樂道。
    不過,倘若純粹就是兩個參數的事,那就沒有必要另搞一套了。事實上互斥門機制有一些特殊性,下面讀者就會看到。
    為互斥門的創建和打開提供了NtCreateMutant()和NtOpenMutant()兩個系統調用,代碼就不用看了。下面是互斥門對象的數據結構:

[code]typedef struct _KMUTANT {
  DISPATCHER_HEADER    Header;
  LIST_ENTRY             MutantListEntry;
  struct _KTHREAD         *RESTRICTED_POINTER OwnerThread;
  BOOLEAN               Abandoned;
  UCHAR                  ApcDisable;
} KMUTANT, *PKMUTANT, KMUTEX, *PKMUTEX;[/code]
    這個數據結構的定義見之于Windows NT的DDK,所以是“正宗”的??梢?,這數據結構就與信號量對象的不同。
    跟信號量機制一樣,請求(試圖)通過互斥門進入臨界區的操作就是系統調用NtWaitForSingleObject()或NtWaitForMultipleObjects()。不過,在NtWaitForSingleObject()內部,特別是在判定能否進入臨界區時所調用的函數KiIsObjectSignaled()中,其實是按不同的對象類型分別處置的。我們不妨看一下。

[code][NtWaitForSingleObject() > KeWaitForSingleObject() > KiIsObjectSignaled()]

BOOLEAN inline FASTCALL
KiIsObjectSignaled(PDISPATCHER_HEADER Object, PKTHREAD Thread)
{
    /* Mutants are...well...mutants! */
   if (Object->Type == MutantObject) {
        /*
         * Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0
         * Well, only if they are recursivly acquired (i.e if we own it right now).
         * Of course, they are also signaled if their signal state is 1.
         */
        if ((Object->SignalState <= 0 && ((PKMUTANT)Object)->OwnerThread == Thread) ||
            (Object->SignalState == 1)) {
            /* Signaled Mutant */
            return (TRUE);
        } else {
            /* Unsignaled Mutant */
            return (FALSE);
        }
    }
   
    /* Any other object is not a mutated freak, so let's use logic */
   return (!Object->SignalState <= 0);
}[/code]
    可見,互斥門在這里是作為一種特殊情況處理的,使KiIsObjectSignaled()返回TRUE、從而允許當事進程進入臨界區的條件之一是SignalState為1。另一個條件表明,只要是互斥門對象當前的“業主(Owner)”,就不受這個限制,即使沒有通行證也可以進入。那么誰是互斥門對象當前的業主呢?那就是當前已經在此臨界區中的線程,這一點讀者看了下面的代碼就會清楚??墒羌热皇且呀浽谂R界區中的線程,怎么又會企圖通過同一個互斥門進入同一個臨界區呢?這意味著一個線程可能遞歸地多次通過同一個互斥門。這個問題先擱一下,等一下再來探討。
    在上一篇漫談中,我們看了KeWaitForSingleObject()的代碼,這是NtWaitForSingleObject()的主體,正是這個函數調用了KiIsObjectSignaled()。如果KiIsObjectSignaled()返回TRUE,那就說明當前進程可以領到通行證而進入臨界區,此時需要執行KiSatisfyObjectWait(),一方面是進行“賬面”上的處理,一方面也還有一些附加的操作需要進行,而這些附加的操作是因具體的對象而異的。我們再重溫一下這個函數的代碼。

[code][NtWaitForSingleObject() > KeWaitForSingleObject() > KiSatisfyObjectWait()]

VOID  FASTCALL
KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread)
{
    /* Special case for Mutants */
    if (Object->Type == MutantObject) {
        /* Decrease the Signal State */
        Object->SignalState--;
        /* Check if it's now non-signaled */
        if (Object->SignalState == 0) {
            /* Set the Owner Thread */
            ((PKMUTANT)Object)->OwnerThread = Thread;
            /* Disable APCs if needed */
            Thread->KernelApcDisable -= ((PKMUTANT)Object)->ApcDisable;
            /* Check if it's abandoned */
            if (((PKMUTANT)Object)->Abandoned) {
                /* Unabandon it */
                ((PKMUTANT)Object)->Abandoned = FALSE;
                /* Return Status */
                Thread->WaitStatus = STATUS_ABANDONED;
            }
            /* Insert it into the Mutant List */
            InsertHeadList(&Thread->MutantListHead,
                                    &((PKMUTANT)Object)->MutantListEntry);
        }
    } else if ((Object->Type & TIMER_OR_EVENT_TYPE) == EventSynchronizationObject) {
        /* These guys (Syncronization Timers and Events) just get un-signaled */
        Object->SignalState = 0;
    } else if (Object->Type == SemaphoreObject) {
        /* These ones can have multiple signalings, so we only decrease it */
        Object->SignalState--;
    }
}[/code]
    我們只看對于互斥門對象的處理。首先是遞減SignalState,這就是所謂“賬面”上的處理,也是P操作的一部分。由于前面已經通過KiIsObjectSignaled()進行過試探,如果當時的SignalState數值為1,或者說如果當時的臨界區是空的,那么現在的SignalState數值必定變成了0。所以,下面if語句中的代碼是在一個線程首次進入一個互斥門時執行的。這里說的“首次進入”并不是指退出以后又進去那樣的反復進出中的首次,而是指嵌套多次進入中的首次。當一個線程首次順利進入互斥門時,它就成了這個互斥門當前的業主,直至退出;所以把互斥門數據結構中的OwnerThread字段設置成指向當前線程的KTHREAD數據結構。此外,如果Abandoned字段顯示這個互斥門行將被丟棄,則暫時將其改成繼續使用(因為又有線程進來了),但是把這情況記錄在當前線程的KTHREAD數據結構中。互斥門數據結構中的ApcDisable字段表明通過互斥門進入臨界區的線程是否需要關閉APC請求,現在當前進程通過了互斥門,所以要把這信息記錄在它的數據結構中。注意這里是從Thread->KernelApcDisable的數值中減去互斥門的ApcDisable的值,結果為非0(負數)表示關閉APC請求,而ApcDisable的值則非1即0。舉例言之,假定Thread->KernelApcDisable原來是0,而ApcDisable為1,則相減以后的結果為-1,表示關閉APC請求。最后,當前進程既已成為這個互斥門的主人,二者之間就有了連系,所以通過隊列把它們結合起來,這是因為一個線程有可能同時存在于幾個臨界區中。
    應該說這里別的都還好理解,成為問題的是為什么要允許嵌套進入互斥門。據“Programming the Microsoft Windows Driver Model”書中說,互斥門的特點之一就是允許嵌套進入,而優點之一則是可以防止死鎖。書中并沒有明確講這二者之間是否存在因果關系,所以我們只能分析和猜測。首先,如過互斥門不允許嵌套進入(在前面的代碼中取消允許當前業主進入的條件),而已經通過互斥門進入臨界區的線程又對同一個互斥門進行P操作,那么肯定是會引起死鎖的。這個線程會因為在P操作中不能通過互斥門而進入睡眠,能喚醒其睡眠的是已經在這個臨界區中的線程(如果它執行V操作的話),可是這正是已經在睡眠等待的那個線程本身,所以就永遠不會被喚醒。反之,有了前面KiIsObjectSignaled()中那樣的安排,即允許互斥門當前的業主遞歸通過,那確實就可以避免由此而導致的死鎖。
    可是,為什么要企圖遞歸通過同一個互斥門呢?既然已經通過這個具體的互斥門進入了臨界區,為什么還要再一次試圖進入同一個互斥門呢?應該說,在精心設計和實現的軟件中是不應該有這種情況出現的??墒?,考慮到應用軟件的可重用(reuse),有時候也許會有這種情況。例如,一個線程在臨界區內可能調用某個軟件模塊所提供的操作,而這個軟件模塊可能需要通過NtWaitForMultipleObjects()進入由多個互斥門保護的復合臨界區,可是其中之一就是已經進入的那個互斥門。在這種情況下,對于已經進入的那個互斥門而言,就構成了遞歸進入。當然,我們可以通過修改那個軟件模塊來避免此種遞歸,但這可能又不是很現實。在這樣的條件下,允許遞歸進入不失為一個簡單的解決方案。
    還要說明,允許遞歸通過互斥門固然可以防止此種特定形式的死鎖,卻并不是對所有的死鎖都有效。真要防止死鎖,還是得遵守有關的準則,精心設計,精心實現。
    讀者也許會問:這里所引的代碼出自ReactOS,所反映的是ReactOS的作者們對Windows互斥門的理解,但是他們的理解是否正確呢?確實,Windows的代碼是不公開的,所以也無從對比??墒牵m然Windows的代碼不公開,它的一些數據結構的定義卻是公開的,這里面就包括KMUTANT,所以前面特地說明了這是來自Windows DDK(其實ReactOS的許多數據結構都可以在DDK中找到)。既然我們知道互斥門允許遞歸進入,又看到KMUTANT中確有OwnerThread這個指針,那么我們就有理由相信ReactOS的這些代碼離“真相”不會太遠。當然,我們還可以、也應該、設計出一些實驗來加以對比、驗證。

    再看從臨界區退出并交還“通行證”的操作、即V操作,這就是系統調用NtReleaseMutant()。

[code]NTSTATUS  STDCALL
NtReleaseMutant(IN HANDLE MutantHandle, IN PLONG PreviousCount  OPTIONAL)
{
    PKMUTANT Mutant;
    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
    NTSTATUS Status = STATUS_SUCCESS;
  
    . . . . . .
    if(PreviousMode == UserMode && PreviousCount) {
        _SEH_TRY . . . . . . _SEH_END;
        if(!NT_SUCCESS(Status)) return Status;
    }
    /* Open the Object */
    Status = ObReferenceObjectByHandle(MutantHandle, MUTANT_QUERY_STATE,
                       ExMutantObjectType, PreviousMode, (PVOID*)&Mutant, NULL);

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美高清性hdvideosex| 日韩伦理av电影| 欧美国产综合一区二区| 亚洲一级二级三级在线免费观看| 精品一区二区三区免费| 91福利视频久久久久| 久久久久国产免费免费| 日韩黄色片在线观看| 色综合久久九月婷婷色综合| 久久久久久亚洲综合| 日韩电影在线观看网站| 在线亚洲免费视频| 欧美国产日韩精品免费观看| 久久99国产精品麻豆| 欧美乱妇15p| 亚洲一区视频在线观看视频| 不卡一卡二卡三乱码免费网站| 26uuu精品一区二区三区四区在线| 亚洲影视在线播放| 色婷婷久久久亚洲一区二区三区| 久久久综合激的五月天| 免费不卡在线观看| 91精品国产一区二区三区蜜臀 | 欧美日韩一区不卡| 国产精品福利一区二区三区| 国产精品一区二区免费不卡| 欧美不卡一区二区三区四区| 日韩av在线播放中文字幕| 欧美体内she精高潮| 亚洲精品国产无天堂网2021| 91美女在线视频| 亚洲色图欧美在线| 91日韩精品一区| 亚洲三级视频在线观看| 91在线国产观看| 亚洲婷婷综合色高清在线| 91在线小视频| 一区二区三区精品久久久| 日本国产一区二区| 亚洲国产日韩a在线播放| 欧美日韩在线免费视频| 婷婷丁香久久五月婷婷| 欧美一区二区三区男人的天堂| 亚洲18女电影在线观看| 欧美一级视频精品观看| 久久成人麻豆午夜电影| 久久久精品国产免大香伊| 国产精品一区二区在线观看网站 | 国产精品综合二区| 国产精品午夜久久| 99精品久久99久久久久| 亚洲一区中文日韩| 制服丝袜成人动漫| 国产一区二区剧情av在线| 国产女人aaa级久久久级| 91尤物视频在线观看| 午夜在线成人av| 26uuu亚洲综合色欧美| 不卡一区在线观看| 婷婷六月综合网| 国产婷婷色一区二区三区在线| 成人黄页毛片网站| 午夜电影一区二区三区| 久久综合国产精品| 色偷偷88欧美精品久久久| 日本不卡视频一二三区| 日本一区二区三区在线不卡| 欧美伊人久久大香线蕉综合69| 蜜臂av日日欢夜夜爽一区| 国产精品久久久久一区二区三区| 在线精品视频小说1| 国模娜娜一区二区三区| 亚洲精选一二三| xvideos.蜜桃一区二区| 91国偷自产一区二区三区成为亚洲经典 | 国产精品福利一区| 亚洲一二三区视频在线观看| 免费高清不卡av| 国产精品污www在线观看| 欧美制服丝袜第一页| 久久电影网电视剧免费观看| 最新不卡av在线| 精品日韩99亚洲| 在线观看国产日韩| 国产成人av电影在线| 午夜精品影院在线观看| 亚洲欧洲国产日本综合| 精品剧情在线观看| 在线观看成人免费视频| 国产91丝袜在线播放九色| 日韩高清不卡一区| 亚洲一区影音先锋| 中文字幕在线一区免费| 久久嫩草精品久久久精品一| 欧美人与性动xxxx| 色婷婷av一区二区三区gif| 国产美女精品一区二区三区| 奇米影视一区二区三区| 亚洲午夜激情av| 亚洲色图视频网| 91免费视频观看| 国产综合成人久久大片91| 亚洲一区二区三区中文字幕| 一区二区中文视频| 欧美国产一区二区在线观看| 欧美精品一区二区不卡| 精品欧美乱码久久久久久| 欧美二区在线观看| 欧美精品日日鲁夜夜添| 欧美日韩综合色| 欧美性生活影院| 91视频免费看| 色综合久久88色综合天天6| 成人av在线网站| 成人精品免费视频| 成人app下载| 91在线国产观看| 91美女视频网站| 在线观看亚洲精品视频| 一本色道综合亚洲| 91国产视频在线观看| 欧美性感一类影片在线播放| 日本高清成人免费播放| 欧美视频完全免费看| 欧美色国产精品| 69堂成人精品免费视频| 日韩免费福利电影在线观看| 26uuuu精品一区二区| 国产精品视频一区二区三区不卡| 中文av字幕一区| 一区二区三区在线视频播放| 亚洲成人三级小说| 久久99最新地址| 国产91精品久久久久久久网曝门| 高清不卡一二三区| 日本精品免费观看高清观看| 欧美亚洲愉拍一区二区| 欧美一区二区不卡视频| 久久久久久久久久美女| 亚洲天堂精品视频| 奇米777欧美一区二区| 国内精品不卡在线| 99国产一区二区三精品乱码| 欧美日韩亚洲国产综合| 久久综合久久综合久久| 国产精品卡一卡二| 亚洲国产色一区| 国产一区免费电影| 色久优优欧美色久优优| 91精品国产色综合久久不卡电影| 久久久国产精华| 亚洲激情自拍视频| 国内久久精品视频| 91麻豆视频网站| 欧美xfplay| 亚洲免费观看视频| 久久99热这里只有精品| 99国产精品久久久久久久久久久| 欧美日韩国产电影| 国产农村妇女毛片精品久久麻豆| 亚洲综合另类小说| 国产精品一二三区| 欧美日韩午夜精品| 成人欧美一区二区三区视频网页| 日韩和的一区二区| 91色porny蝌蚪| 欧美精品一区二区三区在线| 亚洲国产精品嫩草影院| 成人福利视频在线| 精品国产乱码久久久久久免费| 亚洲美女视频在线观看| 国内精品免费**视频| 欧美理论电影在线| 亚洲黄色免费电影| 成人一级片网址| www一区二区| 青青国产91久久久久久| 欧美日韩五月天| 亚洲免费色视频| 99国产精品国产精品久久| 久久久精品日韩欧美| 日韩vs国产vs欧美| 欧美日韩免费观看一区二区三区 | 裸体歌舞表演一区二区| 亚洲一本大道在线| 51精品视频一区二区三区| 国产精品欧美一区喷水| 精品一区二区久久久| 777精品伊人久久久久大香线蕉| 亚洲精品乱码久久久久久日本蜜臀| 精品写真视频在线观看 | 国产精品正在播放| 91精品国产91热久久久做人人 | 最新高清无码专区| 成人少妇影院yyyy| 国产精品美女久久久久久久久| 激情综合色综合久久| 精品久久久久99| 激情综合网最新| 精品国产sm最大网站免费看|