Existe uma maneira de obter CLOCK_TAI correto no Linux?

7

Minha máquina Linux suporta CLOCK_TAI , mas seu deslocamento de CLOCK_REALTIME é incorretamente zero (esse é o padrão). Existe software ou outra solução que irá manter CLOCK_TAI como TAI?

De respostas aqui e < href="https://stackoverflow.com/questions/32652688/what-is-the-epoch-of-clock-tai"> aqui , parece que nem ntpd nem chronyd fazem isso.

Eu ficaria feliz em configurar meu relógio de hardware para o TAI para obter isso, desde que CLOCK_REALTIME e gettimeofday etc. retornem a hora POSIX (essencialmente UTC).

    
por Ashley Yakeley 15.12.2016 / 08:05

3 respostas

4

Acho que você deseja que clock_gettime com CLOCK_TAI funcione corretamente. Eu também.

A sentença crítica na resposta referenciada é: "Por favor note que o offset de CLOCK_REALTIME é inicializado no boot para zero e nem o ntpd nem o chronyd o configuram por padrão para o valor correto (atualmente 35)."

Isso ainda pode ser verdade, exceto pelo deslocamento de 37, mas um ntpd recente pode pelo menos ser configurado para definir o deslocamento. Eu fiz o seguinte em uma máquina do openSUSE:

vi /etc/ntp.conf # Add the line: leapfile /var/lib/ntp/etc/ntp.leapseconds
update-leap
service ntpd restart
less /var/log/ntp # Check for errors

Então clock_gettime(CLOCK_TAI, &res) pareceu funcionar corretamente.

Acho que o ntp define o deslocamento usando ntp_adjtime com MOD_TAI . A pesquisa na fonte de chrony com grep -P '(ADJ|MOD)_TAI' não encontra correspondências, portanto, parece que o chrony ainda não possui esse recurso.

    
por 05.01.2017 / 15:45
3

Você pode usar libtai do djb: link

What is it?

libtai is a library for storing and manipulating dates and times.

libtai supports two time scales: (1) TAI64, covering a few hundred billion years with 1-second precision; (2) TAI64NA, covering the same period with 1-attosecond precision. Both scales are defined in terms of TAI, the current international real time standard.

libtai provides an internal format for TAI64, struct tai, designed for fast time manipulations. The tai_pack() and tai_unpack() routines convert between struct tai and a portable 8-byte TAI64 storage format. libtai provides similar internal and external formats for TAI64NA.

libtai provides struct caldate to store dates in year-month-day form. It can convert struct caldate, under the Gregorian calendar, to a modified Julian day number for easy date arithmetic.

libtai provides struct caltime to store calendar dates and times along with UTC offsets. It can convert from struct tai to struct caltime in UTC, accounting for leap seconds, for accurate date and time display. It can also convert back from struct caltime to struct tai for user input. Its overall UTC-to-TAI conversion speed is 100x better than the usual UNIX mktime() implementation.

This version of libtai requires a UNIX system with gettimeofday(). It will be easy to port to other operating systems with compilers supporting 64-bit arithmetic.

The libtai source code is in the public domain.

    
por 19.12.2016 / 20:51
3

Como estou executando chrony em vez do antigo ntpd , não tenho uma maneira automatizada de acertar o parâmetro do kernel, então procurei uma alternativa.

Como o deslocamento entre TAI e UTC é relativamente constante (mudanças < uma vez por ano), é possível definir estaticamente o parâmetro do kernel e, em seguida, usar o relógio CLOCK_TAI em um aplicativo fornecerá o valor correto.

Existe um aplicativo de teste para definir o deslocamento do kernel nos fontes do kernel, em tools/testing/selftests/timers/set-tai.c . E, supondo que você tenha o pacote tzdata instalado, há um arquivo com o deslocamento entre UTC e TAI em /usr/share/zoneinfo/leap-seconds.list .

Eu reduzi o aplicativo de teste do kernel para que o principal se tornasse:

int main(int argc, char **argv)
{
    int i, ret;

    ret = get_tai();
    printf("tai offset started at %i\n", ret);

    if (argc < 2)
    {
        printf("New offset not given, not setting\n");
    }
    else
    {
        i = strtol(argv[1],NULL,10);
        printf("Attempting to set TAI offset to %d\n",i);
        printf("Checking tai offsets can be properly set: ");
        ret = set_tai(i);
        ret = get_tai();
        if (ret != i) {
            printf("[FAILED] expected: %i got %i\n", i, ret);
            return EXIT_FAILURE;
        }
    }
    printf("[OK]\n");
    return EXIT_SUCCESS;
}

Em seguida, para o meu caso de uso, era apenas uma questão de extrair o valor correto do arquivo leap-seconds.list e executar set-tai com isso como um parâmetro (em /etc/rc.local para que isso acontecesse no momento da inicialização) . Um exemplo de como fazer isso é:

TAI_OFFSET=$(grep -v '^#' /usr/share/zoneinfo/leap-seconds.list | tail -1 | awk '{ print $2 }')
if [ -x /usr/local/sbin/set-tai ]; then
  /usr/local/sbin/set-tai $TAI_OFFSET
fi

Espero que isso seja útil para outra pessoa!

    
por 24.01.2018 / 10:52