#include  /* Определение uint64_t */

#include "itimerspec_from_str.h" /* Объявляет itimerspecFromStr() */

#include "tlpi_hdr.h"

int

main(int argc, char *argv[])

{

struct itimerspec ts;

struct timespec start, now;

int maxExp, fd, secs, nanosecs;

uint64_t numExp, totalExp;

ssize_t s;

if (argc < 2 || strcmp(argv[1], "-help") == 0)

usageErr("%s secs[/nsecs][: int-secs[/int-nsecs]] [max-exp]\n", argv[0]);

itimerspecFromStr(argv[1], &ts);

maxExp = (argc > 2)? getInt(argv[2], GN_GT_0, "max-exp"): 1;

fd = timerfd_create(CLOCK_REALTIME, 0);

if (fd == –1)

errExit("timerfd_create");

if (timerfd_settime(fd, 0, &ts, NULL) == –1)

errExit("timerfd_settime");

if (clock_gettime(CLOCK_MONOTONIC, &start) == –1)

errExit("clock_gettime");

for (totalExp = 0; totalExp < maxExp;) {

/* Считываем данные о срабатываниях и выводим время, прошедшее с момента запуска

таймера, и число срабатываний (зафиксированное на текущий момент и общее). */

s = read(fd, &numExp, sizeof(uint64_t));

if (s!= sizeof(uint64_t))

errExit("read");

totalExp += numExp;

if (clock_gettime(CLOCK_MONOTONIC, &now) == –1)

errExit("clock_gettime");

secs = now.tv_sec — start.tv_sec;

nanosecs = now.tv_nsec — start.tv_nsec;

if (nanosecs < 0) {

secs-;

nanosecs += 1000000000;

}

printf("%d.%03d: expirations read: %llu; total=%llu\n",

secs, (nanosecs + 500000) / 1000000,

(unsigned long long) numExp, (unsigned long long) totalExp);

}

exit(EXIT_SUCCESS);

}

timers/demo_timerfd.c

23.8. Резюме

Процесс может использовать вызовы setitimer() и alarm() для установки таймера, чтобы получить сигнал по прошествии реального или процессорного времени. Одно из применений таймеров заключается в ограничении времени блокирования системных вызовов.

Приложения, которым нужно приостанавливать выполнение на определенное количество времени, могут использовать для этого целый ряд функций перехода в режим сна.

Linux 2.6 реализует расширения стандарта POSIX.1b, которые предусматривают программный интерфейс для высокоточных часов и таймеров. Такие таймеры имеют ряд преимуществ перед своими традиционными аналогами (вызов setitimer() в UNIX). Они позволяют создавать несколько таймеров, выбирать сигнал, который будет доставляться при срабатывании, извлекать количество дополнительных срабатываний, чтобы определить, срабатывал ли таймер с момента последнего уведомления, а также указывать способ доставки уведомлений — с помощью функции в отдельном потоке или посредством сигнала.

Linux также предоставляет нестандартный программный интерфейс timerfd, аналогичный POSIX-интерфейсу. Он тоже содержит несколько вызовов для создания таймеров, но позволяет считывать уведомления о срабатывании с помощью файлового дескриптора. Этот дескриптор можно отслеживать с использованием вызовов select() и poll(), а также интерфейса epoll.

Дополнительная информация

Вместе с обоснованием необходимости отдельных функций в стандарте SUSv3 указаны полезные примечания относительно (стандартных) интерфейсов для таймеров и перехода в режим сна, описанных в этой главе. В книге [Gallmeister, 1995] обсуждаются часы и таймеры стандарта POSIX.1b.

23.9. Упражнения

23.1. Функция alarm() реализована в виде системного вызова внутри ядра Linux. Реализуйте ее самостоятельно на основе вызова setitimer().

23.2. Попробуйте запустить программу из листинга 23.3 (t_nanosleep.c) в фоне и с 60-секундным интервалом сна; в то же время запустите следующую команду, чтобы послать фоновому процессу как можно больше сигналов SIGINT:

$ while true; do kill — INT pid; done

Вы должны обнаружить, что программа находится в режиме сна дольше, чем ожидалось. Поменяйте вызов nanosleep() на функции clock_gettime() (используя часы CLOCK_REALTIME) и clock_nanosleep() с флагом TIMER_ABSTIME (для этого упражнения требуется ядро не ниже версии 2.6). Проделайте те же действия с измененной программой и объясните, с чем связаны различия.

23.3. Напишите программу, которая демонстрирует, что передача вызову timer_create() аргумента evp, равного NULL, эквивалентно присвоению этому аргументу указателя на структуру sigevent, чьи поля sigev_notify, sigev_signo и si_value.sival_int равны SIGEV_SIGNAL, SIGALRM и соответственно идентификатору таймера.

23.4. Модифицируйте программу ptmr_sigev_signal.c из листинга 23.5, заменив обработчик сигнала вызовом sigwaitinfo().

<p>24. Создание процессов</p>

В этой и следующих четырех главах мы рассмотрим создание и завершение процессов, а также то, как процесс может выполнить новую программу. Эта глава посвящена созданию процессов. Но прежде, чем углубляться в эту тему, начнем с краткого обзора главных системных вызовов, которые нам понадобятся.

24.1. Обзор вызовов fork(), exit(), wait() и execve()
Перейти на страницу:

Похожие книги