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 条评论
登录 后参与评论

相关文章

来自专栏Python

Flask-SQLAlchemy

一.SQLAlchemy介绍 SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之...

6129
来自专栏皮振伟的专栏

​[linux][pthread]qemu的一次pthread create失败的分析

前言: qemu发生了crash。这种类型的问题比较少见,这里说一下这个问题的分析过程。 分析: 1,coredump 生成的coredump,一种是配置了...

3416
来自专栏IT可乐

Java 多线程详解(二)------如何创建进程和线程

Java 多线程详解(一)------概念的引入:https://cloud.tencent.com/developer/article/1012542   在...

1806
来自专栏更流畅、简洁的软件开发方式

100w条记录分页,可以有多快?—— DataReader分页与SQL语句分页的对比测试(在线演示)

  上周看到了两篇关于DataReader分页的帖子,帖子的观点都是可以是用DataReader来分页,而且效率还不错。   根据我的分页经历来看,很难理解Da...

1747
来自专栏惨绿少年

练习题二上

第1章 linux启动过程 1、开机自检bios 2、mbr引导 3、GRUB 菜单:选择不同的内核 4、加载内核 5、运行init进程 6、读取/etc/in...

1940
来自专栏柠檬先生

hibernate-笔记

什么是 hibernate 框架     1.hibernate 框架应用在 javaee 三次结构中 dao 层框架     2.在dao 层里面对数据库做c...

1827
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片

《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片 (原创内容,转载请注明来源,谢谢) 一、集群中执行命令 1、节点对命令的判断 ...

2886
来自专栏云计算与大数据

linux 系统 ulimit 对系统资源限制

文件系统及程序的限制关系: ulimit ulimit 限制用户的某些系统资源 包括可以开启的档案数量 ...

744
来自专栏决胜机器学习

Redis专题(三) ——Redis事务与过期时间(缓存分析)

Redis专题(三)——Redis事务与过期时间(缓存分析) (原创内容,转载请注明来源,谢谢) 一、事务(Transaction) 1、概述 事务的定义和...

3897
来自专栏java一日一条

Java 多线程处理任务的封装

最近公司项目很多地方使用多线程处理一些任务,逻辑代码和java多线程处理代码混合在一起,造成代码的可读性超级差,现在把Java多线程相关的处理抽出来,方面代码中...

564

扫码关注云+社区