2013-03-27 45 views
6

Tôi đã giảm một mã bộ lập lịch sợi lớn đang tạo ra vấn đề cho các dòng bên dưới.
Điều tôi mong đợi là sự trở lại sạch sẽ trong bối cảnh, được truyền cho người xử lý, mọi lúc.
Điều tôi nhận được là "Trình xử lý" được in ra ba lần và sau đó là Lỗi phân đoạn.Sử dụng tham số thứ ba (void * context) của một trình xử lý sigaction với kết quả SIG_INFO trong một lỗi phân đoạn

#include <ucontext.h> 
#include <signal.h> 
#include <stdio.h> 

ucontext_t currently_executed_context; 

void handler_sigusr1(int signum, siginfo_t* siginfo, void* context) 
{ 
    currently_executed_context = (*(ucontext_t*)context); 

    printf("Handler. "); 
    setcontext(&currently_executed_context); 
} 

int main() 
{ 
    setbuf(stdout,0); 

    struct sigaction action_handler; 

    action_handler.sa_sigaction = handler_sigusr1; 
    action_handler.sa_flags = SA_SIGINFO; 

    sigaction(SIGUSR1,&action_handler,NULL); 

    for(;;) { kill(getpid(),SIGUSR1); sleep(1); } 

    return 0; 
} 

Được sử dụng cả hai gcc-4.4.3 và gcc-4.4.5 trên hai bản phân phối Linux khác nhau.

+0

Không chắc chắn 100% về điều này, nhưng bạn có thực sự cần sao chép 'ucontext_t' như thế không? Thay vào đó, chỉ cần làm 'setcontext ((ucontext_t *) context);' trong handler của bạn (đúc 'void *' sang đúng loại và truyền nó lên ...). – twalberg

+0

Luôn luôn an toàn hơn khi lấy dữ liệu mà con trỏ trỏ tới (khi đối tượng gốc không cần thiết hoặc lớn), đặc biệt trong trường hợp bạn có thể mất nó. Ngoài ra, do thiếu ý tưởng và vài giờ thay đổi, tôi đã thử mọi biến thể của giải pháp đó (và thậm chí đã thử lại nó ngay bây giờ chỉ để chắc chắn) - không đi. –

+0

Nói chung, tôi đồng ý về an toàn, nhưng tôi đã lưu ý trang người dùng cho 'setcontext()' tuyên bố 'ucontext_t' * phải * là một từ xuất phát từ' getcontext() ',' makecontext() ', hoặc là thông số được truyền đến một trình xử lý tín hiệu, mà bản sao chép thủ công bỏ qua. Không chắc làm thế nào làm một bản sao byte-khôn ngoan của cấu trúc có thể làm mất hiệu lực đó, nhưng figured nó không làm tổn thương để yêu cầu ... – twalberg

Trả lời

1

Tại thời điểm này, nghiên cứu của riêng tôi về vấn đề này có thể được cung cấp dưới dạng câu trả lời một phần.

Trước hết, tôi đã tìm thấy this article, cũ và không trích dẫn bất kỳ nguồn thông tin chính thức nào: http://zwillow.blogspot.com/2007/04/linux-signal-handling-is-broken.html. Đây là trích dẫn có liên quan:

Vấn đề thứ hai: Bạn không thể sử dụng setcontext() để thoát xử lý tín hiệu và chuyển sang ngữ cảnh khác, đã lưu trước đó. (Hoặc, cho rằng vấn đề, bạn không thể sử dụng nó để trở về bối cảnh rất giống như thông qua như đối số cho xử lý tín hiệu.) Nói cách khác, xử lý tín hiệu như

static void sighandler(
    int signo, siginfo_t *psi, void *pv) 
{ 
    memcpy(puc_old, pv, sizeof(ucontext_t)); 
    /* choose another context to dispatch */ 
    setcontext(puc_another); 
} 

không hoạt động. Nó không khôi phục lại mặt nạ tín hiệu được chỉ định trong puc_other, không thiết lập lại ngăn xếp tín hiệu thay thế, vv Tuy nhiên, lược đồ này hoạt động hoàn hảo trên Solaris.

Nếu ai đó có thể xác nhận một phần về Solaris, nó sẽ được đánh giá cao. Thứ hai, sau khi nói chuyện với một giảng viên đại học, tôi đã hiểu rằng việc thiết lập/hoán đổi ngữ cảnh từ một trình xử lý tín hiệu không thẳng thắn như làm như vậy trong các tình huống khác. Đáng buồn thay, người đã giải thích điều này với tôi không thể cung cấp thêm chi tiết vào thời điểm đó.

Do đó, cả hai nguồn của tôi dường như không hoàn toàn đáng tin cậy, nhưng dù sao cũng là manh mối.