[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