Час UNIX вимірюється на вашому комп’ютері під керуванням UNIX.
Ця відповідь очікує, що ви дізнаєтесь, що таке Координаційний універсальний час (UTC), Міжнародний атомний час (ТАІ) та СІ другий. Пояснення їх виходить далеко за рамки Unix та Linux Stack Exchange. Це не обмін стеками фізики чи астрономії.
Апаратне забезпечення
Ваш комп'ютер містить різні генератори, які приводять у дію годинники та таймери. Точно те, що воно має, залежить від комп'ютера до комп'ютера, залежно від його архітектури. Але зазвичай і в дуже загальних рисах:
- Десь існує програмований інтервал таймера (PIT), який може бути запрограмований для підрахунку заданої кількості коливань і викликає перерву в центральний процесорний блок.
- На центральному процесорі є лічильник циклів, який просто нараховує 1 для кожного циклу інструкцій, який виконується.
Теорія функціонування, в дуже широкому плані
Ядро операційної системи використовує PIT для створення кліщів . Він налаштовує ПІТ на вільний хід, підраховуючи потрібну кількість коливань за часовий інтервал, скажімо, соту частину секунди, генеруючи переривання, а потім автоматично скидаючи лічильник знову. У цьому є різні варіанти, але по суті це призводить до того, що клітинне переривання піднімається з фіксованою частотою.
У програмному забезпеченні ядро збільшує лічильник кожного галочки. Він знає частоту галочок, оскільки запрограмував ПДФО в першу чергу. Тож відомо, скільки кліщів складає секунда. Він може використовувати це, щоб знати, коли збільшувати лічильник, який відлічує секунди. Останнє - ідея ядра "UNIX Time". Дійсно, просто рахувати вгору зі швидкістю один на SI секунду, якщо залишити його власним пристроям.
Чотири речі ускладнюють це, що я збираюся представити в дуже загальних рисах.
Обладнання не ідеально. ПІТ, в описі якого описується, що у нього частота коливань N Герц може замість цього мати частоту (скажімо) N .00002 Герц, з очевидними наслідками.
Ця схема дуже погано взаємодіє з управлінням живленням, оскільки процесор прокидається сотні разів за секунду, щоб зробити трохи більше, ніж збільшення числа в змінній. Тож деякі операційні системи мають, як відомо, «безголосні» конструкції. Замість того, щоб змусити ПДФО надсилати переривання за кожну галочку, ядро розраховує (із планувальника низького рівня), скільки кліщів буде проходити, не вичерпавшись жодних квантових потоків, і програмує ПІФО рахувати за стільки кліків у майбутнього перед тим, як видавати галочку переривання. Він знає, що тоді він повинен записати проходження N кліщів при наступному перериванні кліща, замість 1 галочки.
Прикладне програмне забезпечення має можливість змінювати поточний час ядра. Він може переходити до значення або може знижувати значення. Спати передбачає регулювання кількості кліщів, які повинні пройти, щоб збільшити лічильник секунд. Таким чином, лічильник секунд не обов'язково рахується зі швидкістю один на SI секунду в будь-якому випадку , навіть припускаючи ідеальні осцилятори. Крок передбачає просто записати нове число в лічильник секунд, що зазвичай не відбудеться до 1 SI секунди з моменту останньої позначки.
Сучасні ядра не тільки рахують секунди, але і рахують наносекунд. Але смішно і часто відверто нездійсненно перервати кліща один раз за наносекунд. Тут грають такі речі, як лічильник циклів . Ядро запам'ятовує значення лічильника циклу на кожній секунді (або на кожній галочці) і може розробитись із поточного значення лічильника, коли щось хоче знати час у наносекундах, скільки наносекунд повинно пройти з останньої секунди (або галочка). Знову ж таки, керування живленням та термічним режимом призводить до хаосу, оскільки частота циклу інструкцій може змінюватися, тому ядра роблять такі речі, як посилання на додаткове обладнання (наприклад, високоточний таймер подій (HPET)).
Мова C та POSIX
Стандартна бібліотека мови Сі описує час в термінах непрозорого типу, time_t
, типу структури tm
з різними заданими полями, а також різні функції , такі як бібліотеки time()
, mktime()
, і localtime()
.
Коротко: на мові С самого всього в гарантує , що time_t
є одним з доступних числових типів даних , і що єдиний надійний спосіб різниці у часі вираховує є difftime()
функцією. Саме стандарт POSIX надає більш жорсткі гарантії, що time_t
насправді є одним із цілих типів і що він рахує секунди після Епохи . Також стандарт POSIX визначає timespec
тип структури.
time()
Функція іноді описується як системний виклик. Насправді, це вже давно не є базовим системним викликом у багатьох системах. Наприклад, у FreeBSD лежить в основі системного виклику clock_gettime()
, який має різні "годинники", які вимірюють секунди або секунди + наносекунди різними способами. Саме цей системний виклик, за допомогою якого програмне забезпечення читає UNIX Time з ядра. (Відповідний clock_settime()
системний виклик дозволяє їм переходити, а adjtime()
системний виклик дозволяє виконувати його.)
Багато людей махають стандартом POSIX навколо дуже чіткими і точними твердженнями щодо того, що він призначає. Такі люди частіше за все насправді не читають стандарт POSIX. Як випливає з його обґрунтування, ідея рахувати "секунди з епохи", це фраза, яку використовує стандарт, навмисно не визначає, що POSIX секунди мають таку саму тривалість, як і секунди SI, і що результат gmtime()
"обов'язково" UTC, незважаючи на його появу ". Стандарт POSIX навмиснодостатньо розпущеним, так що він дозволяє (скажімо) UNIX-систему, куди йде адміністратор і вручну виправляє стрибкові секундні коригування, встановлюючи годинник через тиждень після того, як вони відбудуться. Справді, обґрунтування вказує на те, що навмисно досить вільно розміщувати системи, де годинник навмисно встановлений не так, ніж інший час UTC.
UTC та TAI
Інтерпретація часу UNIX, отриманого з ядра, полягає в підпрограмах бібліотеки, що працюють в додатках. POSIX вказує ідентичність між часом ядра та "часом розбиття" в a struct tm
. Але, як одного разу зазначав Даніель Дж. Бернштейн, видання стандарту 1997 року сприйняло цю особу бентежно неправильно, зіпсувавши правило випускного року григоріанського календаря (те, що вивчають школярі), так що розрахунок був помилковим з 2100 року. "Більше шанувань у порушенні, ніж дотримання" - це фраза, яка легко приходить на розум.
І справді це так. Зараз деякі інтерпретації базують цю інтерпретацію на бібліотечних процедурах, написаних Артуром Девідом Олсоном, які консультуються з сумнозвісною "базою даних часового поясу Олсона", яка зазвичай кодується у файлах баз даних під /usr/share/zoneinfo/
. Система Олсона мала два режими:
- "Секундами з епохи" ядра вважається вважати UTC секундами з 1970-01-01 00:00:00 UTC, за винятком високосних секунд. Тут використовується
posix/
набір файлів баз даних часового поясу Olson. Усі дні мають 86400 секунд ядра, і ніколи не буває 61 секунду за хвилину, але вони не завжди тривають секунду SI, а годинник ядра потребує повороту або кроку, коли трапляються високосні секунди.
- "Секундами з епохи" ядра вважається рахувати секунди TAI з 1970-01-01 00:00:10 TAI. Тут використовується
right/
набір файлів баз даних часового поясу Ольсона. Секунда в ядрі довга 1 SI секунди, а годинник ядра ніколи не потребує перемикання або кроку, щоб налаштувати стрибкові секунди, але розбитий час може мати такі значення, як 23:59:60, а дні не завжди мають 86400 секунд ядра.
М. Бернштейн написав кілька інструментів, включаючи свій daemontools
набір інструментів, який потрібен, right/
оскільки вони просто додали 10, time_t
щоб отримати секунди TAI з 1970-01-01 00:00:00 TAI. Він це задокументував на сторінці посібника.
Ця вимога була (можливо, несвідомо) успадкована наборами інструментів, такими як daemontools-encore
і runit
Фелікс фон Лейтнер libowfat
. Наприклад, використовуйте Бернштейнаmultilog
, Гюнтераmultilog
або Папуsvlogd
з posix/
конфігурацією Олсона , і всі часові позначки TAI64N будуть (на момент написання цього запису) на 26 секунд відставати від фактичного другого рахунку TAI з 1970-01-01 00:00:10 ТАІ.
Ми з Лораном Беркотом вирішили це в s6 and nosh, хоча ми використовували різні підходи. М. Беркот tai_from_sysclock()
покладається на прапор часу збирання. інструменти, що працюють в TAI64N, переглядають змінні TZ
та TZDIR
оточення для автоматичного виявлення, posix/
і right/
якщо вони можуть.
Цікаво, що документи FreeBSD time2posix()
та posix2time()
функції, які дозволяють еквівалентно right/
режиму Олсона з time_t
TAI секундами. Однак, очевидно, вони не включені.
Ще раз…
Час UNIX вимірюється на вашому комп'ютері під управлінням UNIX за допомогою осциляторів, що містяться в апараті комп'ютера. Він не використовує СІ секунд; це не UTC, хоча він може зовні нагадувати його; і це навмисно дозволяє вашому годиннику помилятися.
Подальше читання