博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux中TLS
阅读量:7103 次
发布时间:2019-06-28

本文共 5300 字,大约阅读时间需要 17 分钟。

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 == &current->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。

参考:

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来理解。

转载于:https://www.cnblogs.com/long123king/p/3501936.html

你可能感兴趣的文章
开源还是商用?十大云运维监控工具横评
查看>>
python3 科学计算2
查看>>
Mysql启动失败Can’t connect to local MySQL server throu
查看>>
大学四年的学习经历
查看>>
viewController
查看>>
Filebeat入门
查看>>
Java之字符串和字符串缓冲区
查看>>
tomcat、oracle、centos时区异常处理
查看>>
Raspberry Pi双网卡bonding
查看>>
HDU1022
查看>>
Nginx - 文章 - 伯乐在线 大量 Nginx资料
查看>>
Genymotion初体验
查看>>
JBoss 系列二十一:JBossCache 核心API
查看>>
Apache下htaccess文件不起作用/rewrite 没有效果
查看>>
WinXP补丁升级极疯狂 《关于svchost.exe的CPU占用率过高的原因以及解决方法》
查看>>
Linux VMware 安装问题
查看>>
int型的单个数字转换为char型
查看>>
JavaScript 秘密花园
查看>>
c++ 使用深度优先搜索算法计算N位水仙数
查看>>
ERP实施过程中的阻碍,你hold住了吗?
查看>>