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。

参考: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的更多相关文章

  1. 在Linux中使用线程

    我并不假定你会使用Linux的线程,所以在这里就简单的介绍一下.如果你之前有过多线程方面的编程经验,完全可以忽略本文的内容,因为它非常的初级. 首先说明一下,在Linux编写多线程程序需要包含头文件p ...

  2. Linux中安装python3.6和第三方库

    Linux中安装python3.6和第三方库 如果本机安装了python2,尽量不要管他,使用python3运行python脚本就好,因为可能有程序依赖目前的python2环境,比如yum!!!!! ...

  3. Linux中搭建一个ftp服务器详解

    来源:Linux社区  作者:luzhi1024 详解Linux中搭建一个ftp服务器. ftp工作是会启动两个通道:控制通道 , 数据通道在ftp协议中,控制连接均是由客户端发起的,而数据连接有两种 ...

  4. 每天进步一点点——Linux中的线程局部存储(一)

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/26469435    在Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同 ...

  5. 在Linux中安装和配置OpenVPN Server的最简便方法!

    本文介绍了如何在基于RPM和DEB的系统中安装和配置OpenVPN服务器.我们在本文中将使用一个名为openvpn-install的脚本,它使整个OpenVPN服务器的安装和配置过程实现了自动化.该脚 ...

  6. 在 Linux 中安装 Oracle JDK 8 以及 JVM 的类加载机制

    参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...

  7. Linux中find常见用法示例

    ·find   path   -option   [   -print ]   [ -exec   -ok   command ]   {} \; find命令的参数: pathname: find命 ...

  8. Linux中检索文件

    1 , Use locate command It is a fast way to find the files location, but if a file just created ,it w ...

  9. 如何在Linux中搭建禅道8.4.1(httpd+php+mysql)

    1.安装httpd 命令:yum install httpd 然后一路y即可 2.安装php 命令:yum install php   3.安装php-mysql 命令:yum install php ...

随机推荐

  1. SSAS MDX语句 期末查询简单示例

    WITH Member [Measures].[num Last Day of Month] AS( [时间].[YQMD].CurrentMember.LastChild,[Measures].[门 ...

  2. C++中的静态成员函数

    1,问完成的需求: 1,统计在程序运行期间某个类的对象数目: 1,静态成员变量满足了这个需求: 2,保证程序的安全性(不能使用全局变量): 3,随时可以获取当前对象的数目: 1,有没有什么特别的地方或 ...

  3. BZOJ 2724蒲公英 (分块) 【内有块大小证明】

    题面 luogu传送门 分析 先分块,设块大小为x(之后我们会证明块大小取何值会更优) 步骤1 把所有的数离散化,然后对每个值开一个vector pos[i],pos[i]存储数i出现的位置 我们设查 ...

  4. 52-python基础-python3-列表-常用列表方法- reverse()方法

    reverse()方法 永久性地修改列表元素的排列顺序,但可随时恢复到原来的排列顺序,为此只需对列表再次调用reverse() 即可. 实例:  

  5. springCloud的使用06-----分布式配置

    1 分布式配置中心的搭建 1.1 在git仓库中创建配置文件 1.2 创建springboot项目引入相应jar依赖 <project xmlns="http://maven.apac ...

  6. How To Release and/or Renew IP Addresses on Windows XP | 2000 | NT

    Type 'ipconfig' (without the quotes) to view the status of the computer's IP address(es). If the com ...

  7. SpringBoot-技术专区-异步编程

    最近在实现一个聚合搜索的需求时,由于需要从五个索引中查询数据,然后再将搜索结果组合返回给前端app展现,显然这个地方不能再用同步的方式来操作了,如果有一个索引查询出现耗时较长,那么其余的请求都会排同步 ...

  8. wireshark简单的过滤条件

    http://blog.csdn.net/blue_jjw/article/details/8467885 一.IP过滤:包括来源IP或者目标IP等于某个IP比如:ip.src addr==192.1 ...

  9. XML 和 HTML 之间的差异

    XML 和 HTML 为不同的目的而设计: XML 被设计用来传输和存储数据,其焦点是数据的内容. HTML 被设计用来显示数据,其焦点是数据的外观. HTML 旨在显示信息,而 XML 旨在存储和传 ...

  10. jquery实现可以中英切换的导航条

    html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...