Thread Local Storageの初期値について調べた

## 前置き
本記事は[Fusic Advent Calendar 2018](https://qiita.com/advent-calendar/2018/fusic)の23日目の記事です。
日ごろから、スレッドローカルな変数を定義することなどないので、あんまり身近でないですが、日ごろからお世話にはなっているので、そういった感じでスレッドローカルな初期値について考察します。

## 動機
きっかけはTwitter上で見かけたこのつぶやきでした:

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">\_\_thread in:file NOT &quot;Invalid \_\_thread specifiers&quot; extension:c でどうだろうと思ったら \_\_ が消えた（というのは、\_\_thread なんて誰も使ってない？）</p>&mdash; _ko1 (@_ko1) <a href="https://twitter.com/_ko1/status/1075296186871906304?ref_src=twsrc%5Etfw">December 19, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

何かスレッドローカルに関して他のコードでも参考にしたいのかなー？といったふうに受け取ったので、仕事中のCI待ちに暇つぶしがてら調べてました。

その後、詳しくお聞きすると:
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">なんの話かというと、native thread のキャッシュを導入予定なんですが、ほんとに大丈夫なんだろうか、という。</p>&mdash; _ko1 (@_ko1) <a href="https://twitter.com/_ko1/status/1075303379188932608?ref_src=twsrc%5Etfw">December 19, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

とのことで、何かスレッドごとの最適化でもするのかなーといった感じみたいです。

## スレッドローカルストレージとは？
そもそもスレッドローカルストレージとはなんぞやですが、通常のグローバル変数がプロセスごとに割り当てる変数だとすると、スレッドローカルストレージの置かれるスレッドローカル変数はスレッドごとの領域に割り当てられています。そして、その領域をスレッドローカルストレージといいます。
広い意味で使うと、 `pthread_t` から参照できる情報などもスレッドローカルストレージになるかと思われます。

スレッドごとにデータがあって嬉しいものの不動の代表といいますと、UNIXのAPIで使う `errno` です。
`errno` 自体がマルチスレッドという概念が導入される前のものなのでスレッドローカルにしないとよそのスレッドでのシステムコール呼び出しの結果で `errno` が上書きされるという事故に繋がります。マルチスレッドモードのフラグを立てたりすると自動的にスレッドローカルに切り替わるといったlibcの実装もあるようです。

他に、スレッドごとに持ちたいデータの参照元として使うなどマルチスレッドなプログラムを書く場合には不可欠な存在です。

C言語で書いてるプログラムでとある変数とスレッドローカルにしたい場合は、GCC拡張の `__thread` を使ったり、C11から導入された `_Thread_local` や `<thread.h>` をインクルードすると使える `thread_local` ストレージクラス指定子を使います。詳しくは[cppreference.com](https://en.cppreference.com/w/c/language/storage_duration)のページを参照してください。規格のどこに定義があるのかととか詳しいのでおすすめです。

また、プログラムで必ずしも必要でない場合は、[`pthread_key_t`](http://pubs.opengroup.org/onlinepubs/007904975/functions/pthread_key_create.html)を使ってスレッドローカルストレージを動的に割り付けるといったことも可能です。C11準拠でない処理系の場合にもこちらの方法を使うようです。

## 元ツイートの方が知りたかったこと
どうやら、明示的に初期化をしなかった場合の挙動を知りたかったようです。

[規格上](https://en.cppreference.com/w/c/language/storage_duration)は、 `static` ストレージ期間に近い `thread` ストレージ期間なので、 `static` がプロセスの初期化と破棄時にデフォルトの初期値（数値だったら0、ポインタだったらNULLなど）で割り当てられるのが、代わりにスレッドの初期化と破棄時になります。
ということは、グローバル変数で明示的に初期化をしなかった場合の挙動をスレッドという単位に落とし込んで考えればよさそうです。

ただ、それはあくまで規格上で、実装というのは往々にして規格を完全に再現することを期待してはいけないので、もう少し実装よりなところを調べました。

### ELFでは
[ELF Handling For Thread-Local Storage](https://akkadia.org/drepper/tls.pdf)というのがあったので読んでみました。
けっこういろいろ書いてあるんですが、わたしが知りたかったのは、どうゆうふうにデータが扱われるかだったので、 `.tbss` や `.tdata` というセクションがあるとわかれば十分でした。

どうやら、 `.bss` や `.data` のスレッド版である `.tbss` や `.tdata` というセクションがあるのでやってることは `.bss` や `.data` と変わらないとあたりがついたので、明示的な初期値がない場合は `.bss` セクションみたいにゼロで埋められるのではないかと思われます。
（本当は、プログラムの動的ローダーまで読みたかったんですが、そこら辺はまた今度にしました。。。）

### Clangの生成するコードのテスト
[このファイル](https://github.com/llvm-project/clang/blob/a1a49a7b666a6a9d9b55b52602f9773a9e00b4f5/test/CodeGen/tls-model.c#L25)を見ると

```C
int __thread x;
```

というコードが

```LLVM
@x = thread_local global i32 0
```

というスレッドローカルなグローバルでint32_tで0初期化な領域になるように期待しているようです。
これが、どうネイティブコードに変換されるかまでは特におってないですが、ひとまず規格で期待しているようなコードにLLVM IRの段階ではないっていることはわかりました。

### glibcでは
やっぱり実際に使われているコードというのを参照するのが元ツイートの人が求めていたことだと思うので、他に調べていたら[osdev.org](https://wiki.osdev.org/Thread_Local_Storage)の解説ページで、 `errno` が最初に例として出ていたので、代表的な移植性の高いlibcであるglibcとmusl libcを調べてみることにしました。
[musl libc](https://www.musl-libc.org/)では、 `pthread_t` のデータに `errno` が埋めてあったので今回は不適当だったので[glibc](https://www.gnu.org/software/libc/)の例を出します。

[csu/errno.c](https://sourceware.org/git/?p=glibc.git;a=blob;f=csu/errno.c;hb=bbb7dc8475b5c06b3e5d1dcf51a1ec6e045bfc6f#l31)というファイルに

```C
__thread int errno;
```

と求めてやまなかった書き方のスレッドローカル変数の定義がありました！

### おまけ: Qt
Qtのコードベースはとても大きいのでなんか叩けば出てくるだろうと思って探したら、コンパイラのテストおぼしきものが出てきました。
[QGlobal関連のファイル](https://github.com/qt/qtbase/blob/c5307203f5c0b0e588cc93e70764c090dd4c2ce0/tests/auto/corelib/global/qglobal/qglobal.c#L110-L115)で以下のようなコードがありました。

```c++
#ifdef Q_COMPILER_THREAD_LOCAL
static thread_local int gt_var;
void thread_local_test()
{
    static thread_local int t_var;
    t_var = gt_var;
}
#endif
```

ただ、他で `thread_local_test` が参照されるといったことがなかったのでコンパイラのテスト用だけみたいです。
それから、QtはC++で書かれているのでCと初期化の事情がそもそも違うので例としてあんまりよろしくなかったりします。

### おまけ: Rustのスレッドローカル変数定義
`pthread_key_t` を使った方に近い感じみたいです。
[`std::thread_local!` マクロ](https://doc.rust-lang.org/std/macro.thread_local.html)があるんですが、内部的に `pthread_key_t` に近いものに落としてそうなAPIでした。
もしかしたらLLVM intrinsicでがんばって最適化してるのかもしれませんが。。。

### おまけ: [C11/C++11 TLS変数への間接アクセス](http://d.hatena.ne.jp/yohhoy/20120627/p1)
元記事を読めばわかるんですが、C++11になるとC++の生存期間の定義があるのでより厳密になるみたいです。
CとC++はやっぱり別言語だなとこうゆうときに感じますね。

## 結論とか
スレッドローカルであろうとつべこべ言わず、変数はちゃんと初期化しましょう。（え

というのも、「[初期化してない変数と.bssセクション](http://www.ertl.jp/~takayuki/readings/info/no03.html)」という神記事があるのでそれを読んでください。（というか、最初からこの神記事で十分だった気がします。。。）
`.bss` のちゃんとした解説もありますし、ABIによっては敢えてゼロ初期化しないこともあるというのは（現代でもあるのか知りませんが）大事です。

ちなみに、glibcの　`errno` の例を出したんですが:
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">あー。でもerrnoは毎回関数ごとに初期化しそう？</p>&mdash; _ko1 (@_ko1) <a href="https://twitter.com/_ko1/status/1075309731995049984?ref_src=twsrc%5Etfw">December 19, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

というごもっともな指摘で玉砕です。
やはり、言語処理系でスレッドローカル変数をちゃんと使ってるものを探すべきだったのかもしれません。

そんな感じで、業務の隙間時間で調べてたことを記事にまとめさせてもらいました。
たまに気になったことがあればコードリーディングの訓練も兼ねて調べてみると楽しいかもしれません。