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