经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Linux/Shell » 查看文章
驱动IO模型-select
来源:cnblogs  作者:Yangtai  时间:2021/6/15 9:05:03  对本文有异议

新人学习,欢迎指正
image

部分select.c代码

  1. 应用层
  2. select(maxfd+1,&rfds,NULL,NULL,NULL);
  3. -------------------(系统调用)------------------------------
  4. kernel-3.4.39/arch/arm/kernel$ vi calls.S
  5. //系统调用相关的汇编文件
  6. CALL(sys_select)
  7. VFS:vi -t sys_select
  8. ->SYSCALL_DEFINE5宏,5代表有五个参数,替换得到sys_select
  9. SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,fd_set __user *, exp, struct timeval __user *, tvp)
  10. ->
  11. #define SYSCALL_DEFINE5(select, ...)
  12. SYSCALL_DEFINEx(5, _select, __VA_ARGS__)
  13. ->
  14. #define SYSCALL_DEFINEx(x,_select, ...)
  15. __SYSCALL_DEFINEx(x, _select, __VA_ARGS__)
  16. ->
  17. #define __SYSCALL_DEFINEx(x, _select, ...)
  18. long sys_select(int n, fd_set __user * inp,
  19. fd_set __user *outp,fd_set __user *exp,
  20. struct timeval __user * tvp)
  21. {
  22. ret = core_sys_select(n, inp, outp, exp, to);
  23. }
  24. --------------------------------------------------------------
  25. core_sys_select(n, inp, outp, exp, to);
  26. //1.校验最大的文件描述符
  27. struct fdtable *fdt;
  28. fdt = files_fdtable(current->files);
  29. max_fds = fdt->max_fds;
  30. if (n > max_fds)
  31. n = max_fds;
  32. //2.分配文件描述符的内存
  33. bits = kmalloc(6 * size, GFP_KERNEL);
  34. fds.in = bits;
  35. fds.out = bits + size;
  36. fds.ex = bits + 2*size;
  37. //在内核空间分配的读表,写表,其他表的首地址
  38. fds.res_in = bits + 3*size;
  39. fds.res_out = bits + 4*size;
  40. fds.res_ex = bits + 5*size;
  41. //在内核空间分配的准备好的读表,写表,其他表的首地址
  42. //3.将用户空间的读表,写表,其他的表拷贝到内核空间
  43. if ((ret = get_fd_set(n, inp, fds.in)) ===>copy_from_user
  44. (ret = get_fd_set(n, outp, fds.out))
  45. (ret = get_fd_set(n, exp, fds.ex)))
  46. //4.文件描述符的检查,如果所有的文件描述符的数据
  47. 都没有准备好,进程休眠,否则将准备好的文件描
  48. 述符放入到fds.res_infds.res_outfds.res_ex
  49. ret = do_select(n, &fds, end_time);
  50. //5.判断是否是信号唤醒的进程
  51. ret = -ERESTARTNOHAND;
  52. if (signal_pending(current))
  53. goto out; ====>信号唤醒的就跳过拷贝
  54. ret = 0;
  55. //6.如果不是信号唤醒的休眠,将文件描述符拷贝到用户空间
  56. if (set_fd_set(n, inp, fds.res_in) ||
  57. set_fd_set(n, outp, fds.res_out) || ====>copy_to_user
  58. set_fd_set(n, exp, fds.res_ex))
  59. ret = -EFAULT;
  60. ---------------------------------------------------------------------
  61. 驱动:
  62. unsigned int (*poll) (struct file *file, struct poll_table_struct *wait);

部分do_select代码

  1. int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
  2. {
  3. struct poll_wqueues table;
  4. poll_table *wait;
  5. int retval, i;
  6. unsigned long slack = 0;
  7. retval = max_select_fd(n, fds);
  8. //通过文件描述符表中的对应的被设置
  9. //为1的位来校验最大的文件描述符的值
  10. n = retval;
  11. //将校验完的文件描述符赋值给n
  12. poll_initwait(&table);
  13. //poll相关结构体的初始化
  14. //只需要关心函数指针的初始化过程就行了
  15. //函数指针,执行的是__pollwait
  16. //在__pollwait会拿到你提交的等待队列头,然后
  17. //在等待队列头后面添加当前进程的等待队列项
  18. retval = 0;
  19. //retval是用来判断是否需要退出文件描述符遍历
  20. //的循环的。
  21. for (;;)
  22. {
  23. unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
  24. inp = fds->in;
  25. outp = fds->out;
  26. exp = fds->ex;
  27. rinp = fds->res_in;
  28. routp = fds->res_out;
  29. rexp = fds->res_ex;
  30. //定义6个指针,将结构体中的6个指针
  31. //赋值给这6个指针变量
  32. for (i = 0; i < n; ++rinp, ++routp, ++rexp)
  33. {
  34. //用来取第几个unsigned long类型的数据
  35. unsigned long in, out, ex, all_bits, bit = 1, mask, j;
  36. unsigned long res_in = 0, res_out = 0, res_ex = 0;
  37. const struct file_operations *f_op = NULL;
  38. struct file *file = NULL;
  39. in = *inp++;
  40. out = *outp++;
  41. ex = *exp++;
  42. all_bits = in | out | ex;
  43. if (all_bits == 0)
  44. {
  45. i += BITS_PER_LONG;
  46. continue;
  47. }
  48. for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1)
  49. {
  50. //用来unsigned long类型中的第几位的
  51. file = fget_light(i, &fput_needed);
  52. //这里的i就是获取到的文件描述符,fget_light
  53. //通过文件描述符找到file结构体
  54. //fd->fd_array[fd]->struct file
  55. //POLLIN
  56. if (file)
  57. {
  58. f_op = file->f_op;
  59. if (f_op && f_op->poll)
  60. {
  61. mask = (*f_op->poll)(file, wait);
  62. }
  63. //如果file存在,并且fops存在,并且fops中的
  64. //poll函数存在,就调用这个存在的poll函数
  65. //就会得到mask
  66. if ((mask & POLLIN_SET) && (in & bit))
  67. {
  68. res_in |= bit;
  69. //将当前的文件描述符放到
  70. //要返回的文件描述符表中
  71. retval++;
  72. }
  73. if ((mask & POLLOUT_SET) && (out & bit))
  74. {
  75. res_out |= bit;
  76. retval++;
  77. }
  78. if ((mask & POLLEX_SET) && (ex & bit))
  79. {
  80. res_ex |= bit;
  81. retval++;
  82. }
  83. //如果mask中的POLLIN/POLLOUT/POLLEX被置位了
  84. //将这些文件描述符放到准备好的文件描述表中
  85. //并且将retval这个变量加1,只要retval不为0,
  86. //死循环就会被退出
  87. }
  88. }
  89. }
  90. if (retval || timed_out || signal_pending(current))
  91. break;
  92. //如果retval不为0,或者超时时间到了或者信号到来了
  93. //这个死循环就会被退出
  94. if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,
  95. to, slack))
  96. //如果上述的条件都不满足,循环没有退出,进程
  97. //就进入休眠状态
  98. }
  99. return retval;
  100. }
  101. }

原文链接:http://www.cnblogs.com/yangtai/p/14860505.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号