版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、read 系統(tǒng)調(diào)用剖析級(jí)別:初級(jí)趙健博(),碩士,中國(guó)科學(xué)院計(jì)算技術(shù)研究所2008年3月13日大部分程序員可能會(huì)有這樣的疑問:當(dāng)在程序中調(diào)用庫(kù)函數(shù)read時(shí),這個(gè)請(qǐng)求是經(jīng)過哪些處理最終到達(dá)磁盤的呢,數(shù)據(jù)又是怎么被拷貝到用戶緩存區(qū)的呢?本文介紹了從read系統(tǒng)調(diào)用發(fā)出到結(jié)束處理的全過程。該過程包括兩個(gè)部分:用戶空間的處理、核心空間的處理。用戶空間處理部分是系統(tǒng)調(diào)用從用戶態(tài)切到核心態(tài)的過程。核心空間處理部分則是read系統(tǒng)調(diào)用在linux內(nèi)核中處理的整個(gè)過程。Read系統(tǒng)調(diào)用在用戶空間中的處理過程Linux系統(tǒng)調(diào)用(SCI,system call interface)的實(shí)現(xiàn)機(jī)制實(shí)際上是一個(gè)多路匯聚
2、以及分解的過程,該匯聚點(diǎn)就是0x80中斷這個(gè)入口點(diǎn)(X86系統(tǒng)結(jié)構(gòu))。也就是說(shuō),所有系統(tǒng)調(diào)用都從用戶空間中匯聚到0x80中斷點(diǎn),同時(shí)保存具體的系統(tǒng)調(diào)用號(hào)。當(dāng)0x80中斷處理程序運(yùn)行時(shí),將根據(jù)系統(tǒng)調(diào)用號(hào)對(duì)不同的系統(tǒng)調(diào)用分別處理(調(diào)用不同的內(nèi)核函數(shù)處理)。系統(tǒng)調(diào)用的更多內(nèi)容,請(qǐng)參見參考資料。Read系統(tǒng)調(diào)用也不例外,當(dāng)調(diào)用發(fā)生時(shí),庫(kù)函數(shù)在保存read系統(tǒng)調(diào)用號(hào)以及參數(shù)后,陷入0x80中斷。這時(shí)庫(kù)函數(shù)工作結(jié)束。Read系統(tǒng)調(diào)用在用戶空間中的處理也就完成了。Read系統(tǒng)調(diào)用在核心空間中的處理過程0x80中斷處理程序接管執(zhí)行后,先檢察其系統(tǒng)調(diào)用號(hào),然后根據(jù)系統(tǒng)調(diào)用號(hào)查找系統(tǒng)調(diào)用表,并從系統(tǒng)調(diào)用表中得到處
3、理read系統(tǒng)調(diào)用的內(nèi)核函數(shù)sys_read,最后傳遞參數(shù)并運(yùn)行sys_read函數(shù)。至此,內(nèi)核真正開始處理read系統(tǒng)調(diào)用(sys_read是read系統(tǒng)調(diào)用的內(nèi)核入口)。在講解read系統(tǒng)調(diào)用在核心空間中的處理部分中,首先介紹了內(nèi)核處理磁盤請(qǐng)求的層次模型,然后再按該層次模型從上到下的順序依次介紹磁盤讀請(qǐng)求在各層的處理過程。Read系統(tǒng)調(diào)用在核心空間中處理的層次模型圖1顯示了read系統(tǒng)調(diào)用在核心空間中所要經(jīng)歷的層次模型。從圖中看出:對(duì)于磁盤的一次讀請(qǐng)求,首先經(jīng)過虛擬文件系統(tǒng)層(vfs layer),其次是具體的文件系統(tǒng)層(例如ext2),接下來(lái)是cache層(page cache層)、通用
4、塊層(generic block layer)、IO調(diào)度層(I/O scheduler layer)、塊設(shè)備驅(qū)動(dòng)層(block device driver layer),最后是物理塊設(shè)備層(block device layer)圖1 read系統(tǒng)調(diào)用在核心空間中的處理層次虛擬文件系統(tǒng)層的作用:屏蔽下層具體文件系統(tǒng)操作的差異,為上層的操作提供一個(gè)統(tǒng)一的接口。正是因?yàn)橛辛诉@個(gè)層次,所以可以把設(shè)備抽象成文件,使得操作設(shè)備就像操作文件一樣簡(jiǎn)單。在具體的文件系統(tǒng)層中,不同的文件系統(tǒng)(例如ext2和NTFS)具體的操作過程也是不同的。每種文件系統(tǒng)定義了自己的操作集合。關(guān)于文件系統(tǒng)的更多內(nèi)容,請(qǐng)參見參考資料
5、。引入cache層的目的是為了提高linux操作系統(tǒng)對(duì)磁盤訪問的性能。Cache層在內(nèi)存中緩存了磁盤上的部分?jǐn)?shù)據(jù)。當(dāng)數(shù)據(jù)的請(qǐng)求到達(dá)時(shí),如果在cache中存在該數(shù)據(jù)且是最新的,則直接將數(shù)據(jù)傳遞給用戶程序,免除了對(duì)底層磁盤的操作,提高了性能。通用塊層的主要工作是:接收上層發(fā)出的磁盤請(qǐng)求,并最終發(fā)出IO請(qǐng)求。該層隱藏了底層硬件塊設(shè)備的特性,為塊設(shè)備提供了一個(gè)通用的抽象視圖。IO調(diào)度層的功能:接收通用塊層發(fā)出的IO請(qǐng)求,緩存請(qǐng)求并試圖合并相鄰的請(qǐng)求(如果這兩個(gè)請(qǐng)求的數(shù)據(jù)在磁盤上是相鄰的)。并根據(jù)設(shè)置好的調(diào)度算法,回調(diào)驅(qū)動(dòng)層提供的請(qǐng)求處理函數(shù),以處理具體的IO請(qǐng)求。驅(qū)動(dòng)層中的驅(qū)動(dòng)程序?qū)?yīng)具體的物理塊設(shè)備
6、。它從上層中取出IO請(qǐng)求,并根據(jù)該IO請(qǐng)求中指定的信息,通過向具體塊設(shè)備的設(shè)備控制器發(fā)送命令的方式,來(lái)操縱設(shè)備傳輸數(shù)據(jù)。設(shè)備層中都是具體的物理設(shè)備。定義了操作具體設(shè)備的規(guī)范。相關(guān)的內(nèi)核數(shù)據(jù)結(jié)構(gòu):Dentry:聯(lián)系了文件名和文件的i節(jié)點(diǎn)inode:文件i節(jié)點(diǎn),保存文件標(biāo)識(shí)、權(quán)限和內(nèi)容等信息file:保存文件的相關(guān)信息和各種操作文件的函數(shù)指針集合:操作文件的函數(shù)接口集合address_space:描述文件的page cache結(jié)構(gòu)以及相關(guān)信息,并包含有操作page cache的函數(shù)指針集合address_space_operations:操作page cache的函數(shù)接口集合bio:IO請(qǐng)求的描述
7、數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系:圖2示意性地展示了上述各個(gè)數(shù)據(jù)結(jié)構(gòu)(除了bio)之間的關(guān)系。可以看出:由dentry對(duì)象可以找到inode對(duì)象,從inode對(duì)象中可以取出address_space對(duì)象,再由address_space對(duì)象找到address_space_operations對(duì)象。File對(duì)象可以根據(jù)當(dāng)前進(jìn)程描述符中提供的信息取得,進(jìn)而可以找到dentry對(duì)象、address_space對(duì)象和對(duì)象。圖2數(shù)據(jù)結(jié)構(gòu)關(guān)系圖:前提條件:對(duì)于具體的一次read調(diào)用,內(nèi)核中可能遇到的處理情況很多。這里舉例其中的一種情況:要讀取的文件已經(jīng)存在文件經(jīng)過page cache要讀的是普通文件磁盤上文件系統(tǒng)為ext
8、2文件系統(tǒng),有關(guān)ext2文件系統(tǒng)的相關(guān)內(nèi)容,參見參考資料準(zhǔn)備:注:所有清單中代碼均來(lái)自linux 2.6.11內(nèi)核原代碼讀數(shù)據(jù)之前,必須先打開文件。處理open系統(tǒng)調(diào)用的內(nèi)核函數(shù)為sys_open。所以我們先來(lái)看一下該函數(shù)都作了哪些事。清單1顯示了sys_open的代碼(省略了部分內(nèi)容,以后的程序清單同樣方式處理)清單1 sys_open函數(shù)代碼asmlinkage long sys_open(const char _user* flags,int mode)fd=get_unused_fd();if(fd=0)struct (tmp,flags,mode);fd_install(fd,f);
9、return fd;代碼解釋:get_unuesed_fd():取回一個(gè)未被使用的文件描述符(每次都會(huì)選取最小的未被使用的文件描述符)。filp_open():調(diào)用open_namei()函數(shù)取出和該文件相關(guān)的dentry和inode(因?yàn)榍疤嶂该髁宋募呀?jīng)存在,所以dentry和inode能夠查找到,不用創(chuàng)建),然后調(diào)用dentry_open()函數(shù)創(chuàng)建新的file對(duì)象,并用dentry和inode中的信息初始化file對(duì)象(文件當(dāng)前的讀寫位置在file對(duì)象中保存)。注意到dentry_open()中有一條語(yǔ)句:f-f_op=fops_get(inode-i_fop);這個(gè)賦值語(yǔ)句把和具體文
10、件系統(tǒng)相關(guān)的,操作文件的函數(shù)指針集合賦給了file對(duì)象的f _op變量(這個(gè)指針集合是保存在inode對(duì)象中的),在接下來(lái)的sys_read函數(shù)中將會(huì)調(diào)用中的成員read。fd_install():以文件描述符為索引,關(guān)聯(lián)當(dāng)前進(jìn)程描述符和上述的file對(duì)象,為之后的read和write等操作作準(zhǔn)備。函數(shù)最后返回該文件描述符。圖3顯示了sys_open函數(shù)返回后,file對(duì)象和當(dāng)前進(jìn)程描述符之間的關(guān)聯(lián)關(guān)系,以及file對(duì)象中操作文件的函數(shù)指針集合的來(lái)源(inode對(duì)象中的成員i_fop)。圖3 file對(duì)象和當(dāng)前進(jìn)程描述符之間的關(guān)系到此為止,所有的準(zhǔn)備工作已經(jīng)全部結(jié)束了,下面開始介紹read系統(tǒng)
11、調(diào)用在圖1所示的各個(gè)層次中的處理過程。虛擬文件系統(tǒng)層的處理:內(nèi)核函數(shù)sys_read()是read系統(tǒng)調(diào)用在該層的入口點(diǎn),清單2顯示了該函數(shù)的代碼。清單2 sys_read函數(shù)的代碼asmlinkage ssize_t sys_read(unsigned int fd,char _user*buf,size_t count)struct ;ssize_t ret=-EBADF;int fput_needed;(fd,&fput_needed);if(file)loff_t pos=(file);ret=vfs_read();();fput_light();return ret;代碼解析:fge
12、t_light():根據(jù)fd指定的索引,從當(dāng)前進(jìn)程描述符中取出相應(yīng)的file對(duì)象(見圖3)。如果沒找到指定的file對(duì)象,則返回錯(cuò)誤如果找到了指定的file對(duì)象:調(diào)用()函數(shù)取出此次讀寫文件的當(dāng)前位置。調(diào)用vfs_read()執(zhí)行文件讀取操作,而這個(gè)函數(shù)最終調(diào)用()指向的函數(shù),代碼如下:if()ret=();調(diào)用()更新文件的當(dāng)前讀寫位置。調(diào)用fput_light()更新文件的引用計(jì)數(shù)。最后返回讀取數(shù)據(jù)的字節(jié)數(shù)。到此,虛擬文件系統(tǒng)層所做的處理就完成了,控制權(quán)交給了ext2文件系統(tǒng)層。在解析ext2文件系統(tǒng)層的操作之前,先讓我們看一下file對(duì)象中read指針來(lái)源。File對(duì)象中read函數(shù)指針
13、的來(lái)源:從前面對(duì)sys_open內(nèi)核函數(shù)的分析來(lái)看,來(lái)自于inode-i_fop。那么inode-i_fop來(lái)自于哪里呢?在初始化inode對(duì)象時(shí)賦予的。見清單3。清單3 ext2_read_inode()函數(shù)部分代碼void ext2_read_inode(struct inode*inode)if(S_ISREG(inode-i_mode)inode-i_op=&ext2_;inode-i_fop=&ext2_;if(test_opt(inode-i_sb,NOBH)inode-i_mapping-a_ops=&ext2_nobh_aops;else inode-i_mapping-a_o
14、ps=&ext2_aops;從代碼中可以看出,如果該inode所關(guān)聯(lián)的文件是普通文件,則將變量ext2_的地址賦予inode對(duì)象的i_fop成員。所以可以知道:inode-i_fop.read函數(shù)指針?biāo)赶虻暮瘮?shù)為ext2_變量的成員read所指向的函數(shù)。下面來(lái)看一下ext2_變量的初始化過程,如清單4。清單4 ext2_的初始化struct ext2_.llseek=generic_,;該成員read指向函數(shù)generic_。所以,inode-i_fop.read指向generic_函數(shù),進(jìn)而指向generic_函數(shù)。最終得出結(jié)論:generic_函數(shù)才是ext2層的真實(shí)入口。Ext2文件系
15、統(tǒng)層的處理圖4 read系統(tǒng)調(diào)用在ext2層中處理時(shí)函數(shù)調(diào)用關(guān)系由圖4可知,該層入口函數(shù)generic_調(diào)用函數(shù)_generic_,后者判斷本次讀請(qǐng)求的訪問方式,如果是直接io(filp-f_flags被設(shè)置了O_DIRECT標(biāo)志,即不經(jīng)過cache)的方式,則調(diào)用generic_函數(shù);如果是page cache的方式,則調(diào)用do_generic_函數(shù)。函數(shù)do_generic_僅僅是一個(gè)包裝函數(shù),它又調(diào)用do_generic_mapping_read函數(shù)。在講解do_generic_mapping_read函數(shù)都作了哪些工作之前,我們?cè)賮?lái)看一下文件在內(nèi)存中的緩存區(qū)域是被怎么組織起來(lái)的。文件的
16、page cache結(jié)構(gòu)圖5顯示了一個(gè)文件的page cache結(jié)構(gòu)。文件被分割為一個(gè)個(gè)以page大小為單元的數(shù)據(jù)塊,這些數(shù)據(jù)塊(頁(yè))被組織成一個(gè)多叉樹(稱為radix樹)。樹中所有葉子節(jié)點(diǎn)為一個(gè)個(gè)頁(yè)幀結(jié)構(gòu)(struct page),表示了用于緩存該文件的每一個(gè)頁(yè)。在葉子層最左端的第一個(gè)頁(yè)保存著該文件的前4096個(gè)字節(jié)(如果頁(yè)的大小為4096字節(jié)),接下來(lái)的頁(yè)保存著文件第二個(gè)4096個(gè)字節(jié),依次類推。樹中的所有中間節(jié)點(diǎn)為組織節(jié)點(diǎn),指示某一地址上的數(shù)據(jù)所在的頁(yè)。此樹的層次可以從0層到6層,所支持的文件大小從0字節(jié)到16 T個(gè)字節(jié)。樹的根節(jié)點(diǎn)指針可以從和文件相關(guān)的address_space對(duì)象(該
17、對(duì)象保存在和文件關(guān)聯(lián)的inode對(duì)象中)中取得(更多關(guān)于page cache的結(jié)構(gòu)內(nèi)容請(qǐng)參見參考資料)。圖5文件的page cache結(jié)構(gòu)現(xiàn)在,我們來(lái)看看函數(shù)do_generic_mapping_read都作了哪些工作,do_generic_mapping_read函數(shù)代碼較長(zhǎng),本文簡(jiǎn)要介紹下它的主要流程:根據(jù)文件當(dāng)前的讀寫位置,在page cache中找到緩存請(qǐng)求數(shù)據(jù)的page如果該頁(yè)已經(jīng)最新,將請(qǐng)求的數(shù)據(jù)拷貝到用戶空間否則,Lock該頁(yè)調(diào)用readpage函數(shù)向磁盤發(fā)出添頁(yè)請(qǐng)求(當(dāng)下層完成該IO操作時(shí)會(huì)解鎖該頁(yè)),代碼:error=mapping-a_ops-readpage(filp,p
18、age);再一次lock該頁(yè),操作成功時(shí),說(shuō)明數(shù)據(jù)已經(jīng)在page cache中了,因?yàn)橹挥蠭O操作完成后才可能解鎖該頁(yè)。此處是一個(gè)同步點(diǎn),用于同步數(shù)據(jù)從磁盤到內(nèi)存的過程。解鎖該頁(yè)到此為止數(shù)據(jù)已經(jīng)在page cache中了,再將其拷貝到用戶空間中(之后read調(diào)用可以在用戶空間返回了)到此,我們知道:當(dāng)頁(yè)上的數(shù)據(jù)不是最新的時(shí)候,該函數(shù)調(diào)用mapping-a_ops-readpage所指向的函數(shù)(變量mapping為inode對(duì)象中的address_space對(duì)象),那么這個(gè)函數(shù)到底是什么呢?Readpage函數(shù)的由來(lái)address_space對(duì)象是嵌入在inode對(duì)象之中的,那么不難想象:add
19、ress_space對(duì)象成員a_ops的初始化工作將會(huì)在初始化inode對(duì)象時(shí)進(jìn)行。如清單3中后半部所顯示。if(test_opt(inode-i_sb,NOBH)inode-i_mapping-a_ops=&ext2_nobh_aops;else inode-i_mapping-a_ops=&ext2_aops;可以知道address_space對(duì)象的成員a_ops指向變量ext2_aops或者變量ext2_nobh_aops。這兩個(gè)變量的初始化如清單5所示。清單5變量ext2_aops和變量ext2_nobh_aops的初始化struct address_space_operations
20、ext2_aops=.readpage=ext2_readpage,.readpages=ext2_readpages,.writepage=ext2_writepage,.sync_page=block_sync_page,.prepare_write=ext2_prepare_write,.commit_write=generic_commit_write,.bmap=ext2_bmap,.direct_IO=ext2_direct_IO,.writepages=ext2_writepages,;struct address_space_operations ext2_nobh_aops=
21、.readpage=ext2_readpage,.readpages=ext2_readpages,.writepage=ext2_writepage,.sync_page=block_sync_page,.prepare_write=ext2_nobh_prepare_write,.commit_write=nobh_commit_write,.bmap=ext2_bmap,.direct_IO=ext2_direct_IO,.writepages=ext2_writepages,;從上述代碼中可以看出,不論是哪個(gè)變量,其中的readpage成員都指向函數(shù)ext2_readpage。所以可以
22、斷定:函數(shù)do_generic_mapping_read最終調(diào)用ext2_readpage函數(shù)處理讀數(shù)據(jù)請(qǐng)求。到此為止,ext2文件系統(tǒng)層的工作結(jié)束。Page cache層的處理從上文得知:ext2_readpage函數(shù)是該層的入口點(diǎn)。該函數(shù)調(diào)用mpage_readpage函數(shù),清單6顯示了mpage_readpage函數(shù)的代碼。清單6 mpage_readpage函數(shù)的代碼int mpage_readpage(struct page*page,get_block_t get_block)struct bio*bio=NULL;sector_t last_block_in_bio=0;bio=
23、do_mpage_readpage(bio,page,1,&last_block_in_bio,get_block);if(bio)mpage_bio_submit(READ,bio);return 0;該函數(shù)首先調(diào)用函數(shù)do_mpage_readpage函數(shù)創(chuàng)建了一個(gè)bio請(qǐng)求,該請(qǐng)求指明了要讀取的數(shù)據(jù)塊所在磁盤的位置、數(shù)據(jù)塊的數(shù)量以及拷貝該數(shù)據(jù)的目標(biāo)位置-緩存區(qū)中page的信息。然后調(diào)用mpage_bio_submit函數(shù)處理請(qǐng)求。mpage_bio_submit函數(shù)則調(diào)用submit_bio函數(shù)處理該請(qǐng)求,后者最終將請(qǐng)求傳遞給函數(shù)generic_make_request,并由generi
24、c_make_request函數(shù)將請(qǐng)求提交給通用塊層處理。到此為止,page cache層的處理結(jié)束。通用塊層的處理generic_make_request函數(shù)是該層的入口點(diǎn),該層只有這一個(gè)函數(shù)處理請(qǐng)求。清單7顯示了函數(shù)的部分代碼清單7 generic_make_request函數(shù)部分代碼void generic_make_request(struct bio*bio)dochar bBDEVNAME_SIZE;q=bdev_get_queue(bio-bi_bdev);block_wait_queue_running(q);/*If this device has partitions,re
25、map block n*of partition pto block n+start(p)of the disk.*/blk_partition_remap(bio);ret=q-make_request_fn(q,bio);while(ret);主要操作:根據(jù)bio中保存的塊設(shè)備號(hào)取得請(qǐng)求隊(duì)列q檢測(cè)當(dāng)前IO調(diào)度器是否可用,如果可用,則繼續(xù);否則等待調(diào)度器可用調(diào)用q-make_request_fn所指向的函數(shù)將該請(qǐng)求(bio)加入到請(qǐng)求隊(duì)列中到此為止,通用塊層的操作結(jié)束。IO調(diào)度層的處理對(duì)make_request_fn函數(shù)的調(diào)用可以認(rèn)為是IO調(diào)度層的入口,該函數(shù)用于向請(qǐng)求隊(duì)列中添加請(qǐng)求。該函數(shù)
26、是在創(chuàng)建請(qǐng)求隊(duì)列時(shí)指定的,代碼如下(blk_init_queue函數(shù)中):q-request_fn=rfn;blk_queue_make_request(q,_make_request);函數(shù)blk_queue_make_request將函數(shù)_make_request的地址賦予了請(qǐng)求隊(duì)列q的make_request_fn成員,那么,_make_request函數(shù)才是IO調(diào)度層的真實(shí)入口。_make_request函數(shù)的主要工作為:檢測(cè)請(qǐng)求隊(duì)列是否為空,若是,延緩驅(qū)動(dòng)程序處理當(dāng)前請(qǐng)求(其目的是想積累更多的請(qǐng)求,這樣就有機(jī)會(huì)對(duì)相鄰的請(qǐng)求進(jìn)行合并,從而提高處理的性能),并跳到3,否則跳到2試圖將當(dāng)前
27、請(qǐng)求同請(qǐng)求隊(duì)列中現(xiàn)有的請(qǐng)求合并,如果合并成功,則函數(shù)返回,否則跳到3該請(qǐng)求是一個(gè)新請(qǐng)求,創(chuàng)建新的請(qǐng)求描述符,并初始化相應(yīng)的域,并將該請(qǐng)求描述符加入到請(qǐng)求隊(duì)列中,函數(shù)返回將請(qǐng)求放入到請(qǐng)求隊(duì)列中后,何時(shí)被處理就由IO調(diào)度器的調(diào)度算法決定了(有關(guān)IO調(diào)度器的算法內(nèi)容請(qǐng)參見參考資料)。一旦該請(qǐng)求能夠被處理,便調(diào)用請(qǐng)求隊(duì)列中成員request_fn所指向的函數(shù)處理。這個(gè)成員的初始化也是在創(chuàng)建請(qǐng)求隊(duì)列時(shí)設(shè)置的:q-request_fn=rfn;blk_queue_make_request(q,_make_request);第一行是將請(qǐng)求處理函數(shù)rfn指針賦給了請(qǐng)求隊(duì)列的request_fn成員。而rfn則是在創(chuàng)建請(qǐng)求隊(duì)列時(shí)通過參數(shù)傳入的。對(duì)請(qǐng)求處理函數(shù)request_fn的調(diào)用意味著IO調(diào)度層的處理結(jié)束了。塊設(shè)備驅(qū)動(dòng)層的處理request_fn函數(shù)是塊設(shè)備驅(qū)動(dòng)層的入口。它是在驅(qū)動(dòng)程序創(chuàng)建請(qǐng)求隊(duì)列時(shí)由驅(qū)動(dòng)程序傳遞給IO調(diào)度層的。IO調(diào)度層通過回調(diào)request_fn函數(shù)的方式,把請(qǐng)求交給了驅(qū)動(dòng)程序。而驅(qū)動(dòng)程序從該函數(shù)的參數(shù)中獲得上層發(fā)出的IO請(qǐng)求,并根據(jù)請(qǐng)求中指定的信息操作設(shè)備控制器(這一請(qǐng)求的發(fā)
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 農(nóng)業(yè)科技園區(qū)智能化管理與服務(wù)平臺(tái)建設(shè)
- 物流倉(cāng)儲(chǔ)設(shè)施建設(shè)及管理服務(wù)合同
- 樓板漏水如何驗(yàn)收施工方案
- 旅游休閑行業(yè)智慧旅游產(chǎn)品開發(fā)與營(yíng)銷方案
- 內(nèi)蒙古節(jié)日彩燈施工方案
- IT服務(wù)行業(yè)企業(yè)級(jí)云服務(wù)解決方案
- 拔劍特訓(xùn)七下數(shù)學(xué)試卷
- 汽車行業(yè)智能生產(chǎn)制造執(zhí)行系統(tǒng)方案
- 工業(yè)自動(dòng)化控制系統(tǒng)開發(fā)投資協(xié)議
- 專業(yè)會(huì)展服務(wù)提供與承接合同
- 2023-2024學(xué)年仁愛版七上期末考試英語(yǔ)(試題)
- 無(wú)人機(jī)表演服務(wù)合同
- 2024年醫(yī)院培訓(xùn)計(jì)劃
- 呼吸內(nèi)科臨床診療指南及操作規(guī)范
- 學(xué)生管理教育課件
- 物業(yè)經(jīng)理轉(zhuǎn)正述職
- 貿(mào)易崗位招聘面試題及回答建議(某大型國(guó)企)2025年
- 世界職業(yè)院校技能大賽高職組“關(guān)務(wù)實(shí)務(wù)組”賽項(xiàng)參考試題及答案
- 高中歷史教師資格考試面試試題及解答參考(2024年)
- 銀行貸款房產(chǎn)抵押合同樣本
- 北師大版(2024新版)生物七年級(jí)上冊(cè)期末考點(diǎn)復(fù)習(xí)提綱
評(píng)論
0/150
提交評(píng)論