專利名稱:操作系統中構件的連接方法
技術領域:
本發明屬于計算機操作系統構造領域,具體涉及一種操作系統中構件的連接方法。
背景技術:
操作系統的構造方式包括,結構化軟件開發方法和構件化軟件開發方法。采用結構化軟件開發方法開發的操作系統中,操作系統的各功能模塊主要用高級語言編寫(部分與硬件結合緊密或性能要求苛刻的部分采用匯編語言),經編譯器編譯并經由匯編器匯編成目標文件之后,靜態鏈接成內核映像(或內核的各組成部分)。參考圖1,在操作系統模塊化方式的鏈接中,參與鏈接的模塊A和B之間存在緊密不可分的聯系——即function_B2的地址在兩個目標模塊被鏈接時,即在模塊A中填寫好,不可更改。模塊A執行調用到模塊B中函數function_B2時,過程是相當直接的。結構化開發方法中雖然也提供了諸如管程、類程之類的集中式并發控制方案,但系統內的其他互斥與同步操作仍分散于各模塊之中沒有很好的解決。采用構件化軟件開發方法開發的操作系統則是,用事先構造好的操作系統構件,靜態/動態組裝出操作系統內核及服務。基于構件的操作系統和采用模塊化方法開發的操作系統(包括微內核操作系統)之間的最大區別在于,組成系統的主要成分不再是模塊,而是一個個可復用的構件。構件與模塊相比,其主要不同體現在構件強調可復用性、可替換性,因此其接口與實現必須分離,而模塊則無此要求。但是,采用構件化開發和結構化開發一樣,在多道程序環境下,構件連接存在并發控制、互斥與同步問題、安全問題、提供分布式、網絡環境支持等問題。特別是操作系統領域缺乏公認的構件封裝標準、接口標準,給構件組裝帶來了很大的難度,此外,與應用層軟件構件組裝相比,操作系統構件的組裝需要對運行效率、額外空間開銷、共享與隔離、保護與安全等均需予以特殊考慮。
發明內容
本發明克服了上述操作系統構造中無法解決與構件連接特征相關的互斥與同步、安全等問題的不足,提供一種操作系統的構件連接方法,通過在構件和構件之間增加間接層,解決多道程序環境下的并發控制、安全、提供分布式、網絡環境支持等問題。
本發明的技術內容一種操作系統中構件的連接方法,步驟包括1、在需要連接的操作系統構件之間插入序程模塊和跋程模塊,在序程模塊和跋程模塊中設置構件間的連接處理流程;2、源構件調用目標構件后,序程模塊截取該調用,根據構件間的連接需求,執行連接處理流程,完成相應的處理;3、序程模塊處理后,將控制交給目標構件,目標構件實現源構件所請求的服務;4、目標構件完成服務后,跋程模塊截取返回的目標代碼,執行與序程模塊相對應的處理,并返回到源構件。
進一步包括將序程模塊和跋程模塊中的連接處理流程作為通用的預制連接方法函數,放入連接方法表中,由序程模塊和跋程模塊根據具體連接需要進行調用,調用步驟包括1、源構件調用目標構件后,序程模塊截獲源構件到目標構件的調用;2、序程模塊判斷構件間連接的需求,根據實際需求,調用連接方法表中對應的處理流程,完成相應的處理;3、處理后返回到序程模塊,如果還有其它需求,則再次重復步驟2,調用連接方法表中的其它相應處理流程,完成相應的處理,再返回,否則轉步驟4;4、序程模塊將控制交給目標構件;5、目標構件完成源構件所請求的服務之后,執行返回指令;6、跋程模塊截獲目標構件的返回指令,針對步驟2所作的處理,調用連接方法表中相對應的處理流程,完成相應的處理;7、處理后返回到跋程模塊,如果連接需求有多種,繼續步驟6,直到所有需求處理完畢,否則轉步驟8;8、返回至源構件。
在系統中只保留一個序程模塊和跋程模塊的模板,連接時,將序程模塊和跋程模塊復制到內存中,通過填寫序程模塊和跋程模塊中的重定位信息、調用堆棧,在源構件與序程之間、序程與連接方法表中的連接函數之間、序程與和目標構件之間、目標構件與跋程之間、跋程與連接方法表中的連接函數之間以及跋程與源構件之間分別建立鏈接。
為保證目標構件返回時,進入跋程模塊執行,需調整堆棧。調整堆棧的方法是(1)序程模塊將調用堆棧中存放的返回地址(即源構件中地址)復制出來,保存;(2)序程模塊將跋程模塊的起始地址壓入調用堆棧;(3)目標構件執行完畢后,在返回時,從堆棧中彈出返回地址;(4)返回地址是跋程的入口,跋程模塊開始執行;(5)跋程模塊將步驟1中序程模塊保存的實際返回地址填回調用堆棧;(6)跋程模塊返回時,從堆棧中彈出返回地址,返回到源構件。
為了解決構件的并發處理,連接處理流程包括獲取、釋放互斥量以支持構件的互斥訪問;掛起、恢復構件執行以支持對構件的同步訪問。序程模塊將互斥量更改為忙狀態;跋程模塊將互斥量更改為空閑狀態;為支持同步訪問,序程模塊將源構件掛接到目標構件的等待隊列上,設置為阻塞狀態;跋程模塊恢復執行代碼,喚醒源構件恢復執行。
為了透明支持跨保護域的構件間連接,進一步包括系統調用和上行調用。其中系統調用處理源構件位于用戶態,目標構件處于核心態的情況,具體過程如下(1)用戶級構件借助序程模塊生成系統調用,陷入核心態;(2)核心態代碼完成系統調用后,返回到用戶空間,通過信號機制截獲系統調用返回數據并加以處理;(3)在系統調用返回后,跋程模塊恢復調用現場,將系統結果返回給源構件。
上行調用處理源構件位于核心態,目標構件處于用戶態的情況,具體過程如下(1)序程代碼為核心態源構件生成信號,并將跋程代碼作為信號掛接到目標構件所在的任務上;(2)系統從核心態返回至用戶態,目標構件被調度執行;(3)操作系統內核保證目標構件的信號處理程序首先得到執行,最后將控制權交給目標構件。
為了支持實時應用,連接處理流程進一步包括設置最高中斷級,恢復最高中斷級。在序程模塊中調用根據中斷級別,設置可編程中斷控制器的屏蔽位的操作;在跋程模塊中調用重新設置可編程中斷控制器中屏蔽位,恢復原來的中斷屏蔽的操作。
為了支持分布式應用,所述連接處理流程進一步包括遠程消息發送、遠程消息接收。在序程模塊中調用將源構件的調用信息打包為網絡消息,并發送到目標構件所在節點的操作,在跋程模塊中調用從網絡接收來自目標構件的返回消息,并拆包以本地過程調用的形式返回到源構件的操作。
為了實現操作系統構件的動態加載、卸載與替換,所述連接處理流程包括讀寫鎖操作和引用計數操作。通過讀鎖操作控制目標構件的“空閑”狀態,通過引用計數增一、減一操作,記錄目標構件的被使用情況。在序程中調用獲取讀鎖操作及構件引用計數增一操作,在跋程中調用釋放讀鎖操作及構件引用計數減一操作。當構件引用計數為零,處于“空閑”狀態時,替換的管理服務獲得寫鎖后,構件可被卸載或替換。
本發明的技術效果在待連接構件之間插入序程模塊和跋程模塊,通過截取源構件和目標構件之間的交互通道,操縱構件之間的交互過程,提供系統層連接功能,將分散于操作系統各模塊中的并發控制、互斥同步、安全保護等問題集中起來進行處理。且不對參與連接的構件的功能代碼進行修改,直接操縱構件間調用的重定位信息,完成控制的截獲、連接的建立。
操作系統構件的編寫者不必編寫與并發控制、互斥同步、安全保護等相關的代碼,可將更多精力投入到構件本身的功能設計、開發中去。只需在功能劃分時將需要特別處理的流程用單獨的過程、函數實現,并在構件開發完畢后,于構件接口描述中給出相應的需求即可。構件本身的質量因代碼量小,可靠性好,功能單一,易測試、易復用。由于綁定代碼中實現的功能是操作系統中不可或缺的代碼,采用同一處理的方法并不會帶來顯著的性能開銷和空間開銷。
所有與連接特征相關的處理,均可在序程和跋程代碼中直接實現,也可作為通用的預制連接方法函數,放入連接方法表中,由序程和跋程代碼根據具體連接需要進行調用。本發明可提供統一的并發控制處理例程,如互斥訪問和同步訪問處理、統一的構件引用計數處理例程、統一的遠程過程調用處理例程、或提供統一的中斷請求級別處理例程,以及提供檢查源構件身份驗證措施、提供跨保護域的構件間連接處理,如系統調用、上行調用;提供傳統IPC方法的等價實現,包括共享內存、消息隊列、信號、套接字、事件等;提供傳統網絡(分布式)環境下節點間構件間通信支持,用發送消息和接收消息的連接方法,完成異地構件間連接。通過本發明可集中地處理操作系統中并發控制(包括互斥與同步)、跨保護域連接與通信,改進對實時應用的支持、統一處理分布式環境下構件間連接與通信的手段,并通過構件生命期管理,為操作系統結構的動態演化提供了解決方案。
下面結合附圖,對本發明/實用新型做出詳細描述。
圖1為模塊化方式的連接示意圖;圖2為本發明操作系統的構件結構圖;圖3為本發明連接方法表結構圖;圖4為本發明連接調用示意圖;圖5本發明實施例中序程模塊的流程示意圖;圖6為本發明實施例中跋程模塊的流程示意圖;圖7為本發明連接后調用堆棧的示意圖;7-a為方法調用之前;7-b為執行調用指令之后;7-c表示序程模塊改寫返回地址為跋程模塊入口q,進入目標方法之后不變;
7-d表示目標方法返回之后,返回地址被彈出,進入跋程模塊;7-e表示跋程模塊手工壓棧原有的返回地址A,模擬原有調用;7-f表示跋程模塊返回后,繼續執行調用構件的代碼。
圖8為另一個實施例中序跋模塊的流程示意圖。
具體實施例方式
根據構件的本質屬性建立構件間連接是基于構件的系統的組裝過程中最具實質意義的一步。本發明首先對參與組裝(連接)的操作系統構件進行規格化,參考圖2,在構件提供的接口信息中給出各個接口方法的本質屬性及基調,屬性信息包括該接口方法是否需要互斥、同步,是否遠程調用、系統調用、運行所需要的中斷級別;基調是用某種形式編碼組織成的字符串,其中給出方法的名稱、返回值類型、參數表信息等。本發明不對具體的封裝格式作要求,實現時,可以在構件目標代碼中或另外的存儲文件(如注冊表)中保存此類信息。具體可包括1)接口方法的實現情況(假定允許構件部分地實現某接口);2)是否需要互斥訪問,即該接口方法是否支持重入;3)是否同步方法,若是,則調用方需要等待該方法結束后才能繼續執行;否則,調用方構件可在方法開始執行時繼續執行;4)方法執行時,最小中斷級設置的參考值;5)接口方法的訪問控制設置。
本發明在兩個構件之間的連接多了兩段預先寫好的代碼,即序程模塊和跋程模塊。此外,根據事先給定的需求,連接處理例程中對應的處理流程也在序程模塊和跋程模塊中事先寫好。當源構件調用目標構件后,序程模塊截取該調用,根據構件間的連接需求,序程模塊執行相應的與連接特征相關的處理,序程模塊處理后,將控制交給目標構件,目標構件實現源構件所請求的服務后,跋程模塊截取返回的目標代碼,執行與序程模塊相對的處理,并將目標代碼返回給源構件。
序程模塊和跋程模塊可以包含若干具體的連接處理流程,例如,直接在序程模塊中包含增加構件引用計數的代碼等。但是,這樣做不靈活,不便于擴展。因此,可以把連接處理的邏輯獨立出來,用單獨的函數實現,制作成連接方法,插入到連接方法表中。序程模塊和跋程模塊中僅保留對方法表中對應方法的調用痕跡。連接方法表提供了建立構件間連接時要處理問題的統一處理方法。參考圖3,例如,針對互斥問題,方法表中提供獲取讀寫鎖的過程和釋放讀寫鎖的過程,分別由序程模塊和跋程模塊調用;針對同步問題,分別提供源構件排入等待隊列和將源構件中從等待隊列移到就緒隊列的過程,分別由序程模塊和跋程模塊調用,連接方法表中包含若干這樣的連接方法。連接方法的全集能夠滿足系統中所有構件間不同連接方式的處理。為了實現分別被序程模塊和跋程模塊調用,在綁定方法表形成的框架代碼中,將重定位信息在二進制級清空(置零),待建立連接時填寫。
構件間連接關系可在構造目標系統映像時建立,也可在系統啟動時靜態建立。參考圖4,利用本發明給出的方法建立連接后,源構件A和目標構件B間交互步驟過程如下1、源構件A欲按正常方式調用構件B的接口函數Function_B2。通過綁定過程,構件A中對Function_B2的調用代碼被修改成調用序程代碼。綁定服務在這個過程中只需要修改源構件A中的符號重定位地址即可。
2、序程被當作Function_B2得到調用,按連接處理流程,作同步綁定、互斥綁定、跨域綁定處理。參考圖5,這里以維護構件B的引用計數為例,調用綁定處理例程中的函數inc_ref_count,并將構件B的指針作為參數傳遞。
3、序程做完相應前期處理之后,直接跳轉(注意不是調用指令call)到目標實現函數Function_B2的入口。構件B的函數Function_B2對此過程無覺察。至此實現前期處理的透明。同時,保存堆棧中壓入的返回地址loc_call,將堆棧中返回地址修改成跋程的入口。
4、構件B的接口函數Function_B2執行至結束。
構件B的接口函數Function_B2執行返回指令ret,從堆棧中彈出返回地址。實際上開始執行的不是原來構件A中loc_call處的指令,而是跋程代碼的指令。
5、跋程代碼執行,作與序程相對的處理,參考圖6,如釋放讀寫鎖、互斥量,將構件B的引用計數減一等。其中各個綁定處理例程的代碼也通過綁定處理例程表調用。
6、跋程代碼結束,直接跳轉到原來保存的loc_call位置,即構件A中執行Funcion_B2調用之后的代碼。至此,整個調用過程處理結束。調用方構件A和被調用方構件B都無法感知中間的處理過程。
連接時,將序程模塊代碼復制到內存中某位置(假定為p)。填寫序程代碼中的重定位信息(二進制代碼中為0的各個部分),與實際被調用的處理流程建立鏈接,必要時(如本地同步方法調用),可同時復制一份跋程代碼到內存中某位置(假定為q)。參考圖7,序程代碼中首先將調用堆棧中存放的返回地址復制出來,接著將跋程代碼的起始地址q壓入調用堆棧,跳轉到目標構件的方法執行。被調用方法對堆棧調整情況不知情,返回時反彈到跋程代碼入口q。跋程代碼首先將序程中已經保存的實際返回地址填寫回調用堆棧,執行完邏輯后,返回真實的調用構件。跨保護域的調用堆棧情況與在同一保護域內類似,只是所用的堆棧會有細微不同。
本發明只需通過在序程和跋程代碼中直接設置與連接特征相關的處理流程,或在連接方法表中預制連接方法函數,即可集中地處理操作系統中并發控制(包括互斥與同步)、跨保護域連接與通信,改進對實時應用的支持、統一處理分布式環境下構件間連接與通信的手段,并通過構件生命期管理,為操作系統結構的動態演化提供了解決方案。
如對互斥訪問的處理,在連接方法表中設置兩個連接方法函數獲取互斥量,釋放互斥量,即利用處理器的原子性操作原語,將所傳遞參數作為互斥量更改為忙或空閑狀態。在序程中調用獲取互斥量方法,在跋程中調用釋放互斥量方法。
如對同步訪問的處理,需要實現兩個連接方法構件掛起、構件恢復執行。在序程中調用構件掛起代碼,將源構件掛接到目標構件的等待隊列上,設置為阻塞狀態。在跋程中調用構件恢復執行代碼喚醒源構件,恢復執行。
如對安全保護的處理,只需要一個連接方法,檢查源構件所屬用戶ID,確定是否可以訪問目標構件所提供的服務。此方法由序程調用,跋程中不需要相應處理。
參考圖8,本發明還可透明支持跨保護域的構件間連接。具體包括系統調用和上行調用。用戶級構件可借助序程生成系統調用,陷入核心態。實現方法是,在序程中將系統調用功能號填寫到指定寄存器,執行軟件中斷指令(如,在IA32體系結構上用INT指令,在ARM體系結構上可用SWI指令)。核心態代碼完成系統調用后,返回到用戶空間后,可用信號機制截獲系統調用返回數據并加以處理。方法是將跋程視為系統調用的發出者,在系統調用返回后,恢復調用現場,將系統結果返回給源構件。上行調用的方向與系統調用相反源構件在核心級,目標構件在用戶級。序程需要為源構件生成信號,并將信號掛接到目標構件所在的任務。目標構件所在任務被再次調用運行,信號處理例程首先得到執行,最后將控制權交給目標構件。跋程代碼可以為空。
本發明進一步對跨保護域構件間通信予以支持。構件間跨保護域的通信,在傳統操作系統中主要用各種IPC方法處理。利用本發明提供的方法,可以透明提供傳統IPC的等價實現。例如,支持共享內存(shm)機制,需要增加兩個連接方法內存塊映射,內存塊解除映射。內存塊映射操作將所給內存塊映射到目標構件地址空間,此操作由序程調用;內存塊解除映射操作將所給內存塊重新映射到源構件地址空間,此操作由跋程調用。
本發明對實時應用的支持,通過提升目標構件的優先級,確保其執行過程不受無關外部中斷干擾的方案實現。具體做法是,增加兩個連接處理流程設置最高中斷級,恢復最高中斷級。序程模塊根據目標方法中所給的中斷級別,設置PIC(可編程中斷控制器)的屏蔽位,屏蔽無關中斷;跋程模塊重新設置PIC,恢復原來的中斷屏蔽設置。
本發明還可直接支持分布式應用。源構件和目標構件本身在實現時無需考慮分布式環境的處理,只需在接口中給出分布式連接需求。提供分布式應用支持,需要實現透明的遠程過程調用機制。具體而言,增加兩個連接方法遠程消息發送、遠程消息接收。遠程消息發送操作負責將源構件的調用信息打包為網絡消息,并發送到目標構件所在節點,此操作由序程調用。遠程消息接收操作負責從網絡接收來自目標構件的返回消息,并拆包,以本地過程調用的形式返回到源構件。遠程消息接收操作由跋程調用。因為實際的服務提供位于遠程節點,因此序程中可以去掉對目標構件的過程調用。
本發明進一步支持操作系統結構的動態演化。支持操作系統結構的演化,首先要支持對系統構件生命期的管理。為此,可實現讀寫鎖、引用計數連接方法。具體而言,實現獲取讀鎖、獲取寫鎖、釋放讀鎖、釋放寫鎖方法。即序程中調用獲取讀鎖操作,在跋程中調用釋放讀鎖操作。而執行構件終止、替換的管理服務則需要分別在序程中調用獲取寫鎖操作,在跋程中調用釋放寫鎖操作。實現增加目標構件引用計數、減少目標構件引用計數方法,分別在序程和跋程中調用,只有構件引用計數為零,且處于“空閑”狀態時,并獲得寫鎖時,才允許被卸載或替換。
除上述方案,所有與連接特征相關的處理,均可在序程和跋程模塊中直接實現,也可作為通用的預制連接方法函數,放入連接方法表中,由序程和跋程代碼根據具體連接需要進行調用。
權利要求
1.一種操作系統中構件的連接方法,步驟包括(1)在需要連接的操作系統構件之間插入序程模塊和跋程模塊,在序程模塊和跋程模塊中設置構件間的連接處理流程;(2)源構件調用目標構件后,序程模塊截取該調用,根據構件間的連接需求,執行連接處理流程,完成相應的處理;(3)序程模塊處理后,將控制交給目標構件,目標構件完成源構件所請求的服務;(4)目標構件完成服務后,跋程模塊截取返回的目標代碼,執行與序程模塊相對應的逆向處理,并返回到源構件。
2.如權利要求1所述的操作系統中構件的連接方法,其特征在于將序程模塊和跋程模塊中的連接處理流程作為通用的預制連接方法函數,放入連接方法表中,由序程模塊和跋程模塊根據具體連接需要進行調用,調用步驟包括(1)源構件調用目標構件后,序程模塊截獲源構件到目標構件的調用;(2)序程模塊判斷構件間連接的需求,根據實際需求,調用連接方法表中對應的連接方法函數,完成相應的處理;(3)處理后返回到序程模塊,如果還有其它需求,則再次重復步驟2,調用連接方法表中的其它相應連接方法函數,完成相應的處理,再返回,否則轉步驟4;(4)序程模塊將控制交給目標構件;(5)目標構件完成源構件所請求的服務之后,執行返回指令;(6)跋程模塊截獲目標構件的返回指令,針對步驟2所作的處理,調用連接方法表中相對應的連接方法函數,完成相應的處理;(7)處理后返回到跋程模塊,如果連接需求有多種,繼續步驟6,直到所有需求處理完畢,否則轉步驟8;(8)返回至源構件。
3.如權利要求2所述的操作系統中構件的連接方法,其特征在于在系統中只保留一個序程模塊和跋程模塊的模板,連接時,將序程模塊和跋程模塊復制到內存中,通過填寫序程模塊和跋程模塊中的重定位信息、調用堆棧,在源構件與序程模塊之間、序程模塊與連接方法表中的連接方法函數之間、序程模塊與和目標構件之間、目標構件與跋程模塊之間、跋程模塊與連接方法表中的連接方法函數之間以及跋程模塊與源構件之間分別建立鏈接。
4.如權利要求3所述的操作系統中構件的連接方法,其特征在于截獲目標構件返回控制的調用堆棧處理步驟包括(1)序程模塊將調用堆棧中存放的返回地址復制出來,保存;(2)序程模塊將跋程模塊的起始地址壓入調用堆棧;(3)目標構件執行完畢后,在返回時,從堆棧中彈出返回地址;(4)返回地址是跋程的入口,跋程模塊開始執行;(5)跋程模塊將步驟1中序程模塊保存的實際返回地址填回調用堆棧;(6)跋程模塊返回時,從堆棧中彈出返回地址,返回到源構件。
5.如權利要求1所述的操作系統中構件的連接方法,其特征在于對參與連接的操作系統構件進行規格化,構件提供的接口信息包括各個接口方法的本質屬性和基調。
6.如權利要求1或2所述的操作系統中構件的連接方法,其特征在于連接處理流程為獲取或釋放互斥量時,序程模塊將互斥量更改為忙狀態;跋程模塊將互斥量更改為空閑狀態。
7.如權利要求1或2所述的操作系統中構件的連接方法,其特征在于連接處理流程為構件掛起或恢復執行時,序程模塊將源構件掛接到目標構件的等待隊列上,設置為阻塞狀態狀態;跋程模塊則恢復執行代碼,喚醒源構件恢復執行。
8.如權利要求1或2所述的操作系統中構件的連接方法,其特征在于連接處理流程為設置或恢復最高中斷級時,序程模塊根據目標方法中所給的中斷級別,設置可編程中斷控制器的屏蔽位,屏蔽無關中斷;跋程模塊重新設置可編程中斷控制器,恢復原來的中斷屏蔽設置。
9.如權利要求1或2所述的操作系統中構件的連接方法,其特征在于連接處理流程為遠程消息發送或接收時,序程模塊將源構件的調用信息打包為網絡消息,并發送到目標構件所在節點;跋程模塊從網絡接收來自目標構件的返回消息,并拆包,以本地過程調用的形式返回到源構件。
10.如權利要求1或2所述的操作系統中構件的連接方法,其特征在于連接處理流程為讀、寫鎖操作和計數操作時,序程模塊獲取讀鎖并將構件引用計數增一;跋程模塊釋放讀鎖并將構件引用計數減一。
全文摘要
本發明提供一種操作系統構件連接方法,屬于操作系統構造領域。該方法為了解決操作系統中存在的與構件連接相關的并發控制、安全保護等問題,在構件之間插入序程模塊和跋程模塊,通過這兩模塊提供系統層連接功能。步驟為當源構件調用目標構件后,序程模塊截取源構件到目標構件的調用,根據構件間的連接需求,序程模塊執行相應的與連接特征相關的處理,序程模塊處理后,將控制交給目標構件,目標構件實現源構件所請求的服務后,跋程模塊截取返回的目標代碼,執行與序程模塊相對的處理,并將控制返回給源構件。本發明不僅集中處理操作系統中并發控制、跨保護域連接與通信,還可支持實時應用、分布式應用以及操作系統結構的動態演化。
文檔編號G06F9/46GK1584841SQ200410009180
公開日2005年2月23日 申請日期2004年6月7日 優先權日2004年6月7日
發明者藤啟明, 陳向群, 楊芙清 申請人:北京大學