gettimeofday
ある日、ふと携帯を確認したら、兄貴より怒涛の着信履歴が。。。携帯と言いつつ常に身に着けている訳ではないので(散歩の時は、迷子札宜しく携帯しろよ。)気がつかなかったよ。
何か重大な事でも有ったのか? 慌てて連絡すると、携帯変えたですって! とうとう身内を語る、オレオレ詐欺がやって来たかと思ったぞ。あんたの生年月日は?とか、小学校の担任の先生の名前は?とかは、あえて確認するの止めたおいた。
なんでも、携帯からスマホにチェンジしたんで、通話出来るかの試験をしたんだって。で、さっぱり応答が無いものだから、何回も電話したとな。気持ち分かりますよ。登録ミスがあったのか、操作を間違えているんではと、不安になりますからね。
暫くして、遊びに来た。孫の所へ行っていたんで、その時の土産と孫の動画を見せにね。下手なアングルでの動画だった。孫の頭のアップなんて見せられても面白くないぞ。もっと修行してユーチューバーぐらいの腕前になったら、見せておくれ。
アンドドロイドの携帯。字が小さくてオイラーは扱えんな。女房はさかんに携帯止めてスマホにしろって、携帯屋の回し者のように勧めてくるけど、いよいよスマホ拒否症だな。使いもしないのに、毎日充電なんてヤナこったい。家にはパソコンは有るしipadも有る。幾ら使っても、ギガが減るってソワソワする必要無し。携帯屋の思惑にはハマりませんよ。
兄貴はLINEで苦労してるみたい。入力方法が分からんですって。それはオイラーは知ってるぞ。 タッチしてからスライドでしょ。あの人がずっと昔に自慢記事を書いてたのを思い出したら、一発で使えたよ。でも、慣れるまで大変そう。逆に慣れたら、キーボードもスライドしちゃったりして。
まあ、頑張って老化現象に歯止めをかけてくださいな。
gettimeofday
最近トランプ野郎の弾劾裁判で無罪を勝ち取った野郎が、それを伝える新聞を掲げて、久しぶりに良い記事を書いたと誉めていた。何時もはフェイクニュースを垂れ流すとメディアを攻撃してるのにね。子供だね、実に分かり易い人だ。
Linuxカーネル5.6、32ビット版で2038年問題への対応が行われるこんなのを前回取り上げた。真偽を確かめるのが大人の仕事です。記事を追って行くと、2038年問題に対応した「OpenBSD 5.5」リリースに達する。ここから先は、自分で調べろだな。
前回の投稿のサンプルをコンパイルしてみる。
OpenBSD o32.localdomain 6.6 GENERIC.MP#4 i386 o32$ cc t.c o.c:7:29: warning: format specifies type 'long' but the argument has type 'time_t' (aka 'long long') [-Wformat] printf("%ld %06lu\n", tv.tv_sec, tv.tv_usec); ~~~ ^~~~~~~~~ %lld 1 warning generated.
実験環境は、言うまでもない32Bit機だ。コンパイラーから警告が出てきた。修正方法も提示されている。警告なんで、無視しても2038年1月までは、問題が表面化しないんだな。
でも、『冷酒と親の小言は後で効く』って、分かっているんで、早期に剪定しておけば、後は左団扇で暮らせる。最近は私のHPも外国の方が(翻訳しながら)読んで下さっているようなんで、ググル翻訳を困らせるような日本固有の格言は控えた方が良いのかな?
o32$ ./a.out 1581115660 487071 o32$ date -r 1581115660 Sat Feb 8 07:47:40 JST 2020 o32$ date +%s 1581115689
リナではdateコマンドに直交性が無くてイライラするけど、BSDは綺麗なものだ、とディスっておこう。ストレス発散で健康生活!!
o32$ gdb -q a.out Reading symbols from a.out...done. (gdb) b main Breakpoint 1 at 0x12c6: file t.c, line 6. (gdb) r Starting program: /tmp/a.out Breakpoint 1, main (argc=1, argv=0xcf7d9204) at t.c:6 6 gettimeofday(&tv, NULL); (gdb) p sizeof(struct timeval) $1 = 12 (gdb) p sizeof(&tv) $2 = 4
gdbを立ち上げて、構造体のサイズとポインターのサイズを確認してみた。12ってのは、プチ半端な数字だな。まて、12 = 8 + 4 ではなかろうか。
(gdb) p sizeof(tv.tv_sec) $3 = 8 (gdb) p sizeof(tv.tv_usec) $4 = 4
ビンゴでしたね。こいつぁ朝から縁起が良い。
o32$ cc -E t.c | grep time_t typedef __int64_t __time_t; typedef __time_t time_t; time_t tv_sec; time_t tv_sec; : o32$ cc -E t.c | grep suseconds_t typedef long __suseconds_t; typedef __suseconds_t suseconds_t; suseconds_t tv_usec;
ヘッダーファイルを紐解いてみると、上記のような定義だった。32Bit環境では、憧れのlongも実体は32Bitなんすね。
所で、man gettimeofday すると
GETTIMEOFDAY(2) System Calls Manual GETTIMEOFDAY(2)
冒頭にシステムコールって書いてある。そう、あちゃらの世界とのやり取りをする規約なんだな。間にlibcなんてのを挟まないストレートなやつ。
in kernel
と言う事で、場面は転換して、カーネルソースエリアに突入します。
o32$ cd /sys o32$ find . -name '*.c' | xargs grep gettimeofday : ./kern/kern_time.c:sys_gettimeofday(struct proc *p, void *v, register_t *retval) ./kern/kern_time.c: struct sys_gettimeofday_args /* { ./kern/syscalls.c: "gettimeofday", /* 67 = gettimeofday */ ./kern/syscalls.c: "#116 (obsolete t32_gettimeofday)", /* 116 = obsolete t32_gettimeofday */
昔の痕跡(化石)が、しっかり残っていました。消してしまわない所が偉いぞ。kern_time.cを見てたら、
if (tp) { memset(&atv, 0, sizeof(atv)); microtime(&atv); if ((error = copyout(&atv, tp, sizeof (atv)))) return (error); #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrabstimeval(p, &atv); #endif
カーネル内部では、atvって構造体を用意して、それを引数にしてmicrotimeを呼ぶと、そこに答えがセットされる。そのデータをユーザランド側のtpに転送するんだな。 ktraceを使うとカーネル側の結果をモニター出来るとな。これってSolarisのあれ(名前が出てこない -- 暫くしたら記憶が蘇ってきた。dtrace)にそっくりだな。
o32$ ktrace -tc+ ./a.out o32$ kdump : 42072 a.out CALL gettimeofday(0xcf7bdd68,0) 42072 a.out STRU struct timeval { 1581120065<"Feb 8 09:01:05 2020">.645563 } 42072 a.out RET gettimeofday 0
2038問題の検証
幸いな事に、32Bit版のdebianが有るので、 2038年問題の検証してみる。Y2Kを思い出すなぁ。とにかくunix時間の終末近くに時刻を設定。
debian:tmp$ sudo date -u 011903102038 Tue 19 Jan 2038 03:10:00 AM UTC debian:tmp$ touch aaa debian:tmp$ date Sat 14 Dec 1901 05:51:58 AM JST debian:tmp$ touch bbb
オーバーフローすると、1901年と言う過去へ行っちゃうのね。
debian:tmp$ ls -l aaa bbb -rw-r--r-- 1 sakae sakae 0 Jan 19 2038 aaa -rw-r--r-- 1 sakae sakae 0 Dec 14 1901 bbb
それぞれの時代?のスタンプを残しておいたので、年代を鑑定してみた。
debian:tmp$ date +%s -2147482801 debian:tmp$ date +%s -2147482787
epoc timeは、マイナスですよ。時間軸の原点は、言うまでもなく、1970/01/01 00:00:00 UTCです。
さて、現代に戻ってくるかな。
debian:tmp$ sudo ntpdate ntp.nict.jp 8 Feb 15:22:08 ntpdate[4674]: step time server 133.243.238.244 offset -566341822.235377 sec debian:tmp$ date Sat 08 Feb 2020 03:22:28 PM JST
と言う事で、18年程の未来へ旅をし、そこからワープさせられて1901年まで飛ばされ、やっとこさ現代に復帰。どう足掻いたって、この時空に閉じ込められているからね。
この試験をやった翌日に、debian 10.3が降ってきたけど、改善はされていないんだろうね。
date
再びOpneBSDに戻って、大きな秒を与えたらどうなるか、検証(お遊び)。宇宙が果てると思われる秒数で試験
ob$ bc 2^60 1152921504606846976 ob$ date -r 1152921504606846976 date: conversion error
そんな大きな数字は想定してないってか。じゃ、小さめな数値
ob$ bc 2^32 4294967296 ob$ date -r 4294967296 Sun Feb 7 15:28:16 JST 2106 ob$ date -r -4294967296 Mon Nov 25 02:50:43 LMT 1833
未来はJSTで頷けるけど、江戸時代はLMTってか。一体それは何?
ob$ cc -g date.c -lutil ob$ ./a.out Mon Feb 10 05:26:49 JST 2020
取り合えず試運転しておいて、gdbにかける。
(gdb) 130 tp = localtime(&tval); (gdb) p tval $1 = -4294967296 (gdb) n 131 if (tp == NULL) (gdb) 133 (void)strftime(buf, sizeof(buf), format, tp); (gdb) 134 (void)printf("%s\n", buf); (gdb) Mon Nov 25 02:50:43 LMT 1833
ふーん、strftimeの仕業なのね。あっ違った。本当の変換をやってるのはlocalsubだ。
(gdb) bt #0 localsub (timep=0xa72a09e7008 <tval>, offset=0, tmp=0xa75284109c0 <tm>) at /usr/src/lib/libc/time/localtime.c:1181 #1 0x00000a75283c94ce in _libc_localtime_r (timep=<optimized out>, p_tm=0xa75284109c0 <tm>) at /usr/src/lib/libc/time/localtime.c:1273 #2 _libc_localtime (timep=0xa72a09e7008 <tval>) at /usr/src/lib/libc/time/localtime.c:1287 #3 0x00000a72a09e46ea in main (argc=0, argv=0x7f7ffffd2fb0) at date.c:130
この関数を抜けると、値がセットされた。
(gdb) p *p_tm $9 = { tm_sec = 43, tm_min = 50, tm_hour = 2, tm_mday = 25, tm_mon = 10, tm_year = -67, tm_wday = 1, tm_yday = 328, tm_isdst = 0, tm_gmtoff = 33539, tm_zone = 0xa7508caf248 "LMT" }
man localtimeすると
int tm_sec; /* seconds (0 - 60) */ int tm_min; /* minutes (0 - 59) */ int tm_hour; /* hours (0 - 23) */ int tm_mday; /* day of month (1 - 31) */ int tm_mon; /* month of year (0 - 11) */ int tm_year; /* year - 1900 */ int tm_wday; /* day of week (Sunday = 0) */ int tm_yday; /* day of year (0 - 365) */ int tm_isdst; /* is summer time in effect? */ long tm_gmtoff; /* offset from UTC in seconds */ char *tm_zone; /* abbreviation of timezone name */
こんなのが出てきた。そして、/usr/share/zoneinfoこんな関係者も参照してるとな。ここで、うるう秒の調整もしてるとな。
この関数に入ってすぐの所で、zoneinfoのdbを呼び出しているっぽい。
(gdb) p *lclptr : chars = "LMT\000JDT\000JST", '\000' <repeats 500 times>,
こんな文字列が伺えたよ。
そんな訳で、zoneinfoのソースを閲覧
ob$ pwd /usr/src/share/zoneinfo/datfiles ob$ lv leapseconds # If the leap second is Rolling (R) the given time is local time (unused here). Leap 1972 Jun 30 23:59:60 + S Leap 1972 Dec 31 23:59:60 + S Leap 1973 Dec 31 23:59:60 + S Leap 1974 Dec 31 23:59:60 + S : Leap 2005 Dec 31 23:59:60 + S Leap 2008 Dec 31 23:59:60 + S Leap 2012 Jun 30 23:59:60 + S Leap 2015 Jun 30 23:59:60 + S Leap 2016 Dec 31 23:59:60 + S
何時、うるう秒が挿入されたかと言う、地球の公転の記録がファイルになってました。
それから、timezoneの名前は、地域別になってて、Japan はAsiaに属しているんで、それを見ると、
# Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u 9:00 Japan J%sT
こんな記録になってました。各国の事情が反映されてる訳ですな。 尚、LMTってのは、Local Mean Time の略で、この場合は、名無しの権兵衛と言った所でしょうか。明治21年から日本固有の時間(JST)だよと、喜んで宣言したんだな。
zone.tab
#country- #code coordinates TZ comments AD +4230+00131 Europe/Andorra AE +2518+05518 Asia/Dubai AF +3431+06912 Asia/Kabul AG +1703-06148 America/Antigua : JP +353916+1394441 Asia/Tokyo
これ、リナとかのOSをインストールする時に(裏で)お世話になってるテーブル。そう、時刻を設定する時に、地図が出てくるじゃないですか。そのデータだ。
東京の北緯は、35度41分、東経139度45分(@千代田区役所)らしいですから、まあそんなものでしょう。 あっ、日本標準時に比べて、19分進んでいるそうですよ。国内の基準は兵庫県明石市です。
札幌と沖縄では、時差が1時間近くも有るのね。
etc
任意の波形が、sin/cos波で合成出来るという検証環境。なかなか面白い。