根据传统的posix,errno只是一个整数左值,它在fork中工作得非常好,但ovy在线程中工作得不太好。根据pthreads,errno是线程本地整数左值。在linux/ntpl下,作为实现细节,errno是一些“扩展为返回整数左值的函数的宏”。
在我的debian系统上,这似乎是*__errno_location (),在其他一些系统上,我看到过类似&(gettib()->errnum
TL;博士
假设我已经使用clone创建了一个线程,我可以只调用errno并期望它能够工作,还是必须做一些特殊的雨舞?例如,我需要读取线程信息块中的某个特殊字段,或某个特殊的tls值,还是需要设置glibc以某种方式存储错误值的线程局部变量的地址?可能是什么?
或者,它会像现在这样“管用”吗?
不可避免地,有人会试图回答“简单地使用phtreas”--请不要这样做。我不想使用pthreads。我想要__set_errno_location()。我不希望pthreads有任何不明智的功能,也不希望处理它的任何怪癖,也不希望实现这些怪癖的开销。我认识到pthread中的大部分crud来自于这样一个事实:对于一些已经有近30年历史的完全崩溃的系统来说,它必须工作(而且,令人惊讶的是,它成功地工作),但这并不意味着它对每个人和每种情况都一定是一件好事。在这种情况下,可移植性并不重要。
在这种特殊情况下,我只需要启动另一个进程,运行在与父进程相同的地址空间中,通过一个简单的锁(比如一个futex)进行同步,并且clone工作正常(这意味着我还必须能够正确地读取write)。尽可能少的开销,不需要或甚至不需要其他功能或特殊行为。

最佳答案

根据glibc source codeerrno被定义为一个线程局部变量。不幸的是,这需要大量的c库支持。使用pthread_create()创建的任何线程都将知道线程局部变量。我甚至不想让glibc接受你的外线。
另一种方法是使用不同的libc实现,如果errno是它的一部分,它可能允许您提取它的一些内部结构并手动设置线程控制块。这将是令人难以置信的黑客和不可靠。我不相信你会找到像__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的一个非常小的子集。或者,您可以用自定义存根编写自己的“ccc>系统调用”,以处理write(),并将其与选定的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 - 克隆后如何访问errno(或:如何设置errno位置),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19892800/

10-15 04:12