stdin, stdout, stderr - это некоторые целые числа, которые индексируют в структуре данных, которая «знает», какие каналы ввода / вывода должны использоваться для процесса. Я понимаю, что эта структура данных уникальна для каждого процесса. Являются ли каналы ввода-вывода ничем иным, как некоторыми структурами массивов данных с динамическим распределением памяти?
8
Ответы:
В Unix-подобных операционных системах, стандартные ввода, вывода и ошибок потоков определены файловых дескрипторов
0
,1
,2
. В Linux они видны вproc
файловой системе в/proc/[pid]/fs/{0,1,2}
. Эти файлы на самом деле являются символическими ссылками на псевдотерминальное устройство в/dev/pts
каталоге.Псевдотерминал (PTY) - это пара виртуальных устройств, главный псевдотерминал (PTM) и подчиненный псевдотерминал (PTS) (совместно именуемые псевдотерминальной парой ), которые обеспечивают канал IPC, что-то вроде двунаправленной трубы между программой, которая ожидает быть подключенным к терминальному устройству и программе драйвера, которая использует псевдотерминал для отправки ввода и получения ввода от предыдущей программы.
Ключевым моментом является то, что псевдотерминальный подчиненный выглядит как обычный терминал, например, он может переключаться между неканоническим и каноническим режимом (по умолчанию), в котором он интерпретирует определенные входные символы, например генерирует
SIGINT
сигнал, когда символ прерывания (обычно генерируется) нажатием Ctrl+ Cна клавиатуре) записывается в мастер псевдотерминала или вызываетread()
возврат следующего,0
когда встречается символ конца файла (обычно генерируемый Ctrl+ D). Другими операциями, поддерживаемыми терминалами, является включение или выключение эха, настройка группы процессов переднего плана и т. Д.Псевдотерминалы имеют ряд применений:
Они позволяют таким программам
ssh
управлять терминально-ориентированными программами на другом хосте, подключенном через сеть. Ориентированная на терминал программа может быть любой программой, которая обычно запускается в сеансе интерактивного терминала. Стандартный ввод, вывод и ошибка такой программы не могут быть подключены напрямую к сокету, так как сокеты не поддерживают вышеупомянутую функциональность, связанную с терминалом.Они позволяют таким программам
expect
управлять интерактивной терминально-ориентированной программой из сценария.Они используются эмуляторами терминала, например,
xterm
для обеспечения функциональности терминала.Они используются такими программами, как
screen
мультиплексирование одного физического терминала между несколькими процессами.Они используются такими программами, как
script
запись всех входных и выходных данных во время сеанса оболочки.PTY-файлы в стиле Unix98 , используемые в Linux, настраиваются следующим образом:
Программа драйвера открывает главный мультиплексор псевдотерминала
dev/ptmx
, на котором она принимает файловый дескриптор для PTM, и в/dev/pts
каталоге создается устройство PTS . Каждый дескриптор файла, полученный при открытии,/dev/ptmx
является независимым PTM со своим собственным PTS.Драйвер программы вызывает
fork()
для создания дочернего процесса, который, в свою очередь, выполняет следующие шаги:Ребенок вызывает,
setsid()
чтобы начать новый сеанс, из которых ребенок является лидером сеанса. Это также приводит к тому, что ребенок теряет свой контролирующий терминал .Ребенок переходит к открытию устройства PTS, которое соответствует PTM, созданному программой драйвера. Поскольку дочерний объект является лидером сеанса, но не имеет управляющего терминала, PTS становится управляющим терминалом дочернего объекта.
Дочерний объект использует
dup()
для дублирования файловый дескриптор для ведомого устройства на нем стандартный ввод, вывод и ошибку.Наконец, ребенок вызывает
exec()
запуск ориентированной на терминал программы, которая должна быть подключена к псевдотерминальному устройству.В этот момент все, что программа драйвера записывает в PTM, отображается как входная информация для ориентированной на терминал программы в PTS, и наоборот.
При работе в каноническом режиме вход в PTS буферизуется построчно. Другими словами, как и в случае с обычными терминалами, программа, считывающая данные из PTS, получает строку ввода только тогда, когда символ PTL записывается в PTM. Когда буферная емкость исчерпана, дальнейшие
write()
вызовы блокируются до тех пор, пока не будут использованы некоторые входные данные.В ядре Linux системные вызовы
open()
, связанные с файламиread()
,write()
stat()
и т. Д. Реализованы на уровне виртуальной файловой системы (VFS), который обеспечивает единый интерфейс файловой системы для программ пользовательского пространства. VFS позволяет различным реализациям файловой системы сосуществовать в ядре. Когда пользовательские программы вызывают вышеупомянутые системные вызовы, VFS перенаправляет вызов соответствующей реализации файловой системы.Устройства PTS ниже
/dev/pts
управляются реализациейdevpts
файловой системы, определенной в/fs/devpts/inode.c
, в то время как драйвер TTY, обеспечивающий устройство в стиле Unix98,ptmx
определен вdrivers/tty/pty.c
.Буферизация между устройствами TTY и дисциплинами линий TTY , такими как псевдотерминалы, обеспечивается структурой буфера, поддерживаемой для каждого устройства tty, определенной в
include/linux/tty.h
До версии ядра 3.7 буфер был перекидным :
Структура содержит хранилище, разделенное на два буфера одинакового размера. Буферы были пронумерованы
0
(первая половинаchar_buf/flag_buf
) и1
(вторая половина). Драйвер сохранил данные в буфере, указанномbuf_num
. Другой буфер может быть сброшен в дисциплину строки.Буфер был «перевернут» переключением
buf_num
между0
и1
. Когдаbuf_num
изменено,char_buf_ptr
иflag_buf_ptr
было установлено в начало буфера, идентифицированногоbuf_num
, иcount
было установлено в0
.Начиная с версии ядра 3.7, буферы переключения TTY были заменены объектами, выделенными через
kmalloc()
организованные в кольцах . В обычной ситуации для последовательного порта, управляемого IRQ, на типичных скоростях их поведение почти такое же, как и в случае старого откидного буфера; Два буфера в итоге распределяются, и ядро циклически переключается между ними, как и раньше Однако, когда есть задержки или скорость увеличивается, новая реализация буфера работает лучше, так как буферный пул может немного увеличиться.источник
Из справочных страниц для любого из трех он объясняет ответ:
источник
stdin
,stdout
иstderr
с точки зрения библиотеки C, но вопрос явно о реализации ядра. Я попытался объяснить точку зрения ядра в своем ответе .