跨线程的 ucontext

发布于 2024-10-07 14:40:44 字数 228 浏览 7 评论 0原文

上下文(由 ucontext.h 中的函数操作的对象)是否允许跨线程共享?也就是说,我可以使用第二个参数来 swapcontext 来作为另一个线程上的 makecontext 创建的上下文吗?测试程序似乎表明这可以在 Linux 上运行。我找不到这方面的文档,而 Windows 光纤似乎明确支持这种用例。一般来说,这样做安全吗?这是标准的 POSIX 行为吗?

Are contexts (the objects manipulated by functions in ucontext.h) allowed to be shared across threads? That is, can I swapcontext with the second argument being a context created in makecontext on another thread? A test program seems to show this working on Linux. I can't find documentation one way or the other on this, whereas Windows fibers appear to explicitly support such a use case. Is this safe and OK to do in general? Is it standard POSIX behavior that this should work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风月客 2024-10-14 14:40:44

实际上,Linux 有一个 NGPT - 线程库,它使用的不是当前的 1:1 线程模型(每个用户线程都是内核线程或 LWP),而是 M:N 线程模型(多个用户线程对应于另一个更小的线程)内核线程数)。

根据 ftp://ftp.uni-duisburg.de/ Linux/NGPT/ngpt-0.9.4.tar.gz/ngpt-0.9.4/pth_sched.c:170 pth_scheduler 可以在本机(内核)线程之间移动用户线程上下文:

        /*
         * See if the thread is unbound...
         * Break out and schedule if so...
         */
        if (current->boundnative == 0)
            break;
        /*
         * See if the thread is bound to a different native thread...
         * Break out and schedule if not...
         */
        if (current->boundnative == this_sched->lastrannative)
            break;

保存和恢复用户线程时,可以使用 ucontext ftp://ftp.uni-duisburg.de/Linux/NGPT/ngpt-0.9.4.tar.gz/ngpt-0.9.4/pth_mctx.c:64 似乎这是一种首选方法 (mcsc):

/*
 * save the current machine context
 */
#if PTH_MCTX_MTH(mcsc)
#define pth_mctx_save(mctx) \
        ( (mctx)->error = errno, \
          getcontext(&(mctx)->uc) )
#elif
....
/*
 * restore the current machine context
 * (at the location of the old context)
 */
#if PTH_MCTX_MTH(mcsc)
#define pth_mctx_restore(mctx) \
        ( errno = (mctx)->error, \
          (void)setcontext(&(mctx)->uc) )
#elif PTH_MCTX_MTH(sjlj)
...

#if PTH_MCTX_MTH(mcsc)

/*
 * VARIANT 1: THE STANDARDIZED SVR4/SUSv2 APPROACH
 *
 * This is the preferred variant, because it uses the standardized
 * SVR4/SUSv2 makecontext(2) and friends which is a facility intended
 * for user-space context switching. The thread creation therefore is
 * straight-foreward.
 */

因此,即使 NGPT 已失效且未使用,它也会选择 *context() 来切换用户线程,甚至在内核线程之间切换。我认为,在 Linux 上使用 *context() 系列是足够安全的。

混合 ucontexts 和其他本机线程库时可能会出现一些问题。我会考虑 NPTL,它是自 glibc 2.4 以来的标准 Linux 本机线程库。主要问题是 THREAD_SELF - 指向当前线程的 struct pthread 的指针。 TLS(线程本地存储)也通过 THREAD_SELF 工作。 THREAD_SELF 通常存储在寄存器中(r2 on powerpc% x86 上的 gs 等)。 get/setcontext 可能会保存和恢复该寄存器,从而破坏本机 pthread 库的内部结构(例如线程本地存储、线程标识等)。

glibc setcontext 不会保存/恢复%gs 注册 以与 pthread 兼容:

    /* Restore the FS segment register.  We don't touch the GS register
       since it is used for threads.  */
    movl    oFS(%eax), %ecx
    movw    %cx, %fs

