海野秀之(うんのひでゆき)の外部記憶
Twitter (twilog) / RSS / アンテナ / ぶくま
http://slashdot.jp/~yt/journal/380676
ところで PEM_write_RSAPrivateKey() で保存した暗号化済み秘密鍵を PEM_read_RSAPrivateKey() で読む処理がどうしても上手くいかなくて小一時間はまったのだが, 正解は OpenSSL_add_all_algorithms() を先に呼んでおかないといけなかったということでした. ドキュメントにもはっきりと書いて無くてだいぶ時間をつぶしました.誰かのお役にたてばと思い, こんなところにメモしておきます.
小一時間どころじゃなくはまって、もう、暗号化された PEM ファイルを読むのは諦めようかと思ったところで、 この文書のことを思い出しました(実は、前に見かけていたんだけど……)。
ざっとググってみると、OpenSSL_add_all_algorithms() は、あるバージョン以降なくなっているとか、 なんとか、気になることが書いてあるので、それは、それで要チェックか。
どうやら、「要らない」で良いらしい。
When memory accesses are protected by a mutex, POSIX guarantees that memory is synchronized between threads and therefore volatile is not needed. See XBD 4.11 Memory Synchronization. There are very many (probably thousands) of existing pthread applications that rely on this. It's worth remembering that when pthreads were added to POSIX, it did not require implementations to support the C Standard (they had the option of supporting standard C or "common usage C", i.e. K&R), so there was no way it could require applications to use volatile.
ううむ。解せなかったんだが、XBD 4.11 を確認しておわりってことになりそうだ。
ぼくの C 言語仕様に関する理解では、mutex lock は必要、volatile も必要と考えるのが自然だと思う。
ここで問題になるのは、
のふたつだと思うのだが、ライブラリとして実現されている pthread_mutex_lock/unlock() は、 前者について適切に処理できても*1、 後者には手がだせないはずだから(と思っていた)。
"POSIX guarantees that memory is synchronized between threads and therefore volatile is not needed."っていうけどさ、 synchronized between threads っていうのは、 メモリオーダに関する(つまりメモリバリアを適切に挿入せよって) 話であって、volatile 云々は、コンパイラによる最適化を抑止して、 必ずメモリを参照してねって話でしょ。 両者は独立している筈なのに*2、なんで "therefore" っていえちゃうんだろうね。
が、どうやら、C の処理系として、どっちもよきにはからえというのが POSIX の要求らしい。
ふーん。
それって、リーズナブルな要求かなぁ。
「人にやさしい」という意味で妥当なのはわかるけど、 C の処理系にとって、適切に処理可能な問題なんだろうか?
この要求にこたえようとすると、すべての変数を、副作用のある関数コールをまたいで値を保持していないかもしれない(= volatile) ものとして扱うことにならない?
C の関数プロトタイプでは、「この関数によってクリティカルセッションに入ったり出たりします」なんて属性が表現されてたりしないし、 仮に宣言可能だとしても、ラップされちゃったらわかんなくなっちゃう。
まあいいけど。
volatile は要らないらしいというのは、わかった。
でも、納得はしない。「へんなのー」と思う。 C に関する「仕様」のなかで、一番嫌いかも知れない。C らしくないよ。
Applications shall ensure that access to any memory location by more than one thread of control (threads or processes) is restricted such that no thread of control can read or modify a memory location while another thread of control may be modifying it. Such access is restricted using functions that synchronize thread execution and also synchronize memory with respect to other threads. The following functions synchronize memory with respect to other threads:
The pthread_once() function shall synchronize memory for the first call in each thread for a given pthread_once_t object.
Unless explicitly stated otherwise, if one of the above functions returns an error, it is unspecified whether the invocation causes memory to be synchronized.
Applications may allow more than one thread of control to read a memory location simultaneously.
僕には、「これらの関数がロック変数の制御だけでなくて、メモリバリアも適切にいれてくれますよ」 と言っているだけにしか思えないんだけど。 なんでこれが「volatile qualifier いらない」の根拠になるのか、おっちゃん(僕)にはわからん。
http://www.lambdacs.com/cpt/FAQ.html#Q56
ほかにも、http://ml.tietew.jp/cppll/cppll/article/11701 も教えてもらった。そこには、以下のような記述が:
ちなみに、大抵のC++環境でのmutex lockは、保護の対象となるオブジェクトだけでなく メモリの全領域に対してメモリアクセス最適化を排除してしまうことになると思います。
うんうん、そう思う。
さらに、上で、「なんでこれが『volatile qualifier いらない』の根拠になるのか、おっちゃん(僕)にはわからん」とほざいてしまいましたが、 4.10 だけじゃなくて、A.4.10 も読むべきだった模様。
いまから読む。
→読んだけど…どうだろ。わたしのように、「メモリモデルと volatile は別問題では?」と考えている人間にとって納得のいく説明にはなってませんでした。
けど、まあいいや。
ってことなんだよね。