変数(整数)の読み書き・演算のアトミック性

複数のスレッドやシグナルハンドラーから変数を読み書き・演算するときはアトミック性に注意な。
3
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

Samba の tevent という実装にシグナルハンドラー内で uint32_t な変数に加算、イベント処理ループなどでそれを参照しているんだけど、どれくらいヤバい? sig_atomic_t に変えるだけで直るかな…。

2014-05-28 12:03:36
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

sig_atomic_t のアトミック性がどんな操作にあてはまるのか把握してないマン。tevent のコードはいわゆる 32bit 以上の CPU+OS なら uint32_t がアトミックな操作できると想定しているようだけど、これは駄目だよね。

2014-05-28 12:07:49
SODA Noriyuki @n_soda

@satoh_fumiyasu volatileにしとけば、同一CPUコアからなら見えます。他コアにも即座に見せようとしたら、メモリバリアが必要。uint32_tなら、おそらくsig_atomic_t的にはまあOKでしょう。(sig_atomic_tにした方がいいけど)

2014-05-28 12:16:01
鯉江 @koie

@satoh_fumiyasu 加算はアトミックなのを使わないとダメでしょうね

2014-05-28 12:21:35
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

@n_soda そうそう、volatile にもなってないんですよね。それと uint32_t の変数は構造体の一部で、構造体をメンバー変数ごとでなく丸ごとコピーしたりするのがバグってる原因かなーと想像しているところです。ほかの人に見てもらっているので詳細は不明ですが…。

2014-05-28 12:21:59
SODA Noriyuki @n_soda

@satoh_fumiyasu volatileにしてないのは論外です

2014-05-28 12:23:15
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

@koie C で n++; とかすると、アトミックでない機械語になる可能性があるってことですかね。加算するのはシグナルハンドラー内だけで、それ以外では参照だけしているので、それなら大丈夫…かな。いや駄目か?? うーん。

2014-05-28 12:24:25
鯉江 @koie

@n_soda @satoh_fumiyasu pthreadもつかっててバリアが入ってるとか?

2014-05-28 12:24:45
SODA Noriyuki @n_soda

@satoh_fumiyasu @koie 複数の異なるシグナルハンドラで n++ してなければ、そこは大丈夫でしょう。

2014-05-28 12:26:09
鯉江 @koie

@satoh_fumiyasu 普通はアトミックな命令は生成しないと思います、遅いので。 ループ変数はレジスタに乗ってなかったらvolatile指定してなくても動いちゃいそう。

2014-05-28 12:27:30
SODA Noriyuki @n_soda

@koie @satoh_fumiyasu 参照する側が、適切なタイミングでpthread APIを呼び出してれば、そのタイミングでメモリにも書くのでvolatile要らないし、バリアもpthread API側で発行してくれるので不要ですね。

2014-05-28 12:27:42
SODA Noriyuki @n_soda

@koie @satoh_fumiyasu 「レジスタに乗ってなかったら」って仮定がヤバそうですが。

2014-05-28 12:29:45
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

@n_soda @koie 複数のシグナルハンドラーで同一インスタンスである sig_state->got_signal->count を ++ してますぅ…。駄目ですか? シグナルハンドラー実行中に別のシグナルハンドラーが割り込むことってあるんでしたっけ。(よく知らない

2014-05-28 12:29:50
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

@n_soda @koie あ、「複数のシグナルハンドラー」でなく、ある一つにシグナルハンドラーをすべてのシグナルのハンドラーとして登録しています。その中で sig_state->got_signal->count++ してます。

2014-05-28 12:31:07
SODA Noriyuki @n_soda

@satoh_fumiyasu @koie 現在実行中のシグナルと同一のシグナルは保留されますが、他のシグナルは入ります。なのでシグナルハンドラが同一関数でも、シグナルが異なれば、atomicであるという保証はないです。→atomic API使うか、さもなくば変数を分けるか

2014-05-28 12:37:28
鯉江 @koie

@n_soda @satoh_fumiyasu SA_NODEFERつけたりふるいBSDつかったりすればシグナルハンドらに催乳してくるんじゃないでしょうか。ハンドら実行中にシグナルうけたくなかったらsa_mask設定しないと。

2014-05-28 12:46:47
鯉江 @koie

@n_soda @satoh_fumiyasu でっかい関数かくと意外とのらなかったり(汗

2014-05-28 12:49:10
SODA Noriyuki @n_soda

@koie @satoh_fumiyasu SA_NODEFERだとダメでしょうね。古いBSDの方は、ハンドラ実行中はブロックしてるんじゃないかな。

2014-05-28 12:54:16
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

@koie ありがとうございます。arm で発生して amd64 では発生しない→amd64(x86?)ではメモリ内の値を加算する命令がある(らしい)、ということみたいです。

2014-05-28 12:54:19
SODA Noriyuki @n_soda

@satoh_fumiyasu @koie <atomic.h>があるOSなら、それを使うのが安全ですが、必ずしもないのが問題ですね。

2014-05-28 13:00:48
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

sig_atomic_t のアトミック性、参照と設定はいいけど、演算(加減算)は駄目ってことでよいみたい。なるほどー。

2014-05-28 13:01:09
中村 実 @nminoru_jp

@satoh_fumiyasu sig_atomic_tはリード・ライトしか保証してません。最初、0xCAFEBABEが入っていた変数に0xDEADBEAFを代入しようとした時にシグナルハンドラに処理が移っても0xDEADBABEのような中間値が見えないことを保証しているだけです

2014-05-28 13:05:47
ふみやす@元シェルまおう(自称でない) @satoh_fumiyasu

@n_soda @koie なるほど、tnozaki さんのツイートで atomic.h は調べた記憶。apt-file search /atomic.h →それっぽいのはない…。orz stdatomic.h は C11 かー。へぇ。

2014-05-28 13:06:11
SODA Noriyuki @n_soda

@satoh_fumiyasu @koie SolarisやNetBSDにはあるんですけどね。ただし、APIは微妙に違います(ぉ

2014-05-28 13:08:35
鯉江 @koie

@n_soda @satoh_fumiyasu gcc限定なら組み込みで__sync_xxx_and_fetch()というのがあります

2014-05-28 13:11:13