Linux中TLS
TLS(Thread Local Storage)
线程局部存储。
在Linux操作系统中,TLS保存成GDT中描述的一个段。
1: /*
2: * This creates a new process as a copy of the old one,
3: * but does not actually start it yet.
4: *
5: * It copies the registers, and all the appropriate
6: * parts of the process environment (as per the clone
7: * flags). The actual kick-off is left to the caller.
8: */
9: static struct task_struct *copy_process(unsigned long clone_flags,
10: unsigned long stack_start,
11: struct pt_regs *regs,
12: unsigned long stack_size,
13: int __user *child_tidptr,
14: struct pid *pid,
15: int trace)
16: {
17: ......
18: retval = copy_thread(clone_flags, stack_start, stack_size, p, regs);
19: ......
20: }
1: int copy_thread(unsigned long clone_flags, unsigned long sp,
2: unsigned long unused,
3: struct task_struct *p, struct pt_regs *regs)
4: {
5: struct pt_regs *childregs;
6: struct task_struct *tsk;
7: int err;
8:
9: childregs = task_pt_regs(p);
10: *childregs = *regs;
11: childregs->ax = 0;
12: childregs->sp = sp;
13:
14: p->thread.sp = (unsigned long) childregs;
15: p->thread.sp0 = (unsigned long) (childregs+1);
16:
17: p->thread.ip = (unsigned long) ret_from_fork;
18:
19: task_user_gs(p) = get_user_gs(regs);
20:
21: p->thread.io_bitmap_ptr = NULL;
22: tsk = current;
23: err = -ENOMEM;
24:
25: memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
26:
27: if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
28: p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
29: IO_BITMAP_BYTES, GFP_KERNEL);
30: if (!p->thread.io_bitmap_ptr) {
31: p->thread.io_bitmap_max = 0;
32: return -ENOMEM;
33: }
34: set_tsk_thread_flag(p, TIF_IO_BITMAP);
35: }
36:
37: err = 0;
38:
39: /*
40: * Set a new TLS for the child thread?
41: */
42: if (clone_flags & CLONE_SETTLS)
43: err = do_set_thread_area(p, -1,
44: (struct user_desc __user *)childregs->si, 0);
45:
46: if (err && p->thread.io_bitmap_ptr) {
47: kfree(p->thread.io_bitmap_ptr);
48: p->thread.io_bitmap_max = 0;
49: }
50: return err;
51: }
1: /*
2: * Set a given TLS descriptor:
3: */
4: int do_set_thread_area(struct task_struct *p, int idx,
5: struct user_desc __user *u_info,
6: int can_allocate)
7: {
8: struct user_desc info;
9:
10: if (copy_from_user(&info, u_info, sizeof(info)))
11: return -EFAULT;
12:
13: if (idx == -1)
14: idx = info.entry_number;
15:
16: /*
17: * index -1 means the kernel should try to find and
18: * allocate an empty descriptor:
19: */
20: if (idx == -1 && can_allocate) {
21: idx = get_free_idx();
22: if (idx < 0)
23: return idx;
24: if (put_user(idx, &u_info->entry_number))
25: return -EFAULT;
26: }
27:
28: if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
29: return -EINVAL;
30:
31: set_tls_desc(p, idx, &info, 1);
32:
33: return 0;
34: }
1: static void set_tls_desc(struct task_struct *p, int idx,
2: const struct user_desc *info, int n)
3: {
4: struct thread_struct *t = &p->thread;
5: struct desc_struct *desc = &t->tls_array[idx - GDT_ENTRY_TLS_MIN];
6: int cpu;
7:
8: /*
9: * We must not get preempted while modifying the TLS.
10: */
11: cpu = get_cpu();
12:
13: while (n-- > 0) {
14: if (LDT_empty(info))
15: desc->a = desc->b = 0;
16: else
17: fill_ldt(desc, info);
18: ++info;
19: ++desc;
20: }
21:
22: if (t == ¤t->thread)
23: load_TLS(t, cpu);
24:
25: put_cpu();
26: }
1: static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info)
2: {
3: desc->limit0 = info->limit & 0x0ffff;
4:
5: desc->base0 = (info->base_addr & 0x0000ffff);
6: desc->base1 = (info->base_addr & 0x00ff0000) >> 16;
7:
8: desc->type = (info->read_exec_only ^ 1) << 1;
9: desc->type |= info->contents << 2;
10:
11: desc->s = 1;
12: desc->dpl = 0x3;
13: desc->p = info->seg_not_present ^ 1;
14: desc->limit = (info->limit & 0xf0000) >> 16;
15: desc->avl = info->useable;
16: desc->d = info->seg_32bit;
17: desc->g = info->limit_in_pages;
18:
19: desc->base2 = (info->base_addr & 0xff000000) >> 24;
20: /*
21: * Don't allow setting of the lm bit. It is useless anyway
22: * because 64bit system calls require __USER_CS:
23: */
24: desc->l = 0;
25: }
从上面的call_tree可以看到,在fork系统调用创建一个新的进程时,会为新的任务设置TLS。
参考:http://blog.csdn.net/dog250/article/details/7704898
fill_ldt设置GDT中第6个段描述符的基址和段限以及DPL等信息,这些信息都是从sys_set_thread_area系统调用的u_info参数中得来的。本质上,最终GDT的第6个段中描述的信息其实就是一块内存,这块内存用于存储TLS节,这块内存其实也是使用brk,mmap之类调用在主线程的堆空间申请的,只是后来调用sys_set_thread_area将其设置成了本线程的私有空间罢了,主线程或者其它线程如果愿意,也是可以通过其它手段访问到这块空间的。
因为TLS是一个对应于C/C++ Runtime库的概念,所以要深入了解TLS,需要结合glibc来理解。
Linux中TLS的更多相关文章
- 在Linux中使用线程
我并不假定你会使用Linux的线程,所以在这里就简单的介绍一下.如果你之前有过多线程方面的编程经验,完全可以忽略本文的内容,因为它非常的初级. 首先说明一下,在Linux编写多线程程序需要包含头文件p ...
- Linux中安装python3.6和第三方库
Linux中安装python3.6和第三方库 如果本机安装了python2,尽量不要管他,使用python3运行python脚本就好,因为可能有程序依赖目前的python2环境,比如yum!!!!! ...
- Linux中搭建一个ftp服务器详解
来源:Linux社区 作者:luzhi1024 详解Linux中搭建一个ftp服务器. ftp工作是会启动两个通道:控制通道 , 数据通道在ftp协议中,控制连接均是由客户端发起的,而数据连接有两种 ...
- 每天进步一点点——Linux中的线程局部存储(一)
转载请说明出处:http://blog.csdn.net/cywosp/article/details/26469435 在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同 ...
- 在Linux中安装和配置OpenVPN Server的最简便方法!
本文介绍了如何在基于RPM和DEB的系统中安装和配置OpenVPN服务器.我们在本文中将使用一个名为openvpn-install的脚本,它使整个OpenVPN服务器的安装和配置过程实现了自动化.该脚 ...
- 在 Linux 中安装 Oracle JDK 8 以及 JVM 的类加载机制
参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...
- Linux中find常见用法示例
·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数: pathname: find命 ...
- Linux中检索文件
1 , Use locate command It is a fast way to find the files location, but if a file just created ,it w ...
- 如何在Linux中搭建禅道8.4.1(httpd+php+mysql)
1.安装httpd 命令:yum install httpd 然后一路y即可 2.安装php 命令:yum install php 3.安装php-mysql 命令:yum install php ...
随机推荐
- Java学习之多线程(定义)
进程:正在运行中的程序线程:负责执行程序的控制单元(执行路径)一个进程中可以有多个执行路径,称之为多线程一个进程中至少要有一个线程 创建新执行线程有两种方式 一.继承Thread类步骤:1.定义一个类 ...
- delphi xe2 panel 无法 遮盖 label 的 解决方案。
百度 没有找到此答案. 问群,也没答案. 根据群友的提示. 找到的解决的办法. 很简单. ParentBackground 设置为 false.
- 记录MNIST采用卷积方式实现与理解
从时间上来说,这篇文章写的完了,因为这个实验早就做完了:但从能力上来说,这篇文章出现的早了,因为很多地方我都还没有理解.如果不现在写,不知道什么时候会有时间是其一,另外一个原因是怕自己过段时间忘记. ...
- 重新认识Maven
PS:第一次接触maven大约是两年前吧,隐约记得之前都是人工寻找并下载很多jar,放在项目的lib中(表示太年轻,没有接触过Ant或者其他类似的工具,就不找别人写的比较了).懒人永远有着自己的小聪明 ...
- 关系型数据库MySQL(二)_索引
优点 大大加快数据的查询速度 创建唯一性索引,保证数据库表中每一行数据的唯一性 在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间 缺点 索引需要占物理空间 当对表中的数据进行增删 ...
- Java + selenium 元素定位(2)之By LinkText/PartialLinkText
本章介绍的两种方法都是对于网页上的文字链接的定位操作.根据名字,我们就可以看出来,这两者其实很相似,那么他们的不同在哪里呢. By LinkText()方法,是对一个的网页超链接,我们所需要输入的关键 ...
- 2019牛客国庆集训派对day1(A, B E F K)
链接:https://ac.nowcoder.com/acm/contest/1099#question A:可知符合条件的图中间肯定存在一个由1构成的矩形,找到由1构成矩形的边界,判断出现的1的数量 ...
- Python基础代码1
Python基础代码 import keyword#Python中关键字 print(keyword.kwlist) ['False', 'None', 'True', 'and', 'as', 'a ...
- 常用命令--find
语法 find path -option [ -print ] [-exec -ok command ] {} \; find . -maxdepth 1 -type f -exec mv {} /t ...
- 安装vue开发环境→安装淘宝镜像的时候报错
问题: npm WARN deprecated socks@1.1.10: If using 2.x branch, please upgrade to at least 2.1.6 to avoid ...