เชลล์แบบโต้ตอบควรทำอย่างไรในกลุ่มกระบวนการที่ถูกโยงถึง


10

(โพสต์ซ้ำในยูนิกซ์ตามคำแนะนำใน/programming/13718394/what-should-interactive-shells-do-in-orphaned-process-group )

คำถามสั้น ๆ คือเชลล์ควรทำอย่างไรถ้าอยู่ในกลุ่มกระบวนการที่ถูกโยงถึงที่ไม่มี tty อยู่? แต่ฉันแนะนำให้อ่านคำถามยาว ๆ เพราะมันสนุก

นี่คือวิธีที่สนุกและน่าตื่นเต้นในการเปลี่ยนแล็ปท็อปของคุณให้เป็นเครื่องทำพื้นที่พกพาโดยใช้เปลือกที่คุณชื่นชอบ (ยกเว้นว่าคุณเป็นหนึ่งในพวก tcsh weirdos):

#include <unistd.h>   
int main(void) {
    if (fork() == 0) {
        execl("/bin/bash", "/bin/bash", NULL);
    }
    return 0;
}

ทำให้ bash ตรึง CPU ที่ 100% zsh และปลาทำแบบเดียวกันในขณะที่ ksh และ tcsh พึมพำอะไรบางอย่างเกี่ยวกับการควบคุมงานและจากนั้นก็กระดูกงูซึ่งดีกว่าเล็กน้อย แต่ไม่มาก โอ้และเป็นผู้กระทำความผิดที่ไม่เชื่อเรื่องพระเจ้าแพลตฟอร์ม: OS X และ Linux ได้รับผลกระทบทั้งคู่

คำอธิบายของฉัน (อาจผิด) เป็นดังนี้: เปลือกลูกตรวจพบว่าไม่ได้อยู่เบื้องหน้า: tcgetpgrp(0) != getpgrp(). ดังนั้นจึงพยายามหยุดตัวเอง: killpg(getpgrp(), SIGTTIN). แต่กลุ่มกระบวนการของมันเป็นเด็กกำพร้าเนื่องจากผู้ปกครอง (โปรแกรม C) เป็นผู้นำและเสียชีวิตและSIGTTINส่งไปยังกลุ่มกระบวนการที่ถูกกำพร้าเพียงแค่ตกหล่น (ไม่เช่นนั้นจะไม่สามารถเริ่มต้นได้อีก ดังนั้นเปลือกลูกจะไม่หยุดทำงาน แต่ก็ยังคงอยู่ในพื้นหลังดังนั้นมันจะทำอีกครั้งทันที ล้างและทำซ้ำ

คำถามของฉันคือเชลล์บรรทัดคำสั่งจะตรวจสอบสถานการณ์นี้ได้อย่างไรและสิ่งที่ถูกต้องสำหรับการทำคืออะไร ฉันมีวิธีแก้ปัญหาสองข้อไม่เหมาะอย่างยิ่ง:

  1. ลองส่งสัญญาณกระบวนการที่ pid ตรงกับ ID กลุ่มของเรา ถ้าสิ่งนั้นล้มเหลวESRCHนั่นหมายความว่าเราอาจกำพร้า
  2. /dev/ttyลองอ่านไม่ปิดกั้นของหนึ่งไบต์จาก ถ้าสิ่งนั้นล้มเหลวEIOนั่นหมายความว่าเราอาจกำพร้า

(ปัญหาของเราติดตามนี่คือhttps://github.com/fish-shell/fish-shell/issues/422 )

ขอบคุณสำหรับความคิดของคุณ!

คำตอบ:


4

ฉันเห็นด้วยกับการวิเคราะห์ของคุณและฉันเห็นว่าดูเหมือนว่าคุณต้องตรวจสอบว่ากลุ่มกระบวนการของคุณเป็นเด็กกำพร้าหรือไม่

tcsetattrนอกจากนี้ยังหมายถึงการส่งคืนEIOถ้ากลุ่มกระบวนการนั้นถูกกำพร้า (และเราไม่ได้ปิดกั้น / เพิกเฉย SIGTT OUซึ่งอาจเป็นวิธีที่รบกวนน้อยกว่าreadบนเทอร์มินัล

โปรดทราบว่าคุณสามารถทำซ้ำได้ด้วย:

(bash<&1 &)

คุณต้องเปลี่ยนเส้นทางมิฉะนั้น stdin จะถูกเปลี่ยนเส้นทางไปที่ / dev / null เมื่อใช้คำสั่งในพื้นหลัง

(bash<&1 & sleep 2)

ให้พฤติกรรมที่น่ากลัวยิ่งขึ้นเพราะคุณจบลงด้วยการอ่านกระสุนสองอันจากเทอร์มินัล พวกเขาไม่สนใจSIGTTINและตัวใหม่ไม่ได้ตรวจพบเมื่อเริ่มต้นแล้วจะไม่อยู่ในกลุ่มกระบวนการพื้นหน้าอีกต่อไป

ksh93วิธีแก้ปัญหาของมันก็ไม่ได้เลวร้ายเพียงแค่ขึ้นไป 20 ครั้ง (แทนอนันต์) ผ่านลูปนั้นก่อนที่จะยอมแพ้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.