问题的简短版本:如果我想为我所在的线程分配一个新的TLS区域,我需要将哪个参数传递给x86_64 Linux系统上的clone
系统调用创建
长版:
我正在研究一个研究项目,对于我正在尝试的事情,我想使用clone
系统调用而不是pthread_create
来创建线程。但是,我也希望能够使用线程本地存储。我现在不打算创建多个线程,所以我可以为我使用克隆系统调用创建的每个线程创建一个新的TLS区域。
我正在查看clone
的手册页,它包含有关TLS参数标志的以下信息:
CLONE_SETTLS (since Linux 2.5.32)
The newtls argument is the new TLS (Thread Local Storage) descriptor.
(See set_thread_area(2).)
所以我查看了set_thread_area
的手册页,注意到以下内容看起来很有希望:
When set_thread_area() is passed an entry_number of -1, it uses a
free TLS entry. If set_thread_area() finds a free TLS entry, the value of
u_info->entry_number is set upon return to show which entry was changed.
然而,在尝试了一些之后,我的系统(x86_64平台上的Ubunut 10.04)中似乎没有实现set_thread_area
。当我运行以下代码时,我收到一条错误消息:set_thread_area() failed: Function not implemented
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/unistd.h>
#include <asm/ldt.h>
int main()
{
struct user_desc u_info;
u_info.entry_number = -1;
int rc = syscall(SYS_set_thread_area,&u_info);
if(rc < 0) {
perror("set_thread_area() failed");
exit(-1);
}
printf("entry_number is %d",u_info.entry_number);
}
我还看到当我使用strace时,看看调用pthread_create
时会发生什么,我看不到对set_thread_area
的任何调用。我一直在查看nptl pthread源代码,试图了解它们在创建线程时所做的工作。但我还没有完全理解它,我认为它比我正在尝试做的更复杂,因为我不需要在pthread实现中具有强大功能的东西。我假设set_thread_area
系统调用是针对x86的,并且x86_64
使用了不同的机制。但目前我还没弄清楚它是什么,所以我希望这个问题可以帮助我了解一些我需要了解的内容。
答案 0 :(得分:5)
我正在研究一个研究项目,并且正在尝试我想要使用克隆系统调用创建线程而不是使用pthread_create
在极其不太可能的场景中,你的新线程从不调用任何libc函数(直接或通过调用其他调用libc的东西;这也包括动态符号解析通过PLT),然后你可以将你想要的任何TLS存储作为new_tls参数传递给clone
。
您应该忽略对set_thread_area
的所有引用 - 它们仅适用于32位/ ix86案例。
如果 计划在新创建的线程中使用libc,则应放弃您的方法:libc
期望要以某种方式设置TLS,并且当您直接呼叫clone
时,您无法无法安排此类设置。当libc
发现您没有正确设置TLS时,您的新线程将间歇地崩溃。调试此类崩溃非常困难,唯一可靠的解决方案是......使用pthread_create
。
答案 1 :(得分:0)
另一个答案是绝对正确的,因为在libc的控制之外设置一个线程可以保证在某一点上造成麻烦。您可以这样做,但您不能再依赖libc的服务,绝对不能依赖任何pthread_*
函数或线程局部变量(使用__thread
或{{1定义) }})。
话虽这么说,你甚至可以在x86-64上设置一个用于TLS(GS和FS)的段寄存器。要查找的系统调用是thread_local
。
您可以在this piece of code中看到比较在i386和x86-64上设置TLS寄存器的示例。