0

我遇到了一个不寻常的问题,无法找到导致它的原因。

我正在开发用户级非抢占线程库。

void MyThreadYield(void) {
    if(myThreadLib.readyQ->size > 0) {
        ucontext_t currentContext;
        getcontext(&currentContext);
        myThreadLib.runningMyThread->ctx = currentContext;
        queueEnqueue(myThreadLib.readyQ, myThreadLib.runningMyThread);
        myThreadLib.runningMyThread = queueDequeue(myThreadLib.readyQ);
        setcontext(&(myThreadLib.runningMyThread->ctx));
    }
}

执行后getcontext(&currentContext),currentContext 中的 ss_stack 为 NULL。以下是 currentContext 的快照

在此处输入图像描述 并且在myThreadLib.runningMyThread->ctx = currentContext;执行之后它修改了readyQ,不知道为什么。

但是,setcontext(&(myThreadLib.runningMyThread->ctx));执行良好并且上下文已成功更改,但在再次调用 MyThreadYield() 时会出现 Segfault。

你能帮我解决这个问题吗?

谢谢。

4

1 回答 1

0

在 glib-2.17 中,我得到了 getcontext() 汇编代码:

0x0000000000401b50 <+0>:     mov    %rbx,0x80(%rdi)
0x0000000000401b57 <+7>:     mov    %rbp,0x78(%rdi)
0x0000000000401b5b <+11>:    mov    %r12,0x48(%rdi)
0x0000000000401b5f <+15>:    mov    %r13,0x50(%rdi)
0x0000000000401b63 <+19>:    mov    %r14,0x58(%rdi)
0x0000000000401b67 <+23>:    mov    %r15,0x60(%rdi)
0x0000000000401b6b <+27>:    mov    %rdi,0x68(%rdi)
0x0000000000401b6f <+31>:    mov    %rsi,0x70(%rdi)
0x0000000000401b73 <+35>:    mov    %rdx,0x88(%rdi)
0x0000000000401b7a <+42>:    mov    %rcx,0x98(%rdi)
0x0000000000401b81 <+49>:    mov    %r8,0x28(%rdi)
0x0000000000401b85 <+53>:    mov    %r9,0x30(%rdi)
0x0000000000401b89 <+57>:    mov    (%rsp),%rcx
0x0000000000401b8d <+61>:    mov    %rcx,0xa8(%rdi)
0x0000000000401b94 <+68>:    lea    0x8(%rsp),%rcx
0x0000000000401b99 <+73>:    mov    %rcx,0xa0(%rdi)
0x0000000000401ba0 <+80>:    lea    0x1a8(%rdi),%rcx
0x0000000000401ba7 <+87>:    mov    %rcx,0xe0(%rdi)
0x0000000000401bae <+94>:    fnstenv (%rcx)
0x0000000000401bb0 <+96>:    fldenv (%rcx)
0x0000000000401bb2 <+98>:    stmxcsr 0x1c0(%rdi)
0x0000000000401bb9 <+105>:   lea    0x128(%rdi),%rdx
0x0000000000401bc0 <+112>:   xor    %esi,%esi
0x0000000000401bc2 <+114>:   xor    %edi,%edi
0x0000000000401bc4 <+116>:   mov    $0x8,%r10d
0x0000000000401bca <+122>:   mov    $0xe,%eax
0x0000000000401bcf <+127>:   syscall
0x0000000000401bd1 <+129>:   cmp    $0xfffffffffffff001,%rax
0x0000000000401bd7 <+135>:   jae    0x410f70 <__syscall_error>
0x0000000000401bdd <+141>:   xor    %eax,%eax
0x0000000000401bdf <+143>:   retq

似乎只有 uc_mcontext 在 getcontext() 调用中被修改。uc_stack 保持不变。

通过阅读 getcontext info,得到以下单词:

Unix 标准提供了一组函数来控制执行路径,这些函数比本章迄今为止讨论的函数更强大。这些函数原始 System V API 的一部分,并通过此路径添加到 Unix API。除了品牌的 Unix 实现之外,这些接口并不广泛可用。并非 GNU C 库的所有平台和/或体系结构都提供此接口。使用“配置”来检测可用性。

而 man getcontext 有以下几句话:

符合 SUSv2,POSIX.1-2001。POSIX.1-2008 删除了 getcontext() 的规范,引用了可移植性问题,并建议重写应用程序以改用 POSIX 线程。

所以我认为 getcontext/setcontext/swapcontext/makecontext 都是过时的,应该避免使用。

于 2013-09-11T04:34:30.960 回答