Программный поиск процесса по имени в QNX 6.5.0

от автора

Периодически при разработке приложений в ОС РВ QNX 6.5.0 возникает задача найти процесс зная только его символьное имя, или выяснить какую либо информацию о процессе, или собрать какую либо статистику о процессе. Это может понадобиться для широкого круга задач.

image

Данная задача является платформо-специфичной и единое кроссплатформенное решение доступно только в виде сторонних библиотек.

В данной статье мы реализуем небольшой класс «обертку», позволяющий получить информацию о процессе, зная только его имя. Использовать мы будем ЯП 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *