LINUX.ORG.RU

Файловые дескрипторы

 , ,


1

2

Пытаюсь разобраться в файловых дескрипторах. Читаю разные статьи, пока не очень понятно как потрогать эти самые дескрипторы.

Вот я выбрал интересующий процесс (vlc с открытым фильмом).

pidof vlc

Получил его PID.

lsof -p PID

По идее это покажет список всех файлов, открытых процессом, а заодно и их дескрипторы. Ожидал увидеть 1 строку с названием фильма. А там (помимо фильма) - просто МИЛЛИОННАЯ ПРОСТЫНЯ! Сотни файлов типа dir, reg, chr, fifo, unix, a_inode. Что это такое?

Неужели, чтобы плеер запустил простое видео, нужно действительно открыть сотни этих файлов?

Отдельно заинтересовала графа FD (думал что это файловый дескриптор). Там всякие cwd, rtd, mem, del, txt... а ближе к концу вида «0r, 1w, 2w, 3r...26u...» и т.д. Что это означает? Я читал, что файловый дескриптор это целое число... Значит, это не файловый дескриптор?

Еще интересно что значат числа вроде «253,1» и «0,12» в графе device.

Еще нашел какую-то команду:

List File Descriptors in Kernel Memory

sysctl fs.file-nr

Но что-то не то выдает. Хотелось получить файловый дескриптор одного из файлов, вызванных процессом vlc, например.

Хотелось получить файловый дескриптор одного из файлов, вызванных процессом vlc, например.

А зачем? Это просто небольшое число. Обычно от 5 до 15.

cvv ★★★★★ ()
Ответ на: комментарий от cvv

А зачем?

Чтобы убедиться, у всех ли файлов он есть, уникальный ли он. Пока я что-то ни одной команды не нашел, чтобы посмотреть дескриптор, читаю man, как советовали выше.

Это просто небольшое число. Обычно от 5 до 15.

Про дескрипторы 0, 1 и 2 я уже прочитал в вики. С этими числами я уже сталкивался в теме перенаправления ввода-вывода в консоли. Думал что это какие-то особенные дескрипторы, а все остальные уникальны, вроде PID'ов. Но вот ты говоришь что это не так, осталось только найти способ проверить.

shkolnik_2019 ()
Ответ на: комментарий от cvv

А зачем? Это просто небольшое число. Обычно от 5 до 15.

А существует ли практическая польза от этих знаний? Наверно где-то в программировании используется номер дескриптора?

shkolnik_2019 ()

чтобы плеер запустил простое видео

ну ты чел. хотел бы я посмотреть, как ты пишешь «простую» реализацию «простого» декодера h264, многопоточного и все дела. а потом собственно весь плеер с реализацией всех возможностей что он предоставляет

anonymous ()

Неужели, чтобы плеер запустил простое видео, нужно действительно открыть сотни этих файлов?

Скорее всего открыты shared библиотеки, необходимые для запуска и работы приложения

xionovermazes ()

Пытаюсь разобраться в файловых дескрипторах. Читаю разные статьи, пока не очень понятно как потрогать эти самые дескрипторы.

С какой целью интересуетесь? Тяжело внятно объяснить, не ударившись в программирование.

Сотни файлов типа dir, reg, chr, fifo, unix, a_inode. Что это такое?

Это разные типы. dir - понятно, каталог, reg - regular file (обычный файл), a_inode - анонимный (т.е. без соответствующего ему файла на диске) inode, и т.д. Кроме первых двух это уже «внутренности» системы.

Там всякие cwd, rtd, mem, del, txt… а ближе к концу вида «0r, 1w, 2w, 3r…26u…» и т.д. Что это означает?

cwd - это current working directory (текущий каталог), rtd - корневой, mem - это файлы, отображённые в память (см. mmap), и т.д. См. man lsof.

