スピンロックその1
今回は趣向を変えて、少しだけカーネル内部に触れてみたいと思います。
みなさん「スピンロック」という言葉に馴染みがあるでしょうか。そのメカニズムを詳しく知ってる方も多いかもしれませんし、例えばどこかで「スピンロック待ちの『ビジーウェイト』でCPUにロスが発生した」のような会話を小耳に挟む機会などもあるかもしれません。しかし、Linux カーネルにおけるスピンロックの実装部分を読んだことのある方は、もしかして意外に多くないかもしれません。ということで、今回はそのあたり(ただし i386 アーキテクチャのみ)を追ってみたいと思います。スピンロックの概念についての説明は省きます。
いきなりソースコードに飛び込んでみましょう(これがミラクル流です)。C言語に馴染みのない方はごめんなさい。弊社MIRACLE LINUXでもいいのですが、ここでは本家の http://www.kernel.org/pub/linux/kernel/v2.6/ に置いてある一番新しそうな linux-2.6.16.20.tar.bz2 を拾ってきて解凍しました。Linux カーネルは更新が速く、コードがどんどん変わっています。異なるバージョンでは以下の文章とは違う実装になっていると思いますので、そのへんは注意して下さい。
スピンロックはカーネル内の色々なところで使われています。どこでもよいのですが、ここではプロセス・スケジューラ kernel/sched.c でも覗いてみましょうか。。。
void __init sched_init(void)
{
runqueue_t *rq;
int i, j, k;for_each_cpu(i) {
prio_array_t *array;rq = cpu_rq(i);
spin_lock_init(&rq->lock);
rq->nr_running = 0;
スケジューラを初期化する関数 sched_init() の中で、ランキューのスピンロック情報を保持する lock メンバを spin_lock_init() で初期化している処理が見つかりました。この lock メンバは spinlock_t 型で、これは include/linux/spinlock_types.h で次のように定義されています。
typedef struct {
raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
} spinlock_t;
メインは raw_spinlock_t 型の raw_lock メンバのようです。この型は i386 では include/asm-i386/spinlock_types.h で次のように定義されています。
typedef struct {
volatile unsigned int slock;
} raw_spinlock_t;
この slock 変数の値がロックの状態を保持するんですね。
データ構造が分かったところで、スピンロックの初期化処理に戻りましょう。 spinlock_t 型の &rq->lock メンバを初期化する spin_lock_init() は実は関数ではなくマクロで、 include/linux/spinlock.h で定義されていました。
#define spin_lock_init(lock) do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0)
この SPIN_LOCK_UNLOCKED は、普通のカーネル (CONFIG_DEBUG_SPINLOCK が未定義のカーネル) では、次のように定義されています。
include/linux/spinlock_types.h
# define SPIN_LOCK_UNLOCKED \
(spinlock_t) { .raw_lock = __RAW_SPIN_LOCK_UNLOCKED }
include/asm-i386/spinlock_types.h
#define __RAW_SPIN_LOCK_UNLOCKED { 1 }
ということで、slock に 1 が代入された状態が初期状態、すなわち UNLOCKED 状態であることがわかりました。
区切りが良いので、今回はここまでです。ロックが取得されることで、この slock の値が 1 からどのように変化するのか、あるいはどんなコードで実装されているのか、それらは次回、またコードを追ってみることにします。



コメント