Книга: Разработка ядра Linux

Абсолютное время

Абсолютное время

Текущее значение абсолютного времени (time of day, wall time, время дня) определено в файле kernel/timer.c следующим образом.

struct timespec xtime;

Структура данных timespec определена в файле <linux/time.h> в следующем виде.

struct timespec {
 time_t tv_sec; /* seconds */
 long tv_nsec; /* nanoseconds */
};

Поле xtime.tv_sec содержит количество секунд, которые прошли с 1 января 1970 года (UTC, Universal Coordinated Time, всеобщее скоординированное время). Указанная дата называется epoch (начало эпохи). В большинстве Unix-подобных операционных систем счет времени ведется с начала эпохи. В поле xtime.tv_nsec хранится количество наносекунд, которые прошли в последней секунде.

Чтение или запись переменной xtime требует захвата блокировки xtime_lock. Это блокировка — не обычная спин-блокировка, а секвентная блокировка, которая рассматривается в главе 9, "Средства синхронизации в ядре".

Для обновления значения переменной xtime необходимо захватить секвентную блокировку на запись следующим образом.

write_seqlock(&xtime_lock);
/* обновить значение переменной xtime ... */
write_sequnlock(&xtime_lock);

Считывание значения переменной xtime требует применения функций read_seqbegin() и read_seqretry() следующим образом.

do {
 unsigned long lost;
 seq = read_seqbegin(&xtime_lock);
 usec = timer->get_offset();
 lost = jiffies — wall_jiffies;
 if (lost)
  usec += lost * (1000000 / HZ);
 sec = xtime.tv_sec;
 usec += (xtime.tv_nsec / 1000);
} while (read_seqretry(&xtime_lock, seq));

Этот цикл повторяется до тех пор, пока не будет гарантии того, что во время считывания данных не было записи. Если во время выполнения цикла приходит прерывание таймера и переменная xtime обновляется во время выполнения цикла, возвращаемый номер последовательности будет неправильным и цикл повторится снова.

Главный пользовательский интерфейс для получения значения абсолютного времени — это системный вызов gettimeofday(), который реализован как функция sys_gettimeofday() следующим образом.

asmlinkage long sys_gettimeofday(struct timeval *tv,
 struct timezone *tz) {
 if (likely(tv !=NULL)) {
  struct timeval_ktv;
  do_gettimeofday(&ktv);
  if (copy_to_userftv, &ktv, sizeof(ktv))
   return -EFAULT;
 }
 if (unlikely(tz != NULL)) {
  if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
   return -EFAULT;
 }
 return 0;
}

Если из пространства пользователя передано ненулевое значение параметра tv, то вызывается аппаратно-зависимая функция do_gettimeofday(). Эта функция главным образом выполняет цикл считывания переменной xtime, который был только что рассмотрен. Аналогично, если параметр tz не равен нулю, пользователю возвращается значение часового пояса (time zone), в котором находится операционная система. Этот параметр хранится в переменной sys_tz. Если при копировании в пространство пользователя значения абсолютного времени или часового пояса возникли ошибки, то функция возвращает значение -EFAULT. В случае успеха возвращается нулевое значение.

Ядро предоставляет системный вызов time()[58], однако системный вызов gettimeofday() полностью перекрывает его возможности. Библиотека функций языка С также предоставляет другие функции, связанные с абсолютным временем, такие как ftime() и ctime().

Системный вызов settimeofday() позволяет установить абсолютное время в указанное значение. Для того чтобы его выполнить, процесс должен иметь возможность использования CAP_SYS_TIME.

Если не считать обновления переменной xtime, то ядро не так часто использует абсолютное время, как пространство пользователя. Одно важное исключение— это код файловых систем, который хранят в индексах файлов значения моментов времени доступа к файлам.

Оглавление книги


Генерация: 4.431. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз