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

в 7:54, , рубрики: neutrino, QNX, системное программирование

Периодически при разработке приложений в ОС РВ 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(так как одному имени может соответствовать несколько процессов) и многое многое другое. Но, я уверен, что читатель вполне справится с этим сам. Данная статья преследовала цель лишь показать направление деятельности.

Полные исходники доступны по ссылке.

Автор: makemaker

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js