微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > linux内核中的dup系统调用

linux内核中的dup系统调用

时间:11-22 来源:互联网 点击:
内核版本:2.6.14

dup系统调用的服务例程为sys_dup函数,定义在fs/fcntl.c中。sys_dup()的代码也许称得上是最简单的之一了,但是就是这么一个简单的系统调用,却成就了linux系统最著名的一个特性:输入/输出重定向。sys_dup()的主要工作就是用来“复制”一个打开的文件号,并使两个文件号都指向同一个文件,下面我们来分析一下它的代码。

1.sys_dup源码分析

[plain]view plaincopyprint?

  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 plaincopyprint?

  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 plaincopyprint?

  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 plaincopyprint?

  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. //打开控制台,这样init进程就拥有一个控制台,并可以从中读取输入信息,也可以向其中写入信息
  7. (void)sys_dup(0);//调用dup打开/dev/console文件描述符两次,这样控制太设备也可以供表述输出和标准错误使用(文件描述符为1和2)
  8. (void)sys_dup(0);
  9. //假设sys_open((constchar__user*)"/dev/console",O_RDWR,0)成功执行,init进程就拥有3个文件描述符(标准输入、标准输出和标准错误)
  10. ...
  11. }

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三个文件,请注意,这时

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top