2012-07-16 2 views
0

나는 progame 스택을 변경하기 위해 sigsetjmp/siglongjmp를 사용한다. 데모입니다 :C를 사용하여 프레임 워크를 만들고 erlang과 같은 미래를 보자.

#include <stdio.h> 
#include <stddef.h> 
#include <setjmp.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <string.h> 
#include <unistd.h> 
#define POOLSIZE 4096 
int active = 0; 
int total = 0; 

struct thread 
{ 
    int tid; 
    sigjmp_buf env; 
    char buf[4096]; 
    int state; 
    ssize_t size; 
}; 

struct thread *thread_pool = 0L; 
char* anchor_beg = 0L; 
char* anchor_end = 0L; 
void(*new_thread)(int) = 0L; 


void sig_call(int sig) 
{ 
    char anchor; 
    anchor_end = &anchor; 
    if(sigsetjmp(thread_pool[active].env, 0) == 0) 
    { 
     thread_pool[active].size = anchor_beg - anchor_end; 
     memcpy(thread_pool[active].buf, anchor_end, thread_pool[active].size); 
     siglongjmp(thread_pool[0].env, 1); 
    } 
    else 
    { 
     memcpy(anchor_beg - thread_pool[active].size, thread_pool[active].buf, thread_pool[active].size); 
    } 
} 

void thread_new(void(*pfn)(int)) 
{ 
    alarm(0); 
    new_thread = pfn; 
    thread_pool[0].state = 2; 
// printf("create new thread:%d\n", total + 1); 
    raise(SIGUSR1); 
} 

void test(int thread) 
{ 
    int i = 0; 
    for(;i != 1000000; i++) 
    { 
    } 
} 

void thread_main(int thread) 
{ 
    int i = 0; 
    for(i = 0; i < 4000; i++) 
     thread_new(test); 
} 

void call(void(*pfn)(int)) 
{ 
    active = ++ total; 
    thread_pool[active].tid = active; 
    thread_pool[active].state = 1; 
    ualarm(500, 0); 
    pfn(active); 
    thread_pool[active].state = 0; 
} 

void dispatcher() 
{ 
    thread_pool = (struct thread*)malloc(sizeof(struct thread) * POOLSIZE); 
    char anchor; 
    anchor_beg = &anchor; 
    thread_pool[0].tid = 0; 
    thread_pool[0].state = 1; 
    if(sigsetjmp(thread_pool[0].env, 0) == 0) 
    { 
     signal(SIGUSR1, sig_call); 
     signal(SIGALRM, sig_call); 

     call(thread_main); 
    } 
    else if(thread_pool[0].state == -1) 
    { 
     return; 
    } 
    else if(thread_pool[0].state == 2) 
    { 
     thread_pool[0].state = 1; 
     call(new_thread); 
    } 

    while(1) 
    { 
     int i, alive = 0; 
     for(i = 1; i <= total; i++) 
     { 
      if(thread_pool[i].state == 1) 
      { 
       alive ++; 
       ualarm(500, 0); 
       active = thread_pool[i].tid; 
       siglongjmp(thread_pool[i].env, 1); 
      } 
     } 
     if(alive == 0) 
      return; 
    } 

} 


int main() 
{ 
    dispatcher(); 
} 

여기에 어떤 문제가 있습니까? 그리고 제 3 자 인터페이스를 호출하고 블록 I/O가있을 때 실행할 다른 문맥을 변경할 수 있습니까? 그리고 어떻게?

답변

3

불행하게도, 당신이 뭘하려는 건지 때문에합니다 (setjmp 수동 당), 작동하지 않습니다

The longjmp() routines may not be called after the routine which called 
the setjmp() routines returns. 

을합니다 (sig 변종 포함) 기능의 setjmp/longjmp 가족이 할 수 있기 때문입니다 프로세스 스택의 전체 내용을 보존하지 않습니다.

+0

스택을 jmp 앞에 힙에 복사하여 백업 했으므로 다른 jmp 후에 다시 시작할 수 있습니다. – user1400047

+2

그건 확실히 창의적이지만 여전히 안정적으로 작동하지는 않습니다. 이것을 원한다면 ucontext 함수 ('makecontext','getcontext','setcontext')를보십시오. – duskwuff

관련 문제