<число><r|w|u> (например, «0r», «1w», «26u») - это как раз то, что вас интересует. Число - дескриптор, символ - режим, в котором открыт файл: на чтение, на запись или оба.

Еще интересно что значат числа вроде «253,1» и «0,12» в графе device.

Устройства в Linux однозначно идентифицируются парой чисел major-minor. Если упрощённо, то первое - это тип устройства, а второе - его индекс. Т.е. пара 253,1 означает «устройство типа 253 номер 1».

Неужели, чтобы плеер запустил простое видео, нужно действительно открыть сотни этих файлов?

Плеер - это довольно сложная программа, которой нужно взаимодействовать как с самой собой (между разными её компонентами), так и со средой, в которой она работает: графическая система, менеджер сессии (чтобы экран не гасился во время воспроизведения) и т.д. Чтобы не плодить 100500 специфических способов общения на каждый частный случай, всё строится поверх существующего файлового и сетевого API - отсюда и множество открытых файлов.

Rootlexx ()
Последнее исправление: Rootlexx (всего исправлений: 1)

Ты зря начал с такой сложной программы, как видеоплеер. там и звук и аппаратное скорение декодирования и аппаратное ускорение вывода и сеть и интерфейс и ещё куча всего.

Возми что-нибудь попроще:

# cat < /dev/zero > /dev/null &
[1] 19228
# lsof -p `pidof cat`
lsof: WARNING: can't stat() tracefs file system /sys/kernel/debug/tracing
      Output information may be incomplete.
COMMAND   PID     USER   FD   TYPE DEVICE  SIZE/OFF    NODE NAME
cat     19228 legolegs  cwd    DIR 253,16     12288 1721345 /home/legolegs
cat     19228 legolegs  rtd    DIR  253,8      4096       2 /
cat     19228 legolegs  txt    REG  253,8     52120  790266 /usr/bin/cat
cat     19228 legolegs  mem    REG  253,8 217750512  940018 /usr/lib/locale/locale-archive
cat     19228 legolegs  mem    REG  253,8   5591560  787730 /usr/lib64/libc-2.29.so
cat     19228 legolegs  mem    REG  253,8    356392  786496 /usr/lib64/ld-2.29.so
cat     19228 legolegs    0r   CHR    1,5       0t0    3077 /dev/zero
cat     19228 legolegs    1w   CHR    1,3       0t0    3075 /dev/null
cat     19228 legolegs    2u   CHR  136,4       0t0       7 /dev/pts/4
# kill $!
[1]+  Terminated              cat < /dev/zero > /dev/null
# 
legolegs ★★★★★ ()
Последнее исправление: legolegs (всего исправлений: 1)

Ну давай по порядку.

  1. файловый дескриптор - это просто целое неотрицательное число, идентифицирующее поток ввода-вывода для процесса. Поток ввода-вывода - это в простейшем случае открытый файл, но сюда же попадают и сетевые сокеты, и пайпы.
    lsof показывает больше, чем список дескрипторов - например, он показывает области памяти, полученные в результате mmap() (работа с файлом через отображение этого файла в память и работу с памятью). У таких областей памяти в столбце FD вместо дескриптора указана строка mem.
    Там же показана текущая рабочая директория процесса (cwd), корневая директория процесса (rtd).
    У обычных дескрипторов в этой колонке пишется номер дескриптора и режим, в котором он открыт (r - read, w - write, u - read+write).
  2. дескрипторы могут быть связаны с разными типами файлов. Это отображается в столбце TYPE. Как я уже писал выше, это могут быть обычные файлы (REG, regular file), пайпы (FIFO), юниксовые сокеты (unix), сетевые сокеты (IPv4), символьные устройства (CHR, character device), и т.д. Смотри в мане полный (на самом деле нет :) ) список. В списке не описан тип a_inode. Если процесс работает с inotify, ему тоже возвращаются объекты-дескрипторы, они имеют тип a_inode (anonymous inode, вероятно).
  3. в моей бубунте vlc это динамический бинарник. Соответственно, в списке открытых файлов - все динамические библиотеки, которые нужны для его запуска; они обычно заммаплены (FD=mem).
    Дальше идут нумерованные дескрипторы, в моём случае это:
    • 3 стандартных (0, 1, 2)
    • две пары дескрипторов, связанных с одним и тем же пайпом (один на запись, другой на чтение, зачем - хз, возможно, для межпотокового взаимодействия)
    • некоторое количество юниксовых сокетов, связанных с DM и около того (pulseaudio, dbus-daemon, mate-session)
    • некоторое количество дескрипторов от inotify
    • пара символьных устройств - /dev/urandom и /dev/dri/card0 (для direct rendering, вестимо)
    • и, наконец-то, дескриптор, связанный с проигрываемым на данный момент файлом.
  4. числа в графе device - major и minor numbers - идентификаторы устройства, на котором лежит указанный файл.
  5. файловый дескриптор имеет смысл только в контексте процесса, работающего с вводом-выводом, у разных процессов одни и те же файловые дескрипторы могут быть (и будут!) связаны с разными файлами и прочими потоками ввода-вывода.

