systemdにclock_reset_timewarp
(当該コード) という謎の処理を行なう関数があったので調べてみた。
settimeofday(2)でタイムゾーンを設定するだけの処理だけど、そこに書かれているコメントが意味深なのである。
/*
* The very first call to settimeofday() does time warp magic. Do a
* dummy call here, so the time warping is sealed and all later calls
* behave as expected.
*/
これが何を意味しているのかはsettimeofday(2)のマニュアル (英語版) に書いてあるのだが、Linuxのsettimeofdayは妙な動作をするらしい。
Linux では、 settimeofday() システムコールに関連して、独特の「クロックのズレ (warp clock)」が存在する場合がある。 これは (ブート後の) 最初の呼び出しで tz 引き数が NULL でなく、 tv 引き数が NULL で tz_minuteswest フィールド が 0 でない場合に起こる (この場合 tz_dsttime フィールドは 0 にすべきである)。 このような場合、 settimeofday() は CMOS クロックが地方時 (local time) であり、 UTC システム時間を得るためには、tz_minuteswest の分だけ増加させなくてはなら ないとみなしてしまう。 疑いもなく、この機構を使うことは良い考えではない。
Man page of GETTIMEOFDAYより引用
ちょっと分かりにくいが、どうもLinuxはブート直後の最初のsettimeofday(2)でCMOSの時間がローカルタイムかどうか判定しているらしい。そして、ローカルタイムと判断した場合は、以降のgettimeofday(2)でローカルタイム補正をした値を返すようになるようだ。systemdは補正がかからないようにするために0 (DST_NONE
)を設定している。(普通は補正はユーザランドでやるはず。)
initならではの処理だなーと思った。