El tiempo UNIX se mide en su computadora, ejecutando UNIX.
Esta respuesta esperará que sepas qué son la hora universal coordinada (UTC), la hora atómica internacional (TAI) y el segundo SI. Explicarlos está más allá del alcance de Unix y Linux Stack Exchange. Este no es el intercambio de pilas de física o astronomía.
El hardware
Su computadora contiene varios osciladores que manejan relojes y temporizadores. Exactamente lo que tiene varía de computadora a computadora dependiendo de su arquitectura. Pero generalmente, y en términos muy generales:
- Hay un temporizador de intervalo programable (PIT) en alguna parte, que se puede programar para contar un número determinado de oscilaciones y activar una interrupción en la unidad central de procesamiento.
- Hay un contador de ciclos en el procesador central que simplemente cuenta 1 para cada ciclo de instrucción que se ejecuta.
La teoría de la operación, en términos muy amplios.
El kernel del sistema operativo utiliza el PIT para generar ticks . Configura el PIT para que se ejecute libremente, contando el número correcto de oscilaciones durante un intervalo de tiempo de, por ejemplo, una centésima de segundo, generando una interrupción y luego restableciendo automáticamente el conteo para que vuelva a funcionar. Hay variaciones en esto, pero en esencia esto provoca que se levante una interrupción de tic con una frecuencia fija.
En software, el kernel incrementa un contador en cada tic. Conoce la frecuencia de tick, porque programó el PIT en primer lugar. Entonces sabe cuántas garrapatas forman un segundo. Puede usar esto para saber cuándo incrementar un contador que cuenta segundos. Esta última es la idea del núcleo de "Tiempo UNIX". De hecho, simplemente cuenta hacia arriba a razón de uno por segundo de SI si se deja en sus propios dispositivos.
Cuatro cosas complican esto, que voy a presentar en términos muy generales.
El hardware no es perfecto. Un PIT cuya hoja de datos dice que tiene una frecuencia de oscilador de N Hertz podría tener una frecuencia de (digamos) N .00002 Hertz, con las consecuencias obvias.
Este esquema interopera muy mal con la administración de energía, porque la CPU se está despertando cientos de veces por segundo para hacer poco más que incrementar un número en una variable. Entonces, algunos sistemas operativos tienen lo que se conoce como diseños "sin tick". En lugar de hacer que el PIT envíe una interrupción por cada tic, el kernel calcula (desde el planificador de bajo nivel) cuántos ticks van a pasar sin que se agote el quanta de subprocesos, y programa el PIT para contar esos tantos ticks en el futuro antes de emitir una interrupción de tic. Sabe que luego tiene que registrar el paso de N ticks en la próxima interrupción de tick, en lugar de 1 tick.
El software de aplicación tiene la capacidad de cambiar la hora actual del núcleo. Puede aumentar el valor o puede cambiar el valor. La rotación implica ajustar el número de tics que deben pasar para incrementar el contador de segundos. Por lo tanto, el contador de segundos no cuenta necesariamente a razón de uno por segundo de SI de todos modos , incluso suponiendo osciladores perfectos. El paso implica simplemente escribir un nuevo número en el contador de segundos, lo que generalmente no va a suceder hasta 1 SI segundo desde el último segundo marcado.
Los núcleos modernos no solo cuentan segundos sino que también cuentan nanosegundos. Pero es ridículo y, a menudo, absolutamente inviable tener una interrupción de marca de una vez por nanosegundo. Aquí es donde entran en juego cosas como el contador de ciclos . El núcleo recuerda el valor del contador del ciclo en cada segundo (o en cada tic) y puede calcular, a partir del valor actual del contador cuando algo quiere saber el tiempo en nanosegundos, cuántos nanosegundos deben haber transcurrido desde el último segundo (o garrapata). Una vez más, sin embargo, la administración de energía y térmica causa estragos con esto, ya que la frecuencia del ciclo de instrucciones puede cambiar, por lo que los núcleos hacen cosas como confiar en hardware adicional como (por ejemplo) un temporizador de eventos de alta precisión (HPET).
El lenguaje C y POSIX
La biblioteca estándar del lenguaje C describe el tiempo en términos de un tipo, opaca time_t
, un tipo de estructura tm
con varios campos especificados, y varias funciones de biblioteca como time()
, mktime()
, y localtime()
.
En resumen: el lenguaje C en sí mismo simplemente garantiza que time_t
es uno de los tipos de datos numéricos disponibles y que la única forma confiable de calcular las diferencias de tiempo es la difftime()
función. Es el estándar POSIX que proporciona las garantías más estrictas, que time_t
de hecho es uno de los tipos enteros y que cuenta segundos desde la época . También es el estándar POSIX que especifica el timespec
tipo de estructura.
La time()
función a veces se describe como una llamada al sistema. De hecho, no ha sido la llamada del sistema subyacente en muchos sistemas durante mucho tiempo, hoy en día. En FreeBSD, por ejemplo, la llamada al sistema subyacente es clock_gettime()
, que tiene varios "relojes" disponibles que miden en segundos o segundos + nanosegundos de varias maneras. Es esta llamada al sistema por la cual el software de aplicaciones lee el tiempo UNIX del núcleo. (Una clock_settime()
llamada del sistema coincidente les permite avanzar y una adjtime()
llamada del sistema les permite demorarlo).
Muchas personas agitan el estándar POSIX con afirmaciones muy definidas y exactas sobre lo que prescribe. Esas personas, en la mayoría de los casos, no han leído el estándar POSIX. Como establece su justificación, la idea de contar "segundos desde la Época", que es la frase que usa el estándar, no especifica intencionalmente que los segundos POSIX tengan la misma duración que los segundos SI, ni que el resultado de gmtime()
"necesariamente" UTC, a pesar de su apariencia ". El estándar POSIX es intencionalmentelo suficientemente flojo como para permitir (por ejemplo) un sistema UNIX donde el administrador va y arregla manualmente los segundos ajustes de salto reajustando el reloj la semana después de que sucedan. De hecho, la justificación señala que es lo suficientemente flexible como para acomodar sistemas en los que el reloj se ajustó deliberadamente en otro momento que no sea la hora UTC actual.
UTC y TAI
La interpretación del tiempo UNIX obtenida del núcleo depende de las rutinas de la biblioteca que se ejecutan en las aplicaciones. POSIX especifica una identidad entre el tiempo del núcleo y un "tiempo descompuesto" en a struct tm
. Pero, como Daniel J. Bernstein señaló una vez, la edición de 1997 del estándar se equivocó vergonzosamente esta identidad, estropeando la regla del año bisiesto del calendario gregoriano (algo que los escolares aprenden) para que el cálculo fuera un error a partir del año 2100 en adelante. "Más honrado en la violación que la observancia" es una frase que viene a la mente.
Y de hecho lo es. En la actualidad, varios sistemas basan esta interpretación en rutinas de biblioteca escritas por Arthur David Olson, que consultan la infame "base de datos de zonas horarias de Olson", generalmente codificada en archivos de bases de datos /usr/share/zoneinfo/
. El sistema Olson tenía dos modos:
- Se considera que los "segundos desde la Época" del núcleo cuentan los segundos UTC desde 1970-01-01 00:00:00 UTC, excepto los segundos intercalares. Esto utiliza el
posix/
conjunto de archivos de la base de datos de zonas horarias de Olson. Todos los días tienen 86400 segundos de kernel y nunca hay 61 segundos en un minuto, pero no siempre tienen la duración de un segundo SI y el reloj del kernel necesita girar o avanzar cuando se producen segundos de salto.
- Se considera que los "segundos desde la Época" del núcleo cuentan los segundos TAI desde 1970-01-01 00:00:10 TAI. Esto utiliza el
right/
conjunto de archivos de la base de datos de zonas horarias de Olson. Los segundos del kernel duran 1 SI segundo y el reloj del kernel nunca necesita girar o ajustarse para ajustarse durante los segundos bisiestos, pero los tiempos desglosados pueden tener valores como 23:59:60 y los días no siempre duran 86400 segundos del kernel.
M. Bernstein escribió varias herramientas, incluido su daemontools
conjunto de herramientas, que requirieron right/
porque simplemente agregaron 10 time_t
para obtener TAI segundos desde 1970-01-01 00:00:00 TAI. Lo documentó en la página del manual.
Este requisito fue (tal vez sin saberlo) heredada por conjuntos de herramientas tales como daemontools-encore
e runit
y por Felix von Leitner libowfat
. Utilice Bernsteinmultilog
, Guentermultilog
o Papesvlogd
con una posix/
configuración de Olson , por ejemplo, y todas las marcas de tiempo TAI64N estarán (en el momento de escribir esto) 26 segundos detrás del segundo recuento real de TAI desde 1970-01-01 00:00:10 TAI
Laurent Bercot y yo abordamos esto en s6 y nosh, aunque tomamos diferentes enfoques. M. Bercot se tai_from_sysclock()
basa en una bandera de tiempo de compilación. nosh herramientas que tienen que ver en la mirada tai64n a las TZ
y TZDIR
variables de entorno para detectar automáticamente posix/
y right/
si pueden.
Curiosamente, los documentos time2posix()
y posix2time()
funciones de FreeBSD que permiten el equivalente del right/
modo Olson con time_t
segundos TAI. Sin embargo, aparentemente no están habilitados.
Una vez más…
El tiempo UNIX se mide en su computadora que ejecuta UNIX, mediante osciladores contenidos en el hardware de su computadora. No usa segundos SI; no es UTC aunque superficialmente se parezca a él; e intencionalmente permite que su reloj esté equivocado.
Otras lecturas