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

とバッサリ消されるのである、南無。