Czas w systemie UNIX jest mierzony na komputerze z systemem UNIX.
Ta odpowiedź oczekuje, że będziesz wiedział, co to jest uniwersalny czas Coördinated (UTC), międzynarodowy czas atomowy (TAI) i sekunda SI. Wyjaśnienie ich znacznie wykracza poza zakres Unix i Linux Stack Exchange. To nie jest wymiana stosów fizyki ani astronomii.
Sprzęt
Twój komputer zawiera różne oscylatory, które napędzają zegary i timery. Dokładnie to, co ma, różni się w zależności od architektury w zależności od architektury. Ale zwykle i bardzo ogólnie:
- Gdzieś jest programowalny zegar interwałowy (PIT), który można zaprogramować tak, aby zliczał określoną liczbę oscylacji i wyzwalał przerwanie w centralnej jednostce przetwarzania.
- Na centralnym procesorze znajduje się licznik cykli, który po prostu zlicza 1 dla każdego wykonywanego cyklu instrukcji.
Teoria działania w bardzo szerokim ujęciu
Jądro systemu operacyjnego wykorzystuje PIT do generowania tików . Ustawia PIT na swobodny bieg, odliczając odpowiednią liczbę oscylacji w przedziale czasowym, powiedzmy, setnej sekundy, generując przerwanie, a następnie automatycznie resetując licznik, aby przejść ponownie. Istnieją różne warianty, ale w gruncie rzeczy powoduje to, że przerwanie tikowania jest podnoszone ze stałą częstotliwością.
W oprogramowaniu jądro zwiększa licznik co tyknięcie. Zna częstotliwość tykania, ponieważ w pierwszej kolejności zaprogramował PIT. Więc wie, ile tyknięć stanowi sekundę. Może to wykorzystać, aby wiedzieć, kiedy zwiększyć licznik, który liczy sekundy. To ostatnie jest pomysłem jądra na „UNIX Time”. Rzeczywiście po prostu liczy się w górę o jedną sekundę na sekundę SI, jeśli pozostawia się go własnym urządzeniom.
Komplikują to cztery rzeczy, które przedstawię bardzo ogólnie.
Sprzęt nie jest idealny. PIT, którego arkusz danych mówi, że ma częstotliwość oscylatora N Hertz, może zamiast tego mieć częstotliwość (powiedzmy) N .00002 Hertz, z oczywistymi konsekwencjami.
Ten schemat bardzo słabo współpracuje z zarządzaniem energią, ponieważ procesor budzi się setki razy na sekundę, aby zrobić niewiele więcej niż zwiększyć liczbę w zmiennej. Dlatego niektóre systemy operacyjne mają tak zwane „tykające” projekty. Zamiast zmuszać PIT do wysyłania przerwania dla każdego tiku, jądro oblicza (z poziomu niskiego poziomu harmonogramu), ile tików minie bez wyczerpania kwanty wątków, i programuje PIT, aby liczył tak wiele tików do przyszłość przed wydaniem przerwania kleszcza. Wie, że następnie musi zarejestrować przejście N tyknięć przy następnym przerwaniu tykania, zamiast 1 tyknięcia.
Oprogramowanie aplikacji może zmieniać aktualny czas jądra. To może zwiększyć wartość lub można go zabił wartość. Slewing polega na dostosowaniu liczby tyknięć, które muszą przejść, aby zwiększyć licznik sekund. Więc sekundy licznik nie musi liczyć w tempie jednego na drugi SI w każdym razie , nawet zakładając idealny oscylatorów. Stepping polega po prostu na wpisaniu nowej liczby w liczniku sekund, co zwykle nie nastąpi do 1 sekundy SI od ostatniej sekundy.
Nowoczesne jądra nie tylko liczą sekundy, ale także liczą nanosekundy. Ale przerywanie tyknięcia raz na nanosekundę jest śmieszne i często wręcz niemożliwe. W tym miejscu pojawiają się takie rzeczy, jak licznik cykli . Jądro pamięta wartość licznika cykli w każdej sekundzie (lub w każdym tiku) i może obliczyć, na podstawie bieżącej wartości licznika, gdy coś chce poznać czas w nanosekundach, ile nanosekund musiało upłynąć od ostatniej sekundy (lub kleszcz). Ponownie jednak zarządzanie energią i temperaturą powoduje spustoszenie, ponieważ częstotliwość cyklu instrukcji może się zmieniać, więc jądra polegają na dodatkowym sprzęcie, takim jak (powiedzmy) High Precision Event Timer (HPET).
Język C i POSIX
Biblioteka standardowa języka C opisuje czas pod względem nieprzezroczystego typu time_t
, rodzaju konstrukcja tm
z różnych określonych dziedzinach i różne funkcje, takie jak biblioteki time()
, mktime()
oraz localtime()
.
W skrócie: sam język C gwarantuje jedynie, że time_t
jest jednym z dostępnych typów danych liczbowych i że jedynym niezawodnym sposobem obliczania różnic czasowych jest difftime()
funkcja. Jest to standard POSIX, który zapewnia surowsze gwarancje, które time_t
w rzeczywistości są jednym z typów całkowitych i liczą sekundy od Epoki . Jest to również standard POSIX, który określa timespec
typ struktury.
time()
Funkcja czasami określa się jako połączenie systemu. W rzeczywistości od dawna nie było to wywołanie systemowe wielu systemów. Na przykład we FreeBSD bazowe wywołanie systemowe clock_gettime()
ma różne „zegary”, które mierzą w sekundach lub sekundach + nanosekundy na różne sposoby. Jest to wywołanie systemowe, za pomocą którego oprogramowanie aplikacji odczytuje czas UNIX z jądra. (Dopasowane clock_settime()
wywołanie systemowe pozwala im wykonać krok, a adjtime()
wywołanie systemowe pozwala im go zabić.)
Wiele osób macha standardem POSIX z bardzo określonymi i dokładnymi twierdzeniami na temat tego, co zaleca. Tacy ludzie najczęściej nie czytają standardu POSIX. Zgodnie z uzasadnieniem pomysł liczenia „sekund od epoki”, który jest zwrotem używanym przez standard, celowo nie określa, że sekundy POSIX mają taką samą długość jak sekundy SI, ani że wynik gmtime()
jest „koniecznie UTC, pomimo swojego wyglądu ”. Standard POSIX jest celowona tyle luźne, że pozwala (powiedzmy) systemowi UNIX, w którym administrator idzie i ręcznie naprawia drobne korekty, ustawiając ponownie zegar tydzień po ich wystąpieniu. W rzeczywistości uzasadnienie wskazuje, że jest celowo wystarczająco luźny, aby pomieścić systemy, w których zegar został celowo ustawiony nieprawidłowo na inny czas niż bieżący czas UTC.
UTC i TAI
Interpretacja czasu UNIX uzyskanego z jądra zależy od procedur bibliotecznych działających w aplikacjach. POSIX określa tożsamość między czasem jądra a „czasem awarii” w pliku struct tm
. Ale, jak kiedyś zauważył Daniel J. Bernstein, wydanie standardu z 1997 r. Wprowadziło tę zawstydzająco błędną tożsamość, zaburzając zasadę roku przestępnego w kalendarzu gregoriańskim (coś, czego uczą się uczniowie), tak że obliczenia były błędne od roku 2100. „Więcej honoru w naruszeniu niż w przestrzeganiu” to zdanie, które przychodzi mi do głowy.
I rzeczywiście tak jest. Wiele systemów obecnie opiera tę interpretację na procedurach bibliotecznych napisanych przez Arthura Davida Olsona, które sprawdzają niesławną „bazę danych stref czasowych Olsona”, zwykle zakodowaną w plikach bazy danych /usr/share/zoneinfo/
. System Olson miał dwa tryby:
- Uważa się, że „sekundy od epoki” jądra liczą sekundy UTC od 1970-01-01 00:00:00 UTC, z wyjątkiem sekund przestępnych. Wykorzystuje
posix/
zestaw plików bazy danych strefy czasowej Olson. Wszystkie dni mają 86400 sekund jądra i nigdy nie ma 61 sekund na minutę, ale nie zawsze mają one długość sekundy SI, a zegar jądra wymaga obracania lub stopniowania, gdy występują sekundy przestępne.
- Uważa się, że „sekundy od epoki” jądra liczą sekundy TAI od 1970-01-01 00:00:10 TAI. Wykorzystuje
right/
zestaw plików bazy danych strefy czasowej Olson. Sekundy jądra mają długość 1 sekundy SI, a zegar jądra nigdy nie potrzebuje zmiany ani kroku, aby dostosować się do sekund przestępnych, ale czasy awarii mogą mieć wartości takie jak 23:59:60, a dni nie zawsze wynoszą 86400 sekund jądra.
M. Bernstein napisał kilka narzędzi, w tym swój daemontools
zestaw narzędzi, które były wymagane, right/
ponieważ po prostu dodali 10, time_t
aby uzyskać sekundy TAI od 1970-01-01 00:00:00 TAI. Udokumentował to na stronie podręcznika.
Wymóg ten (być może nieświadomie) został odziedziczony przez zestawy narzędzi, takie jak daemontools-encore
i runit
Felixa von Leitnera libowfat
. Na przykład użyj Bernsteinamultilog
, Guenteramultilog
lub Pape'asvlogd
z posix/
konfiguracją Olsona , a wszystkie znaczniki czasu TAI64N będą (w chwili pisania tego tekstu) 26 sekund za faktyczną drugą liczbą TAI od 1970-01-01 00:00:10 TAI.
Laurent Bercot i ja zajęliśmy się tym w s6 i nosh, choć przyjęliśmy inne podejście. M. Bercot tai_from_sysclock()
opiera się na flagi czasu kompilacji. Narzędzia nosh, które działają w TAI64N, sprawdzają zmienne środowiskowe TZ
i, TZDIR
aby automatycznie wykryć posix/
i right/
jeśli potrafią.
Co ciekawe, dokumenty time2posix()
i posix2time()
funkcje FreeBSD, które pozwalają na ekwiwalent right/
trybu Olson z time_t
sekundami TAI. Jednak najwyraźniej nie są one włączone.
Jeszcze raz…
Czas w systemie UNIX jest mierzony na komputerze z systemem UNIX za pomocą oscylatorów zawartych w sprzęcie komputera. Nie używa sekund SI; to nie jest UTC, nawet jeśli powierzchownie może go przypominać; i celowo pozwala na to, aby Twój zegar się mylił.
Dalsza lektura