[cdev] Задание ps
Grigoriy A. Sitkarev
sinclair80 на gmail.com
Вс Мар 14 19:22:21 MSK 2010
Замечаний много, перечислю самые основные.
1. Не злоупотребляйте typedef потому что за-typedef-ливание типов
ведёт к их неоптимальному использованию (не видно являются ли они
базовыми типами или же структурами) и усложняет понимание программы. В
некоторых случаях использование typedef оправдано, особенно в целях
переносимости, когда через typedef определяются машинно-зависимые
типы.
Поэтому стуктуру process оставьте без всяких typedef.
Кроме того, вам не нужна дополнительная структура tnode. Просто в
struct process добавьте поле:
struct process *next;
в самом верху, и всё. Делайте список из них сразу напрямую.
2. Из структуры process надо "подчистить" поля которые мы использовать
не будем а также добавить те, которые мы будем вычислять, например
использованное время. Это можно сделать по мере реализации частей
программы.
3. При выводе списка процессов поля имеют заголовки. Посмотрите в
спецификацию Open Group и посмотрите как это делает ps(1) в Linux:
$ ps -Al
$ ps -Af
Вам надо будет очень красиво написать функцию вывода полей. Дизайн
должен предусматривать возможность включить и выключить вывод каждого
поля в отдельности. Каждое поле вы должны определить как бит в маске
(например через макрос) и функция вывода списка процессов должна будет
как минимум один аргумент в виде битовой маски получать на вход.
#define SHOW_FLAGS 0x01
#define SHOW_STATE 0x02
#define SHOW_UID 0x04
#define SHOW_PID 0x08
#define SHOW_PPID 0x10
...
#define SHOW_LONG (SHOW_FLAGS | SHOW_STATE | ...)
#define SHOW_FULL (SHOW_UID | SHOW_PPID | ...)
#define SHOW_ALL (SHOW_PID | SHOW_TTY | ...)
int mask;
mask = SHOW_LONG | SHOW_ALL;
4. Для проверки имени каталога в /proc, является ли оно числом, можно
было использовать несколько подходов, проще:
а) воспользоваться функцией strtoul(3), если после преобразования
строки в число **endptr не равен 0, тогда не вся строка была
преобразована а значит она не является целым числом.
б) переписать функцию isproc проще, а у вас очень сложно, получится
что-то вроде:
int
isprocdir(const char *dn)
{
while (isdigit(*dn))
dn++;
return (*dn == 0);
}
4. По поводу памяти вы видимо меня не совсем поняли. Вам надо было
написать функцию xmalloc которая:
а) выделяет запрошенную память.
б) проверяет значение, которое вернул malloc(3).
в) в случае если malloc(3) вернул NULL, завершает работу программы
через exit(2) c сообщением на stderr или через errx(3).
void *xmalloc(size_t size);
5. Когда вам надо скопировать строку в буфер, память под который вы
динамически выделяете, это удобнее сделать с использовании стандартной
функции strdup(3) или strndup(3). Так как эти функции могут и не
выделить памяти, надо проверять значение, которое они вернули. Удобно
их также обвернуть в xstrdup и xstrndup, по аналогии с xmalloc. Вам
вероятнее всего strndup(3) не понадобится, хотя во многих случаях
нельзя доверять исходной строке или же целесообразно ограничивать
размер копируемой строки.
6. Обработка ошибок не сделана, потому что во-первых, они должны
печататься на stderr, для этого у нас есть целый дескриптор, который
всегда открыт. Поэтому:
fprintf(stderr, "error: %s\n", strerror(errno));
Описание ошибки должно быть кратким и понятным.
Вы должны не только проверять наличие ошибки и печатать сообщение, но
и алгоритм работы вашей программы должен изменяться если что-то пошло
не так. Например, если вам не удалось открыть каталог с файлами
/proc/<PID> то наверное этот каталог надо пропустить, потому что вы
ничего из него не прочтёте и смысла читать его нет.
7. Я нашёл ещё один вариант, как узнать сколько тиков в секунду у
системного таймера. POSIX говорит что функция sysconf(3) для этого
подходит, но надо проверить будет:
int ticks_per_sec;
ticks_per_sec = sysconf(_SC_CLK_TCK);
8. Есть нюанс с аргументами командной строки в /proc/<PID>/cmdline. У
нас там может быть пусто ещё и потому что процесс стал зомби. Поэтому
вам нужно смотреть в поле state, которое вы прочитаете из stat, там
буквами определено состояние процесса и зомби он или нет вы легко
определите.
Если вспомню что-то ещё, напишу.
Обратите внимание, что само задание у вас есть, это спецификация Open
Group. Поэтому что вам ещё доделывать - написано там. Я в предыдущем
письме просил как минимум -l и -f опции, -A и -a конечно же придётся
тоже (это само собой разумеющееся).
--
Г.А.
Подробная информация о списке рассылки cdev