您的位置 首页 编程

linux内核中的dup体系调用

内核版本:2614dup系统调用的服务例程为sys_dup函数,定义在fsfcntlc中。sys_dup()的代码也许称得上是最简单的之一了,但是就是这么一

内核版别:2.6.14

dup体系调用的服务例程为sys_dup函数,界说在fs/fcntl.c中。sys_dup()的代码或许称得上是最简略的之一了,可是便是这么一个简略的体系调用,却成果了linux体系最著名的一个特性:输入/输出重定向。sys_dup()的首要作业便是用来“仿制”一个翻开的文件号,并使两个文件号都指向同一个文件,下面咱们来剖析一下它的代码。

1.sys_dup源码剖析

[plain]view plaincopy

print?

  1. asmlinkagelongsys_dup(unsignedintfildes)//sys_dup函数的参数,即fildes,是文件描述符fd
  2. {
  3. intret=-EBADF;
  4. structfile*file=fget(fildes);//经过文件描述符找到对应的文件
  5. if(file)
  6. ret=dupfd(file,0);//分配一个新的文件描述符fd,并将fd和file联络起来
  7. returnret;
  8. }

1.1fget(fildes)

[plain]view plaincopy

print?

  1. structfilefastcall*fget(unsignedintfd)
  2. {
  3. structfile*file;
  4. structfiles_struct*files=current->files;//取得当时进程的翻开文件表
  5. rcu_read_lock();
  6. file=fcheck_files(files,fd);//依据fd从翻开文件表files里取出相应的file结构变量
  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);//设置翻开文件符号
  12. FD_CLR(fd,fdt->close_on_exec);
  13. spin_unlock(&files->file_lock);
  14. fd_install(fd,file);//树立fd和file的联络,之后经过fd就能够找到file
  15. }else{
  16. spin_unlock(&files->file_lock);
  17. fput(file);
  18. }
  19. returnfd;
  20. }

2.内核初始化中的相关源码剖析

[plain]view plaincopy

print?

  1. staticintinit(void*unused)
  2. {
  3. if(sys_open((constchar__user*)”/dev/console”,O_RDWR,0)<0)
  4. printk(KERN_WARNING”Warning:unabletoopenaninitialconsole.\n”);
  5. //翻开操控台,这样init进程就具有一个操控台,并能够从中读取输入信息,也能够向其间写入信息
  6. (void)sys_dup(0);//调用dup翻开/dev/console文件描述符两次,这样操控太设备也能够供表述输出和规范过错运用(文件描述符为1和2)
  7. (void)sys_dup(0);
  8. //假定sys_open((constchar__user*)”/dev/console”,O_RDWR,0)成功履行,init进程就具有3个文件描述符(规范输入、规范输出和规范过错)
  9. }

3.体系重定向

咱们经过一个简略的来解说重定向。
当咱们在shell下输入如下指令:“echo hello!”,这条指令要求shell进程履行一个可履行文件echo,参数为“hello!”。当shell接收到指令之后,先找到bin/echo,然后fork()出一个子进程让他履行bin/echo,并将参数传递给它,而这个进程从shell承继了三个规范文件,即规范输入(stdin),规范输出(stdout)和规范犯错信息(stderr),它们三个的文件号分别为0、1、2。而至于echo进程的作业很简略,便是将参数“hello!”写道规范输出文件中去,一般都是咱们的显示器上。可是假如咱们将指令改成“echo hello! > foo”,则在履行时输出将会被重定向到磁盘文件foo中。咱们假定在此之前该shell进程只需三个规范文件翻开,文件号分别为0、1、2,以上指令行将按如下序列履行:

  • (1) 翻开或创立磁盘文件foo,假如foo中本来有内容,则铲除本来内容,其文件号为3。
  • (2) 经过dup()仿制文件stdout,行将文件号1出的file结构指针仿制到文件号4处,意图是将stdout的file指针暂时保存一下
  • (3) 封闭stdout,即1号文件,可是由于4号文件对stdout也一起有个引证,所以stdout文件并未真实封闭,仅仅腾出1号文件号方位。
  • (4) 经过dup(),仿制3号文件(即磁盘文件foo),由于1号文件封闭,其方位空缺,故3号文件被仿制到1号,即进程中本来指向stdout的指针指向了foo。
  • (5) 经过体系调用fork()和exec()创立子进程并履行echo,子进程在履行echo前夕封闭3号和4号文件,只留下0、1、2三个文件,请注意,这时的1号文件现已不是stdout而是磁盘文件foo了。当echo想向stdout文件写入“hello!”时天然就写入到了foo中。
  • (6) 回到shell后,封闭指向foo的1号与3号文件,再用dup()和close()将2号康复至stdout,这样shell就康复了0、1、2三个规范输入/输出文件。

由此可见,当echo程序(或其他)在运转的时分并不知道stdout(关于stdin和stderr相同)指向什么,进程与实践输出文件或设备的结合是在运转时由其父进程“包揽”的。这样就简化了子进程的程序设计,由于在设计时只需跟三个逻辑上存在的文件打交道就能够了,类似于面向对象中的多态和重载。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/biancheng/262398.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部