一種基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方法
【專利摘要】本發(fā)明公開了一種基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方法,包括:基于動(dòng)態(tài)插樁的方式能夠在二進(jìn)制級(jí)而非源碼層次上向正在運(yùn)行的源程序插入關(guān)鍵代碼,使得升級(jí)不需要依賴特定編譯器;基于異步檢查點(diǎn)算法能夠確保所有線程在動(dòng)態(tài)升級(jí)前處于阻塞狀態(tài),從而能夠一次性更新所有線程并避免新舊版本維護(hù)帶來的開銷;采用二進(jìn)制重寫的方式實(shí)現(xiàn)函數(shù)間接跳轉(zhuǎn),能夠升級(jí)未在執(zhí)行的待更新函數(shù);利用堆棧重構(gòu)的方式能夠升級(jí)正在執(zhí)行的待更新函數(shù),使得動(dòng)態(tài)升級(jí)消除了諸如更新循環(huán)體和主函數(shù)等帶來的無法預(yù)計(jì)的等待時(shí)間。本發(fā)明能夠?yàn)榫哂懈呖煽啃孕枨蟮膽?yīng)用和服務(wù)(例如電子支付系統(tǒng))將因版本維護(hù)宕機(jī)而導(dǎo)致的損失降到最低,減少增加冗余硬件帶來的成本開銷。
【專利說明】一種基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方法
【技術(shù)領(lǐng)域】
[0001] 本發(fā)明屬于軟件可靠性研究中的安全領(lǐng)域,更具體地,涉及一種基于異步檢查點(diǎn) 的多線程軟件動(dòng)態(tài)升級(jí)方法。
【背景技術(shù)】
[0002] 為了針對(duì)提供7/24小時(shí)服務(wù)可靠性,從軟件的角度考慮,傳統(tǒng)的軟件更新方法通 常要求停止軟件的運(yùn)行,應(yīng)用更新后再次重啟軟件方可完成。這樣的停止--重啟方式不 可避免地破壞了運(yùn)行服務(wù)的執(zhí)行,降低了軟件的可用性。從硬件的角度,有的方案可以在增 加服務(wù)器鏡像的前提下實(shí)現(xiàn)動(dòng)態(tài)遷移,待到升級(jí)完畢后,將數(shù)據(jù)重新同步回主服務(wù)器,從而 保證應(yīng)用(服務(wù))的可靠性,然而這種方案需要購買額外的冗余硬件,大大的增加了維護(hù) 成本。綜上所述,基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方案將能夠很好的提升在線程序 (服務(wù))的可靠性,減少宕機(jī)時(shí)間,增加盈利。為了解決以上問題,動(dòng)態(tài)軟件更新(DSU)孕育 而生,并且成為目前急切需要的新技術(shù)。在動(dòng)態(tài)軟件更新當(dāng)中,多線程支持又是一個(gè)新的挑 戰(zhàn),因?yàn)榫€程執(zhí)行相同的函數(shù)并試圖修改相同的數(shù)據(jù),這樣很難保證數(shù)據(jù)的一致性。
[0003] -般來講,很多現(xiàn)存的方法都是基于更新點(diǎn)(待更新的數(shù)據(jù)和代碼當(dāng)前還未被調(diào) 用的位置稱為更新點(diǎn))。這樣在更新一個(gè)運(yùn)行系統(tǒng)的時(shí)候只有在某些特定執(zhí)行點(diǎn)才能應(yīng)用, 例如待更新的代碼沒有被執(zhí)行,數(shù)據(jù)未被引用的時(shí)候,否則系統(tǒng)很容易出現(xiàn)不一致的狀態(tài)。
[0004] 基于更新點(diǎn)的方法有幾個(gè)缺點(diǎn)。首先能夠找到安全更新點(diǎn)在很大程度上依賴于編 譯器或程序員的分析能力。對(duì)于像C語言一樣靈活的語言,編譯器經(jīng)常很難分析指針和別 名。因此,它們不得不做出保守的假設(shè),分析結(jié)果中可能產(chǎn)生誤報(bào)。雖然最近提出的建議有 利于轉(zhuǎn)換編譯器使程序變得可更新,但是他們的方法僅適用于單線程應(yīng)用程序,并且無法 維持二進(jìn)制兼容性。所以,它不能用于編譯的二進(jìn)制文件和當(dāng)前的運(yùn)行軟件。其次,很難在 多線程軟件中找到更新點(diǎn),一個(gè)繁忙的系統(tǒng)中某些模塊甚至可能沒有一個(gè)安全點(diǎn)。當(dāng)涉及 數(shù)據(jù)變化時(shí),對(duì)于多線程軟件無法分析其可更新性。如果不能及時(shí)到達(dá)或檢測(cè)到更新點(diǎn),某 些安全更新將會(huì)延遲,脆弱的系統(tǒng)可能暴露在外部攻擊之下。最后,對(duì)于一些基于更新點(diǎn)機(jī) 制的動(dòng)態(tài)更新系統(tǒng),操作員可能在動(dòng)態(tài)更新進(jìn)程中沒有任何控制權(quán),在系統(tǒng)到達(dá)安全更新 點(diǎn)應(yīng)用更新時(shí),操作員將一無所知。如果操作員無法知曉系統(tǒng)是否已經(jīng)完成當(dāng)前更新,另一 個(gè)處于進(jìn)展中的更新可能在不經(jīng)意間應(yīng)用。
[0005] 綜上所述,現(xiàn)有的動(dòng)態(tài)軟件升級(jí)系統(tǒng)的方案存在如下不足:
[0006] 有的方案(例如UpStare)需要依賴特定的編譯器,在重新編譯源程序時(shí)添加相關(guān) 的動(dòng)態(tài)升級(jí)輔助代碼,這對(duì)于已經(jīng)部署的應(yīng)用程序是行不通的;有的方案(例如Polus)無 法更新正在執(zhí)行的函數(shù),需要等待函數(shù)調(diào)用完畢才能生效,這意味著如果主函數(shù)有改動(dòng),則 直到程序退出應(yīng)用程序?qū)⒂肋h(yuǎn)無法動(dòng)態(tài)升級(jí)成新的版本;有的方案則只對(duì)單線程應(yīng)用程序 有效,顯然在多線程應(yīng)用程序如此流行的今天,這也是不實(shí)用的。
【發(fā)明內(nèi)容】
[0007] 針對(duì)現(xiàn)有技術(shù)的以上缺陷或改進(jìn)需求,本發(fā)明提供了一種基于異步檢查點(diǎn)的多線 程軟件動(dòng)態(tài)升級(jí)方法,其目的在于,解決現(xiàn)有針對(duì)已經(jīng)部署的多線程應(yīng)用程序進(jìn)行動(dòng)態(tài)升 級(jí)中出現(xiàn)的上述技術(shù)問題,確保升級(jí)的可行性,使得更新過程不會(huì)處于無限期的等待中。
[0008] 為實(shí)現(xiàn)上述目的,按照本發(fā)明的一個(gè)方面,提供了一種基于異步檢查點(diǎn)的多線程 軟件動(dòng)態(tài)升級(jí)方法,包括以下步驟:
[0009] (1)獲取待升級(jí)軟件的新舊版本,分別提取新舊版本中的項(xiàng)目源文件,并分別將該 新舊版本的項(xiàng)目源文件整合;
[0010] (2)對(duì)整合后的新版本的項(xiàng)目源文件和舊版本的項(xiàng)目源文件進(jìn)行對(duì)比,以生成初 級(jí)補(bǔ)??;
[0011] (3)將異步檢查點(diǎn)插入初級(jí)補(bǔ)丁中,以生成動(dòng)態(tài)升級(jí)補(bǔ)丁,其中異步檢查點(diǎn)中保存 了待升級(jí)軟件的新舊版本的延續(xù)點(diǎn)的映射關(guān)系;
[0012] (4)將生成的動(dòng)態(tài)升級(jí)補(bǔ)丁加載到運(yùn)行中的待升級(jí)軟件的舊版本中;
[0013] (5)接收用戶的初始化請(qǐng)求,并根據(jù)該初始化請(qǐng)求使用動(dòng)態(tài)升級(jí)補(bǔ)丁中待更新的 函數(shù)名查找內(nèi)存中對(duì)應(yīng)的函數(shù)體,并將步驟(3)中的異步檢查點(diǎn)插入該函數(shù)體中;
[0014] (6)接收用戶的應(yīng)用請(qǐng)求,并根據(jù)該應(yīng)用請(qǐng)求利用異步檢查點(diǎn)算法使待升級(jí)軟件 中的所有線程達(dá)到阻塞狀態(tài);
[0015] (7)對(duì)于待升級(jí)軟件中的線程中未被使用和執(zhí)行的函數(shù)及變量,采用二進(jìn)制重寫 的方式實(shí)現(xiàn)函數(shù)的間接跳轉(zhuǎn),對(duì)于待升級(jí)軟件中的線程中正在使用和執(zhí)行的函數(shù)及變量, 采用堆棧重構(gòu)的方式進(jìn)行映射和狀態(tài)轉(zhuǎn)換;
[0016] (8)根據(jù)動(dòng)態(tài)升級(jí)補(bǔ)丁中異步檢查點(diǎn)中保存的新舊版本的延續(xù)點(diǎn)的映射關(guān)系恢復(fù) 執(zhí)行所有線程,過程結(jié)束。
[0017] 優(yōu)選地,步驟(1)是采用通用中間語言中的合并功能進(jìn)行項(xiàng)目源文件的整合。
[0018] 優(yōu)選地,步驟(5)將異步檢查點(diǎn)插入函數(shù)體中是利用動(dòng)態(tài)插樁方式,插入函數(shù)體 的位置是位于該函數(shù)體的頭部、循環(huán)體的開頭、函數(shù)調(diào)用之前。
[0019] 優(yōu)選地,步驟(6)具體包括以下子步驟:
[0020] (6-1)接收用戶的應(yīng)用請(qǐng)求,該應(yīng)用請(qǐng)求中包括待更新軟件的進(jìn)程ID、以及步驟 (3)中動(dòng)態(tài)升級(jí)補(bǔ)丁文件的路徑;
[0021] (6-2)初始化空的第一映射表和第二映射表,其中第一映射表表不線程已經(jīng)獲得 的臨界變量以及協(xié)助動(dòng)態(tài)升級(jí)的鎖,第二映射表表示線程希望獲得的臨界變量以及協(xié)助動(dòng) 態(tài)升級(jí)的鎖;
[0022] (6-3)通過包裝替換系統(tǒng)調(diào)用來追蹤線程的共享臨界變量和協(xié)助動(dòng)態(tài)升級(jí)的鎖, 當(dāng)系統(tǒng)每次對(duì)共享臨界變量和協(xié)助動(dòng)態(tài)升級(jí)的鎖有操作時(shí),查找步驟¢-2)中的第一映射 表和第二映射表,然后進(jìn)入步驟¢-4),若沒有則將臨界變量名和協(xié)助動(dòng)態(tài)升級(jí)的鎖的名稱 添加到第一映射表和第二映射表中,并在每個(gè)變量或鎖的后面添加對(duì)其操作的線程ID,然 后進(jìn)入步驟¢-4)。
[0023] (6-4)判斷線程是占用協(xié)助動(dòng)態(tài)升級(jí)的鎖,還是占用共享臨界變量,如果是前者則 先將其線程ID添加到第二映射表中,如果第一映射表中協(xié)助動(dòng)態(tài)升級(jí)的鎖沒有線程ID,則 將其線程ID添加到第一映射表中對(duì)應(yīng)的位置,并將該線程標(biāo)記為協(xié)助狀態(tài),如果第一映射 表中協(xié)助動(dòng)態(tài)升級(jí)的鎖有線程ID將該線程標(biāo)記為阻塞狀態(tài);如果是后者則先將其線程ID 添加到第二映射表中,如果第一映射表中對(duì)應(yīng)的共享臨界變量沒有線程ID,則將其線程ID 添加到第一映射表中對(duì)應(yīng)的位置,并將該線程標(biāo)記為協(xié)助狀態(tài),如果第一映射表中對(duì)應(yīng)的 共享臨界變量有線程ID將該線程標(biāo)記為阻塞狀態(tài);
[0024] (6-5)持續(xù)檢查所有線程的狀態(tài),當(dāng)發(fā)現(xiàn)沒有線程處于run狀態(tài)時(shí),則將標(biāo)記為協(xié) 助狀態(tài)的線程阻塞,此時(shí)所有線程都進(jìn)入阻塞狀態(tài),通知系統(tǒng)可以進(jìn)行后續(xù)的動(dòng)態(tài)升級(jí)操 作。
[0025] 按照本發(fā)明的另一方面,提供了一種基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)系 統(tǒng),包括:
[0026] 第一模塊,用于獲取待升級(jí)軟件的新舊版本,分別提取新舊版本中的項(xiàng)目源文件, 并分別將該新舊版本的項(xiàng)目源文件整合;
[0027] 第二模塊,用于對(duì)整合后的新版本的項(xiàng)目源文件和舊版本的項(xiàng)目源文件進(jìn)行對(duì) t匕,以生成初級(jí)補(bǔ)丁;
[0028] 第三模塊,用于將異步檢查點(diǎn)插入初級(jí)補(bǔ)丁中,以生成動(dòng)態(tài)升級(jí)補(bǔ)丁,其中異步檢 查點(diǎn)中保存了待升級(jí)軟件的新舊版本的延續(xù)點(diǎn)的映射關(guān)系;
[0029] 第四模塊,用于將生成的動(dòng)態(tài)升級(jí)補(bǔ)丁加載到運(yùn)行中的待升級(jí)軟件的舊版本中;
[0030] 第五模塊,用于接收用戶的初始化請(qǐng)求,并根據(jù)該初始化請(qǐng)求使用動(dòng)態(tài)升級(jí)補(bǔ)丁 中待更新的函數(shù)名查找內(nèi)存中對(duì)應(yīng)的函數(shù)體,并將第三模塊中的異步檢查點(diǎn)插入該函數(shù)體 中;
[0031] 第六模塊,用于接收用戶的應(yīng)用請(qǐng)求,并根據(jù)該應(yīng)用請(qǐng)求利用異步檢查點(diǎn)算法使 待升級(jí)軟件中的所有線程達(dá)到阻塞狀態(tài);
[0032] 第七模塊,用于對(duì)于待升級(jí)軟件中的線程中未被使用和執(zhí)行的函數(shù)及變量,采用 二進(jìn)制重寫的方式實(shí)現(xiàn)函數(shù)的間接跳轉(zhuǎn),對(duì)于待升級(jí)軟件中的線程中正在使用和執(zhí)行的函 數(shù)及變量,采用堆棧重構(gòu)的方式進(jìn)行映射和狀態(tài)轉(zhuǎn)換;
[0033] 第八模塊,用于根據(jù)動(dòng)態(tài)升級(jí)補(bǔ)丁中異步檢查點(diǎn)中保存的新舊版本的延續(xù)點(diǎn)的映 射關(guān)系恢復(fù)執(zhí)行所有線程,過程結(jié)束。
[0034] 總體而言,通過本發(fā)明所構(gòu)思的以上技術(shù)方案與現(xiàn)有技術(shù)相比,能夠取得下列有 益效果:
[0035] (1)二進(jìn)制兼容性(不依賴于特定編譯器):本發(fā)明的方法并未使用程序改造或重 建將程序變得可更新,它利用調(diào)試API獲得補(bǔ)丁進(jìn)程的控制權(quán)并修改運(yùn)行程序的狀態(tài),這 和調(diào)試器的實(shí)現(xiàn)原理相似。此外,不依靠更新點(diǎn)來消除類型上的許多制約因素,本發(fā)明的方 法增加了更新的靈活性。
[0036] (2)多線程支持:處理多線程軟件的難點(diǎn)在于有可能幾個(gè)線程同時(shí)訪問更新中的 數(shù)據(jù),本發(fā)明放棄了基于更新點(diǎn)的方法而采用更新立即應(yīng)用。其追蹤試圖向舊版本中的臨 界變量進(jìn)行寫訪問并且采用一次性更新所有線程的方式保證同一時(shí)刻軟件只執(zhí)行調(diào)用同 一版本的函數(shù)和變量,避免了數(shù)據(jù)的不一致性。
[0037] (3)防止線程之間的死鎖問題:考慮到有些軟件在更新前有可能已經(jīng)處于一個(gè)異 常狀態(tài)例如一些軟件內(nèi)部錯(cuò)誤或是外部攻擊。因此不考慮這些情況很有可能導(dǎo)致這些軟 件更新的失敗,雖然要完全解決這些問題是不大可能的,在某些時(shí)候無法知曉正確的運(yùn)行 狀態(tài),但是本發(fā)明的方法可以包裝替換系統(tǒng)調(diào)用來獲悉各個(gè)線程是否處于阻塞狀態(tài),維護(hù) WANT和HAVE列表能夠有效避免線程之間的死鎖問題。
[0038] (4)可用性和可管理性:為了減輕操作員的負(fù)擔(dān),本發(fā)明的方法開發(fā)了一種用戶 界面方便整個(gè)更新過程。操作員只需要告訴系統(tǒng)少量的信息(進(jìn)程ID和補(bǔ)丁名稱)就能 應(yīng)用更新。同時(shí),打補(bǔ)丁的過程對(duì)于操作員也是可見的。為了幫助用戶構(gòu)建動(dòng)態(tài)補(bǔ)丁,本發(fā) 明的方法提供了一個(gè)源代碼到源代碼的編譯器,它可以識(shí)別新舊版本代碼的語義差別。通 過一些簡(jiǎn)單的手動(dòng)調(diào)整,動(dòng)態(tài)補(bǔ)丁可以自動(dòng)地生成。
[0039] (5)低開銷:由于使用二進(jìn)制重寫來指示舊版本到新版本的函數(shù)調(diào)用,這就只會(huì) 產(chǎn)生函數(shù)間接尋址的一點(diǎn)點(diǎn)開銷。而應(yīng)用異步檢查點(diǎn)算法一次性更新所有線程并完成堆棧 重構(gòu)是在所有線程都處于阻塞的狀態(tài)下進(jìn)行的,實(shí)際上,這樣的開銷是很小的,性能測(cè)試表 明對(duì)于大多數(shù)應(yīng)用程序它的開銷小于5%。
【專利附圖】
【附圖說明】
[0040] 圖1是本發(fā)明基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方法的流程圖。
[0041] 圖2(a)和(b)示出異步檢查點(diǎn)算法能夠解決的死鎖問題。
[0042] 圖3示出函數(shù)間接跳轉(zhuǎn)的實(shí)現(xiàn)原理。
[0043] 圖4示出堆棧重構(gòu)的概況。
【具體實(shí)施方式】
[0044] 為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點(diǎn)更加清楚明白,以下結(jié)合附圖及實(shí)施例,對(duì) 本發(fā)明進(jìn)行進(jìn)一步詳細(xì)說明。應(yīng)當(dāng)理解,此處所描述的具體實(shí)施例僅僅用以解釋本發(fā)明,并 不用于限定本發(fā)明。此外,下面所描述的本發(fā)明各個(gè)實(shí)施方式中所涉及到的技術(shù)特征只要 彼此之間未構(gòu)成沖突就可以相互組合。
[0045] 本發(fā)明的整體思路在于,用戶可以根據(jù)新舊版本的開源軟件生成初級(jí)動(dòng)態(tài)升級(jí)補(bǔ) 丁,對(duì)初級(jí)動(dòng)態(tài)升級(jí)補(bǔ)丁進(jìn)行加工并在常規(guī)編譯器下編譯得到動(dòng)態(tài)升級(jí)補(bǔ)丁,然后加載動(dòng) 態(tài)升級(jí)補(bǔ)丁利用異步檢查點(diǎn)算法使待更新軟件的所有線程達(dá)到阻塞狀態(tài),對(duì)于未被執(zhí)行使 用的函數(shù)和變量采取間接跳轉(zhuǎn)的方式進(jìn)行更新,對(duì)于正在執(zhí)行使用的函數(shù)和變量則采取一 次性對(duì)所有線程進(jìn)行堆棧重構(gòu)的方式來更新。
[0046] 如圖1所示,本發(fā)明基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方法包括以下步驟:
[0047] (1)獲取待升級(jí)軟件的新舊版本,分別提取新舊版本中的項(xiàng)目源文件,并分別將 該新舊版本的項(xiàng)目源文件整合;具體而言,是采用通用中間語言(Common Intermediate Language,簡(jiǎn)稱CIL)中的合并(Merge)功能進(jìn)行項(xiàng)目源文件的整合;
[0048] (2)對(duì)整合后的新版本的項(xiàng)目源文件和舊版本的項(xiàng)目源文件進(jìn)行對(duì)比,以生成 初級(jí)補(bǔ)??;具體而言,是利用強(qiáng)大在線升級(jí)系統(tǒng)(Powerful Live Updating System,簡(jiǎn)稱 Polus)進(jìn)行比對(duì)工作,生成的初級(jí)補(bǔ)丁是.c類型的程序文件;
[0049] (3)將異步檢查點(diǎn)插入初級(jí)補(bǔ)丁中,以生成動(dòng)態(tài)升級(jí)補(bǔ)?。痪唧w而言,將異步檢 查點(diǎn)的代碼插入.c類型的程序文件中,并使用常規(guī)編譯器(比如GCC)對(duì)其進(jìn)行編譯,最 終生成.so類型的程序文件;此外,異步檢查點(diǎn)中保存了待升級(jí)軟件的新舊版本的延續(xù)點(diǎn) (Continuation point)的映射關(guān)系;
[0050] (4)將生成的動(dòng)態(tài)升級(jí)補(bǔ)丁加載到運(yùn)行中的待升級(jí)軟件的舊版本中;
[0051] (5)接收用戶的初始化請(qǐng)求,并根據(jù)該初始化請(qǐng)求使用動(dòng)態(tài)升級(jí)補(bǔ)丁中待更新的 函數(shù)名查找內(nèi)存中對(duì)應(yīng)的函數(shù)體,并將步驟(3)中的異步檢查點(diǎn)插入該函數(shù)體中;具體而 言,將異步檢查點(diǎn)插入函數(shù)體中是利用動(dòng)態(tài)插樁方式,插入函數(shù)體的位置是位于該函數(shù)體 的頭部、循環(huán)體的開頭、函數(shù)調(diào)用之前。
[0052] (6)接收用戶的應(yīng)用請(qǐng)求,并根據(jù)該應(yīng)用請(qǐng)求利用異步檢查點(diǎn)算法使待升級(jí)軟件 中的所有線程達(dá)到阻塞狀態(tài);本步驟具體包括以下子步驟:
[0053] (6-1)接收用戶的應(yīng)用請(qǐng)求,該應(yīng)用請(qǐng)求中包括待更新軟件的進(jìn)程ID、以及步驟 (3)中動(dòng)態(tài)升級(jí)補(bǔ)丁文件的路徑;
[0054] (6-2)初始化空的第一映射表(HAVE列表)和第二映射表(WANT列表),其中第一 映射表表示線程已經(jīng)獲得的臨界變量以及協(xié)助動(dòng)態(tài)升級(jí)的鎖(Lock),第二映射表表示線程 希望獲得的臨界變量以及協(xié)助動(dòng)態(tài)升級(jí)的鎖;
[0055] (6-3)通過包裝替換(replaced with wrapper calls)系統(tǒng)調(diào)用來追蹤線程的共 享臨界變量和協(xié)助動(dòng)態(tài)升級(jí)的鎖,當(dāng)系統(tǒng)每次對(duì)共享臨界變量和協(xié)助動(dòng)態(tài)升級(jí)的鎖有操作 時(shí),查找步驟¢-2)中的第一映射表和第二映射表,然后進(jìn)入步驟¢-4),若沒有則將臨界 變量名和協(xié)助動(dòng)態(tài)升級(jí)的鎖的名稱添加到第一映射表和第二映射表中,并在每個(gè)變量或鎖 的后面添加對(duì)其操作的線程ID,然后進(jìn)入步驟(6-4)。
[0056] (6-4)判斷線程是占用協(xié)助動(dòng)態(tài)升級(jí)的鎖,還是占用共享臨界變量,如果是前者則 先將其線程ID添加到WANT列表中,如果HAVE列表中協(xié)助動(dòng)態(tài)升級(jí)的鎖沒有線程ID,則將 其線程ID添加到HAVE列表中對(duì)應(yīng)的位置,并將該線程標(biāo)記為協(xié)助(cooperate)狀態(tài),如果 HAVE列表中協(xié)助動(dòng)態(tài)升級(jí)的鎖有線程ID將該線程標(biāo)記為阻塞(block)狀態(tài);如果是后者 則先將其線程ID添加到WANT列表中,如果HAVE列表中對(duì)應(yīng)的共享臨界變量沒有線程ID, 則將其線程ID添加到HAVE列表中對(duì)應(yīng)的位置,并將該線程標(biāo)記為協(xié)助(run)狀態(tài),如果 HAVE列表中對(duì)應(yīng)的共享臨界變量有線程ID將該線程標(biāo)記為阻塞(block)狀態(tài)。
[0057] (6-5)持續(xù)檢查所有線程的狀態(tài),當(dāng)發(fā)現(xiàn)沒有線程處于run狀態(tài)時(shí),則將標(biāo)記為協(xié) 助狀態(tài)的線程阻塞,此時(shí)所有線程都進(jìn)入阻塞狀態(tài),通知系統(tǒng)可以進(jìn)行后續(xù)的動(dòng)態(tài)升級(jí)操 作。
[0058] (7)對(duì)于待升級(jí)軟件中的線程中未被使用和執(zhí)行的函數(shù)及變量,采用二進(jìn)制重寫 的方式實(shí)現(xiàn)函數(shù)的間接跳轉(zhuǎn),具體而言,將函數(shù)體開頭的二進(jìn)制代碼替換成jmp指令,跳轉(zhuǎn) 到新版本函數(shù),變量采用重定向的方式映射到新版本的內(nèi)存地址;而對(duì)于待升級(jí)軟件中的 線程中正在使用和執(zhí)行的函數(shù)及變量,采用堆棧重構(gòu)的方式進(jìn)行映射和狀態(tài)轉(zhuǎn)換,具體而 言,首先保存現(xiàn)場(chǎng),記錄當(dāng)前函數(shù)棧中的數(shù)據(jù)和寄存器的值,然后展開堆棧,根據(jù)現(xiàn)場(chǎng)信息 和步驟(3)中的動(dòng)態(tài)升級(jí)補(bǔ)丁中待更新函數(shù)的信息,重寫函數(shù)參數(shù)、返回地址、前棧幀指針 和局部變量,修改替換新的函數(shù)指令。
[0059] (8)根據(jù)動(dòng)態(tài)升級(jí)補(bǔ)丁中異步檢查點(diǎn)中保存的新舊版本的延續(xù)點(diǎn)的映射關(guān)系恢復(fù) 執(zhí)行所有線程,過程結(jié)束,此時(shí)運(yùn)行軟件現(xiàn)在執(zhí)行和使用的函數(shù)及變量都是新的版本。
[0060] 如圖2(a)和(b)所示,線程8,13,(3,(1,64正常運(yùn)行,在這個(gè)時(shí)候更新監(jiān)控進(jìn)程向 應(yīng)用程序發(fā)出將要更新的信號(hào)。線程a首先到達(dá)檢查點(diǎn),于是它獲得了協(xié)助動(dòng)態(tài)升級(jí)的鎖, 線程b,c,d也接著到達(dá)檢查點(diǎn),但是此時(shí)協(xié)助動(dòng)態(tài)升級(jí)的鎖已經(jīng)被線程a獲得,所以它們處 于被阻塞的狀態(tài),更新監(jiān)控進(jìn)程通過協(xié)助動(dòng)態(tài)升級(jí)的鎖的異常捕獲能夠輕易的獲悉這一情 況,然而線程d在阻塞前占有了臨界變量tempi,此時(shí)線程e恰好要訪問臨界變量tempi而 被阻塞,但是更新監(jiān)控進(jìn)程通常情況下不能直接捕獲線程e的狀態(tài),因?yàn)闆]有任何異常被 拋出。然而通過WANT和HAVE列表可以輕易的發(fā)現(xiàn)線程e是被阻塞的,線程f處于繼續(xù)執(zhí) 行的狀態(tài)。也就是說,如果沒有WANT和HAVE列表的支持,當(dāng)線程f也到達(dá)阻塞狀態(tài)時(shí),更 新監(jiān)控進(jìn)程并不知道所有線程都處于阻塞狀態(tài),它仍然會(huì)一直等待,導(dǎo)致應(yīng)用程序的死鎖, 通過維護(hù)WANT和HAVE列表就可以成功避免更新過程中線程間的死鎖問題。
[0061] 本發(fā)明的方法本發(fā)明的方法通過重寫函數(shù)開頭指令的5個(gè)字節(jié)插入一條jmp指 令,但是重寫操作毀壞了一條或多條指令。在指令重寫操作之外,本發(fā)明的方法在立即執(zhí)行 指令之前插入兩個(gè)字節(jié)的兩條nop指令,因?yàn)閮?nèi)核從EIP減去兩個(gè)字節(jié)來重啟系統(tǒng)調(diào)用,如 果ptrace已經(jīng)中斷了一個(gè)系統(tǒng)調(diào)用的執(zhí)行。為了在代碼更新后不需要系統(tǒng)的幫助使得應(yīng) 用程序繼續(xù)執(zhí)行,本發(fā)明的方法應(yīng)該保存已經(jīng)被重寫為jmp和nop指令的原始指令。然而, 當(dāng)應(yīng)該被重寫為nop的原始指令在另一個(gè)分支上時(shí),修改過的指令也許會(huì)被直接執(zhí)行,這 有可能導(dǎo)致非法指令錯(cuò)誤。于是,本發(fā)明的方法重寫指令的另外4個(gè)或7個(gè)字節(jié)(兩條nop 指令要2個(gè)字節(jié),一條短跳jmp指令要2個(gè)字節(jié)或者一條長跳jmp指令要5個(gè)字節(jié))。短跳 jmp指令用來將控制流跳轉(zhuǎn)到另一個(gè)分支和不可能被直接重寫為nop指令的指令。如圖3 所示,通過這種二進(jìn)制重寫的方式,在虛擬內(nèi)存地址的函數(shù)體開頭插入跳轉(zhuǎn)指令,當(dāng)程序再 次調(diào)用該函數(shù)時(shí),它將沿著函數(shù)體中的每一條指令順序執(zhí)行,而第一條指令已經(jīng)被重寫為 jmp跳轉(zhuǎn)指令,程序?qū)⑻叫掳姹竞瘮?shù)的代碼繼續(xù)執(zhí)行,這樣相當(dāng)于程序每次調(diào)用舊版本函 數(shù)實(shí)際上卻在執(zhí)行新版本函數(shù)的指令。
[0062] 堆棧重構(gòu)包括兩個(gè)主要步驟,堆棧信息的保存以及所有函數(shù)棧幀的恢復(fù)。在堆棧 重構(gòu)中恢復(fù)更新的狀態(tài)前它保存現(xiàn)有堆棧的狀態(tài)。為了減少升級(jí)補(bǔ)丁中堆棧重構(gòu)輔助代碼 的大小,有效地保存和恢復(fù)堆棧幀的包裝函數(shù)只在重建時(shí)運(yùn)行的單獨(dú)內(nèi)存區(qū)里的文本段里 生成。如圖4所示,函數(shù)A、B正在執(zhí)行并且都需要更新,這時(shí)候如果所有線程暫停處于阻塞 狀態(tài),則本發(fā)明的方法開始保存現(xiàn)場(chǎng),記錄數(shù)據(jù)和寄存器的值,然后展開堆棧,根據(jù)動(dòng)態(tài)升 級(jí)補(bǔ)丁中待更新函數(shù)的信息,重新對(duì)函數(shù)棧幀中的變量賦值,修改替換新的函數(shù)指令,其中 不需要更新的函數(shù)在堆棧中的部分沒有太大變化,需要更新的函數(shù)如A、B其新版本的數(shù)據(jù) 由舊版本的數(shù)據(jù)映射獲取,寄存器、相對(duì)虛擬地址等值也要重新計(jì)算得到。
[〇〇63] 本領(lǐng)域的技術(shù)人員容易理解,以上所述僅為本發(fā)明的較佳實(shí)施例而已,并不用以 限制本發(fā)明,凡在本發(fā)明的精神和原則之內(nèi)所作的任何修改、等同替換和改進(jìn)等,均應(yīng)包含 在本發(fā)明的保護(hù)范圍之內(nèi)。
【權(quán)利要求】
1. 一種基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)方法,其特征在于,包括以下步驟: (1) 獲取待升級(jí)軟件的新舊版本,分別提取新舊版本中的項(xiàng)目源文件,并分別將該新舊 版本的項(xiàng)目源文件整合; (2) 對(duì)整合后的新版本的項(xiàng)目源文件和舊版本的項(xiàng)目源文件進(jìn)行對(duì)比,以生成初級(jí)補(bǔ) ??; (3) 將異步檢查點(diǎn)插入初級(jí)補(bǔ)丁中,以生成動(dòng)態(tài)升級(jí)補(bǔ)丁,其中異步檢查點(diǎn)中保存了待 升級(jí)軟件的新舊版本的延續(xù)點(diǎn)的映射關(guān)系; (4) 將生成的動(dòng)態(tài)升級(jí)補(bǔ)丁加載到運(yùn)行中的待升級(jí)軟件的舊版本中; (5) 接收用戶的初始化請(qǐng)求,并根據(jù)該初始化請(qǐng)求使用動(dòng)態(tài)升級(jí)補(bǔ)丁中待更新的函數(shù) 名查找內(nèi)存中對(duì)應(yīng)的函數(shù)體,并將步驟(3)中的異步檢查點(diǎn)插入該函數(shù)體中; (6) 接收用戶的應(yīng)用請(qǐng)求,并根據(jù)該應(yīng)用請(qǐng)求利用異步檢查點(diǎn)算法使待升級(jí)軟件中的 所有線程達(dá)到阻塞狀態(tài); (7) 對(duì)于待升級(jí)軟件中的線程中未被使用和執(zhí)行的函數(shù)及變量,采用二進(jìn)制重寫的方 式實(shí)現(xiàn)函數(shù)的間接跳轉(zhuǎn),對(duì)于待升級(jí)軟件中的線程中正在使用和執(zhí)行的函數(shù)及變量,采用 堆棧重構(gòu)的方式進(jìn)行映射和狀態(tài)轉(zhuǎn)換; (8) 根據(jù)動(dòng)態(tài)升級(jí)補(bǔ)丁中異步檢查點(diǎn)中保存的新舊版本的延續(xù)點(diǎn)的映射關(guān)系恢復(fù)執(zhí)行 所有線程,過程結(jié)束。
2. 根據(jù)權(quán)利要求1所述的多線程軟件動(dòng)態(tài)升級(jí)方法,其特征在于,步驟(1)是采用通用 中間語言中的合并功能進(jìn)行項(xiàng)目源文件的整合。
3. 根據(jù)權(quán)利要求1所述的多線程軟件動(dòng)態(tài)升級(jí)方法,其特征在于,步驟(5)將異步檢查 點(diǎn)插入函數(shù)體中是利用動(dòng)態(tài)插樁方式,插入函數(shù)體的位置是位于該函數(shù)體的頭部、循環(huán)體 的開頭、函數(shù)調(diào)用之前。
4. 根據(jù)權(quán)利要求1所述的多線程軟件動(dòng)態(tài)升級(jí)方法,其特征在于,步驟(6)具體包括以 下子步驟: (6-1)接收用戶的應(yīng)用請(qǐng)求,該應(yīng)用請(qǐng)求中包括待更新軟件的進(jìn)程ID、以及步驟(3)中 動(dòng)態(tài)升級(jí)補(bǔ)丁文件的路徑; (6 - 2)初始化空的第一映射表和第二映射表,其中第一映射表表不線程已經(jīng)獲得的臨 界變量以及協(xié)助動(dòng)態(tài)升級(jí)的鎖,第二映射表表示線程希望獲得的臨界變量以及協(xié)助動(dòng)態(tài)升 級(jí)的鎖; (6-3)通過包裝替換系統(tǒng)調(diào)用來追蹤線程的共享臨界變量和協(xié)助動(dòng)態(tài)升級(jí)的鎖,當(dāng)系 統(tǒng)每次對(duì)共享臨界變量和協(xié)助動(dòng)態(tài)升級(jí)的鎖有操作時(shí),查找步驟¢-2)中的第一映射表和 第二映射表,然后進(jìn)入步驟¢-4),若沒有則將臨界變量名和協(xié)助動(dòng)態(tài)升級(jí)的鎖的名稱添加 到第一映射表和第二映射表中,并在每個(gè)變量或鎖的后面添加對(duì)其操作的線程ID,然后進(jìn) 入步驟(6-4)。 (6-4)判斷線程是占用協(xié)助動(dòng)態(tài)升級(jí)的鎖,還是占用共享臨界變量,如果是前者則先將 其線程ID添加到第二映射表中,如果第一映射表中協(xié)助動(dòng)態(tài)升級(jí)的鎖沒有線程ID,則將其 線程ID添加到第一映射表中對(duì)應(yīng)的位置,并將該線程標(biāo)記為協(xié)助狀態(tài),如果第一映射表中 協(xié)助動(dòng)態(tài)升級(jí)的鎖有線程ID將該線程標(biāo)記為阻塞狀態(tài);如果是后者則先將其線程ID添加 到第二映射表中,如果第一映射表中對(duì)應(yīng)的共享臨界變量沒有線程ID,則將其線程ID添加 到第一映射表中對(duì)應(yīng)的位置,并將該線程標(biāo)記為協(xié)助狀態(tài),如果第一映射表中對(duì)應(yīng)的共享 臨界變量有線程ID將該線程標(biāo)記為阻塞狀態(tài); (6-5)持續(xù)檢查所有線程的狀態(tài),當(dāng)發(fā)現(xiàn)沒有線程處于run狀態(tài)時(shí),則將標(biāo)記為協(xié)助狀 態(tài)的線程阻塞,此時(shí)所有線程都進(jìn)入阻塞狀態(tài),通知系統(tǒng)可以進(jìn)行后續(xù)的動(dòng)態(tài)升級(jí)操作。
5. -種基于異步檢查點(diǎn)的多線程軟件動(dòng)態(tài)升級(jí)系統(tǒng),其特征在于,包括: 第一模塊,用于獲取待升級(jí)軟件的新舊版本,分別提取新舊版本中的項(xiàng)目源文件,并分 別將該新舊版本的項(xiàng)目源文件整合; 第二模塊,用于對(duì)整合后的新版本的項(xiàng)目源文件和舊版本的項(xiàng)目源文件進(jìn)行對(duì)比,以 生成初級(jí)補(bǔ)??; 第三模塊,用于將異步檢查點(diǎn)插入初級(jí)補(bǔ)丁中,以生成動(dòng)態(tài)升級(jí)補(bǔ)丁,其中異步檢查點(diǎn) 中保存了待升級(jí)軟件的新舊版本的延續(xù)點(diǎn)的映射關(guān)系; 第四模塊,用于將生成的動(dòng)態(tài)升級(jí)補(bǔ)丁加載到運(yùn)行中的待升級(jí)軟件的舊版本中; 第五模塊,用于接收用戶的初始化請(qǐng)求,并根據(jù)該初始化請(qǐng)求使用動(dòng)態(tài)升級(jí)補(bǔ)丁中待 更新的函數(shù)名查找內(nèi)存中對(duì)應(yīng)的函數(shù)體,并將第三模塊中的異步檢查點(diǎn)插入該函數(shù)體中; 第六模塊,用于接收用戶的應(yīng)用請(qǐng)求,并根據(jù)該應(yīng)用請(qǐng)求利用異步檢查點(diǎn)算法使待升 級(jí)軟件中的所有線程達(dá)到阻塞狀態(tài); 第七模塊,用于對(duì)于待升級(jí)軟件中的線程中未被使用和執(zhí)行的函數(shù)及變量,采用二進(jìn) 制重寫的方式實(shí)現(xiàn)函數(shù)的間接跳轉(zhuǎn),對(duì)于待升級(jí)軟件中的線程中正在使用和執(zhí)行的函數(shù)及 變量,采用堆棧重構(gòu)的方式進(jìn)行映射和狀態(tài)轉(zhuǎn)換; 第八模塊,用于根據(jù)動(dòng)態(tài)升級(jí)補(bǔ)丁中異步檢查點(diǎn)中保存的新舊版本的延續(xù)點(diǎn)的映射關(guān) 系恢復(fù)執(zhí)行所有線程,過程結(jié)束。
【文檔編號(hào)】G06F9/445GK104111848SQ201410305827
【公開日】2014年10月22日 申請(qǐng)日期:2014年6月27日 優(yōu)先權(quán)日:2014年6月27日
【發(fā)明者】鄒德清, 羌衛(wèi)中, 金海 , 王皓 申請(qǐng)人:華中科技大學(xué)