+ -
当前位置:首页 → 问答吧 → select没有把进程放入wait queue吗?

select没有把进程放入wait queue吗?

时间:2010-07-22

来源:互联网

本帖最后由 kgn28 于 2010-07-22 13:20 编辑

记得看过0.12的select实现:
1,检查文件描述符,调用fd->ops->poll,测试文件描述符是否准备好。
2,如果没有,则把自己放到一个wait queue中,然后schedule。
也就是让自己去睡眠,等待被唤醒,但是看2.6的代码时,有些不理解:
http://lxr.linux.no/linux+v2.6.33/fs/select.c
  1. 396int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
  2. 397{
  3. 398        ktime_t expire, *to = NULL;
  4. 399        struct poll_wqueues table;
  5. 400        poll_table *wait;
  6. 401        int retval, i, timed_out = 0;
  7. 402        unsigned long slack = 0;
  8. 403
  9. 404        rcu_read_lock();
  10. 405        retval = max_select_fd(n, fds);
  11. 406        rcu_read_unlock();
  12. 407
  13. 408        if (retval < 0)
  14. 409                return retval;
  15. 410        n = retval;
  16. 411
  17. 412        poll_initwait(&table);
  18. 413        wait = &table.pt;
  19. 414        if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
  20. 415                wait = NULL;
  21. 416                timed_out = 1;
  22. 417        }
  23. 418
  24. 419        if (end_time && !timed_out)
  25. 420                slack = estimate_accuracy(end_time);
  26. 421
  27. 422        retval = 0;
  28. 423        for (;;) {
  29. 424                unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
  30. 425
  31. 426                inp = fds->in; outp = fds->out; exp = fds->ex;
  32. 427                rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
  33. 428
  34. 429                for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
  35. 430                        unsigned long in, out, ex, all_bits, bit = 1, mask, j;
  36. 431                        unsigned long res_in = 0, res_out = 0, res_ex = 0;
  37. 432                        const struct file_operations *f_op = NULL;
  38. 433                        struct file *file = NULL;
  39. 434
  40. 435                        in = *inp++; out = *outp++; ex = *exp++;
  41. 436                        all_bits = in | out | ex;
  42. 437                        if (all_bits == 0) {
  43. 438                                i += __NFDBITS;
  44. 439                                continue;
  45. 440                        }
  46. 441
  47. 442                        for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {
  48. 443                                int fput_needed;
  49. 444                                if (i >= n)
  50. 445                                        break;
  51. 446                                if (!(bit & all_bits))
  52. 447                                        continue;
  53. 448                                file = fget_light(i, &fput_needed);
  54. 449                                if (file) {
  55. 450                                        f_op = file->f_op;
  56. 451                                        mask = DEFAULT_POLLMASK;
  57. 452                                        if (f_op && f_op->poll) {
  58. 453                                                wait_key_set(wait, in, out, bit);
  59. 454                                                mask = (*f_op->poll)(file, wait);
  60. 455                                        }
  61. 456                                        fput_light(file, fput_needed);
  62. 457                                        if ((mask & POLLIN_SET) && (in & bit)) {
  63. 458                                                res_in |= bit;
  64. 459                                                retval++;
  65. 460                                                wait = NULL;
  66. 461                                        }
  67. 462                                        if ((mask & POLLOUT_SET) && (out & bit)) {
  68. 463                                                res_out |= bit;
  69. 464                                                retval++;
  70. 465                                                wait = NULL;
  71. 466                                        }
  72. 467                                        if ((mask & POLLEX_SET) && (ex & bit)) {
  73. 468                                                res_ex |= bit;
  74. 469                                                retval++;
  75. 470                                                wait = NULL;
  76. 471                                        }
  77. 472                                }
  78. 473                        }
  79. 474                        if (res_in)
  80. 475                                *rinp = res_in;
  81. 476                        if (res_out)
  82. 477                                *routp = res_out;
  83. 478                        if (res_ex)
  84. 479                                *rexp = res_ex;
  85. 480                        cond_resched();
  86. 481                }
  87. 482                wait = NULL;
  88. 483                if (retval || timed_out || signal_pending(current))
  89. 484                        break;
  90. 485                if (table.error) {
  91. 486                        retval = table.error;
  92. 487                        break;
  93. 488                }
  94. 489
  95. 490                /*
  96. 491                 * If this is the first loop and we have a timeout
  97. 492                 * given, then we convert to ktime_t and set the to
  98. 493                 * pointer to the expiry value.
  99. 494                 */
  100. 495                if (end_time && !to) {
  101. 496                        expire = timespec_to_ktime(*end_time);
  102. 497                        to = &expire;
  103. 498                }
  104. 499
  105. 500                if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,
  106. 501                                           to, slack))
  107. 502                        timed_out = 1;
  108. 503        }
  109. 504
  110. 505        poll_freewait(&table);
  111. 506
  112. 507        return retval;
  113. 508}
复制代码
看情形,在for( ; ; )之间,不停的调用:
1,测试
2,cond_resched()
那分明是:没有把当前进程放入到wait queue,然后叫其他进程唤醒,而是不停的执行,直到被抢占或者文件描述符准备好。不知道我哪里理解错了???如果是这样cpu周期不是浪费了吗???
也就是说调用select的进程一直是出于running状态的了。。。

作者: kgn28   发布时间: 2010-07-22

在fd->ops->poll里面,如果对应fd没有需要的事件,就会把current加入等待队列。
也就是说,current会被加入所有的fd的等待队列(如果它们都没有需要的事件的话)。 加入等待队列的这些waiter管理在table结构里面,退回do_select之前会清理。

在完成对所有fd的poll之后,如果没有发现需要的事件,最后会跑到poll_schedule_timeout,current在这里进入睡眠。

作者: kouu   发布时间: 2010-07-22

你可以选择用pause()函数来实现

作者: 0vk0   发布时间: 2010-07-22

pause():

     pause函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,errno设置为EINTR,所以pause只有出错的返回值

   参考《apue2》

作者: 0vk0   发布时间: 2010-07-22

热门下载

更多