版本

set_thread_area()首次出现在Linux 2.5.29中。 get_thread_area()首次出现在Linux 2.5.32中。

另外参见

arch_prctl(2),modify_ldt(2),ptrace(2)(PTRACE_GET_THREAD_AREA和PTRACE_SET_THREAD_AREA)

遵循规范

set_thread_area()和get_thread_area()是特定于Linux的,不应在打算移植的程序中使用。

语法

#include <linux/unistd.h>

#if defined __i386__ || defined __x86_64__
# include <asm/ldt.h>

int get_thread_area(struct user_desc *u_info);
int set_thread_area(struct user_desc *u_info);

#elif defined __m68k__

int get_thread_area(void);
int set_thread_area(unsigned long tp);

#elif defined __mips__

int set_thread_area(unsigned long addr);

#endif

注意:这些系统调用没有glibc包装器。请参阅注释。

名称

get_thread_area,set_thread_area-处理线程本地存储信息

SET_THREAD_AREA - Linux手册页

Linux程序员手册 第2部分
更新日期: 2020-02-09

返回值

在x86上,这些系统调用成功返回0,失败返回-1,并正确设置errno。

在MIPS和m68k上,set_thread_area()始终返回0。在m68k上,get_thread_area()返回线程区域指针值(以前是通过set_thread_area()设置的)。

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/

备注

Glibc不为这些系统调用提供包装器,因为它们通常仅供线程库使用。如果您想直接调用它们,请使用syscall(2)。

arch_prctl(2)可能会干扰x86上的set_thread_area()。有关更多详细信息,请参见arch_prctl(2)。这通常不是问题,因为arch_prctl(2)通常仅由64位程序使用。

在MIPS上,可以使用以下指令获取线程区域指针的当前值:

rdhwr dest, 

该指令捕获并由内核处理。

BUGS

在Linux 3.19之前的64位内核上,如果设置了user_desc中的填充位之一,则将防止描述符被视为空(请参见modify_ldt(2))。结果,清除TLS条目的唯一可靠方法是使用memset(3)将整个user_desc结构(包括填充位)清零,然后设置read_exec_only和seg_not_present位。在Linux 3.19上,除了entry_number以外,完全由零组成的user_desc也将被解释为清除TLS条目的请求,但是在较早的内核上,其行为有所不同。

在Linux 3.19之前,DS和ES段寄存器不得引用TLS条目。

错误说明

EFAULT
u_info是无效的指针。
EINVAL
u_info->entry_number超出范围。
ENOSYS
get_thread_area()或set_thread_area()作为64位系统调用被调用。
ESRCH
(set_thread_area())找不到免费的TLS条目。

说明

这些调用为线程本地存储实现提供特定于体系结构的支持。目前,在m68k,MIPS和x86(32位和64位变体)上都可以使用set_thread_area()。 get_thread_area()在m68k和x86上可用。

在m68k和MIPS上,set_thread_area()允许在与调用线程关联的内核数据结构中存储任意指针(在m68k的tp参数和MIPS的addr参数中提供)。以后可以使用get_thread_area()检索此指针(有关在MIPS上获取线程指针的信息,另请参见注释)。

在x86上,Linux将三个全局描述符表(GDT)条目专用于线程本地存储。有关GDT的更多信息,请参阅《英特尔软件开发人员手册》或《 AMD体系结构编程手册》。

这两个系统调用都使用一个参数,该参数是指向以下类型结构的指针:

struct user_desc {
    unsigned int  entry_number;
    unsigned int  base_addr;
    unsigned int  limit;
    unsigned int  seg_32bit:1;
    unsigned int  contents:2;
    unsigned int  read_exec_only:1;
    unsigned int  limit_in_pages:1;
    unsigned int  seg_not_present:1;
    unsigned int  useable:1;
#ifdef __x86_64__
    unsigned int  lm:1;
#endif
};

get_thread_area()读取由u_info-> entry_number指示的GDT条目,并填写u_info中的其余字段。

set_thread_area()在GDT中设置TLS条目。

set_thread_area()设置的TLS数组条目对应于用户传递的u_info-> entry_number的值。如果此值是有界的,则set_thread_area()将u_info指向的TLS描述符写入线程的TLS数组。

当将set_thread_area()传递给entry_number -1时,它将搜索一个空闲的TLS条目。如果set_thread_area()找到一个空闲的TLS条目,则在返回时设置u_info-> entry_number的值以显示更改了哪个条目。

如果将read_exec_only和seg_not_present设置为1并且所有其他字段均为0,则user_desc被视为"空"。如果将"空"描述符传递给set_thread_area(),则将清除相应的TLS条目。有关其他详细信息,请参见错误。

从Linux 3.19开始,尽管清除段还是可以接受的,但是不能使用set_thread_area()写入不存在的段,16位段或代码段。

日期:2019-08-20 17:59:20 来源:oir作者:oir