【问题标题】:How to allocate a new TLS area with clone system call如何使用克隆系统调用分配新的 TLS 区域
【发布时间】:2014-07-04 05:37:57
【问题描述】:

简短版问题:如果我想为我正在创建的线程分配一个新的 TLS 区域,我需要将什么参数传递给 x86_64 Linux 系统上的clone 系统调用。

加长版

我正在做一个研究项目,对于我正在试验的东西,我想使用clone 系统调用而不是pthread_create 创建线程。但是,我也希望能够使用线程本地存储。我现在不打算创建很多线程,所以我可以为使用 clone 系统调用创建的每个线程创建一个新的 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.

但是,在尝试了一些之后,我的系统中似乎没有实现set_thread_area(x86_64 平台上的 Ubunut 10.04)。当我运行以下代码时,我收到一条错误消息: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 使用了不同的机制。但目前我无法弄清楚它是什么,所以我希望这个问题能帮助我对我需要查看的内容有所了解。

【问题讨论】:

    标签: linux pthreads system-calls


    【解决方案1】:

    我正在做一个研究项目,对于我正在试验的东西,我想使用 clone 系统调用而不是使用 pthread_create 创建线程

    非常不太可能的情况下,您的新线程调用任何 libc 函数(直接或通过调用其他调用 libc 的函数;这还包括动态符号解析通过 PLT),然后您可以将所需的任何 TLS 存储作为 new_tls 参数传递给clone

    您应该忽略所有对set_thread_area 的引用——它们仅适用于 32 位/ix86 情况。

    如果你打算计划在你新创建的线程中使用 libc,你应该放弃你的方法:libc期望TLS以某种方式设置,当您直接致电clone 时,您无法安排此类设置。当libc 发现您没有正确设置 TLS 时,您的新线程将间歇性崩溃。调试此类崩溃非常困难,唯一可靠的解决方案是......使用pthread_create

    【讨论】:

    • 感谢您提供的信息,是的,我确实计划调用 libc。出于好奇,libc 将 TLS 区域用于什么用途?此外,由于可能有不使用 pthread_create(单线程)的程序,在这种情况下会发生关于设置 libc 需要使用的 TLS 区域的情况。
    • libc 用它来做一些事情:用于进行加速系统调用 (x86) 的函数指针、堆栈金丝雀(如果使用堆栈保护器)、pid 缓存(由 getpid 使用)、tid 缓存(用于识别锁的所有者) ), errno (这是线程本地的)。我敢肯定还有更多我没有想到的用途。
    【解决方案2】:

    另一个答案是绝对正确的,因为在 libc 控制之外设置线程肯定会在某个点造成麻烦。你可以做到,但你不能再依赖 libc 的服务,绝对不能依赖任何 pthread_* 函数或线程局部变量(使用 __threadthread_local 定义)。

    话虽如此,即使在 x86-64 上,您也可以设置用于 TLS(GS 和 FS)的段寄存器之一。要查找的系统调用是prctl(ARCH_SET_GS, ...)

    您可以在this piece of code 中查看比较在 i386 和 x86-64 上设置 TLS 寄存器的示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-05
      • 1970-01-01
      • 1970-01-01
      • 2012-09-08
      • 1970-01-01
      相关资源
      最近更新 更多