Bagaimana saluran I / O diimplementasikan di kernel Linux?

8

stdin, stdout, stderr adalah beberapa bilangan bulat yang mengindeks ke dalam struktur data yang 'tahu' saluran I / O mana yang akan digunakan untuk proses tersebut. Saya mengerti struktur data ini unik untuk setiap proses. Apakah saluran I / O tidak lain adalah struktur susunan data dengan alokasi memori dinamis?

KawaiKx
sumber
oleh saluran I / O maksud Anda aliran atau pipa? juga, ini mungkin bervariasi berdasarkan kernel. Anda mungkin perlu bertanya tentang kernel tertentu.
strugee
1
@ Strugee Saya berbicara tentang kernel Linux. Maksud saya stream oleh saluran I / O. Bagaimana stream ini diimplementasikan di linux? beberapa array atau sesuatu?
KawaiKx

Jawaban:

14

Dalam Unix-seperti sistem operasi, standar input, output dan kesalahan sungai diidentifikasi oleh deskriptor file 0, 1, 2. Di Linux, ini terlihat di bawah sistem procfile di /proc/[pid]/fs/{0,1,2}. File-file ini sebenarnya tautan simbolis ke perangkat pseudoterminal di bawah /dev/ptsdirektori.

Pseudoterminal (PTY) adalah sepasang perangkat virtual, master pseudoterminal (PTM) dan budak pseudoterminal (PTS) (secara kolektif disebut sebagai pasangan pseudoterminal ), yang menyediakan saluran IPC, agak seperti pipa dua arah antara sebuah program yang mengharapkan untuk dihubungkan ke perangkat terminal , dan program driver yang menggunakan pseudoterminal untuk mengirim input, dan menerima input dari program sebelumnya.

Poin kuncinya adalah bahwa budak pseudoterminal muncul seperti terminal biasa, misalnya ia dapat beralih antara mode noncanonical dan canonical (default), di mana ia menafsirkan karakter input tertentu, seperti menghasilkan SIGINTsinyal ketika karakter interupsi (biasanya dihasilkan dengan menekan Ctrl+ Cpada keyboard) ditulis ke master pseudoterminal atau menyebabkan berikutnya read()kembali 0ketika karakter akhir file (biasanya dihasilkan oleh Ctrl+ D) ditemukan. Operasi lain yang didukung oleh terminal menghidupkan atau mematikan gema, mengatur grup proses latar depan dll.

Pseudoterminals memiliki sejumlah kegunaan:

  • Mereka memungkinkan program suka sshmengoperasikan program berorientasi terminal pada host lain yang terhubung melalui jaringan. Program berorientasi terminal dapat berupa program apa pun, yang biasanya dijalankan dalam sesi terminal interaktif. Input standar, keluaran dan kesalahan dari program semacam itu tidak dapat dihubungkan secara langsung ke soket, karena soket tidak mendukung fungsionalitas terkait terminal yang disebutkan di atas.

  • Mereka memungkinkan program suka expectmenggerakkan program berorientasi terminal interaktif dari sebuah skrip.

  • Mereka digunakan oleh emulator terminal seperti xtermuntuk menyediakan fungsionalitas terkait terminal.

  • Mereka digunakan oleh program-program seperti screenuntuk multiplex terminal fisik tunggal antara beberapa proses.

  • Mereka digunakan oleh program-program seperti scriptuntuk merekam semua input dan output yang terjadi selama sesi shell.

PTYs Unix98-style , digunakan di Linux, diatur sebagai berikut:

  • Program driver membuka master multiplexer pseudo-terminal dev/ptmx, di mana ia menerima deskriptor file untuk PTM, dan perangkat PTS dibuat dalam /dev/ptsdirektori. Setiap deskriptor file yang diperoleh dengan membuka /dev/ptmxadalah PTM independen dengan PTS terkaitnya sendiri.

  • Program driver memanggil fork()untuk membuat proses anak, yang pada gilirannya melakukan langkah-langkah berikut:

    • Anak memanggil setsid()untuk memulai sesi baru, di mana anak adalah pemimpin sesi. Ini juga menyebabkan anak kehilangan terminal pengendali .

    • Anak melanjutkan untuk membuka perangkat PTS yang sesuai dengan PTM yang dibuat oleh program driver. Karena anak adalah pemimpin sesi, tetapi tidak memiliki terminal pengendali, PTS menjadi terminal pengendali anak.

    • Anak itu menggunakan dup()untuk menduplikasi deskriptor file untuk perangkat slave di atasnya input standar, output, dan kesalahan.

    • Terakhir, panggilan anak exec()untuk memulai program berorientasi terminal yang akan terhubung ke perangkat pseudoterminal.

