<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > linux內(nèi)核中的dup系統(tǒng)調(diào)用

          linux內(nèi)核中的dup系統(tǒng)調(diào)用

          作者: 時(shí)間:2016-11-22 來源:網(wǎng)絡(luò) 收藏
          內(nèi)核版本:2.6.14

          dup系統(tǒng)調(diào)用的服務(wù)例程為sys_dup函數(shù),定義在fs/fcntl.c中。sys_dup()的代碼也許稱得上是最簡(jiǎn)單的之一了,但是就是這么一個(gè)簡(jiǎn)單的系統(tǒng)調(diào)用,卻成就了linux系統(tǒng)最著名的一個(gè)特性:輸入/輸出重定向。sys_dup()的主要工作就是用來“復(fù)制”一個(gè)打開的文件號(hào),并使兩個(gè)文件號(hào)都指向同一個(gè)文件,下面我們來分析一下它的代碼。

          本文引用地址:http://www.ex-cimer.com/article/201611/319990.htm

          1.sys_dup源碼分析

          [plain]view plaincopy
          print?
          1. asmlinkagelongsys_dup(unsignedintfildes)//sys_dup函數(shù)的參數(shù),即fildes,是文件描述符fd
          2. {
          3. intret=-EBADF;
          4. structfile*file=fget(fildes);//通過文件描述符找到對(duì)應(yīng)的文件
          5. if(file)
          6. ret=dupfd(file,0);//分配一個(gè)新的文件描述符fd,并將fd和file聯(lián)系起來
          7. returnret;
          8. }

          1.1fget(fildes)

          [plain]view plaincopy
          print?
          1. structfilefastcall*fget(unsignedintfd)
          2. {
          3. structfile*file;
          4. structfiles_struct*files=current->files;//獲得當(dāng)前進(jìn)程的打開文件表
          5. rcu_read_lock();
          6. file=fcheck_files(files,fd);//根據(jù)fd從打開文件表files里取出相應(yīng)的file結(jié)構(gòu)變量
          7. if(file){
          8. if(!rcuref_inc_lf(&file->f_count)){//增加引用
          9. /*Fileobjectrefcouldntbetaken*/
          10. rcu_read_unlock();
          11. returnNULL;
          12. }
          13. }
          14. rcu_read_unlock();
          15. returnfile;
          16. }
          17. staticinlinestructfile*fcheck_files(structfiles_struct*files,unsignedintfd)
          18. {
          19. structfile*file=NULL;
          20. structfdtable*fdt=files_fdtable(files);
          21. if(fdmax_fds)
          22. file=rcu_dereference(fdt->fd[fd]);
          23. returnfile;
          24. }

          1.2dupfd(file, 0)

          [plain]view plaincopy
          print?
          1. staticintdupfd(structfile*file,unsignedintstart)
          2. {
          3. structfiles_struct*files=current->files;
          4. structfdtable*fdt;
          5. intfd;
          6. spin_lock(&files->file_lock);
          7. fd=locate_fd(files,file,start);//分配文件描述符
          8. if(fd>=0){
          9. /*locate_fd()mayhaveexpandedfdtable,loadtheptr*/
          10. fdt=files_fdtable(files);//獲得文件描述符表
          11. FD_SET(fd,fdt->open_fds);//設(shè)置打開文件標(biāo)記
          12. FD_CLR(fd,fdt->close_on_exec);
          13. spin_unlock(&files->file_lock);
          14. fd_install(fd,file);//建立fd和file的聯(lián)系,之后通過fd就可以找到file
          15. }else{
          16. spin_unlock(&files->file_lock);
          17. fput(file);
          18. }
          19. returnfd;
          20. }

          2.內(nèi)核初始化中的相關(guān)源碼分析

          [plain]view plaincopy
          print?
          1. staticintinit(void*unused)
          2. {
          3. ...
          4. if(sys_open((constchar__user*)"/dev/console",O_RDWR,0)<0)
          5. printk(KERN_WARNING"Warning:unabletoopenaninitialconsole.n");
          6. //打開控制臺(tái),這樣init進(jìn)程就擁有一個(gè)控制臺(tái),并可以從中讀取輸入信息,也可以向其中寫入信息
          7. (void)sys_dup(0);//調(diào)用dup打開/dev/console文件描述符兩次,這樣控制太設(shè)備也可以供表述輸出和標(biāo)準(zhǔn)錯(cuò)誤使用(文件描述符為1和2)
          8. (void)sys_dup(0);
          9. //假設(shè)sys_open((constchar__user*)"/dev/console",O_RDWR,0)成功執(zhí)行,init進(jìn)程就擁有3個(gè)文件描述符(標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤)
          10. ...
          11. }

          3.系統(tǒng)重定向

          我們通過一個(gè)簡(jiǎn)單的來講解重定向。
          當(dāng)我們?cè)趕hell下輸入如下命令:“echo hello!”,這條命令要求shell進(jìn)程執(zhí)行一個(gè)可執(zhí)行文件echo,參數(shù)為“hello!”。當(dāng)shell接收到命令之后,先找到bin/echo,然后fork()出一個(gè)子進(jìn)程讓他執(zhí)行bin/echo,并將參數(shù)傳遞給它,而這個(gè)進(jìn)程從shell繼承了三個(gè)標(biāo)準(zhǔn)文件,即標(biāo)準(zhǔn)輸入(stdin),標(biāo)準(zhǔn)輸出(stdout)和標(biāo)準(zhǔn)出錯(cuò)信息(stderr),它們?nèi)齻€(gè)的文件號(hào)分別為0、1、2。而至于echo進(jìn)程的工作很簡(jiǎn)單,就是將參數(shù)“hello!”寫道標(biāo)準(zhǔn)輸出文件中去,通常都是我們的顯示器上。但是如果我們將命令改成“echo hello! > foo”,則在執(zhí)行時(shí)輸出將會(huì)被重定向到磁盤文件foo中。我們假定在此之前該shell進(jìn)程只有三個(gè)標(biāo)準(zhǔn)文件打開,文件號(hào)分別為0、1、2,以上命令行將按如下序列執(zhí)行:

          • (1) 打開或創(chuàng)建磁盤文件foo,如果foo中原來有內(nèi)容,則清除原來內(nèi)容,其文件號(hào)為3。
          • (2) 通過dup()復(fù)制文件stdout,即將文件號(hào)1出的file結(jié)構(gòu)指針復(fù)制到文件號(hào)4處,目的是將stdout的file指針暫時(shí)保存一下
          • (3) 關(guān)閉stdout,即1號(hào)文件,但是由于4號(hào)文件對(duì)stdout也同時(shí)有個(gè)引用,所以stdout文件并未真正關(guān)閉,只是騰出1號(hào)文件號(hào)位置。
          • (4) 通過dup(),復(fù)制3號(hào)文件(即磁盤文件foo),由于1號(hào)文件關(guān)閉,其位置空缺,故3號(hào)文件被復(fù)制到1號(hào),即進(jìn)程中原來指向stdout的指針指向了foo。
          • (5) 通過系統(tǒng)調(diào)用fork()和exec()創(chuàng)建子進(jìn)程并執(zhí)行echo,子進(jìn)程在執(zhí)行echo前夕關(guān)閉3號(hào)和4號(hào)文件,只留下0、1、2三個(gè)文件,請(qǐng)注意,這時(shí)的1號(hào)文件已經(jīng)不是stdout而是磁盤文件foo了。當(dāng)echo想向stdout文件寫入“hello!”時(shí)自然就寫入到了foo中。
          • (6) 回到shell后,關(guān)閉指向foo的1號(hào)與3號(hào)文件,再用dup()和close()將2號(hào)恢復(fù)至stdout,這樣shell就恢復(fù)了0、1、2三個(gè)標(biāo)準(zhǔn)輸入/輸出文件。
          由此可見,當(dāng)echo程序(或其他)在運(yùn)行的時(shí)候并不知道stdout(對(duì)于stdin和stderr同樣)指向什么,進(jìn)程與實(shí)際輸出文件或設(shè)備的結(jié)合是在運(yùn)行時(shí)由其父進(jìn)程“包辦”的。這樣就簡(jiǎn)化了子進(jìn)程的程序設(shè)計(jì),因?yàn)樵谠O(shè)計(jì)時(shí)只要跟三個(gè)邏輯上存在的文件打交道就可以了,類似于面向?qū)ο笾械亩鄳B(tài)和重載。


          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();