ท่อทำงานอย่างไรใน Linux


25

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

  • Linux มี VFS เรียกว่า pipefs ที่ติดตั้งในเคอร์เนล (ไม่ใช่ในพื้นที่ผู้ใช้)
  • pipefs มีซุปเปอร์บล็อกเดียวและติดตั้งที่รูทของมันเอง ( pipe:) ข้างๆ/
  • pipefs ไม่สามารถดูได้โดยตรงเหมือนกับระบบไฟล์ส่วนใหญ่
  • รายการไปยัง pipefs คือผ่านpipe(2)syscall
  • pipe(2)syscall ใช้โดยเปลือกหอยสำหรับท่อกับ|ผู้ประกอบการ (หรือด้วยตนเองจากกระบวนการอื่น ๆ ) สร้างไฟล์ใหม่ใน pipefs ซึ่งทำงานสวยมากเช่นไฟล์ปกติ
  • ไฟล์ทางด้านซ้ายของผู้ประกอบการไปป์ได้stdoutถูกเปลี่ยนเส้นทางไปยังไฟล์ชั่วคราวที่สร้างขึ้นใน pipefs
  • ไฟล์ทางด้านขวาของผู้ปฏิบัติงานไปป์มี stdinไพพ์ตั้งค่าไฟล์ไว้ที่ pipefs
  • pipefs ถูกเก็บไว้ในหน่วยความจำและผ่านเคอร์เนลเวทย์มนตร์บางอย่างไม่ควรทำเพจ

นี่คือคำอธิบายว่าท่ออย่างไร (เช่น ls -la | less ) ว่าถูกต้องหรือไม่?

สิ่งหนึ่งที่ผมไม่เข้าใจคือวิธีการบางอย่างเช่นทุบตีจะตั้งเป็นกระบวนการstdinหรือจะอธิบายไฟล์ที่ส่งกลับโดยstdout pipe(2)ฉันยังไม่พบอะไรเกี่ยวกับสิ่งนั้น


โปรดทราบว่าคุณกำลังพูดถึงสองชั้นที่ต่างกันอย่างมากโดยใช้ชื่อเดียวกัน การpipe()เรียกเคอร์เนลพร้อมกับเครื่องจักรที่รองรับ ( pipefsฯลฯ ) นั้นต่ำกว่า|โอเปอเรเตอร์ที่มีให้ในเปลือก หลังมักจะใช้งานโดยใช้อดีต แต่ไม่จำเป็นต้องเป็น
Greg Hewgill

ใช่ฉันหมายถึงการปฏิบัติการระดับล่างโดยเฉพาะโดยมีข้อสันนิษฐานว่า|โอเปอเรเตอร์กำลังเรียกpipe(2)เช่นเดียวกับกระบวนการที่ทุบตี
Brandon Wamboldt

คำตอบ:


19

การวิเคราะห์ของคุณถูกต้องแล้ว วิธีที่เชลล์อาจตั้งค่า stdin ของกระบวนการเป็น pipe descriptor อาจเป็น (pseudocode):

pipe(p) // create a new pipe with two handles p[0] and p[1]
fork() // spawn a child process
    close(p[0]) // close the write end of the pipe in the child
    dup2(p[1], 0) // duplicate the pipe descriptor on top of fd 0 (stdin)
    close(p[1]) // close the other pipe descriptor
    exec() // run a new process with the new descriptors in place

ขอบคุณ! แค่อยากรู้ว่าทำไมต้องใช้การdup2โทรและคุณไม่สามารถกำหนดให้ตัวบ่งชี้ไปยัง stdin ได้โดยตรง
Brandon Wamboldt

3
pipe()โทรไม่ได้รับการเลือกสิ่งที่ค่าตัวเลขของการอธิบายไฟล์คือเมื่อมันถูกสร้างขึ้นใน การdup2()โทรอนุญาตให้ผู้เรียกคัดลอก file descriptor ไปเป็นค่าตัวเลขเฉพาะ (จำเป็นเนื่องจาก 0, 1, 2 คือ stdin, stdout, stderr) นั่นคือเทียบเท่าเคอร์เนลของ "การกำหนดโดยตรงกับ stdin" โปรดทราบว่าตัวแปรโกลบอลไลบรารีรันไทม์ C stdinคือ a FILE *ซึ่งไม่เกี่ยวข้องกับเคอร์เนล (แม้ว่าจะถูกกำหนดค่าเริ่มต้นให้เชื่อมต่อกับ descriptor 0)
Greg Hewgill

คำตอบที่ดี! ฉันเสียรายละเอียดไปเล็กน้อย แค่สงสัยว่าทำไมคุณถึงปิด (p [1]) ก่อนจะเรียกใช้ exec ()? เมื่อ dup2 ส่งคืนจะไม่ p [1] ชี้ไปที่ fd 0 หรือไม่ จากนั้นปิด (p [1]) ปิดตัวอธิบายไฟล์ 0 แล้วเราจะอ่านจาก stdin ของกระบวนการลูกได้อย่างไร?
user1559897

@ user1559897 การโทรไม่เปลี่ยนแปลงdup2 p[1]แต่จะทำให้ทั้งสองจัดการp[1]และ0ชี้ไปที่วัตถุเคอร์เนลเดียวกัน (ไปป์) ตั้งแต่กระบวนการเด็กไม่จำเป็นต้องสองมือจับ stdin (และจะได้รู้ว่าสิ่งที่จับหมายเลขที่มีความp[1]เป็นอยู่ดี) ปิดให้บริการก่อนp[1] exec
เกร็กฮิวกิล

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