Pada titik ini, apa pun yang ditulis oleh program driver ke PTM, muncul sebagai input untuk program berorientasi terminal pada PTS, dan sebaliknya.

Saat beroperasi dalam mode kanonik, input ke PTS buffered baris demi baris. Dengan kata lain, seperti halnya terminal reguler, program yang membaca dari PTS hanya menerima satu input ketika karakter baris baru ditulis ke PTM. Ketika kapasitas buffering habis, write()panggilan selanjutnya memblokir sampai beberapa input dikonsumsi.

Dalam kernel Linux, file terkait panggilan sistem open(), read(), write() stat()dll dilaksanakan di Filesystem (VFS) lapisan virtual, yang menyediakan antarmuka sistem file yang seragam untuk program userspace. VFS memungkinkan implementasi sistem file yang berbeda untuk hidup berdampingan dalam kernel. Ketika program userspace memanggil panggilan sistem yang disebutkan di atas, VFS mengalihkan panggilan ke implementasi sistem file yang sesuai.

Perangkat PTS di bawah /dev/ptsdikelola oleh devptsimplementasi sistem file yang ditentukan dalam /fs/devpts/inode.c, sedangkan driver TTY yang menyediakan ptmxperangkat gaya Unix98 didefinisikan di dalam drivers/tty/pty.c.

Buffer antara perangkat TTY dan disiplin garis TTY , seperti pseudoterminals, disediakan struktur buffer yang dipertahankan untuk setiap perangkat tty, yang didefinisikan dalaminclude/linux/tty.h

Sebelum kernel versi 3.7, buffer adalah buffer balik :

#define TTY_FLIPBUF_SIZE 512

struct tty_flip_buffer {
        struct tq_struct tqueue;
        struct semaphore pty_sem;
        char             *char_buf_ptr;
        unsigned char    *flag_buf_ptr;
        int              count;
        int              buf_num;
        unsigned char    char_buf[2*TTY_FLIPBUF_SIZE];
        char             flag_buf[2*TTY_FLIPBUF_SIZE];
        unsigned char    slop[4];
};

Struktur berisi penyimpanan dibagi menjadi dua buffer ukuran yang sama. Buffer diberi nomor 0(paruh pertama char_buf/flag_buf) dan 1(babak kedua). Driver menyimpan data ke buffer yang diidentifikasi oleh buf_num. Buffer lain dapat disiram ke garis disiplin.

Buffer 'dibalik' dengan beralih buf_numantara 0dan 1. Ketika buf_numdiubah, char_buf_ptrdan flag_buf_ptr diatur ke awal buffer diidentifikasi oleh buf_num, dan countdiatur ke 0.

Sejak kernel versi 3.7, buffer flip TTY telah diganti dengan objek yang dialokasikan melalui kmalloc()cincin yang diatur . Dalam situasi normal untuk port serial yang digerakkan IRQ dengan kecepatan tipikal, perilaku mereka hampir sama dengan flip buffer lama; dua buffer akhirnya dialokasikan dan siklus kernel di antara mereka seperti sebelumnya. Namun, ketika ada penundaan atau kecepatan meningkat, implementasi buffer baru berkinerja lebih baik karena kumpulan buffer dapat tumbuh sedikit.

Thomas Nyman
sumber
Jawaban sepengetahuan ini sangat sulit didapat.
étale-cohomology
-1

Dari halaman manual untuk salah satu dari ketiganya menjelaskan jawabannya:

   Under  normal circumstances every UNIX program has three streams opened
   for it when it starts up, one for input, one for output,  and  one  for
   printing diagnostic or error messages.  These are typically attached to
   the user's terminal but might instead  refer  to  files  or
   other  devices,  depending  on what the parent process chose to set up.

   The input stream is referred to as "standard input"; the output  stream
   is  referred  to as "standard output"; and the error stream is referred
   to as "standard error".  These terms are abbreviated to form  the  sym-
   bols used to refer to these files, namely stdin, stdout, and stderr.

   Each  of these symbols is a stdio(3) macro of type pointer to FILE, and
   can be used with functions like fprintf(3) or fread(3).

   Since FILEs are a buffering wrapper around UNIX file  descriptors,  the
   same  underlying  files  may  also  be accessed using the raw UNIX file
   interface, that is, the functions like read(2) and lseek(2).

   On program startup, the integer file descriptors  associated  with  the
   streams  stdin,  stdout, and stderr are 0, 1, and 2, respectively.  The
   preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are
   defined  with  these values in <unistd.h>.
Jeight
sumber
Jawaban ini menjelaskan implementasi stdin, stdoutdan stderrdari sudut pandang pustaka C, tetapi pertanyaannya secara eksplisit tentang implementasi kernel. Saya mencoba menjelaskan sudut pandang kernel dalam jawaban saya .
Thomas Nyman