您应该检查 setcontext 是否在您感兴趣的架构上保存 THREAD_SELF 注册。此外,您的代码不能在操作系统和 libc

Actually, there was an NGPT - threading library for linux, which uses not a current 1:1 threading model (each user thread is the kernel thread or LWP), but a M:N threading model (several user threads corresponds to another, smaller number of kernel threads).

According to ftp://ftp.uni-duisburg.de/Linux/NGPT/ngpt-0.9.4.tar.gz/ngpt-0.9.4/pth_sched.c:170 pth_scheduler it was possible of moving user thread contexts between native (kernel) threads:

        /*
         * See if the thread is unbound...
         * Break out and schedule if so...
         */
        if (current->boundnative == 0)
            break;
        /*
         * See if the thread is bound to a different native thread...
         * Break out and schedule if not...
         */
        if (current->boundnative == this_sched->lastrannative)
            break;

To save and restore user threads, the ucontext can be used ftp://ftp.uni-duisburg.de/Linux/NGPT/ngpt-0.9.4.tar.gz/ngpt-0.9.4/pth_mctx.c:64 and seems this was a preferred method (mcsc):

/*
 * save the current machine context
 */
#if PTH_MCTX_MTH(mcsc)
#define pth_mctx_save(mctx) \
        ( (mctx)->error = errno, \
          getcontext(&(mctx)->uc) )
#elif
....
/*
 * restore the current machine context
 * (at the location of the old context)
 */
#if PTH_MCTX_MTH(mcsc)
#define pth_mctx_restore(mctx) \
        ( errno = (mctx)->error, \
          (void)setcontext(&(mctx)->uc) )
#elif PTH_MCTX_MTH(sjlj)
...

#if PTH_MCTX_MTH(mcsc)

/*
 * VARIANT 1: THE STANDARDIZED SVR4/SUSv2 APPROACH
 *
 * This is the preferred variant, because it uses the standardized
 * SVR4/SUSv2 makecontext(2) and friends which is a facility intended
 * for user-space context switching. The thread creation therefore is
 * straight-foreward.
 */

So, even if NGPT is dead and unused, it selected *context() for switching user threads even between kernel threads. I assume, that using *context() family is safe enough on Linux.

There can be some problems when mixing ucontexts and other native threads library. I will consider a NPTL, which is standard linux native threading library since glibc 2.4. The main problem is THREAD_SELF - pointer to struct pthread of the current thread. TLS (Thread-local storage) also works via THREAD_SELF. The THREAD_SELF is usually stored on register (r2 on powerpc, %gs on x86, etc). get/setcontext might save and restore this register breaking internals of native pthread library (e.g. thread-local storage, thread identification, etc).

The glibc setcontext will not save/restore %gs register to be compatible with pthreads:

    /* Restore the FS segment register.  We don't touch the GS register
       since it is used for threads.  */
    movl    oFS(%eax), %ecx
    movw    %cx, %fs

You should check, does setcontext saves THREAD_SELF register on the architecture you are interested in. Also, your code can be not portable between OSes and libcs.

终止放荡 2024-10-14 14:40:44

来自 手册页

在类似 System V 的环境中,一个
ucontext_t 类型定义于
和四个函数
获取上下文(2),设置上下文(2),
makecontext() 和 swapcontext()
允许用户级上下文切换
多个控制线程之间
在一个进程内。

听起来这就是它的用途。

编辑:尽管此讨论似乎表明您应该不要将它们混合在一起。

From the man page

In a System V-like environment, one
has the type ucontext_t defined in
and the four functions
getcontext(2), setcontext(2),
makecontext() and swapcontext() that
allow user-level context switching
between multiple threads of control
within a process.

Sounds like that's what it's for.

EDIT: although this discussion seems to indicate that you shouldn't be mixing them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文