【问题标题】:longjmp from a forked process来自分叉进程的 longjmp
【发布时间】:2011-10-28 15:00:20
【问题描述】:

好的,这就是我想要实现的目标。我希望分叉进程的 threadRoutine 线程仅从特定点开始执行,如注释所示//分叉进程的线程应该从这里开始执行。我为原始堆栈和分叉 threadRoutine 使用相同的内存区域。但我怀疑由于分叉进程的 threadRoutine 在我将 cp_thread 设置为 1 时确实执行了 longjmp,因此它的堆栈开始与 threadRoutine 的原始进程,所以它不能跳转到我想要的地方。

我该如何解决这个问题,即不要在分叉进程的 longjmp 之前将分叉进程的原始堆栈和 threadRoutine 的堆栈分开.

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <setjmp.h>

pthread_attr_t attr;
int cp_thread = 0;
static jmp_buf buf;
pthread_barrier_t bar;

void make_jmp_if_req()
{
    if ( cp_thread )
        longjmp( buf, 1 );
}

void *threadRoutine(void *threadMsg)
{
    size_t myStackSize;
    void *stackAddr;

    make_jmp_if_req();

    printf("%d: TR:{stackAddr pointer = %lx, @threadRoutine = %lx}\n", 
           getpid(), stackAddr, threadRoutine );
    pthread_attr_getstack(&attr,&stackAddr,&myStackSize);

    setjmp( buf );
    pthread_barrier_wait(&bar);

    printf("%d: TR:stack address %p\n", getpid(), stackAddr);
    printf("%d: TR:stack size is %x\n", getpid(), myStackSize);
    //printf("%d\n",*((int *)stackAddr)); // <--------------------Causing segmentation fault..
    pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
    size_t stacksize;
    void *stackAddr;
    int rc;
    size_t i;
    pthread_t thread;
    pid_t pid;

    pthread_attr_init(&attr);
    // So that setjmp in the threadRoutine of the orignal process is called before             
    //  longjmp from threadRoutine of the forked process.
    pthread_barrier_init(&bar, NULL, 2);

    stacksize = 0xC00000; //12582912;
    stackAddr = malloc(stacksize);
    printf("Main:{stackAddr = %lx}\n", stackAddr );
    pthread_attr_setstack(&attr,stackAddr, stacksize);
    pthread_attr_getstack(&attr,&stackAddr, &stacksize);
    printf("Main:stack address %p\n",stackAddr);
    printf("Main:stack size is %x\n",stacksize);

    rc = pthread_create( &thread, &attr, threadRoutine, (void*)0 );
    pthread_barrier_wait(&bar);

    switch(pid = fork())
    {
    case -1:
      printf("fork failed");
      break;
    case 0: // Child
      printf( "Child pid() = %d\n", getpid() );
      cp_thread = 1;
      rc = pthread_create(&thread, &attr, threadRoutine,(void *)0);
      break;
    default:// Leader
      printf( "Parent pid() = %d\n", getpid() );
      //rc = pthread_create(&thread, &attr, threadRoutine,(void *)0);
    }

    if(rc) 
    {
      printf("ERROR:return code from pthread_create %d\n",rc);
      exit(-1);
    }
    pthread_exit(NULL);
}

【问题讨论】:

  • 当您说“所以,请不要说不要使用它并以不同的方式做事”时,您是在要求人们不要回答您的问题。如果您想要一个有用的答案,请向我们展示您真正想要做什么,而不是提出“练习”。

标签: c linux 64-bit x86


【解决方案1】:

我认为您的问题与fork() 不重现子进程中的线程(存在于调用fork 的父进程中)这一事实有关。在 fork() 之后,子进程中只存在一个线程。

另外,您应该始终在longjmp 之前调用setjmp,这样您的线程例程不正确。当然,你不应该 longjmp 进入 另一个 线程。

不要在没有大量预防措施的情况下使用带有 fork 的线程。详细了解pthread_atfork

我真的不明白你为什么要做这一切。我仍然认为你不应该那样编码(或者你没有足够解释你为什么要这样做,以及为什么要这样做)。

问候。

【讨论】:

  • 是的,我知道,这就是我做这个练习的原因。看看是否有可能在分叉的进程中复活死线程。你是对的,不应该在 longjmp 之前调用 setjmp,也许我应该在第一个 pthread_create 之后和从原始线程执行 setjmp 之后设置一个障碍。我在这里要做的是为原始线程和处于分叉进程和 CPU 状态的线程提供相同的堆栈,我试图用 setjmp/longjmp 保存。
  • 现在已经设置了barriers,使得原进程threadRoutine的setjmp在forked进程的threadRoutine调用longjmp之前被调用。
  • 使用这种机制复活线程是完全未定义的。 setjmp/longjmp 仅定义为在同一线程内使用,并没有保存足够的状态以供跨线程使用。如果您尝试在分叉后在子进程中重新创建在父进程中运行的线程,那么您应该使用协程进行设计,在其中强制所有线程在分叉之前“加入”,然后从已知线程中恢复它们子进程中的状态。通常尝试在不支持它的操作系统上为多线程进程实现 forkall 类似于进程挂起/恢复
  • Petesh,是的,这正是我正在尝试的。假设我有 4 个线程,我想做的是在障碍点分叉。并通过 setjmp/longjmp 的组合以及在原始进程和分叉进程中为线程使用相同的堆栈,尝试这样做。您说要从已知状态恢复它们。好的,但是我该怎么做,因为线程在分叉的进程中已经死了。我正在做的是针对死线程使用的同一堆栈区域调用 pthread_create 。事实上,我看到堆栈仍然完好无损。 setjmp 额外提供堆栈指针、指令指针等内容。
猜你喜欢
  • 1970-01-01
  • 2020-04-11
  • 2015-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-24
  • 2022-01-27
  • 2017-12-28
相关资源
最近更新 更多