adjtimex, clock_adjtime, ntp_adjtime -
тонкая
настройка
часов в
ядре
Standard C library (
libc,
-lc)
#include <sys/timex.h>
int adjtimex(struct timex *buf);
int clock_adjtime(clockid_t clk_id, struct timex *buf);
int ntp_adjtime(struct timex *buf);
В Linux для
подстройки
часов
используется
алгоритм
Дэвида Л.
Миллса (David L. Mills)
(смотрите
RFC 5905).
Системный
вызов
adjtimex()
читает и
(необязательно)
устанавливает
параметры
подстройки
для этого
алгоритма.
Он берёт
указатель
на
структуру
timex, изменяет
параметры
ядра
согласно
значениям
(некоторых)
её полей и
возвращает
эту уже
обновлённую
структуру
с текущими
значениями
параметров
ядра.
Данная
структура
объявлена
так:
struct timex {
int modes; /* выбор режима */
long offset; /* смещение по времени; в наносекундах, если
установлен флаг состояния STA_NANO, иначе
в микросекундах */
long freq; /* смещение частоты; единицы измерения */
описаны в ЗАМЕЧАНИЯХ */ long maxerror; /* максимальная ошибка (микросекунды) */
long esterror; /* ожидаемая ошибка (микросекунды) */
int status; /* команда/состояние для часов */
long constant; /* константа времени PLL (phase-locked loop) */
long precision; /* точность часов
(микросекунды, только чтение) */
long tolerance; /* допуск тактовой частоты (только чтение);
единицы измерения описаны в ЗАМЕЧАНИЯХ */
struct timeval time;
/* текущее время (только чтение, кроме
ADJ_SETOFFSET); при возврате в time.tv_usec
содержатся наносекунды, если установлен флаг
STA_NANO, иначе микросекунды */
long tick; /* микросекунд между тиками часов */
long ppsfreq; /* частота PPS (импульсов в секунду)
(только чтение); единицы измерения описаны в
ЗАМЕЧАНИЯХ */
long jitter; /* искажение PPS (только чтение); в наносекундах,
если установлен флаг состояния STA_NANO,
иначе в микросекундах
int shift; /* длительность интервала PPS
(секунды, только чтение) */
long stabil; /* устойчивость PPS (только чтение);
единицы измерения описаны в ЗАМЕЧАНИЯХ */
long jitcnt; /* счётчик превышений ограничения искажения
PPS (только чтение) */
long calcnt; /* счётчик интервалов калибровки PPS
(только чтение) */
long errcnt; /* счётчик ошибок калибровки PPS
(только чтение) */
long stbcnt; /* счётчик событий превышения ограничения
устойчивости PPS (только чтение) */
int tai; /* смещение TAI offset, установленное предыдущей
операцией ADJ_TAI (секунды, только чтение,
начиная с Linux 2.6.26) */
/* далее идут байты заполнения, для расширения структуры в будущем */
};
Полем
modes
определяется
какие
параметры,
если это
необходимо,
устанавливаются
(как
описывалось
выше,
константы,
используемые
в
ntp_adjtime(), те же
самые, но
названные
по-другому).
Является
битовой
маской,
содержащей
побитовую (
или)
комбинацию
нуля или
более
следующих
бит:
- ADJ_OFFSET
- Установить
смещение
по времени
из buf.offset.
Начиная с Linux
2.6.26,
переданное
значение
ограничивается
диапазоном
(-0.5s, +0.5s). В старых
ядрах, если
значение
выходит из
диапазона,
то
возвращается
ошибка EINVAL.
- ADJ_FREQUENCY
- Установить
смещение
по частоте
из buf.offset.
Начиная с Linux
2.6.26,
переданное
значение
ограничивается
диапазоном
(-32768000, +32768000) В
старых
ядрах, если
значение
выходит из
диапазона,
то
возвращается
ошибка EINVAL.
- ADJ_MAXERROR
- Установить
максимальную
ошибку
времени из
buf.maxerror.
- ADJ_ESTERROR
- Установить
ожидаемую
ошибку
времени из
buf.esterror.
- ADJ_STATUS
- Установить
биты
состояния
часов из
buf.status.
Описание
бит
представлено
ниже.
- ADJ_TIMECONST
- Установить
константу
времени PLL
из buf.constant. Если
не задан
флаг
состояния
STA_NANO
(смотрите
ниже), то
ядро
добавляет
к этому
значению 4.
-
ADJ_SETOFFSET
(начиная с Linux
2.6.39)
- Добавить
buf.time к
текущему
времени.
Если в buf.status
указан
флаг ADJ_NANO, то
значение
buf.time.tv_usec
считается
заданным в
наносекундах;
в
противном
случае это
микросекунды.
- The value of buf.time is the sum of its two fields,
but the field buf.time.tv_usec must always be nonnegative. The
following example shows how to normalize a timeval with nanosecond
resolution.
-
while (buf.time.tv_usec < 0) {
buf.time.tv_sec -= 1;
buf.time.tv_usec += 1000000000;
}
-
ADJ_MICRO
(начиная с Linux
2.6.26)
- Выбрать
микросекундной
разрешение.
-
ADJ_NANO
(начиная с Linux
2.6.26)
- Выбрать
наносекундной
разрешение.
Должно
быть
указано
что-то
одно: ADJ_MICRO
или ADJ_NANO.
-
ADJ_TAI
(начиная с Linux
2.6.26)
- Установить
смещение TAI
(атомное
международное
время) из
buf.constant.
-
ADJ_TAI не
должно
использоваться
вместе с
ADJ_TIMECONST, так как
последний
режим
также
использует
поле buf.constant.
- Подробное
описание TAI
и различия
между TAI и UTC
смотрите
в
BIPM
- ADJ_TICK
- Установить
значение
тика из buf.tick.
Также в
modes
можно
указывать
любое из
следующих
значений
(многобитовая
маска), биты
которых
нельзя
указать в
modes:
- ADJ_OFFSET_SINGLESHOT
- Старый
вариант
adjtime(3):
(постепенно)
корректировать
время
значением,
указанным
в buf.offset,
которое
задаётся в
микросекундах.
-
ADJ_OFFSET_SS_READ
(работает,
начиная с Linux
2.6.28)
- Получить
(в buf.offset)
остаток
необходимого
откорректированного
времени
после
выполнения
операции
ADJ_OFFSET_SINGLESHOT. Это
возможность
была
добавлена
в Linux 2.6.24, но
работала
неправильно
до Linux 2.6.28.
Обычные
пользователи
могут
задавать в
modes значение
ноль или
ADJ_OFFSET_SS_READ. Только
суперпользователь
может
задавать
любые
параметры.
Поле
buf.status
представляет
собой
битовую
маску,
используется
для
установки/получения
битов
состояния,
связанных
с
реализацией
NTP. Одни биты
в маске
можно и
читать, и
изменять,
другие —
только
читать.
-
STA_PLL
(чтение-запись)
- Включить
обновление
фазовой
подстройки
частоты (PLL)
через ADJ_OFFSET.
-
STA_PPSFREQ
(чтение-запись)
- Включить
частотную
дисциплину
обслуживания
PPS
(импульсов
в секунду).
-
STA_PPSTIME
(чтение-запись)
- Включить
временную
дисциплину
обслуживания
PPS.
-
STA_FLL
(чтение-запись)
- Выбрать
режим
частотной
подстройки
частоты (FLL).
-
STA_INS
(чтение-запись)
- Вставить
високосную
секунду за
последней
секундой
дня UTC, то
есть
удлинить
последнюю
минуту дня
на одну
секунду.
Вставка
високосной
секунды
будет
происходить
каждый
день пока
установлен
этот флаг.
-
STA_DEL
(чтение-запись)
- Удалить
високосную
секунду из
последней
секунды
дня UTC.
Удаление
високосной
секунды
будет
происходить
каждый
день пока
установлен
этот флаг.
-
STA_UNSYNC
(чтение-запись)
- Часы не
синхронизированы.
-
STA_FREQHOLD
(чтение-запись)
- Зафиксировать
частоту.
Обычно
корректировки,
внесённые
через
результат
ADJ_OFFSET,
приводят к
ослаблению
также
проводимых
настроек
по частоте.
Таким
образом,
единичный
вызов
исправляет
текущее
смещение,
но
поскольку
смещения в
том же
направлении
делаются
неоднократно,
маленькие
изменения
по частоте
будут
накапливаться,
чтобы
исправить
длинный
сдвиг.
- Данный
флаг
отключает
маленькие
исправления
по частоте
при
корректировке
значения
ADJ_OFFSET.
-
STA_PPSSIGNAL
(только
чтение)
- Присутствует
сигнал PPS
(импульсов
в секунду).
-
STA_PPSJITTER
(только
чтение)
- Превышено
искажение
сигнала PPS.
-
STA_PPSWANDER
(только
чтение)
- Превышено
отклонение
сигнала PPS.
-
STA_PPSERROR
(только
чтение)
- Ошибка
калибровки
сигнала PPS.
-
STA_CLOCKERR
(только
чтение)
- Проблема
с
аппаратурой
часов.
-
STA_NANO
(только
чтение;
начиная с Linux
2.6.26)
- Единица
данных (0 =
микросекунды,
1 =
наносекунды).
Устанавливается
с помощью
ADJ_NANO,
очищается
с помощью
ADJ_MICRO.
-
STA_MODE
(начиная с Linux
2.6.26)
- Режим (0 =
фазовая
подстройка
частоты, 1 =
частотная
подстройка
частоты).
-
STA_CLK
(только
чтение;
начиная c Linux
2.6.26)
- Источник
часов (0 = A, 1 = B); не
используется.
Попытки
установить
биты
status,
помеченные
только для
чтения,
просто
игнорируются.
The
clock_adjtime() system call (added in Linux 2.6.39) behaves like
adjtimex() but takes an additional
clk_id argument to specify
the particular clock on which to act.
Библиотечная
функция
ntp_adjtime()
(описана в NTP
"Kernel Application Program API", KAPI)
является
более
переносимым
интерфейсом
для
выполнения
той же
задачи, что
и
adjtimex(). Она
идентична
adjtimex() кроме
следующего:
- •
- Константы,
используемые
в modes,
начинаются
с «MOD_», а не с
«ADJ_», и
содержат
одинаковые
суффиксы (
MOD_OFFSET, MOD_FREQUENCY, and so on),
кроме:
- •
-
MOD_CLKA —
синоним
ADJ_OFFSET_SINGLESHOT.
- •
-
MOD_CLKB —
синоним
ADJ_TICK.
- •
- Синонима
для ADJ_OFFSET_SS_READ в KAPI
нет.
При
успешном
выполнении
adjtimex() и
ntp_adjtime()
возвращают
состояние
часов, а
именно
одно из
следующих
значений:
- TIME_OK
- Часы
синхронизированы,
подстройки
високосной
секундой
не
ожидается.
- TIME_INS
- Показывает,
что в конце
дня по UTC
будет
добавлена
високосная
секунда.
- TIME_DEL
- Показывает,
что в конце
дня по UTC
будет
удалена
високосная
секунда.
- TIME_OOP
- Выполняется
вставка
високосной
секунды.
- TIME_WAIT
- Выполнена
вставка
или
удаление
високосной
секунды.
Это
значение
возвращается
при
следующей
операции
ADJ_STATUS по
очистке
флагов STA_INS и
STA_DEL.
- TIME_ERROR
- Системное
время не
синхронизировано
с
авторитетным
сервером.
Это
значение
возвращается
при любом
утвердительном
значении
следующего:
- •
- Установлен
STA_UNSYNC или STA_CLOCKERR.
- •
- Флаг STA_PPSSIGNAL
сброшен и
установлен
STA_PPSFREQ или STA_PPSTIME.
- •
- Установлены
флаги STA_PPSTIME и
STA_PPSJITTER.
- •
- Установлен
флаг STA_PPSFREQ и
STA_PPSWANDER или STA_PPSJITTER.
- Символическое
имя TIME_BAD —
синоним
TIME_ERROR,
предоставляется
для
обратной
совместимости.
Заметим,
что
начиная с Linux 3.4
вызов
выполняется
асинхронно
и
возвращаемое
значение,
обычно, не
отражает
состояние,
изменённое
самим
вызовом.
On failure, these calls return -1 and set
errno to indicate the error.
- EFAULT
-
buf не
является
указателем
на
доступную
для записи
область
памяти.
-
EINVAL (before Linux 2.6.26)
- Попытка
установить
buf.freq в
значение
вне
диапазона
(-33554432, +33554432).
-
EINVAL (before Linux 2.6.26)
- An attempt was made to set buf.offset to a value
outside the permitted range. Before Linux 2.0, the permitted range was
(-131072, +131072). From Linux 2.0 onwards, the permitted range was
(-512000, +512000).
- EINVAL
- Попытка
установить
buf.status в
значение,
отличное
от
перечисленных
выше.
- EINVAL
- The clk_id given to clock_adjtime() is
invalid for one of two reasons. Either the System-V style hard-coded
positive clock ID value is out of range, or the dynamic clk_id does
not refer to a valid instance of a clock object. See
clock_gettime(2) for a discussion of dynamic clocks.
- EINVAL
- Предпринята
попытка
установить
buf.tick в
значение
вне
диапазона
от 900000/ HZ до 1100000/HZ,
где HZ —
частота
прерываний
системного
таймера.
- ENODEV
- The hot-pluggable device (like USB for example) represented
by a dynamic clk_id has disappeared after its character device was
opened. See clock_gettime(2) for a discussion of dynamic
clocks.
- EOPNOTSUPP
- The given clk_id does not support adjustment.
- EPERM
- Значение
buf.modes не равно
0 или ADJ_OFFSET_SS_READ и
вызывающий
не имеет
необходимых
прав. В Linux для
этого
требуется
мандат CAP_SYS_TIME.
Описание
терминов
данного
раздела
смотрите в
attributes(7).
Интерфейс |
Атрибут |
Значение |
ntp_adjtime() |
Безвредность
в нитях |
MT-Safe |
Эти
интерфейсы
не описаны
в POSIX.1
adjtimex() and
clock_adjtime() are Linux-specific and should not
be used in programs intended to be portable.
Предпочтительным
программным
интерфейсом
для службы NTP
является
ntp_adjtime().
In struct
timex,
freq,
ppsfreq, and
stabil are ppm
(parts per million) with a 16-bit fractional part, which means that a value of
1 in one of those fields actually means 2^-16 ppm, and 2^16=65536 is 1 ppm.
This is the case for both input values (in the case of
freq) and output
values.
Обработка
високосной
секунды,
возникающая
при
установке
STA_INS и
STA_DEL,
выполняется
ядром в
контексте
таймера.
Следовательно,
для
установки
или
удаления
високосной
секунды
потребуется
один тик
для
перехода.
clock_gettime(2),
clock_settime(2),
settimeofday(2),
adjtime(3),
ntp_gettime(3),
capabilities(7),
time(7),
adjtimex(8),
hwclock(8)
NTP
"Kernel Application Program Interface"
Русский
перевод
этой
страницы
руководства
был сделан
Dmitry Bolkhovskikh <
[email protected]> и Yuri Kozlov
<
[email protected]>
Этот
перевод
является
бесплатной
документацией;
прочитайте
Стандартную
общественную
лицензию GNU
версии 3
или более
позднюю,
чтобы
узнать об
условиях
авторского
права. Мы не
несем
НИКАКОЙ
ОТВЕТСТВЕННОСТИ.
Если вы
обнаружите
ошибки в
переводе
этой
страницы
руководства,
пожалуйста,
отправьте
электронное
письмо на
[email protected]