免费注册 查看新帖 |

Chinaunix

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

[网络子系统] tcp_rcv_established函数中的一个问题【已解决】 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-12-03 22:24 |只看该作者 |倒序浏览
本帖最后由 jiufei19 于 2013-12-05 10:24 编辑

大家好,我在阅读V2.6.23版本的网络内核时,遇到如下一个关于tcp_rcv_established函数的问题,实在弄不明白,希望大家帮助,下面我叙述下该问题

tcp_rcv_established(...)
{
      ...
      if (tp->ucopy.task == current && sock_owned_by_user(sk) && !copied_early) {
                __set_current_state(TASK_RUNNING);
                 if (!tcp_copy_to_iovec(sk, skb, tcp_header_len))
                      eaten = 1;
     }
     ...
}

我的疑惑是,既然sock_owned_by_user(sk)为真,则表示用户进程正在使用该sk,并且没有进入休眠状态,那么既然如此为何还要设置自身为RUNNING状态呢,自己不就正在运行中吗?

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
2 [报告]
发表于 2013-12-04 09:00 |只看该作者
jiufei19 发表于 2013-12-03 22:24
大家好,我在阅读V2.6.23版本的网络内核时,遇到如下一个关于tcp_rcv_established函数的问题,实在弄不明白 ...

tcp_rcv_established函数应该是在软中断上下文中调用的,并非在进程上下文,所以此时的current进程并不一定处于running状态,将其设置为running后,在TCP层收包流程处理完后,用户态进程将有机会得到调度以进行进一步处理。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
3 [报告]
发表于 2013-12-04 10:16 |只看该作者
回复 1# jiufei19
大家好,我在阅读V2.6.23版本的网络内核时,遇到如下一个关于tcp_rcv_established函数的问题,实在弄不明白,希望大家帮助,下面我叙述下该问题

tcp_rcv_established(...)
{
      ...
      if (tp->ucopy.task == current && sock_owned_by_user(sk) && !copied_early) {
                __set_current_state(TASK_RUNNING);
                 if (!tcp_copy_to_iovec(sk, skb, tcp_header_len))
                      eaten = 1;
     }
     ...
}

我的疑惑是,既然sock_owned_by_user(sk)为真,则表示用户进程正在使用该sk,并且没有进入休眠状态,那么既然如此为何还要设置自身为RUNNING状态呢,自己不就正在运行中吗?



tcp_recvmsg---->lock_sock---->(!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) ---->(There is no enough data to read from receive_queue,prequeue,backlog, use block mode to read)---->sk_wait_data---->prepare_to_wait(process change state to TASK_INTERRUPTIBLE)---->(Packet arrvied this moment)


softirq---->netif_receive_skb---->...---->tcp_v4_rcv---->tcp_rcv_established---->(Got this condition)

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
4 [报告]
发表于 2013-12-04 12:40 |只看该作者
回复 2# humjb_1983


    很感谢humjb_1983的帮助,不过这里有一个问题需要明确,这个函数可以在软中断环境下调用,但是根据tcp_v4_rcv的前期处理,可以很明确看出软中断将获得sk->sk_lock.slock,并且此时,将没有任何用户进程在使用该套接字,于是那个sk->sk_lock.ownersk->sk_lock.owner将不可能为1,于是,这里将更没有机会执行set RUNNING的机会了,不知道我理解是否正确。

其实tcp_rcv_established这个函数有两个地方可以被执行,一个就是被软中断,另外一个就是被tcp_recvmsg,但是,现在我看无论是哪个地方,都有我这里讲到的矛盾存在

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
5 [报告]
发表于 2013-12-04 12:47 |只看该作者
回复 3# 瀚海书香


        感谢瀚海书香,你给出的调用序列,我之前仔细查看过,这里有一个问题,即在sk_wait_data中将调用sk_wait_event,进一步就会调用release_sock(__sk),于是用户进程将释放对此sk的占用,此时sk->sk_lock.owner将被置为NULL,于是我的问题就出现了,既然都为NULL了,那么如下的红色判断将不可能成立了,所以也没有机会执行set RUNNING

if (tp->ucopy.task == current && sock_owned_by_user(sk) && !copied_early)


