2012-12-26 21 views
11

Tôi đang viết một mini-shell (không, không dành cho trường học: P; vì sự thích thú của riêng tôi) và hầu hết các chức năng cơ bản hiện đang được thực hiện nhưng tôi bị kẹt khi cố gắng xử lý SIGTSTP.waitpid chặn khi nó không nên

Giả sử, khi người dùng nhấn Ctrl+Z, SIGTSTP sẽ được gửi đến tiến trình Foreground của trình vỏ nếu nó tồn tại và Shell sẽ tiếp tục bình thường.

Sau khi tạo mỗi quá trình (nếu đó là một quá trình Foreground), đoạn code sau đợi:

if(waitpid(pid, &processReturnStatus, WUNTRACED)>0){//wait stopped too 
    if(WIFEXITED(processReturnStatus) || WIFSIGNALED(processReturnStatus)) 
     removeFromJobList(pid); 
} 

Và tôi xử lý các tín hiệu như sau:

void sigtstpHandler(int signum) 
{ 
    signum++;//Just to remove gcc's warning 
    pid_t pid = findForegroundProcessID(); 
    if(pid > -1){ 
     kill(-pid, SIGTSTP);//Sending to the whole group 
    } 
} 

gì xảy ra được khi tôi nhấn Ctrl+Z, quy trình con sẽ bị tạm ngưng thực sự (sử dụng ps -all để xem trạng thái của các quy trình) nhưng vỏ của tôi bị treo tại số waitpid r trả về ngay cả khi tôi đã thông qua cờ WUNTRACED mà theo như tôi hiểu là nghĩa vụ phải thực hiện trả lại waitpid khi quá trình được dừng lại quá.
Vì vậy, tôi có thể làm gì sai? hoặc tôi có hiểu hành vi của waitpid không chính xác không?

Ghi chú:
-findForegroundProcessID() trả về đúng pid; Tôi đã kiểm tra lại điều đó.
-Tôi đang thay đổi nhóm của mỗi quá trình khi ngay sau khi tôi fork
-Xử lý Ctrl+C đang làm việc tốt
-Nếu tôi sử dụng thiết bị đầu cuối khác để gửi SIGCONT sau khi bị treo vỏ của tôi, quá trình trẻ sơ yếu lý lịch công việc của mình và vỏ gặt nó cuối cùng.
-Tôi đang bắt SIGTSTP mà theo như tôi đọc (và thử nghiệm) có thể bị bắt. -Tôi đã thử sử dụng waitid thay vì waitpid trong trường hợp, sự cố vẫn tiếp diễn. EDIT:

void sigchldHandler(int signum) 
{ 
    signum++;//Just to remove the warning 
    pid_t pid; 
    while((pid = waitpid(-1, &processReturnStatus, 0)) > 0){  
     removeFromJobList(pid); 
    } 
    if(errno != ECHILD) 
     unixError("kill error"); 
} 

xử lý SIGCHLD My.

+0

IIUC, bạn đang cố gắng nắm bắt SIGSTP. Bạn không thể bắt SIGSTP hoặc SIGKILL. – wildplasser

+1

Tôi không chắc liệu SIGSTOP có giống SIGSTP hay không, nhưng theo một cuốn sách, SIGSTOP không thể bị bắt nhưng SIGTSTP có thể, trên thực tế tôi chắc chắn tôi đã bắt được nó vì tôi đã in một cái gì đó như một bài kiểm tra – Fingolfin

+0

Rất tiếc, xấu của tôi. Nếu tôi đọc chính xác, SIGTSTP đã được cố ý tạo ra để cho phép nó bị bắt, để cho phép nhóm tiến trình/nhóm thiết bị đầu cuối truyền bá nó giữa các thành viên của nó. Nếu cuốn sách bạn đề cập đến là APUE, bạn có thể sẽ làm điều đó một cách chính xác ... – wildplasser

Trả lời

1

