我要理解 EGLContext TLS 的实现原理

背景

  • 在项目中遇到需要讲明白 EGLContext 类「为什么」需要在「创建线程」执行销毁操作问题。然后跟进这个问题理解 pthread 的实现原理,在这里做记录
  • 整理的目的是为了能改写程序

问题

  • 「为什么」EGLContext 实例需要在「创建线程」执行销毁操作?
  • pthread 涉及哪些数据结构和基本操作?
  • 一个进程有多少个栈?

数据结构

pthread 和 EGLContext

pthread 和 EGLContext 数据结构关系

基本执行流程如图

pthread 调用流程
  • 应用层 client.so 调用 C 标准库 libc.so 的 pthread API
  • C 标准库 libc.so 通过「中断」或者「特殊系统调用指令」调用内核 Kernel 函数
  • 用户态切换到内核态,CPU 寄存器 「CS:IP」 和 「SS:SP」 切换到「内核代码段」和「内核栈」
  • 系统调用期间 CPU 处于内核态,特权级别为 Ring0
  • 内核跟 CPU/Memory 等硬件打交道
  • CPU 负责执行指令、读写内存
  • 处理完成后内核切换回用户态,CPU 寄存器 「CS:IP」 和 「SS:SP」 切换到「用户代码段」和「用户栈」
  • pthread 接口在 Android 里面实现在 libc.so 中
  • 当前进程空间内的所有线程组成双向链表结构


    线程结构体用双向链表连接在一起
    • 全局变量 g_thread_list 指向表头节点
    • 每个 pthread 结构体内部包含 prev 和 next 指针
  • 单个 pthread 结构体的内存布局


    单个 pthread 内存布局
    • pthread_internal_t#mmap_size 变量记录该线程在用户空间占用内存大小 1024 * 1024 KB - 16 KB + 4 KB + sizeof(pthread_internal) ,大概 1 MiB 空间
    • 栈内存在低地址,结构体内存在高地址
    • 最低地址处是 1 页内存的保护区,用于触发栈溢出异常,通过 mprotect 系统调用修改页面属性为 NONE,不可读写、执行
    • 由于 pthread 结构体需要 16 字节地址对齐处开始,故最高地址处会留下一些 padding 空间
    • pthread_internal_t#tls 数组变量记录当前线程专用的 Thread Local Storage 空间,数组大小 BIONIC_TLS_SLOTS 枚举控制,共 9 个元素
    • tls 数组第 4 个元素记录 ogles_context_t 类型的指针
    • 通过改变这个地址的值,可以指向不同的 ogles_context_t 实例,这样 opengl 的代
      码就操作当前指向的实例
# 查看某个进程通过 pthread 创建的栈区域
generic_x86:/data/data/com.example.guangli.demo $ cat /proc/18442/maps | grep stack
# 用于栈溢出检查的 1 页内存。没有读写、执行属性,故栈溢出会段错误
cee83000-cee84000 ---p 00000000 00:00 0 [anon:thread stack guard page]
# 线程 18486 对应的栈。大小 0xFB000 字节,大约 1 MB 
cee85000-cef80000 rw-p 00000000 00:00 0 [stack:18486]
...
e3b87000-e3b88000 ---p 00000000 00:00 0 [anon:thread stack guard page]
e3b89000-e3c84000 rw-p 00000000 00:00 0 [stack:18448]

基本操作

eglMakeCurrent 时序图

eglMakeCurrent.png
  • 目的是让一个变量指向给定的 EGLContext 对象
  • 用户通过 android.opengl.EGL14#eglMakeCurrent 调用从 Java 层进入 JNI 层 com_google_android_gles_jni_EGLImpl.cpp#jni_eglMakeCurrent 函数
  • JNI 层调用 /frameworks/native/opengl/libs/EGL/eglApi.cpp#eglMakeCurrent 进入 Native 层
  • 查找到 pthread_internal#tls 数组的基址,并设置 OPENGL_API 下标指向 OpenGL ES 2.0 的函数指针列表
  • 通过 pthread_setspecific 设置 pthread_internal#key_data 数组变量中当前 EGLContext 对象

练习题

  • 阅读 pthread_internal 源码,添加上自己的理解和猜测
  • 根据源码画出内存区域模块图,理清三层结构的关系
  • 画出 pthread_internal 和 EGLContext 的类图
  • 画出 eglMakeCurrent 时序图,目的是串联起前面的数据结构
  • 绑定不同的 EGLContext 看数据是否是对的

答案

  • 「为什么」EGLContext 实例需要在「创建线程」执行销毁操作?
    • 首先执行 eglMakeCurrent 是设置当前 pthread_internal 结构体的 key_data 数组的某个下标指向不同的 EGLContext 对象
    • 其次 android.opengl.EGL14#eglDestroyContext 是销毁 java 层传递下来的一个 EGLContext 对象,这个对象并不是内部从 TLS 读取的
    • 最后销毁就是先判断对象的状态再销毁,并没有跟 TLS 有很强的绑定在一起
    • 所以一个 EGLContext 对象是可以在一个线程创建后传递到另一个线程使用,最后在某个线程销毁。这个问题有点迷惑性
  • pthread 涉及哪些数据结构和基本操作?
    • pthread_internal 结构体
    • 栈 + guard
    • 信号栈 + guard
  • 一个进程有多少个栈?
    • 一个进程包含多个线程,在 linux 中线程是 task
    • 内核每个线程和进程结构体一样,上层通过 clone 创建线程
    • 用户态栈
    • 用户态信号栈
    • 内核态 thread_info 2 页内存的栈

总结

  • 整个流程涉及到知识点较多,中间得带着问题跟踪信息处理的流程,不然会在代码的海洋中迷失自我
  • 理解 pthread 的数据结构、基本操作有助于理解当前进程空间的内存布局,知道哪里可以拿到某些信息,哪里可以改,哪里可以 hook
  • 添加到基础知识点中,丰富知识树
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358