Linuxカーネルソースコードで一般的なマクロ

3618 ワード

#define unlikely(x)	__builtin_expect(!!(x), 0)
#define likely(x)	__builtin_expect(!!(x), 1)

上は2つ目で最も多く見られるマクロで、後ろの_builtin_expectはコンパイラ内蔵関数であり、コンパイラ内蔵関数とは実際にコンパイラに追加されたいくつかのコードクリップまたはフラグがコンパイラに最適化を促すことであり、ここでは最適化注意であり、主な用途は前者が現れるとコードが順次実行される可能性が高く、後者はジャンプする可能性がある.これにより、コンパイラは、いくつかのコード挿入手段によってプロセッサの命令プリフェッチを最適化する効果を達成することができる.この2つのマクロの結果が内部のxの値であるため,xに対する判断として直接用いることができる.そして後ろの_builtin_expect(!(x)、0)によります!!(x)と0が等しいかどうかを判断し、!!(x)形式は,等しくない場合を防止し,x=2と仮定し,1回の求反を経て全0となり,もう一度求反をすれば1となる.
# define __BUG_C0	"2:\t.long 1b, %c0
" #define BUG() \ do { \ asm volatile("1:\tud2
" \ ".pushsection __bug_table,\"a\"
" \ __BUG_C0 \ "\t.word %c1, 0
" \ "\t.org 2b+%c2
" \ ".popsection" \ : : "i" (__FILE__), "i" (__LINE__), \ "i" (sizeof(struct bug_entry))); \ unreachable(); \ } while (0)

上記の命令は実行中にシステムを死なせるが、もちろん全体が2つの部分に分かれているため、第1の部分はud 2命令であり、この命令は未定義の異常を発行し、処理されなければ直接システムの閉鎖を引き起こす.次のセクションでは、デバッグ情報について説明します.処理手順は前回のパラメータチェックと同じです.
#define container_of(ptr, type, member) ({                      \
	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
	(type *)( (char *)__mptr - offsetof(type,member) );})

上記のマクロは、構造体のメンバー変数から構造体のヘッダアドレスを見つけるために使用され、C言語の特性に利用されています.メンバー変数は相対的な位置で計算されますが、現在は高度になり、最終的にはコンパイラが実現する関数ですが、機能は同じです.解釈はtype型構造体のメンバー変数memberポインタptrによってtype型構造体ポインタを返す.
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))

このマクロは、主にプロセッサによるxのプリフェッチ、または命令の並べ替えを防止するために行われ、volatileキーワードによって実現される.
#define typecheck(type,x) \
({	type __dummy; \
	typeof(x) __dummy2; \
	(void)(&__dummy == &__dummy2); \
	1; \
})
#define typecheck_fn(type,function) \
({	typeof(type) __tmp = function; \
	(void)__tmp; \
})

この2つのマクロの1つは、タイプが同じかどうかを検出するために使用され、もう1つは、対応する関数であるかどうかを検出するために使用されます.最初のマクロの鍵はここ(void)(&_dummy=&_dummy 2)で、_dummyと_dummy 2が同じタイプでない場合、コンパイラはエラーを報告し(mingw親測)、最後に1を返すのも使用時にif判断を誤用しないようにするためです.2番目のマクロのキーtypeof(type)tmp=functionです.functionのタイプがtypeでない場合、コンパイル時にエラーが発生します.最後に戻る_tmpは、関数アドレスが有効かどうかを検出するために使用することができる.
#define local_irq_enable()	do { raw_local_irq_enable(); } while (0)
#define local_irq_disable()	do { raw_local_irq_disable(); } while (0)

この2つの命令は,1つはエネルギーを中断させるために用いられ,もう1つは中断を禁止するために用いられる.追跡実装とは,プロセッサ固有のフラグ処理命令を呼び出してクリア割り込みとオープン割り込み処理を行うことである.2つの階層があるのも,具体的なアーキテクチャの下での実装が具体的な命令の違いによって異なるためである.
local_irq_saveとlocal_irq_restoreは、まず現在のプロセッサの状態を保存し、シャットダウン中断の操作を実行します.
#define mb()	asm volatile ("": : :"memory")
#define rmb()	mb()
#define wmb()	asm volatile ("": : :"memory")
#define smp_mb()	mb()
#define smp_rmb()	rmb()
#define smp_wmb()	wmb()

上記の文は実際には他のコンパイラの最適化を阻止するだけで,既存のコード順にマシンコードを生成する.
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))

ポイントは後ろのint:-!!(e).まず、コロンは構造体を設定するビットドメインを表し、ビットドメインが0-31の場合、コンパイルに問題はありません.一方、eは、2回の反転後に0と1の2つの値しかなく、値が0に等しい場合に負の値をとるか0に等しいか、値が1に等しい場合に負の値をとるか-1がビットドメインで表現できる範囲を超えている場合にエラーを報告する.
#define RELOC_HIDE(ptr, off)					\
  ({ unsigned long __ptr;					\
    __asm__ ("" : "=r"(__ptr) : "0"(ptr));		\
(typeof(ptr)) (__ptr + (off)); })

埋め込みアセンブリを用いて入力レジスタと出力レジスタを同じレジスタに指向し,出力にオフセットを加えて再位置決め後の結果を得る.