#include
#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
Процесс может использовать вызовы setitimer() и alarm() для установки таймера, чтобы получить сигнал по прошествии реального или процессорного времени. Одно из применений таймеров заключается в ограничении времени блокирования системных вызовов.
Приложения, которым нужно приостанавливать выполнение на определенное количество времени, могут использовать для этого целый ряд функций перехода в режим сна.
Linux 2.6 реализует расширения стандарта POSIX.1b, которые предусматривают программный интерфейс для высокоточных часов и таймеров. Такие таймеры имеют ряд преимуществ перед своими традиционными аналогами (вызов setitimer() в UNIX). Они позволяют создавать несколько таймеров, выбирать сигнал, который будет доставляться при срабатывании, извлекать количество дополнительных срабатываний, чтобы определить, срабатывал ли таймер с момента последнего уведомления, а также указывать способ доставки уведомлений — с помощью функции в отдельном потоке или посредством сигнала.
Linux также предоставляет нестандартный программный интерфейс timerfd, аналогичный POSIX-интерфейсу. Он тоже содержит несколько вызовов для создания таймеров, но позволяет считывать уведомления о срабатывании с помощью файлового дескриптора. Этот дескриптор можно отслеживать с использованием вызовов select() и poll(), а также интерфейса epoll.
Вместе с обоснованием необходимости отдельных функций в стандарте SUSv3 указаны полезные примечания относительно (стандартных) интерфейсов для таймеров и перехода в режим сна, описанных в этой главе. В книге [Gallmeister, 1995] обсуждаются часы и таймеры стандарта POSIX.1b.
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().
24. Создание процессов
В этой и следующих четырех главах мы рассмотрим создание и завершение процессов, а также то, как процесс может выполнить новую программу. Эта глава посвящена созданию процессов. Но прежде, чем углубляться в эту тему, начнем с краткого обзора главных системных вызовов, которые нам понадобятся.