PostgreSQLのコードはC89の標準で利用可能な言語機能にのみ依存することになっています。 つまり、C89に準拠したコンパイラであれば、少数のプラットフォーム依存の部分を除けばpostgresをコンパイルできるはずです。 代替策が用意されているのであれば、それより後のバージョンの標準Cの機能、あるいはコンパイラに依存した機能を使用することもできます。
例えば、static inline
と_StaticAssert()
は標準Cのより新しいバージョンにあるものですが、現在、使用されています。
それらが利用できない場合は、static inline
の代わりにインラインを使わない関数を定義し、_StaticAssert()
については、同じチェックをする(ただし、やや暗号的なメッセージを発する)C89互換のもので代用します。
引数付きのマクロとstatic inline
の関数のどちらも使用することができます。
マクロとして記述した場合に、複数回評価されるリスクがあるならば、後者を選択します。
例えば次のような場合です。
#define Max(x, y) ((x) > (y) ? (x) : (y))
あるいは、マクロにすると非常に長くなる場合も、インライン関数を選択します。 その他に、マクロだけしか利用できない、あるいはマクロの方が使いやすい場合があります。 例えば、マクロに式や様々な型を渡す必要がある場合などです。
インライン関数の定義がバックエンドの一部としてのみ利用可能なシンボル(つまり、変数、関数)を参照する場合、その関数はフロントエンドのコードからインクルードされたときに不可視かもしれません。
#ifndef FRONTEND static inline MemoryContext MemoryContextSwitchTo(MemoryContext context) { MemoryContext old = CurrentMemoryContext; CurrentMemoryContext = context; return old; } #endif /* FRONTEND */
この例では、バックエンドのみで利用可能なCurrentMemoryContext
が参照されているため、関数は#ifndef FRONTEND
で隠されています。
一部のコンパイラはインライン関数に含まれるシンボルの参照を、その関数が使われていなくても吐き出すため、この規則があります。
シグナルハンドラの内部で実行されるのに適切であるためには、注意深くコードを書く必要があります。 根本的問題は、シグナルハンドラは、ブロックされない限り、いつでもコードに対して割り込むことができるということです。 シグナルハンドラの内側のコードが、外側のコードと同じ状態を使うと、混沌が発生するかもしれません。 例えば、シグナルハンドラが、割り込まれたコードで既に保持されているロックを獲得しようとしたら何が起きるか考えてみてください。
特別に準備された状況を別にすると、シグナルハンドラのコードは、(POSIXで定義される通りの)非同期シグナルで安全な関数だけを呼ぶことができ、型volatile sig_atomic_t
の変数だけにアクセスできます。
postgres
でも、いくつかの関数はシグナルで安全とされており、なかでも重要なのはSetLatch()
です。
ほとんどの場合、シグナルハンドラはシグナルが到着したことを記録し、ハンドラの外部で動作しているコードをラッチを使って呼び起こす以上のことをすべきではありません。 以下はそのようなハンドラの例です。
static void handle_sighup(SIGNAL_ARGS) { int save_errno = errno; got_SIGHUP = true; SetLatch(MyLatch); errno = save_errno; }
errno
はSetLatch()
によって変更されるかもしれないので、保存して、リストアされます。
そうしなければ、割り込まれたコードが、現在errno
を参照している場合、誤った値を見ることになるかもしれません。