Чтобы оставить только обычные дескрипторы, используй команду lsof -a -d 0-9000 -p $(pidof vlc).

tiandrey ★★★★★ ()
Последнее исправление: tiandrey (всего исправлений: 1)
Ответ на: комментарий от Rootlexx

cwd - это current working directory (текущий каталог), rtd - корневой, mem - это файлы, отображённые в память (см. mmap), и т.д. См. man lsof.

<число><r|w|u> (например, «0r», «1w», «26u») - это как раз то, что вас интересует. Число - дескриптор, символ - режим, в котором открыт файл: на чтение, на запись или оба.

Получается, что дескриптор есть не у всего?

90% того что находится в графе/столбце FD - это как раз «mem». И еще несколько записей вроде cwd, rtd, txt, dex.

И только где-то в конце последние 20-30 файлов имеют эти числа. Могу предположить, что файлы, которые находятся в памяти (mem) не имеют дескриптора? У файлов-каталогов его тоже нет?

shkolnik_2019 ()
Ответ на: комментарий от shkolnik_2019

Когда приложение запрашивает ОС открыть файл, то ОС такие запросы нумерует чтобы не тягаться с именами файлов. Когда-то давно это давало жуткую экономию. Этот номер собственно и есть файловым дескриптором.

первые три файла ОС открывает по собственной инициативе и присваивает им номера 0, 1, 2. Поэтому номера присваиваемые запросам самого приложения начинаются с 3. Запрос на открытие пользовательского файла идет после того как приложение запросило файлы нужные ему самому, ну там ресурсы, скины, кодеки и всякое такое. Поэтому номер для файла пользователя начинается где-то от 5. Хотя, впринцыпе, приложение может запросить любой номер для любого файла.

cvv ★★★★★ ()
Ответ на: комментарий от tiandrey

Спасибо за такой емкий ответ, многое стало понятнее!

А еще хотел узнать.

в моей бубунте vlc это динамический бинарник. Соответственно, в списке открытых файлов - все динамические библиотеки, которые нужны для его запуска; они обычно заммаплены (FD=mem).

У меня тоже идет по порядку 0r, 1w, 2w... и т.д.

Но почему-то 0 дескриптору соответствует (файл?) «pipe», а 1 и 2 соответствует файл «/home/aaa/.xsession-errors» - я думал ошибки (STDERR) это 2 дескриптор, а тут оба прописаны.

shkolnik_2019 ()
Ответ на: комментарий от shkolnik_2019

Получается, что дескриптор есть не у всего?

Конечно. Дескриптор - это лишь один из способов сообщить системе, над каким именно файловым объектом мы хотим произвести операцию, и используется лишь для некоторых функций из файлового API. Другие функции могут использовать другие способы идентификации файлового ресурса, с которым идёт работа.

