time_uptime(9) の一貫性
N HEAD では一貫性を保つよう変更になってる
前回 の訂正、N HEAD では time_uptime(9) は今や getuptime() を呼び出すマクロになったんだな。
239 #define time_uptime getuptime()
なのでわざわざ getbinuptime(9) 使うよう書換える必要はないってこと。
こういう変更ってソース互換性失うけど time_uptime(9) に値代入してる箇所が存在する方がやべーのでこれでもいっか。
実装を読んでみる
実装を読むと __HAVE_ATOMIC64_LOADSTORE が定義されていれば
145 volatile time_t time__uptime __cacheline_aligned = 1;
...
253 static inline time_t
254 getuptime(void)
255 {
256 return atomic_load_relaxed(&time__uptime);
257 }
と 64bit time_t のまま inline 関数化することで代入を防いでるけど、定義されてなければ
147 static volatile struct {
148 uint32_t lo, hi;
149 } time__uptime32 __cacheline_aligned = {
150 .lo = 1,
151 }, time__second32 __cacheline_aligned = {
...
233 time_t
234 getuptime(void)
235 {
236 uint32_t lo, hi;
237
238 do {
239 for (;;) {
240 hi = atomic_load_relaxed(&time__uptime32.hi);
241 if (__predict_true(hi != 0xffffffff))
242 break;
243 SPINLOCK_BACKOFF_HOOK;
244 }
245 membar_consumer();
246 lo = atomic_load_relaxed(&time__uptime32.lo);
247 membar_consumer();
248 } while (hi != atomic_load_relaxed(&time__uptime32.hi));
249
250 return ((time_t)hi << 32) | lo;
251 }
のように hi/lo それぞれ 32bit で持ち
- hi を読みとり
- 続けて lo を読みとり
- 再度 hi が lo を読む前と同じ値かを確認
- 一致しない場合は一貫性ないのでやり直し
とすることで正しい値が取れるというテクニック。
前回このテク見たのは OpenSSL の powerpc 32bit のコードだっけな。 TSC(Time Stamp Counter) を読みにいく OpenSSL_rdtscという関数のアセンブラに一貫性問題あったのだ。 この コミット ね。
.OPENSSL_rdtsc:
mftb r3
mftbu r4
blr
だったのが
.OPENSSL_rdtsc:
Loop_rdtsc:
mftbu r5
mftb r3
mftbu r4
cmplw r4,r5
bne Loop_rdtsc
blr
となる。
- mftbu … TSC の上位 32bit を読む命令
- mftb … 〃下位〃
やってることはだいたい同じですやな。
しかし OpenSSL らしいオチがあって OpenSSL_rdtsc の戻り値って uint32_t で上位 32bit 不要なんだよね。
なのでこの コミット で
.OPENSSL_rdtsc_mftb:
mftb r3
blr
とバッサリ消されるのである、南無。