我的理解是否有误?

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
6 [报告]
发表于 2013-12-04 12:54 |只看该作者
回复 5# jiufei19


    我补充说明下我的困惑,之前我没有完整叙述。

    我的困惑在于,无论tcp_rcv_established从用户进程调用还是被软中断调用,则都会有矛盾出现:

   1、假定从用户进程调用,那么进程本身就在running,所以那句调度状态为RUNNING就显得没有意义
   2、假设从软中断调用,则因为进程本身已经在休眠,放弃sk->sk_lock.slock的占用(此时软中断才有机会执行到这里的tcp_rcv_established),则因为此时sk->sk_lock.owner也为NULL,所以也不可能执行唤醒进程为RUNNING的动作

  因此,我觉得两边都无法解释这里的代码,所以,我肯定哪里理解有误!

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
7 [报告]
发表于 2013-12-04 14:09 |只看该作者
回复 5# jiufei19
   感谢瀚海书香,你给出的调用序列,我之前仔细查看过,这里有一个问题,即在sk_wait_data中将调用sk_wait_event,进一步就会调用release_sock(__sk),于是用户进程将释放对此sk的占用,此时sk->sk_lock.owner将被置为NULL,于是我的问题就出现了,既然都为NULL了,那么如下的红色判断将不可能成立了,所以也没有机会执行set RUNNING

if (tp->ucopy.task == current && sock_owned_by_user(sk) && !copied_early)


我的理解是否有误?

Please check the pass carefully!

int sk_wait_data(struct sock *sk, long *timeo)                                                                                
{      
        int rc;
        DEFINE_WAIT(wait);                                                                                                   
        
        prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);   
Softirq can trigged here!(before release_sock())                                                         
        set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue));                                               
        clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);                                                               
        finish_wait(sk_sleep(sk), &wait);                                                                                    
        return rc;                                                                                                            
}

   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
8 [报告]
发表于 2013-12-04 15:35 |只看该作者
瀚海书香 发表于 2013-12-04 14:09
回复 5# jiufei19

Please check the pass carefully!


我还是有点不明白斑竹的说明,我下面继续描述下在斑竹刚才的说明下还存在的问题。我们从tcp_v4_rcv的关键代码开始来分析

tcp_v4_rcv(...)
{
       ...
       bh_lock_sock_nested(sk);                    
       ret = 0;

       if (!sock_owned_by_user(sk)) {  
              if (!tcp_prequeue(sk, skb))
                   ret = tcp_v4_do_rcv(sk, skb);
       }     
       ...
}

刚才斑竹指明了可能在sk_wait_data函数中的prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE)这句话后软中断被激活了,则此时用户进程已经为TASK_INTERRUPTIBLE状态了,但是尚未来得及置sk->sk_lock.owner为NULL,此时则上述代码中蓝色字体的代码就无法为真,于是不可能执行tcp_prequeue,当然也更不可能在软中断中执行tcp_v4_do_rcv了,那么我的问题依然没有得到解决,我的描述有问题吗?

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
9 [报告]
发表于 2013-12-04 15:43 |只看该作者
继续刚才的描述:

于是不可能执行tcp_prequeue,当然也更不可能在软中断中执行tcp_v4_do_rcv了。因此软中断只能将当前skb放入backlog队列中等待处理。接着此时软中断结束,假定用户进程再次恢复刚才中断处继续执行,那么就会开始执行如下两句:
     set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
     rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue))

显然,此时好像仍然继续存在我刚才描述的问题呢?

论坛徽章:
15
射手座
日期:2014-02-26 13:45:082015年迎新春徽章
日期:2015-03-04 09:54:452015年辞旧岁徽章
日期:2015-03-03 16:54:15羊年新春福章
日期:2015-02-26 08:47:552015年亚洲杯之卡塔尔
日期:2015-02-03 08:33:45射手座
日期:2014-12-31 08:36:51水瓶座
日期:2014-06-04 08:33:52天蝎座
日期:2014-05-14 14:30:41天秤座
日期:2014-04-21 08:37:08处女座
日期:2014-04-18 16:57:05戌狗
日期:2014-04-04 12:21:33技术图书徽章
日期:2014-03-25 09:00:29
10 [报告]
发表于 2013-12-04 15:59 |只看该作者
jiufei19 发表于 2013-12-04 15:35
我还是有点不明白斑竹的说明,我下面继续描述下在斑竹刚才的说明下还存在的问题。我们从tcp_v4_rcv的关 ...

个人理解,用户态进程是在如下代码流程中唤醒的:
no_ack:
                        /* 如果数据已经复制到用户空间,则释放该skb */
                        if (eaten)
                                __kfree_skb(skb);
                        else/* 否则说明数据已经就绪,唤醒等待队列上的进程,通知它们读取数据 */
                                sk->sk_data_ready(sk, 0);                        return 0;
其中sk_data_ready=sock_def_readable,其中会
wake_up_interruptible(sk->sk_sleep);
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP