Функции, обслуживающие жизненный цикл потоков трассировки.
На рис. 8.1 показаны основные элементы жизненного цикла потока трассировки и функции, вызов которых трассирующим процессом обеспечивает переход между состояниями.
Рис. 8.1. Основные элементы жизненного цикла потока трассировки.
Создание потока трассировки осуществляется функциями posix_trace_create() или posix_trace_create_withlog() (см. листинг 8.6).
#include <sys/types.h> #include <trace.h> int posix_trace_create (pid_t pid, const trace_attr_t *restrict attr, trace_id_t *restrict trid); int posix_trace_create_withlog (pid_t pid, const trace_attr_t *restrict attr, int fildes, trace_id_t *restrict trid);
Листинг 8.6. Описание функций создания потоков трассировки. (html, txt)
Функция posix_trace_create() создает активный поток, в который будут записываться события трассировки целевого процесса с идентификатором pid (при нулевом pid трассируется вызывающий процесс). Ресурсы в потоке отводятся в соответствии со значениями элементов атрибутного объекта, заданного аргументом attr (если attr равен NULL, используются подразумеваемые значения).
Идентификатор созданного потока записывается по указателю trid. Его может использовать только вызывающий процесс.
Фильтр, ассоциированный с новым потоком, пуст.
Одновременно могут быть активными несколько потоков трассировки, однако их общее число не должно превышать значения конфигурационной константы TRACE_SYS_MAX.
Разумеется, попытки трассировать другие процессы подвержены контролю прав доступа.
Функция posix_trace_create_withlog() делает то же, что и posix_trace_create(), но дополнительно ассоциирует с потоком журнал трассировки, заданный файловым дескриптором fildes.
Сразу после создания потока трассировка считается приостановленной. Чтобы активизировать ее, следует воспользоваться функцией posix_trace_start(); для последующей приостановки нужно вызвать функцию posix_trace_stop() (см. листинг 8.7).
#include <trace.h> int posix_trace_start (trace_id_t trid); int posix_trace_stop (trace_id_t trid);
На рис. 8.1 показаны основные элементы жизненного цикла потока трассировки и функции, вызов которых трассирующим процессом обеспечивает переход между состояниями.
Рис. 8.1. Основные элементы жизненного цикла потока трассировки.
Создание потока трассировки осуществляется функциями posix_trace_create() или posix_trace_create_withlog() (см. листинг 8.6).
#include <sys/types.h> #include <trace.h> int posix_trace_create (pid_t pid, const trace_attr_t *restrict attr, trace_id_t *restrict trid); int posix_trace_create_withlog (pid_t pid, const trace_attr_t *restrict attr, int fildes, trace_id_t *restrict trid);
Листинг 8.6. Описание функций создания потоков трассировки.
Функция posix_trace_create() создает активный поток, в который будут записываться события трассировки целевого процесса с идентификатором pid (при нулевом pid трассируется вызывающий процесс). Ресурсы в потоке отводятся в соответствии со значениями элементов атрибутного объекта, заданного аргументом attr (если attr равен NULL, используются подразумеваемые значения).
Идентификатор созданного потока записывается по указателю trid. Его может использовать только вызывающий процесс.
Фильтр, ассоциированный с новым потоком, пуст.
Одновременно могут быть активными несколько потоков трассировки, однако их общее число не должно превышать значения конфигурационной константы TRACE_SYS_MAX.
Разумеется, попытки трассировать другие процессы подвержены контролю прав доступа.
Функция posix_trace_create_withlog() делает то же, что и posix_trace_create(), но дополнительно ассоциирует с потоком журнал трассировки, заданный файловым дескриптором fildes.
Сразу после создания потока трассировка считается приостановленной. Чтобы активизировать ее, следует воспользоваться функцией posix_trace_start(); для последующей приостановки нужно вызвать функцию posix_trace_stop() (см. листинг 8.7).
#include <trace.h> int posix_trace_start (trace_id_t trid); int posix_trace_stop (trace_id_t trid);
Листинг 8.7.
Листинг 8.7. Описание функций активизации и приостановки трассировки. (html, txt)
После вызова posix_trace_start() в поток помещается системное событие POSIX_TRACE_START, а статус потока получает значение POSIX_TRACE_RUNNING (если трассировка уже шла, вызов posix_trace_start() игнорируется).
После вызова posix_trace_stop() в поток помещается системное событие POSIX_TRACE_STOP, а статус потока получает значение POSIX_TRACE_SUSPENDED (если трассировка уже была приостановлена, вызов posix_trace_stop() игнорируется).
Если поток трассировки заполнен, вызовы posix_trace_start() и posix_trace_stop() игнорируются.
Функция posix_trace_shutdown() (см. листинг 8.8) завершает трассировку и освобождает ресурсы, ассоциированные с потоком, независимо от того, прочитал ли анализирующий процесс все записанные события.
#include <sys/types.h> #include <trace.h> int posix_trace_shutdown (trace_id_t trid);
Листинг 8.8. Описание функции завершения трассировки. (html, txt)
Если с потоком ассоциирован журнал, в него сбрасываются все несохраненные события, записывается необходимая служебная информация (атрибуты трассировки, типы и имена событий и соответствие между ними и т.п.), после чего журнал закрывается.
После возврата из posix_trace_shutdown() аргумент trid перестает быть корректным идентификатором потока трассировки.
Трассировка может завершаться и неявным образом, когда трассирующий процесс терминируется или вызывает функцию семейства exec().
По ходу трассировки управляющий процесс может инициировать сброс потока в журнал, обратившись к функции posix_trace_flush() (см листинг 8.9).
#include <sys/types.h> #include <trace.h> int posix_trace_flush (trace_id_t trid);
Листинг 8.9. Описание функции сброса потока трассировки в журнал. (html, txt)
Сброс осуществляется с учетом правил обработки ситуации заполнения журнала.
После завершения сброса пространство в потоке трассировки, которое занимали записанные в журнал события, может быть использовано повторно.
Узнать о завершении операции сброса можно, опрашивая статус потока трассировки с помощью функции posix_trace_get_status() (см.листинг 8.10).
#include <trace.h> int posix_trace_get_status (trace_id_t trid, struct posix_trace_status_info *statusinfo);
Листинг 8.10. Описание функции опроса статуса потока трассировки. (html, txt)
Функция обеспечивает согласованность данных, которые записываются в структуру типа posix_trace_status_info по указателю statusinfo. Сразу после завершения вызова признаки переполнения и для потока, и для журнала получают значение POSIX_TRACE_NO_OVERRUN, а в поле posix_stream_flush_error помещается нуль.
Описание функций активизации и приостановки трассировки.
После вызова posix_trace_start() в поток помещается системное событие POSIX_TRACE_START, а статус потока получает значение POSIX_TRACE_RUNNING (если трассировка уже шла, вызов posix_trace_start() игнорируется).
После вызова posix_trace_stop() в поток помещается системное событие POSIX_TRACE_STOP, а статус потока получает значение POSIX_TRACE_SUSPENDED (если трассировка уже была приостановлена, вызов posix_trace_stop() игнорируется).
Если поток трассировки заполнен, вызовы posix_trace_start() и posix_trace_stop() игнорируются.
Функция posix_trace_shutdown() (см. листинг 8.8) завершает трассировку и освобождает ресурсы, ассоциированные с потоком, независимо от того, прочитал ли анализирующий процесс все записанные события.
#include <sys/types.h> #include <trace.h> int posix_trace_shutdown (trace_id_t trid);
Листинг 8.8. Описание функции завершения трассировки.
Если с потоком ассоциирован журнал, в него сбрасываются все несохраненные события, записывается необходимая служебная информация (атрибуты трассировки, типы и имена событий и соответствие между ними и т.п.), после чего журнал закрывается.
После возврата из posix_trace_shutdown() аргумент trid перестает быть корректным идентификатором потока трассировки.
Трассировка может завершаться и неявным образом, когда трассирующий процесс терминируется или вызывает функцию семейства exec().
По ходу трассировки управляющий процесс может инициировать сброс потока в журнал, обратившись к функции posix_trace_flush() (см листинг 8.9).
#include <sys/types.h> #include <trace.h> int posix_trace_flush (trace_id_t trid);
Листинг 8.9. Описание функции сброса потока трассировки в журнал.
Сброс осуществляется с учетом правил обработки ситуации заполнения журнала.
После завершения сброса пространство в потоке трассировки, которое занимали записанные в журнал события, может быть использовано повторно.
Узнать о завершении операции сброса можно, опрашивая статус потока трассировки с помощью функции posix_trace_get_status() (см.
листинг 8.10).
#include <trace.h> int posix_trace_get_status (trace_id_t trid, struct posix_trace_status_info *statusinfo);
Листинг 8.10. Описание функции опроса статуса потока трассировки.
Функция обеспечивает согласованность данных, которые записываются в структуру типа posix_trace_status_info по указателю statusinfo. Сразу после завершения вызова признаки переполнения и для потока, и для журнала получают значение POSIX_TRACE_NO_OVERRUN, а в поле posix_stream_flush_error помещается нуль.
Стандартом POSIX-2001 предусмотрен опрос атрибутов потока трассировки. Для этого служит функция posix_trace_get_attr() (см. листинг 8.11).
#include <trace.h> int posix_trace_get_attr ( trace_id_t trid, trace_attr_t *attr);
Листинг 8.11. Описание функции опроса атрибутов потока трассировки.
Для возврата значений атрибутов найдено красивое решение – они помещаются в атрибутный объект по указателю attr, откуда могут быть извлечены рассмотренными выше функциями для работы с атрибутными объектами.
При необходимости поток и журнал трассировки можно очистить от хранящихся там событий (но не от служебной информации), воспользовавшись функцией posix_trace_clear() (см. листинг 8.12).
#include <sys/types.h> #include <trace.h> int posix_trace_clear (trace_id_t trid);
Листинг 8.12. Описание функции очистки потока трассировки.
Разумеется, после очистки признак заполненности получает значение POSIX_TRACE_NOT_FULL.
Если для журнала предусмотрено неограниченное расширение (POSIX_TRACE_APPEND), эффект от вызова posix_trace_clear() не специфицирован.
При опросе и установке фильтров событий трассировки (функции posix_trace_get_filter() и posix_trace_set_filter(), см. листинг 8.13) применяется апробированная в других частях стандарта POSIX-2001 схема работы с множествами, основанная на функциях: posix_trace_eventset_empty(), posix_trace_eventset_fill(), posix_trace_eventset_add(), posix_trace_eventset_del(), posix_trace_eventset_ismember() (см. листинг 8.14).
#include <trace.h> int posix_trace_get_filter ( trace_id_t trid, trace_event_set_t *set); int posix_trace_set_filter (trace_id_t trid, const trace_event_set_t *set, int how);
Листинг 8.13. Описание функций опроса и установки фильтров событий трассировки.
#include <trace.h> int posix_trace_eventset_empty ( trace_event_set_t *set); int posix_trace_eventset_fill ( trace_event_set_t *set, int what); int posix_trace_eventset_add ( trace_event_id_t event_id, trace_event_set_t *set); int posix_trace_eventset_del ( trace_event_id_t event_id, trace_event_set_t *set); int posix_trace_eventset_ismember ( trace_event_id_t event_id, const trace_event_set_t *restrict set, int *restrict ismember);
Листинг 8.14. Описание функций для работы с множествами событий трассировки.
Когда вызывается функция posix_trace_set_filter(), в поток трассировки помещается событие POSIX_TRACE_FILTER с указанием старого и нового фильтров. Аргумент how, определяющий, как меняется фильтр, может принимать следующие значения.
POSIX_TRACE_SET_EVENTSET
Новое значение фильтра задается аргументом set.
POSIX_TRACE_ADD_EVENTSET
Новое значение фильтра вычисляется как объединение текущего значения и множества, заданного аргументом set.
POSIX_TRACE_SUB_EVENTSET
Новое значение фильтра вычисляется как разность текущего значения и множества, заданного аргументом set.
Вероятно, функции для работы с множествами событий трассировки не нуждаются в пространном описании. Аргумент event_id задает тип события. Функция posix_trace_eventset_empty() создает пустое множество событий. Функция posix_trace_eventset_fill() помещает в создаваемое множество события, определяемые аргументом what, который может принимать следующие значения.
POSIX_TRACE_WOPID_EVENTS
Все зависящие от реализации системные события, не ассоциированные с каким-либо процессом.
POSIX_TRACE_SYSTEM_EVENTS
Все зависящие от реализации системные события.
POSIX_TRACE_ALL_EVENTS
Все события (системные и пользовательские).
Для функций posix_trace_eventset_add() и posix_trace_eventset_del() добавление уже присутствующего или, соответственно, удаление отсутствующего типа не считается ошибкой.
Функция posix_trace_eventset_ismember() помещает по указателю ismember ненулевое значение, если тип event_id принадлежит множеству, заданному аргументом set.
Как и (почти) везде в системе трассировки, нормальным для описанных функций является нулевой результат.
Играющие техническую роль функции posix_trace_trid_eventid_open(), posix_trace_eventid_get_name() и posix_trace_eventid_equal() (см. листинг 8.15), обслуживают идентификаторы типов событий, рассматриваемые как абстрактные объекты.
#include <trace.h> int posix_trace_trid_eventid_open ( trace_id_t trid, const char *restrict event_name, trace_event_id_t *restrict event);
int posix_trace_eventid_get_name ( trace_id_t trid, trace_event_id_t event, char *event_name);
int posix_trace_eventid_equal ( trace_id_t trid, trace_event_id_t event1, trace_event_id_t event2);
Листинг 8.15. Описание функций для работы с идентификаторами типов событий трассировки.
Функция posix_trace_trid_eventid_open() ассоциирует с именем event_name, длина которого не должна превышать значения конфигурационной константы TRACE_EVENT_NAME_MAX, уникальный для потока трассировки, заданного аргументом trid, идентификатор типа событий и записывает его по указателю event. При повторном вызове posix_trace_trid_eventid_open() с тем же именем возвращается ранее созданный идентификатор. При попытке превысить максимально допустимое для процесса количество типов пользовательских событий TRACE_USER_EVENT_MAX возвращается предопределенный идентификатор POSIX_TRACE_UNNAMED_USEREVENT.
Функция posix_trace_eventid_get_name() записывает в массив event_name имя события, ассоциированное с типом, заданным аргументом event.
Сравнить два идентификатора типов из одного потока трассировки можно посредством функции posix_trace_eventid_equal(), возвращающей в случае равенства результат, отличный от нуля.
Функции posix_trace_eventtypelist_getnext_id() и posix_trace_eventtypelist_rewind() (см. листинг 8.16) позволяют обрабатывать совокупность идентификаторов типов событий, присутствующих в заданном потоке трассировки.
#include <trace.h> int posix_trace_eventtypelist_getnext_id ( trace_id_t trid, trace_event_id_t *restrict event, int *restrict unavailable); int posix_trace_eventtypelist_rewind (trace_id_t trid);
Листинг 8.16. Описание функций для работы с совокупностью идентификаторов типов событий.
Функция posix_trace_eventtypelist_getnext_id() является итератором. При первом обращении она записывает по указателю event первый идентификатор типа. При каждом следующем вызове туда же помещается очередной идентификатор. Пока перебор идентификаторов не закончен, по указателю unavailable записывается нулевое значение.
Функция posix_trace_eventtypelist_rewind() позволяет вернуться к началу перебора.
Приведем пример программы, выясняющей подразумеваемые значения атрибутов потока трассировки (см. листинг 8.17).
/* * * * * * * * * * * * * * * * * * * * * * * */ /* Программа выясняет подразумеваемые значения */ /* атрибутов потока трассировки */ /* * * * * * * * * * * * * * * * * * * * * * * */
#include <sys/types.h> #include <stdio.h> #include <trace.h> #include <time.h> #include <limits.h> #include <errno.h>
int main (void) { trace_attr_t attr; /* Атрибутный объект потока */ trace_id_t trid; /* Идентификатор потока */ char trbuf [TRACE_NAME_MAX]; /* Буфер для имен */ struct timespec tms; /* Структура для времен */ char dtbuf [LINE_MAX]; /* Буфер для данных о времени */ int res; /* Целочисленные результаты */ size_t mdatsz; /* Максимальный размер данных */ if ((errno = posix_trace_create (0, NULL, &trid)) != 0) { perror ("POSIX_TRACE_CREATE"); return (errno); }
if ((errno = posix_trace_get_attr (trid, &attr)) != 0) { perror ("POSIX_TRACE_GET_ATTR"); return (errno); }
if ((errno = posix_trace_attr_getgenversion (&attr, trbuf)) != 0) { perror ("POSIX_TRACE_ATTR_GETGENVERSION"); return (errno); } printf ("Версия системы трассировки: %s\n", trbuf);
if ((errno = posix_trace_attr_getname (&attr, trbuf)) != 0) { perror ("POSIX_TRACE_ATTR_GETNAME"); return (errno); } printf ("Имя потока трассировки: %s\n", trbuf);
if ((errno = posix_trace_attr_getcreatetime (&attr, &tms)) != 0) { perror ("POSIX_TRACE_ATTR_GETCREATETIME"); return (errno); } (void) strftime (dtbuf, sizeof (dtbuf), "%c", localtime (&tms.tv_sec)); printf ("Время создания потока трассировки: %s\n", dtbuf);
if ((errno = posix_trace_attr_getclockres (&attr, &tms)) != 0) { perror ("POSIX_TRACE_ATTR_GETCLOCKRES"); return (errno); } printf ("Разрешающая способность часов потока " "трассировки: %ld нсек\n", tms.tv_nsec);
if ((errno = posix_trace_attr_getstreamfullpolicy (&attr, &res)) != 0) { perror ("POSIX_TRACE_ATTR_GETSTREAMFULLPOLICY"); return (errno); } printf (" Правило обработки ситуации заполнения потока: "); switch (res) { case POSIX_TRACE_LOOP: printf ("POSIX_TRACE_LOOP\n"); break; case POSIX_TRACE_UNTIL_FULL: printf ("POSIX_TRACE_UNTIL_FULL\n"); break; case POSIX_TRACE_FLUSH: printf ("POSIX_TRACE_FLUSH\n"); break; default: printf ("неизвестно\n"); }
if ((errno = posix_trace_attr_getlogfullpolicy (&attr, &res)) != 0) { perror ("POSIX_TRACE_ATTR_GETLOGFULLPOLICY"); return (errno); } printf ("Правило обработки ситуации заполнения " "журнала трассировки: "); switch (res) { case POSIX_TRACE_LOOP: printf ("POSIX_TRACE_LOOP\n"); break; case POSIX_TRACE_UNTIL_FULL: printf ("POSIX_TRACE_UNTIL_FULL\n"); break; case POSIX_TRACE_APPEND: printf ("POSIX_TRACE_APPEND\n"); break; default: printf ("неизвестно\n"); }
if ((errno = posix_trace_attr_getmaxdatasize (&attr, &mdatsz)) != 0) { perror ("POSIX_TRACE_ATTR_GETMAXDATASIZE"); return (errno); } printf ("Максимальный размер данных в пользовательском " "событии: %d\n", mdatsz);
if ((errno = posix_trace_attr_getmaxusereventsize (&attr, mdatsz, &mdatsz)) != 0) { perror ("POSIX_TRACE_ATTR_GETMAXUSEREVENTSIZE"); return (errno); } printf ("Максимальный размер пользовательского события: " "%d\n", mdatsz);
if ((errno = posix_trace_attr_getmaxsystemeventsize (&attr, &mdatsz)) != 0) { perror ("POSIX_TRACE_ATTR_GETMAXSYSTEMEVENTSIZE"); return (errno); } printf ("Максимальный размер системного события: " "%d\n", mdatsz);
if ((errno = posix_trace_attr_getstreamsize (&attr, &mdatsz)) != 0) { perror ("POSIX_TRACE_ATTR_GETSTREAMSIZE"); return (errno); } printf ("Размер потока трассировки: %d\n", mdatsz);
return 0; }
Листинг 8.17. Пример программы, выясняющей подразумеваемые значения атрибутов потока трассировки.
Обратим внимание на использование конфигурационной константы TRACE_NAME_MAX для задания размера буфера имен.
При запуске этой программы под управлением операционной системы реального времени oc2000 могут быть получены следующие результаты (см. листинг 8.18).
Версия системы трассировки: 2.17 Имя потока трассировки: trace Время создания потока трассировки: Пн 19 АПР 2004 11:54:07 Разрешающая способность часов потока трассировки: 41904 нсек Правило обработки ситуации заполнения потока: POSIX_TRACE_UNTIL_FULL Правило обработки ситуации заполнения журнала трассировки: POSIX_TRACE_LOOP Максимальный размер данных в пользовательском событии: 100 Максимальный размер пользовательского события: 128 Максимальный размер системного события: 84 Размер потока трассировки: 409600
Листинг 8.18. Возможные результаты работы программы, выясняющей подразумеваемые значения атрибутов потока трассировки.
Отметим нестандартность конфигурации системы применительно к обработке ситуации заполнения потока: POSIX-2001 предусматривает, что подразумеваемыми (в зависимости от наличия журнала) могут быть лишь значения POSIX_TRACE_LOOP или POSIX_TRACE_FLUSH, но не POSIX_TRACE_UNTIL_FULL.
Читателю предлагается самостоятельно вычислить, сколько событий максимального размера можно записать в поток.