gpt4 book ai didi

linux - 如何在克隆后访问错误号(或 : How to set errno location)

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:38:46 25 4
gpt4 key购买 nike

根据传统的 POSIX,errno 只是一个整数左值,它与 fork 一起工作得很好,但显然与线程的工作效果不一样。根据 pthreads,errno 是线程局部整数左值。在 Linux/NTPL 下,作为实现细节,errno 是一些“扩展为返回整数左值的函数的宏”。

在我的 Debian 系统上,这似乎是 *__errno_location (),在其他一些系统上我见过类似 &(gettib()->errnum 的东西。

长话短说
假设我已经使用 clone 创建了一个线程,我可以只调用 errno 并期望它会工作,还是我必须做一些特殊的雨舞?例如,我是否需要读取线程信息 block 中的某些特殊字段或某些特殊的 TLS 值,或者我是否需要设置 glibc 以某种方式存储错误值的线程局部变量的地址?可能像 __set_errno_location() 这样的东西?

或者,它会“正常工作”吗?

不可避免地,有人会忍不住回答“只需使用 phtreads”——请不要这样。我不想使用 pthreads。我想要克隆。我不想要 pthreads 的任何不明智的功能,我不想处理它的任何怪癖,我也不想要开销来实现这些怪癖。我认识到 pthreads 中的大部分问题来自于它必须工作(而且,令人惊讶的是,它成功工作)以及其他一些已经有将近 30 年历史的完全损坏的系统,但是并不意味着它对每个人和每种情况都是一件好事。在这种情况下,可移植性不是任何问题。
在这种特殊情况下,我想要的只是启动另一个在与父进程相同的地址空间中运行的进程,通过一个简单的锁(比如 futex)进行同步,并且 write 正常工作(这意味着我 < em>也必须能够正确读取errno)。尽可能少的开销,不需要甚至不需要其他功能或特殊行为。

最佳答案

根据glibc source code , errno 被定义为线程局部变量。不幸的是,这需要重要的 C 库支持。使用 pthread_create() 创建的任何线程都将了解线程局部变量。我什至懒得让 glibc 接受你的外来线程。

另一种方法是使用不同的 libc 实现,如果 errno 是它的一部分,它可能允许您提取它的一些内部结构并手动设置线程控制 block 。这将是令人难以置信的 hacky 和不可靠的。我怀疑您会找到像 __set_errno_location() 这样的东西,而是像 __set_tcb() 这样的东西。

#include <bits/some_hidden_file.h>

void init_errno(void)
{
struct __tcb* tcb;

/* allocate a dummy thread control block (malloc may set errno
* so might have to store the tcb on stack or allocate it in the
* parent) */
tcb = malloc(sizeof(struct __tcb));

/* initialize errno */
tcb->errno = 0;

/* set pointer to thread control block (x86) */
arch_prctl(ARCH_SET_FS, tcb);
}

这假设 errno 宏扩展为:((struct __tcb*)__read_fs())->errno

当然,您始终可以选择自己实现一个极小的 libc 子集。或者您可以使用自定义 stub 编写您自己的 write() 系统调用实现来处理 errno 并让它与所选的 libc 实现共存。

#define my_errno /* errno variable stored at some known location */

ssize_t my_write(int fd, const void* buf, size_t len)
{
ssize_t ret;

__asm__ (
/* set system call number */
/* set up parameters */
/* make the call */
/* retrieve return value in c variable */
);

if (ret >= -4096 && ret < 0) {
my_errno = -ret;
return -1;
}

return ret;
}

我不记得 GCC 内联汇编的具体细节,系统调用调用细节因平台而异。

就我个人而言,我只会实现一个非常小的 libc 子集,它只包含一个小汇编程序和一些常量。有这么多可用的引用代码,这非常简单,尽管它可能过于雄心勃勃。

关于linux - 如何在克隆后访问错误号(或 : How to set errno location),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19892800/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com