Glibc线程局部存储(TLS)的实现

本文深入探讨了glibc中线程局部存储(TLS)的实现机制,包括TLS变量的地址计算、动态链接器如何调整TLS变量偏移量,以及主线程和子线程TLS存储空间的创建过程。
  • 背景

在笔者分析glibc源码中的内存分配模块时,遇到了线程局部变量thread_arena,该变量是线程专有的局部变量。在glibc源码中,有相似的变量errno,也是线程专有的变量。尽管在glibc的其他头文件中,errno被定义为 (* __errno_location()),但线程专有的变量实现机制是相同的,笔者希望了解其实现的具体机制。

  • 调试代码

为了调试分析glibc对线程本地存储(Thread-Local-Storage,即TLS)实现的机制,笔者编写了如下代码(文件名为tls-test.c):

/*
 * Created by xiaoqzye@qq.com
 *
 * Thread-Local-Storage test
 *
 * 2020/05/10
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>

static int myPipe[2];
#define TLSTEST_BUFSIZ   8192
static __thread int datls __attribute__ ((tls_model ("initial-exec")));

static void handle_sigpipe(int signo)
{
	fprintf(stdout, "Received signal: %d, &datls: %p, &errno: %p\n",
		signo, &datls, &errno);
	fflush(stdout);
}

static void * datls_thread(void * what)
{
	int * errp;
	unsigned char * qdat, * rdat;
	void * retval = (void *) 0x20200510;

	datls = 0x1;
	errp = &errno;
	/* dump thread-local-storage variables */
	fprintf(stdout, "In [%s], errno: %p, datls: %p, %d, what: %p, %d\n",
		__FUNCTION__, errp, &datls, datls, what, *((int *) what));
	fflush(stdout);

	/* allocate memory */
	qdat = (unsigned char *) malloc(TLSTEST_BUFSIZ);
	if (qdat == NULL) {
		fputs("Thread out of memory!\n", stderr);
		fflush(stderr);
		return retval;
	}

	for (;;) {
		ssize_t rl0;
readAgain:
		rdat = NULL;
		rl0 = read(myPipe[0], (void *) &rdat, sizeof(rdat));
		if (rl0 < 0) {
			if (*errp == EINTR)
				goto readAgain;
			fprintf(stderr, "Error, failed to read(%d): %s\n",
				myPipe[0], strerror(*errp));
			fflush(stderr);
			break;
		}
		if (rl0 == 0) break;
		if (rl0 != sizeof(rdat)) {
			fprintf(stderr, "Error, partial read of %d: %ld\n",
				myPipe[0], (long) rl0);
			fflush(stderr);
			break;
		}
		fprintf(stdout, "Trying to free memory pointer: %p\n", errp);
		fflush(stdout);
		free(rdat);
	}
	free(qdat);
	return retval;
}

int main(int argc, char *argv[])
{
	void * rval;
	pthread_t threadID;
	unsigned char * pdat;
	int ret, * perr, idx;

	myPipe[0] = myPipe[1] = -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值