Периодически при разработке приложений в ОС РВ QNX 6.5.0 возникает задача найти процесс зная только его символьное имя, или выяснить какую либо информацию о процессе, или собрать какую либо статистику о процессе. Это может понадобиться для широкого круга задач.
Данная задача является платформо-специфичной и единое кроссплатформенное решение доступно только в виде сторонних библиотек.
В данной статье мы реализуем небольшой класс «обертку», позволяющий получить информацию о процессе, зная только его имя. Использовать мы будем ЯП C++.
Для выполнения поставленной задачи можно воспользоваться системным вызовом «system», вызывая утилиту для работы с процессами «pidin», обрабатывая вывод данной утилиты. Но, данное решение нас мало интересует.
Итак, начнем с того, что в QNX первичной организационной структурой(в отличие от например Linux) является поток. Ядро занимается исключительно планировкой потоков. Процессы же являются контейнерами, содержащими в себе один или несколько потоков. Вся работа с процессами вынесена в менеджер процессов procnto.
Данный менеджер ресурсов создает виртуальную директорию /proc/. Попробуем вывести содержимое данной директории.
# ls /proc/ total 41 dr-xr-xr-x 2 root root 1 Sep 04 22:37 1 dr-xr-xr-x 2 root root 1 Sep 04 22:37 110611 dr-xr-xr-x 2 root root 1 Sep 04 22:37 126996 dr-xr-xr-x 2 root root 1 Sep 04 22:37 2 dr-xr-xr-x 2 root root 1 Sep 04 22:37 20489 drwxr-xr-x 2 root root 50 Jul 09 2010 boot nrw------- 1 root root 0 Sep 04 18:15 dumper dr-xr-xr-x 4 root root 1 Sep 04 22:37 self
Я немного сократил вывод утилиты, для экономии места. Можно заметить что в выводе присутствуют:
1) директории с PID запущенных процессов
2) Виртуальная директория «boot», хранящая в себе файлы «вкомпилированные» в образ ОС.
3) Файл dumper, используемый утилитой «core dump»
4) Директория «self» — аналогичная директориям с PID, но предоставляет данные для текущего процесса(в нашем случае ls).
В директориях с PID, содержится единственный файл с именем «as», который невозможно ни читать ни писать штатными утилитами QNX работающими с файлами. Но, зато к данным файлам(а на самом деле к менеджеру procnto) можно обратиться используя системный вызов devctl. Полная информация о работу с менеджером procnto представлена тут.
Этим мы и постараемся воспользоваться в разрабатываемом классе. Как можно заметить — имя получается отдельным, от остальной информации devctl. Поэтому, определим в классе два приватных поля — поле хранящее имя процесса и системную информацию(системная информация о процессе хранится в структуре типа «debug_process_t»).
Итак, для начала определим публичный интерфейс нашего класса. Пусть у нас информация о конкретном процессе хранится в отдельном классе QNXProcInfo. Так как данный класс соответствует одному конкретному процессу, то вполне логично, что бы его конструктор принимал в себя pid процесса(в отличие от имени — pid уникален для каждого запущенного в системе процесса). Для начала пусть он научится отдавать нам имя процесса которому он соответствует и распечатывать в текстовом виде в поток информацию о себе.
Тогда заголовок нашего класса будет выглядеть примерно так:
class QNXProcInfo { public: QNXProcInfo(int pid); std::string GetName(); void PrintInfo(std::ostream &out = std::cout); debug_process_t GetInfo(); private: std::string* name; debug_process_t info; };
Для поиска процесса определим другой класс QNXProcMgr. От него требуется поиск процессов по имени и по переданной функции компаратору.
Заголовок данного класса будет выглядеть примерно так:
class QNXProcMgr { public: static QNXProcInfo* Find(std::string pname); static QNXProcInfo* Find(bool (*comparator)(debug_process_t info)); };
Приступим к реализации.
Для получения информации о имени процесса, используем пользовательскую структуру name, Которая содержит в себе структуру procfs_debuginfo и свободный буфер, в который будет записано имя процесса.
Код будет выглядеть приблизительно так:
QNXProcInfo::QNXProcInfo(int pid) { char paths[PATH_MAX]; int fd; static struct { procfs_debuginfo info; char buff [PATH_MAX]; } name; sprintf(paths, "/proc/%d/as", pid); if ((fd = open (paths, O_RDONLY)) == -1) { //FIXME: Add error handler here } devctl(fd, DCMD_PROC_MAPDEBUG_BASE, &name, sizeof(name), 0); this->name = new string(name.info.path); devctl(fd, DCMD_PROC_INFO, &info, sizeof(info), 0); close (fd); }
Как можно заметить, для получения имени мы используем devctl команду DCMD_PROC_MAPDEBUG_BASE, при получении которой procnto заполняет передаваемую ему структуру и записывает имя в буфер path.
Для получения прочей информации — используется devctl команда DCMD_PROC_INFO, при получении которой procnto заполняет структуру info, которую мы передаем ему в качестве параметра.
Функции получения имени и вывода информации о процессе выглядят совсем тривиально и описываться не будут. Стоит только лишь отметить, что с информацией о полях структуры debug_process_t можно ознакомиться тут.
Перейдем к рассмотрению функциональности класса, отвечающего за поиск процесса.
Вот код, отвечающий за поиск процесса по имени:
QNXProcInfo* QNXProcMgr::Find(string pname) { struct dirent *dirent; DIR *dir; int pid; string name; QNXProcInfo *info; if (!(dir = opendir ("/proc"))) throw QNXProcException("couldn't open /proc"); while ((dirent = readdir(dir))) { if (isdigit(*dirent->d_name)) { pid = atoi(dirent->d_name); info = new QNXProcInfo(pid); name = info->GetName(); if (name == pname) return info; else delete info; } } closedir (dir); throw QNXProcException("Process not found"); }
Как можно заметить, используется простой перебор файлов в директории /proc, для каждого из найденных файлов(если он представляет собой PID), создается новый объект ProcInfo, который проверяется на соответствие условию, и в случае не соответствия удаляется.
Похоже выглядит функция для поиска по функции компаратору:
QNXProcInfo* QNXProcMgr::Find(bool (*comparator)(debug_process_t info)) { struct dirent *dirent; DIR *dir; int pid; QNXProcInfo *info; if (!(dir = opendir ("/proc"))) throw QNXProcException("couldn't open /proc"); while ((dirent = readdir(dir))) { if (isdigit(*dirent->d_name)) { pid = atoi(dirent->d_name); info = new QNXProcInfo(pid); if (comparator(info->GetInfo())) return info; else delete info; } } closedir (dir); throw QNXProcException("Process not found"); }
Вот собственно и все. В случае необходимости читатель может расширить и дополнить указанные классы в соответствии со своими потребностями.
Так же, следует отметить, что код не претендует на полноту. В нем отсутствует обработка некоторых видов ошибок, не оптимально выстроен алгоритм поиска, функция поиска должна уметь отдавать несколько объектов QNXProcInfo(так как одному имени может соответствовать несколько процессов) и многое многое другое. Но, я уверен, что читатель вполне справится с этим сам. Данная статья преследовала цель лишь показать направление деятельности.
Полные исходники доступны по ссылке.
ссылка на оригинал статьи https://habrahabr.ru/post/279509/
Добавить комментарий