免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3852 | 回复: 9
打印 上一主题 下一主题

【请教】关于select的问题。(中断里使用wake_up惹得祸,不知如何避免)。 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-03 17:54 |只看该作者 |倒序浏览
本帖最后由 Anyul 于 2010-02-03 18:01 编辑

请教一个问题。。
我们发现有一个应用使用select来检查十多个fd,结果永远都出不来了,永远等在哪里,直到timeout了。。
于是就去查,结果发现问题是在select里面:

do_select()
{
1.    循环使用poll挨个检查每个fd的状态;
2.    如果所有的poll返回值累计非零就退出;
3.    如果所有的poll都返回为零就schedule_timeout();
}

当在第一行循环poll每一个fd的时候:一共检查10个fd,前八个已经poll完了都是返回零,当poll第九个的时候来了个中断,这个中断改变了前面已经检查过的第一个fd的状态,也就是第一个fd有数据到达了,但是中断返回后,程序继续来检查第九个和第十个fd的poll的结果。
运行到第二行的时候,此时poll的结果当然是零,但实际上fd1已经有数据ready了。但是select没有发现。于是运行schedule_timeout了,进入睡眠。

请问是否有人遇到了这种情况,是否驱动哪里写的不对?中断里面不能wakeup进程吗?

谢谢啊

论坛徽章:
0
2 [报告]
发表于 2010-02-04 11:29 |只看该作者
回复 1# Anyul

查了一下code, 应该是你的f_op->poll函数写的不对。在你的poll函数里应该调用poll_wait把poll_table加到你的wait_queue里。
这样在你的interrupt里call wake_up的时候,会最终调用__pollwake -> pwq->triggered = 1.

而在do_select里,在poll_schedule_timeout里,如果pwq->triggered被设置的话是不会schedule出去,会直接返回并restart poll in do_select。

论坛徽章:
0
3 [报告]
发表于 2010-02-04 17:44 |只看该作者
非常感谢您的回复。可惜我正在用的kernel是2.6.25的,有些old。 这个版本没有pollwake的。
我有查看了2.6.32的果然如你所说,2.6.32的确没有这样的问题了。

但是好像2.6.25就会有这个问题啊。。.
我现在只好把wakeup操作放到workqueue里面了,这只是个workaround。
但是2.6.25好像就是有这个问题啊。。。。难道在2.6.25就会有select唤不醒的问题?

论坛徽章:
0
4 [报告]
发表于 2010-02-05 09:57 |只看该作者
非常感谢您的回复。可惜我正在用的kernel是2.6.25的,有些old。 这个版本没有pollwake的。
我有查看了2.6. ...
Anyul 发表于 2010-02-04 17:44


我觉得你的这个问题应该是一个很基本的问题,kernel不应该会犯这样的错误。select应该不会miss wake_up event,否则的话,这就是kernel select的一个大bug了。

查了一下code,在早一点的版本中,do_select是通过set task state来work的,所以它要求poll不能被block。
do_select:
    set_current_state(TASK_INTERRUPTIBLE);
    poll all fds;
    if (no fd ready)
        schedule_timeout();

如果你的fd在call schedule_timeout之前ready了,wake_up -> default_wake_function()会把task state设成TASK_RUNNING状态,这样schedule_timeout()最多只是做了一下context switch,而select的process还是会在scheduler的run queue里。应该很快就会被调度到,而不会在TASK_INTERRUPTIBLE等待被唤醒。

论坛徽章:
0
5 [报告]
发表于 2010-02-05 10:52 |只看该作者
回复 4# eexplorer


相当之感谢啊。果然如你所说。。。。解了我心中一大惑。。

论坛徽章:
0
6 [报告]
发表于 2010-02-07 13:21 |只看该作者
还想请教一个依然是select的基本问题
在2.6.25上
0:do_select:
1:    set_current_state(TASK_INTERRUPTIBLE);
2:    poll all fds;
3:    if (no fd ready)
4:        schedule_timeout();

在第二行,在poll的时候会调用到 __pollwait() -> poll_get_entry() -> __get_free_page(GFP_KERNEL)

这个 __get_free_page(GFP_KERNEL);是有可能系统进入睡眠吧? 也就是说会发生schedule()
但是一旦发生了schedule(),此时此进程是TASK_INTERRUPTIBLE状态,而且此时__pollwait没有运行完,这时候再也不会有人会唤醒这个进程了。

这岂不是select永远出不来了?我很困惑

论坛徽章:
0
7 [报告]
发表于 2010-02-08 09:36 |只看该作者
还想请教一个依然是select的基本问题
在2.6.25上
0:do_select:
1:    set_current_state(TASK_INTERRUPT ...
Anyul 发表于 2010-02-07 13:21


Good question!

GFP_KERNEL是可能会引起schedule的,但是注意到do_select()会首先利用kernel stack的空间(see poll_wqueues.inline_entries),即poll_get_entry在进入你所说的这种情况之前,__pollwait已经至少把调用select()这个process放到了许多不同的wait queue上了。

所以,即使在get_poll_entry的时候因为out_of_memory被schedule出去了,这个process还是会被唤醒的。

论坛徽章:
0
8 [报告]
发表于 2010-02-08 10:53 |只看该作者
非常感谢您的答复

poll_wqueues确实分配了N_INLINE_POLL_ENTRIES个inline_entries
但是inline_index 永远只增加不会减少,所以这个inline_entries总会用完的啊
所以可能还是很难避免去分配新的页面,之后再去add_wait_queue
(我看的是2.6.27)


static struct poll_table_entry *poll_get_entry(poll_table *_p)
{
        struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt);
        struct poll_table_page *table = p->table;

        if (p->inline_index < N_INLINE_POLL_ENTRIES)   //inline_index总会增加到超过inline entries的时候啊
                return p->inline_entries + p->inline_index++;

        if (!table || POLL_TABLE_FULL(table)) {
                struct poll_table_page *new_table;

                new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL);
                if (!new_table) {
                        p->error = -ENOMEM;
                        __set_current_state(TASK_RUNNING);
                        return NULL;
                }
                new_table->entry = new_table->entries;
                new_table->next = table;
                p->table = new_table;
                table = new_table;
        }

        return table->entry++;
}

我理解的对吗?如果理解的对,我仍然很困惑啊

在进入等待的时候有个必须:就是必须先把进程放到wakeup队列中,然后再设置进程状态到TASK_INTERRUPTIBLE...我怀疑的就是do_select会不会把设置进程状态放到add wait queue之前去了。。。??

论坛徽章:
0
9 [报告]
发表于 2010-02-08 12:31 |只看该作者
非常感谢您的答复

poll_wqueues确实分配了N_INLINE_POLL_ENTRIES个inline_entries
但是inline_index  ...
Anyul 发表于 2010-02-08 10:53



一旦有fd ready,do_select会返回,poll_freewait会释放所有的poll_table_entry。

论坛徽章:
0
10 [报告]
发表于 2010-02-08 20:36 |只看该作者
多谢多谢啊。。我再研究一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP