systemdではthread_local
修飾子が使われている。thread_local
は、C11で導入された、スレッドローカルな変数を定義するための修飾子である (参考: C11: A New C Standard Aiming at Safer Programming)。
とはいえ、かなり新しいコンパイラでないとサポートしていないので、systemdでは以下のようなマクロを定義して、サポートしていないコンパイラでは古い修飾子を使うようにしている。
src/shared/macro.h
/* Define C11 thread_local attribute even on older gcc compiler
* version */
#ifndef thread_local
/*
* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
* see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
*/
#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
#define thread_local _Thread_local
#else
#define thread_local __thread
#endif
#endif
systemdでは主にstaticローカル変数でthread_local
を使っている。staticローカル変数を使いつつ、スレッドセーフを実現するためだと思われる。
例えば、inhibit_what_to_string というユーティリティ関数がある。
src/login/logind-inhibit.c
const char *inhibit_what_to_string(InhibitWhat w) {
static thread_local char buffer[97];
if (w < 0 || w >= _INHIBIT_WHAT_MAX)
return NULL;
p = buffer;
if (w & INHIBIT_SHUTDOWN)
p = stpcpy(p, "shutdown:");
if (w & INHIBIT_SLEEP)
p = stpcpy(p, "sleep:");
/* snip */
return buffer;
エラーコードに従ってエラーメッセージのための文字列を返すのだが、static thread_local
ローカル変数の文字列バッファを使っているので、呼び出し側は文字列を解放しなくても良い。しかも、スレッドセーフである。