SIGCHLD được gửi cho trẻ em đã dừng. Số điện thoại waitpid() gọi trong trình xử lý tín hiệu - không chỉ định WUNTRACED - chặn vĩnh viễn.

Bạn có lẽ không nên xử lý removeFromJobList() ở hai địa điểm khác nhau. Nếu tôi phải đoán, có vẻ như nó chạm vào cấu trúc dữ liệu toàn cầu, và không thuộc về một bộ xử lý tín hiệu.

+0

Tôi nên đọc thêm về SIGCHLD, thực sự bắt nó là nguyên nhân gây ra sự chờ đợi để chặn, không phải chờ đợi trong processCreation bu t thay vì chờ đợi bộ xử lý tín hiệu. Cảm ơn rất nhiều =) – Fingolfin

1

Waitpid không trả lại vì bạn không cài đặt trình xử lý sigchld (mà tôi đã gửi cho bạn trước đó). Bạn có tiến trình con không bị gặt hái. Hơn nữa, waitpid cần phải được trong một vòng lặp while, không phải là nếu (cũng đã gửi cho bạn rằng).

Tín hiệu duy nhất bạn bắt buộc phải là SIGCHLD. Lý do là nếu các quá trình của bạn được chia nhỏ đúng cách, hạt nhân sẽ gửi tín hiệu đó đến tiến trình nền trước và nó sẽ chấm dứt nó hoặc dừng nó hoặc làm bất cứ tín hiệu nào là đúng.

Khi nhóm xử lý không được đặt chính xác, tín hiệu sẽ được gửi đến quy trình không đúng. Một cách để kiểm tra đó là chạy một tiến trình nền trước và nhấn Ctrl-Z.Nếu toàn bộ hệ vỏ của bạn tồn tại, thì tín hiệu Ctrl-Z sẽ được gửi tới toàn bộ hệ vỏ. Điều này có nghĩa là bạn đã không thiết lập quy trình mới trong một nhóm quy trình mới và cho nó một thiết bị đầu cuối.

Bây giờ, đây là những gì bạn cần làm nếu tín hiệu Ctrl-Z của bạn dừng toàn bộ hệ vỏ. Một khi bạn ngã ba một quá trình, trong quá trình con: - Đặt quá trình trong nhóm riêng của mình bằng cách sử dụng setpgid. - Cung cấp cho nó một thiết bị đầu cuối lành mạnh bằng cách chặn SIGTTOU và sau đó cho nó thiết bị đầu cuối bằng cách sử dụng tcsetpgrp.

Trong phụ huynh: - Đồng thời đặt quá trình con bằng cách sử dụng setpgid. Điều này là bởi vì bạn không có ý tưởng nếu đứa trẻ hoặc cha mẹ sẽ thực hiện đầu tiên, do đó, điều này tránh được một điều kiện chủng tộc. Nó không đau để thiết lập nó hai lần.

+0

Cảm ơn bạn đã trả lời, tôi đang thiết lập một hanlder sigchld (do đó tại sao xử lý Ctrl + C hoạt động tốt). Điều này nghe có vẻ hơi kỳ lạ, bạn đang nói tín hiệu duy nhất mà tôi phải xử lý là SIGCHLD? nhưng tôi không nhận được SIGCHLD khi một đứa trẻ nhận được tín hiệu SIGTSTP nhưng tôi nghĩ rằng tôi có thể đã hiểu ý bạn là gì. Ý tưởng là tạo một quy trình mới cho thiết bị đầu cuối của riêng nó và tạo tiền cảnh cho nên khi Ctrl + Z đi, nó chỉ chạm vào tiến trình nền trước chứ không phải vỏ của tôi mà không xử lý Ctrl + Z hoàn toàn? – Fingolfin

+0

Tôi đang thiết lập trình xử lý tín hiệu của mình, như tôi đã nói ở trên, và bây giờ tôi đã xác nhận rằng quá trình con IS nhận tín hiệu và đang bị dừng nhưng chờ đợi vẫn không quay trở lại. – Fingolfin