90% того что находится в графе/столбце FD - это как раз «mem».

Скорее всего, это загруженные разделяемые библиотеки.

И еще несколько записей вроде cwd, rtd, txt, dex.

Это то, что о процессе хранит система, но из программы напрямую к ним доступа нет. Если нужен будет доступ, то придётся задействовать файловый API, который уже вернёт дескриптор.

Могу предположить, что файлы, которые находятся в памяти (mem) не имеют дескриптора?

Для создания отображения с помощью mmap(2) файловый дескриптор нужен, но после успешного mmap его можно закрыть - отображение останется.

У файлов-каталогов его тоже нет?

Если каталог открыть из программы, то он получит дескриптор. Ещё раз: дескриптор - это лишь интерфейс для взаимодействия с ресурсом. Всякие внутренне открытые ресурсы, доступ к которым не предусмотрен, соответственно и не получают дескриптор для операций над ними.

Rootlexx ()
Ответ на: комментарий от shkolnik_2019

Но почему-то 0 дескриптору соответствует (файл?) «pipe», а 1 и 2 соответствует файл «/home/aaa/.xsession-errors» - я думал ошибки (STDERR) это 2 дескриптор, а тут оба прописаны.

Вы запустили VLC из графического интерфейса, а не из терминала - значит, приложению просто некуда выводить как стандартный вывод, так и вывод ошибок, поэтому запустившая этот процесс графическая среда в качестве 1 и 2 дескрипторов «указала» данный файл. Но там может быть и /dev/null, и сокет - эти дескрипторы даже вообще могут не существовать (т.е. быть закрыты).

Rootlexx ()
Ответ на: комментарий от Rootlexx

Если каталог открыть из программы, то он получит дескриптор. Ещё раз: дескриптор - это лишь интерфейс для взаимодействия с ресурсом. Всякие внутренне открытые ресурсы, доступ к которым не предусмотрен, соответственно и не получают дескриптор для операций над ними.

А как понять вот такое определение?

True if file descriptor fd is open and refers to a terminal.

Если дескриптор открыт и ссылается на терминал. Имеется ввиду какая-то консольная программа, использующая некий файл?

shkolnik_2019 ()
Ответ на: комментарий от Rootlexx

Вы запустили VLC из графического интерфейса, а не из терминала - значит, приложению просто некуда выводить как стандартный вывод, так и вывод ошибок, поэтому запустившая этот процесс графическая среда в качестве 1 и 2 дескрипторов «указала» данный файл. Но там может быть и /dev/null, и сокет - эти дескрипторы даже вообще могут не существовать (т.е. быть закрыты).

Сейчас запустил vlc из консоли, посмотрел lsof -p, теперь дескрипторы 0, 1, 2 показывают «5 /dev/pts/2».

vlc     9714  aaa    0u      CHR              136,2      0t0        5 /dev/pts/2
vlc     9714  aaa    1u      CHR              136,2      0t0        5 /dev/pts/2
vlc     9714  aaa    2u      CHR              136,2      0t0        5 /dev/pts/2
shkolnik_2019 ()
Ответ на: комментарий от shkolnik_2019

А как понять вот такое определение?

True if file descriptor fd is open and refers to a terminal.

Если дескриптор открыт и ссылается на терминал. Имеется ввиду какая-то консольная программа, использующая некий файл?

Имеется в виду консольная программа, в которой открыто устройство (псевдо)терминала.

Обычно запускаемые в консоли программы получают 0, 1, 2 -> устройство терминала (которое можно узнать командой tty). В результате программа читает стандартный ввод из терминала и выводит информацию и ошибки в тот же терминал.

Некоторые программы могут менять своё поведение в зависимости от того, является ли стандартный вывод терминалом (man isatty). Например, отключать «раскрашивание» вывода, которое в случае терминала осуществляется последовательностями управляющих символов, которые стали бы мусором в случае вывода в файл.

Rootlexx ()