[cdev] Задание ps
Grigoriy A. Sitkarev
sinclair80 на gmail.com
Пн Мар 15 00:26:32 MSK 2010
> 1) В файле stat у нас tty имеет числовое значение, при том, что ps выводит
> название: как по числовому значению получить название?
Да, всё верно, в stat поле tty_nr дано одним числовым значением.
Фактически, туда упаковано два числа, в битах 31 по 20 и с 7 по 0
находится младший номер (minor number) а в битах с 15 по 8 старший
номер (major number). Чтобы извлечь два целых числа упакованных таким
образом, напишите пару макросов, которые будут битовыми сдвигами
извлекать нужные вам части, например DEV_MAJOR и DEV_MINOR. Это надо
ещё всё проверить, но я думаю что я тут не ошибся.
Вы эти major и minor номера видите в полях, которые обычно в выводе
ls(1) задействованы под размер и количество жёстких ссылок. Если вы
листаете файлы устройств, то в этих колонках показаны старший и
младший номера.
$ ls -la /dev/ttyS0
crw-rw---- 1 root dialout 4, 64 Mar 14 15:31 /dev/ttyS0
Здесь 4 и 64 соответственно старший и младший номера устройства. Они
однозначно идентифицируют драйвер, который должно ядро использовать,
когда вы делаете open(2) с этим файлом.
Вам чтобы получить имя из minor и major номеров придётся бегать по
каталогу /dev и искать там файл устройства (символьного), у которого
будет совпадение. Системный вызов stat(2) в struct stat в поле st_rdev
должен вам в том же формате упаковки эти два числа вернуть для файла,
имя которого указано в первом аргументе.
Есть ещё один способ, может быть он окажется оптимальнее. В Linux в
каталоге /proc/tty есть файл drivers. Обычный текстовый файл с полями
разделёнными пробелами. Третье и четвёртое поля это соответственно
старший номер (major) и область значений младших номеров (minor) от и
до, с чёрточкой разделителем. В Unix принято именовать файлы
устройства с цифрой в конце, которая совпадает с младшим номером
устройства. Можно использовать этот факт.
Кроме того, в /proc/<PID>/fd есть ссылки. На самом деле они выглядят
только как ссылки. Имя ссылки это номер файлового дескриптора (целое
число), а значение ссылки (её можно прочитать вызовом readlink(2)) это
имя файла, которое соответствует дескриптору. Вы бы могли, если у
процесса есть ассоциированный терминал, пробежаться только по этим
ссылкам (с 0 по 2-ю) и найти ассоциированное устройство терминала не
лазая по всему /dev. Имейте в виду, что в теории, у процесса могут
быть разные устройства "привязаны" на стандартный ввод, вывод и вывод
ошибок. Поэтому их надо проверить на совпадение major/minor с тем что
вы прочитали в файле stat в поле tty_nr. И взять имя только того
устройства, с которым есть совпадение, потому что ассоциированный
терминал только один - его и следует показать в поле TTY в выводе.
> 2) В файле stat поле flags представляет собой unsigned int, а ps выводит
> символ - что выводит ps и как это получить?
Open Group говорит что формат вывода этого поля implementation
defined. Вы его просто выводите целым десятичным числом, и всё. Эти
флаги они зависят и от версии ядра в т.ч.
> 3) Что означают следующие поля при выводе ps: C, ADDR и откуда их получить?
Поле C определено Open Group как CPU utilization, правда сам стандарт
не говорит о том как его вычислять, говориться что это некие данные по
использованию процессорного времени в ближайший момент. Я ещё подумаю
как это лучше сделать, дело в том что стандартно в Unix можно получить
процессорное время, использованное процессом (через getrusage(2)
например или в stat оно есть) но считать его нужно относительно
последнего момента. Сейчас я думаю что пришлось бы замерять время в
тиках, потреблённое процессом, два раза (у вас оно есть в файле stat в
полях cutime и cstime) и потом высчитывать сколько каждый процесс
"съел" от общего числа, зная общее количество тиков в секунду, но
может быть позже придумаю способ проще.
Поле ADDR я бы пока не трогал, писал бы там чёрточку. Я думаю что
предназначалось это поле для отображения адреса текущего программного
счётчика, (регистр EIP или PC). Он кстати есть в файле stat в поле
kstkeip.
--
Г.А.
Подробная информация о списке рассылки cdev