2012-10-01 34 views
6

Tôi đang mã hóa một trình bao cơ bản trong C và tôi đang làm việc để tạm ngưng quá trình con ngay bây giờ.Sau khi tạm ngưng quá trình con bằng SIGTSTP, trình bao không phản hồi

Tôi nghĩ rằng trình xử lý tín hiệu của tôi là chính xác và quá trình con của tôi đang tạm dừng, nhưng sau đó, thiết bị đầu cuối phải quay lại quy trình gốc và điều đó không xảy ra.

Đứa trẻ bị tạm ngưng nhưng vỏ của tôi không đăng ký bất kỳ đầu vào hoặc đầu ra nào nữa. tcsetpgrp() dường như không giúp ích gì.

Dưới đây là xử lý tín hiệu của tôi trong mã shell của tôi cho SIGTSTP:

void suspend(int sig) { 
    pid_t pid; 
    sigset_t mask; 
    //mpid is the pgid of this shell. 
    tcsetpgrp(STDIN_FILENO, mpid); 
    tcsetpgrp(STDOUT_FILENO, mpid); 
    sigemptyset(&mask); 
    sigaddset(&mask, SIGTSTP); 
    sigprocmask(SIG_UNBLOCK, &mask, NULL); 
    signal(SIGTSTP, SIG_DFL); 
    //active.pid is the pid of the child currently in the fg. 
    if (active.pid != 0) { 
     kill(active.pid, SIGTSTP); 
    } 
    else{ 
     //if this code is being run in the child, child calls SIGTSTP on itself. 
     pid = getpid(); 
     if (pid != 0 && pid != mpid){ 
      kill(pid, SIGTSTP); 
     } 
    } 
    signal(SIGTSTP, suspend); 
} 

bất cứ ai có thể cho tôi biết những gì tôi đang làm sai?

Tôi có đang treo vỏ của mình cùng với đứa trẻ không và tôi có cần trả về stdin và stdout cho vỏ không? Làm thế nào tôi sẽ làm điều này?

Cảm ơn!

Trả lời

0

tcsetpgrp là để chỉ định công việc tiền cảnh là gì. Khi shell của bạn sinh ra một công việc ở nền trước (không có &), nó sẽ tạo ra một nhóm tiến trình mới và làm cho công việc tiền cảnh (của thiết bị đầu cuối điều khiển, không phải bất kỳ thứ gì trên STDIN). Sau đó, khi nhấn CTRL-Z, công việc đó sẽ nhận được TSTP. Đó là thiết bị đầu cuối đình chỉ công việc, không phải vỏ của bạn. Vỏ của bạn không nên bẫy TSTP hoặc gửi TSTP cho bất kỳ ai.

Nó chỉ nên wait() cho công việc mà nó đã sinh ra và phát hiện khi nó đã bị ngừng (và yêu cầu lại nhóm tiền cảnh và đánh dấu công việc là bị treo nội bộ). lệnh fg của bạn sẽ làm cho công việc của pgid nhóm quá trình foreground một lần nữa và gửi một SIGCONT với nó và chờ cho nó một lần nữa, trong khi bg sẽ chỉ gửi SIGCONT

+1

Cảm ơn bạn đã trả lời. Tôi đã cố gắng làm những gì bạn nói, nhưng khi tôi lấy đi bộ xử lý tín hiệu của tôi thiết bị đầu cuối chỉ đình chỉ cha mẹ và trở về bash. Tôi cần phụ huynh tiếp tục chạy. – user1710304

+1

Điều này là sai, không bắt SIGTSTP chắc chắn sẽ gây ra vỏ của mình để đình chỉ và sẽ cho phép các tiến trình trẻ em đi vào. Anh ta cần bắt nó để vỏ của anh ta không bị treo. Tôi đang đối mặt với cùng một vấn đề ngay bây giờ, ông phải đối mặt trước đó – Fingolfin

+1

@AdelQodmani, chỉ nhóm tiến trình tiền cảnh của thiết bị đầu cuối mới nhận được SIGTSTP khi bạn nhấn Ctrl-Z. Trình bao chỉ đợi kết thúc quá trình mà nó bắt đầu, nằm trong một nhóm tiến trình không phải là nhóm tiến trình nền trước của thiết bị đầu cuối. bạn có thể _ignore_ SIGTSTP nếu bạn thích, đó là có thể xảy ra những gì hầu hết các shell làm. Quan điểm của tôi là bạn cần phải chơi với nhóm tiến trình tiền cảnh của thiết bị đầu cuối. –

2

Đó là một câu hỏi cũ nhưng tôi vẫn nghĩ rằng tôi đã tìm thấy một câu trả lời.
Bạn đã không viết mã của cha mẹ bạn, nhưng tôi giả nhìn một cái gì đó của nó như:

int main(){ 
    pid_t pid = fork(); 
    if(pid == 0){ //child process 
     //call some program 
    else //parent process 
     wait(&status); //or waitpid(pid, &status, 0) 
     //continue with the program 
} 

vấn đề là với sự chờ đợi() hoặc waitpid(), nó trông như thế nào nếu bạn chạy chương trình của bạn trên OS giống như Ubuntu sau khi sử dụng Ctrl + Z quá trình con của bạn đang nhận được SIGTSTP nhưng hàm wait() trong quá trình cha mẹ vẫn đang chờ!

Cách đúng để thực hiện điều đó là thay thế wait() trong parent bằng pause() và thực hiện một handler khác bắt SIGCHLD. Ví dụ:

void sigHandler(int signum){ 
    switch(signum){ 
     case SIGCHLD: 
      // note that the last argument is important for the wait to work 
      waitpid(-1, &status, WNOHANG); 
      break; 
    } 
} 

Trong trường hợp này sau khi quá trình con nhận Ctrl +Z quá trình cha mẹ cũng nhận SIGCHLD và tạm dừng() trả lại.

0

Tôi có thể đến muộn để trả lời câu hỏi ở đây nhưng đây là những gì đã làm việc khi tôi bị mắc kẹt với cùng một vấn đề.Theo các trang người đàn ông cho tcsetpgrp()

Chức năng tcsetpgrp() làm cho nhóm quá trình với nhóm quá trình ID pgrp nhóm foreground quá trình trên thiết bị đầu cuối liên quan đến fd, mà phải là thiết bị đầu cuối kiểm soát của quá trình gọi điện thoại và vẫn được liên kết với phiên của nó. Hơn nữa, pgrp phải là một nhóm quá trình (nonempty) thuộc cùng một phiên như quy trình gọi số .

Nếu tcsetpgrp() được gọi bởi một thành viên của một nhóm quá trình nền trong phiên của nó, và quá trình gọi không chặn hoặc bỏ qua SIGTTOU, một tín hiệu SIGTTOU được gửi đến tất cả các thành viên của nhóm tiến trình nền này.

Vì vậy, những gì hiệu quả đối với tôi là bỏ qua tín hiệu SIGTTOU trong chương trình vỏ, trước khi tôi tạo các quy trình sẽ đến nền trước. Nếu tôi không bỏ qua tín hiệu này, thì hạt nhân sẽ gửi tín hiệu này đến chương trình shell của tôi và tạm ngưng nó.

Các vấn đề liên quan