GNU/Linux >> Belajar Linux >  >> Linux

O_RDWR pada pipa bernama dengan poll()

Menurut halaman manual open(2), Anda dapat meneruskan O_RDONLY|O_NONBLOCK atau O_WRONLY|O_NONBLOCK untuk menghindari open syscall untuk diblokir (Anda akan mendapatkan errno == ENXIO dalam hal ini)

Saat saya berkomentar, baca juga halaman manual fifo(7) dan mkfifo(3).


Pertama, beberapa pendahuluan:

Menggunakan O_NONBLOCK dan poll() adalah praktik umum - bukan sebaliknya. Agar berhasil bekerja, Anda harus memastikan untuk menangani semua poll() dan read() mengembalikan status dengan benar:

  • read() mengembalikan nilai 0 berarti EOF - pihak lain telah menutup koneksinya. Ini sesuai (biasanya, tetapi tidak pada semua OS) ke poll() mengembalikan POLLHUP revent. Anda mungkin ingin memeriksa POLLHUP sebelum mencoba read() , tetapi tidak mutlak diperlukan sejak read() dijamin akan mengembalikan 0 setelah sisi tulisan ditutup.
  • Jika Anda memanggil read() sebelum seorang penulis terhubung, dan Anda memiliki O_RDONLY | O_NONBLOCK , Anda akan mendapatkan EOF (read() mengembalikan 0 ) berulang kali, seperti yang Anda perhatikan. Namun, jika Anda menggunakan poll() untuk menunggu POLLIN acara sebelum memanggil read() , itu akan menunggu penulis terhubung, dan tidak menghasilkan EOF.
  • read() mengembalikan nilai -1 biasanya berarti kesalahan. Namun, jika errno == EAGAIN , ini berarti tidak ada lagi data yang tersedia saat ini dan Anda tidak memblokir, jadi Anda dapat kembali ke poll() jika perangkat lain perlu ditangani. Jika errno == EINTR , lalu read() terputus sebelum membaca data apa pun, dan Anda dapat kembali ke poll() atau cukup panggil read() lagi segera.

Sekarang, untuk Linux:

  • Jika Anda membuka di sisi baca dengan O_RDONLY , lalu:
    • open() akan memblokir sampai ada penulis yang sesuai terbuka.
    • poll() akan memberikan POLLIN revent saat data siap dibaca, atau EOF terjadi.
    • read() akan memblokir sampai jumlah byte yang diminta dibaca, koneksi ditutup (mengembalikan 0), itu terganggu oleh sinyal, atau terjadi kesalahan IO yang fatal. Jenis pemblokiran ini mengalahkan tujuan penggunaan poll() , itulah sebabnya poll() hampir selalu digunakan dengan O_NONBLOCK . Anda dapat menggunakan alarm() untuk bangun dari read() setelah waktu tunggu, tapi itu terlalu rumit.
    • Jika penulis menutup, maka pembaca akan menerima poll() POLLHUP revent dan read() akan mengembalikan 0 sesudahnya tanpa batas waktu. Pada titik ini, pembaca harus menutup pegangan file dan membukanya kembali.
  • Jika Anda membuka di sisi baca dengan O_RDONLY | O_NONBLOCK , lalu:
    • open() tidak akan memblokir.
    • poll() akan memberikan POLLIN revent ketika data siap dibaca, atau EOF terjadi. poll() juga akan memblokir sampai penulis tersedia, jika tidak ada.
    • Setelah semua data yang tersedia saat ini dibaca, read() akan mengembalikan -1 dan menyetel errno == EAGAIN jika koneksi masih terbuka, atau akan mengembalikan 0 jika koneksi ditutup (EOF) atau belum dibuka oleh penulis . Ketika errno == EAGAIN , ini berarti saatnya untuk kembali ke poll() , karena koneksi terbuka tetapi tidak ada data lagi. Ketika errno == EINTR , read() belum membaca byte dan terganggu oleh sinyal, sehingga dapat dimulai ulang.
    • Jika penulis menutup, maka pembaca akan menerima poll() POLLHUP revent, dan read() akan mengembalikan 0 sesudahnya tanpa batas waktu. Pada titik ini pembaca harus menutup pegangan file dan membukanya kembali.
  • (khusus Linux:) Jika Anda membuka di sisi baca dengan O_RDWR , lalu:
    • open() tidak akan memblokir.
    • poll() akan memberikan POLLIN revent ketika data siap untuk dibaca. Namun, untuk pipa bernama, EOF tidak akan menyebabkan POLLIN atau POLLHUP revents.
    • read() akan memblokir sampai jumlah byte yang diminta dibaca, itu terganggu oleh sinyal, atau terjadi kesalahan IO fatal lainnya. Untuk pipa bernama, itu tidak akan mengembalikan errno == EAGAIN , bahkan tidak akan mengembalikan 0 satu dari. Itu hanya akan duduk di sana sampai jumlah persis byte yang diminta dibaca, atau sampai menerima sinyal (dalam hal ini akan mengembalikan jumlah byte yang telah dibaca sejauh ini, atau mengembalikan -1 dan menyetel errno == EINTR jika tidak ada byte yang dibaca sejauh ini).
    • Jika penulis menutup, pembaca tidak akan kehilangan kemampuan untuk membaca pipa bernama nanti jika penulis lain membuka pipa bernama, tetapi pembaca juga tidak akan menerima pemberitahuan apa pun.
  • (khusus Linux:) Jika Anda membuka sisi baca dengan O_RDWR | O_NONBLOCK , lalu:
    • open() tidak akan memblokir.
    • poll() akan memberikan POLLIN revent ketika data siap untuk dibaca. Namun, EOF tidak akan menyebabkan POLLIN atau POLLHUP revent pada pipa bernama.
    • Setelah semua data yang tersedia saat ini dibaca, read() akan mengembalikan -1 dan atur errno == EAGAIN . Inilah saatnya untuk kembali ke poll() untuk menunggu lebih banyak data, kemungkinan dari aliran lain.
    • Jika penulis menutup, pembaca tidak akan kehilangan kemampuan untuk membaca pipa bernama nanti jika penulis lain membuka pipa bernama. Koneksi tetap ada.

