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

前言:

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

分析:

1、coredump

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

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

加载coredump文件,查看trace:

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

2、frame

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

再结合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

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

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

确定了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。

先确认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之后,在原来的环境上一台虚拟机出现的问题,现在改用七台同时复现。目前七台虚拟机已经跑了超过了一天。还没有遇到。

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

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

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏杨龙飞前端

scrollto 到指定位置

2894
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

5798
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2997
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

37910
来自专栏一个爱瞎折腾的程序猿

sqlserver使用存储过程跟踪SQL

USE [master] GO /****** Object: StoredProcedure [dbo].[sp_perfworkload_trace_s...

2810
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3595
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

6866
来自专栏Golang语言社区

【Golang语言社区】GO1.9 map并发安全测试

var m sync.Map //全局 func maintest() { // 第一个 YongHuomap := make(map[st...

5378
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

8338
来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2767

扫码关注云+社区