web-dev-qa-db-ja.com

Linuxで正しいCLOCK_TAIを取得する方法はありますか?

私のLinuxマシンはCLOCK_TAIをサポートしていますが、CLOCK_REALTIMEからのオフセットが誤ってゼロになっています(これがデフォルトです)。 CLOCK_TAIをTAIとして維持するソフトウェアまたはその他のソリューションはありますか?

回答 ここここ から、ntpdchronydもこれを行っていないようです。

CLOCK_REALTIMEgettimeofdayなどがPOSIX時間(基本的にUTC)を返す場合、これを実現するためにハードウェアクロックをTAIに設定できれば幸いです。

8
Ashley Yakeley

_clock_gettime_と_CLOCK_TAI_を正しく機能させたいと思います。私はやった。

参照された回答の重要な文は次のとおりです。「CLOCK_REALTIMEからのオフセットは起動時にゼロに初期化され、ntpdもchronydもデフォルトで正しい値(現在は35)に設定しないことに注意してください。」

オフセットが現在37であることを除けば、これは依然として当てはまる可能性がありますが、最近のntpdは、少なくともオフセットを設定するように構成できます。私は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
_

その後、clock_gettime(CLOCK_TAI, &res)は正しく機能しているように見えました。

Ntpは_ntp_adjtime_と_MOD_TAI_を使用してオフセットを設定すると思います。 grep -P '(ADJ|MOD)_TAI'でchronyソースを検索しても一致するものが見つからないため、chronyにはまだこの機能がないようです。

古いchronyの代わりにntpdを実行しているため、カーネルパラメータを正しく取得する自動化された方法がなかったため、別の方法を検討しました。

TAIとUTCの間のオフセットは比較的一定であるため(1年に1回未満の変更)、カーネルパラメータを静的に設定することが可能であり、アプリケーションでCLOCK_TAIクロックを使用すると正しい値が得られます。

カーネルソースのカーネルオフセットを設定するためのテストアプリケーションがtools/testing/selftests/timers/set-tai.cにあります。また、tzdataパッケージがインストールされているとすると、/usr/share/zoneinfo/leap-seconds.listにUTCとTAIの間にオフセットがあるファイルがあります。

カーネルテストアプリケーションを切り詰めたので、メインは次のようになりました。

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;
}

次に、私のユースケースでは、leap-seconds.listファイルから正しい値を抽出し、これをパラメーターとしてset-taiを実行するだけでした(/etc/rc.localで)。起動時間)。これを行う方法の例は次のとおりです。

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

これが他の誰かに役立つことを願っています!

3
Michael Firth

Djbからlibtaiを使用できます: https://cr.yp.to/libtai.html

それは何ですか?

libtaiは、日付と時刻を保存および操作するためのライブラリです。

libtaiは2つの時間スケールをサポートします。(1)TAI64、1秒の精度で数千億年をカバーします。 (2)TAI64NA、1アト秒の精度で同じ期間をカバーします。どちらのスケールも、現在の国際的なリアルタイム標準であるTAIで定義されています。

libtaiは、高速時間操作用に設計されたTAI64の内部形式であるstructtaiを提供します。 tai_pack()およびtai_unpack()ルーチンは、structtaiとポータブル8バイトTAI64ストレージ形式の間で変換します。 libtaiは、TAI64NAに同様の内部形式と外部形式を提供します。

libtaiは、日付を年-月-日の形式で格納するための構造体caldateを提供します。グレゴリオ暦の下で構造体caldateを変更されたユリウス日番号に変換して、日付を簡単に計算できます。

libtaiは、UTCオフセットとともにカレンダーの日付と時刻を格納するためのstructcaltimeを提供します。正確な日付と時刻を表示するために、うるう秒を考慮して、UTCでstructtaiからstructcaltimeに変換できます。また、ユーザー入力のためにstructcaltimeからstructtaiに戻すこともできます。その全体的なUTCからTAIへの変換速度は、通常のUNIX mktime()実装よりも100倍優れています。

このバージョンのlibtaiには、gettimeofday()を備えたUNIXシステムが必要です。 64ビット演算をサポートするコンパイラを使用すると、他のオペレーティングシステムに簡単に移植できます。

Libtaiのソースコードはパブリックドメインにあります。

3
dfc