Seperti yang Anda khawatirkan, gunakan O_RDWR dengan pipa tidak standar, POSIX atau di tempat lain.

Namun, karena pertanyaan ini tampaknya sering muncul, cara terbaik di Linux untuk membuat "pipa bernama tangguh" yang tetap hidup meskipun satu sisi ditutup, dan yang tidak menyebabkan POLLHUP kembalikan atau kembalikan 0 untuk read() , adalah menggunakan O_RDWR | O_NONBLOCK .

Saya melihat tiga cara utama menangani pipa bernama di Linux:

  1. (Portabel.) Tanpa poll() , dan dengan satu pipa:

    • open(pipe, O_RDONLY);
    • Lingkaran utama:
      • read() data sebanyak yang diperlukan, mungkin berulang pada read() panggilan.
        • Jika read() == -1 dan errno == EINTR , read() lagi.
        • Jika read() == 0 , sambungan ditutup, dan semua data telah diterima.

  2. (Portabel.) Dengan poll() , dan dengan harapan bahwa pipa, bahkan yang bernama, hanya dibuka sekali, dan setelah ditutup, harus dibuka kembali oleh pembaca dan penulis, menyiapkan pipa baru:

    • open(pipe, O_RDONLY | O_NONBLOCK);
    • Lingkaran utama:
      • poll() untuk POLLIN peristiwa, mungkin pada beberapa pipa sekaligus. (Catatan:Ini mencegah read() dari mendapatkan beberapa EOF sebelum seorang penulis terhubung.)
      • read() data sebanyak yang diperlukan, kemungkinan pengulangan pada read() panggilan.
        • Jika read() == -1 dan errno == EAGAIN , kembali ke poll() langkah.
        • Jika read() == -1 dan errno == EINTR , read() lagi.
        • Jika read() == 0 , koneksi ditutup, dan Anda harus mengakhiri, atau menutup dan membuka kembali pipa.

  3. (Non-portabel, khusus Linux.) Dengan poll() , dan dengan harapan bahwa pipa bernama tidak pernah berakhir, dan dapat terhubung dan terputus berkali-kali:

    • open(pipe, O_RDWR | O_NONBLOCK);
    • Lingkaran utama:
      • poll() untuk POLLIN acara, mungkin di beberapa pipa sekaligus.
      • read() data sebanyak yang diperlukan, mungkin berulang pada read() panggilan.
        • Jika read() == -1 dan errno == EAGAIN , kembali ke poll() langkah.
        • Jika read() == -1 dan errno == EINTR , read() lagi.
        • Jika read() == 0 , ada yang salah -- seharusnya tidak terjadi dengan O_RDWR pada pipa bernama, tetapi hanya dengan O_RDONLY atau pipa tanpa nama; itu menunjukkan pipa tertutup yang harus ditutup dan dibuka kembali. Jika Anda mencampur pipa bernama dan tidak bernama dalam poll() yang sama loop penanganan peristiwa, kasus ini mungkin masih perlu ditangani.

Linux
  1. Bekerja dengan pipa di baris perintah Linux

  2. Membaca Baris Dari File Dengan Bash:Untuk Vs. Ketika?

  3. Apa yang poll() lakukan dengan batas waktu 0?

  1. Cara Menggunakan Pipes dan Named Pipes di Linux (dengan Contoh)

  2. Contoh penggunaan pipa bernama di Linux Bash

  3. Mengapa polling tidak diganti dengan epoll?

  1. Kesalahan Pada Kloning Disk Dengan Cat?

  2. Simulasikan perangkat blok yang rusak dengan kesalahan baca?

  3. Linux:apakah ada pembacaan atau pemulihan dari soket dengan batas waktu?