前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux、pthread、qemu 的一次 pthread create 失败的分析

linux、pthread、qemu 的一次 pthread create 失败的分析

原创
作者头像
皮振伟
修改2017-08-11 10:15:34
2.6K0
修改2017-08-11 10:15:34
举报
文章被收录于专栏:皮振伟的专栏皮振伟的专栏

前言:

qemu发生了crash。这种类型的问题比较少见,这里说一下这个问题的分析过程。

分析:

1、coredump

生成的coredump,一种是配置了/proc/sys/kernel/core_pattern并且配置了ulimit的情况,coredump文件会按照core pattern生成。

还有一种是apport的,生成的文件使用apport-unpack可以解压出来。

加载coredump文件,查看trace:

[1502356119300_8228_1502356121307.png]
[1502356119300_8228_1502356121307.png]

看到了原因是abort,那么还好,毕竟不是最难分析的。

2、frame

从trace中来看,应该是frame 3发生了错误,导致了qemu自己主动abort了。那么具体分析一下frame 3

[1502356151249_6895_1502356153304.png]
[1502356151249_6895_1502356153304.png]

再结合frame 2的第一个参数,可见,是pthread_create的返回值是11。

3、EAGAIN

打开/usr/include/asm-generic/errno-base.h可见,errno 11是EAGAIN

既然pthread_create的返回值是EAGAIN,那么只好继续分析glibc的nptl(glibc的pthread在nptl中实现)了。

同时,还要找到对应的glibc的版本。有两种办法供参考:

a,在gdb的命令行中敲info proc mappings

[1502356210553_9537_1502356212194.png]
[1502356210553_9537_1502356212194.png]

可以看到qemu当时映射了哪个glibc的文件,可以判断出来。

b,在shell中敲ldd /bin/qemu-system-x86_64 | grep libc,再通过symbolic link找到对应的文件

[1502356226178_7133_1502356227843.png]
[1502356226178_7133_1502356227843.png]

确定了glibc的版本是2.23,那么就可以去gnu下载对应的glibc的源代码了。

4、pthread_create

找到glibc-2.23/nptl/pthread_create.c,分析EAGAIN的具体原因。

在这里先大致说一下linux平台上pthread的实现:linux并不区分进程和线程,内核中只有task。多个task组成一个group,同一个组里面的task共享虚拟内存空间,fs,signal handler等等几乎所有的资源。但是,每个task都需要有自己的用户栈,所以就需要在创建线程之前先为task分配page size对齐的内存。分配好内存之后,就可以使用系统调用sys_clone创建线程了。

5、allocate stack

找到第一个可能返回EAGAIN的代码

如果在为新的线程分配栈内存的时候失败,那么就会返回EAGAIN。

stack用的内存比较大块,glibc维护了cache,尽量避免每次都需要syscall。

[1502356459821_2773_1502356461699.png]
[1502356459821_2773_1502356461699.png]

先确认cache是不是真的有,如果没有,很可能就是内存分配失败导致的。

再来确认stack_cache的地址。

最后确认pthread的handler的list的内容,通过上面的几个关键字段的地址,可以分析出来pthread的list双链表都是指向了stack_cache。

综上,可以判断出来,内存是分配成功的。一,当时的stack_cache有一个缓存,直接分配给了那次分配;二,当时的stack_cache是空的,向kernel要了内存,并且成功了,在后面执行失败的时候,把内存归还给了cache。

此二者,无论那种情况,都可以认为这条路径下,不会返回EAGAIN的

6、sys_clone

继续分析,看看还有哪里可能返回EAGAIN。

分析到了sys_clone,它的返回值可能是EAGAIN。继续分析linux-4.4/kernel/fork.c,重点do_fork函数中可能返回EAGAIN的可能性:

a,qemu的thread的个数超过了限制?从cat /proc/sys/kernel/threads-max和ulimit看进程的最大线程数,另外在gdb中info threads可以看到所有的线程数。对比之下,coredump进程的线程数远小于限制,排除。

b,copy process执行的时候遇到了ENOMEM?这个看起来也不太像,从host的dmesg中没有看到任何oom信息。

c,host的pid max不足cat /proc/sys/kernel/pid-max,发现只有32768。一来这个数值偏小,二来测试在host上跑过多线程模拟的测试,这里看起来可能性最大了。

7、复现

修改了pid-max之后,在原来的环境上一台虚拟机出现的问题,现在改用七台同时复现。目前七台虚拟机已经跑了超过了一天。还没有遇到。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 分析:
    • 1、coredump
      • 2、frame
        • 3、EAGAIN
          • 4、pthread_create
            • 5、allocate stack
              • 6、sys_clone
                • 7、复现
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档