読者です 読者をやめる 読者になる 読者になる

タダノキロク

日々の考えたことの記録 主に無駄なこと

#詳細Linuxカーネル 5章 同期処理を読む

詳細Linuxカーネル 5章 同期処理を読む

Linuxではマルチプロセッサでの割込み・システムコール・例外発生時に、
同じ変数・メモリへのアクセスを適切に同期(順序付け)が必要になる。

5章ではそのためにの同期処理方法を説明している。
今回は、カーネルが使用している同期技法のスピンロックを読む。

スピンロック

スピンロックによる同期の実現は以下の カーネルは共有しているデータへのアクセス時に資源確保しロックする。
アクセスが終わった時点でロックを解除する。
すでにロックされた状態だと、そのカーネルはロックが解除するまでループして待つ。

スピンロックでは、ロック開放の待ち時間はCPUを消費し続けるので、
無駄に見えるがカーネル資源の多くはロック時間が短いため問題ない。

スピンロックによるデットロックの対策は何かされているのか?

スピンロックの構造体 spinlock_t

スピンロックはspinlock_t構造体で実現。
構造体の中身はraw_spinlock構造体とデバッグ用の何か。

  • slock :スピンロック状態を示す。1がロック開放状態。
  • break_lock :ロックによって待っているプロセスがいることを示す。

スピンロックの確保 spin_lock()

スピンロックを確保するための関数 spin_lock()は、
spinlock_t構造体のアドレスを引数にとる。

Spin_lock()raw_spin_lock()->_raw_spin_lock()ー>__raw_spin_lock()-の順にコール/マクロ化され、実体は__raw_spin_lockになる。

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
  preempt_disable();
  spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
  LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
  1. preempt_disable()をコール
      カーネル内のプリエンプションを禁止(5.1章に書いているから後で読む)

  2. spin_acuore()をコール
      デバック用の関数っぽい。あとでみる

  3. LOCK_CONTENDEDのマクロを実行

    1. do_raw_spin_trylockでスピンロックが取れているか確認。
      実体はarch_spin_trylock。ここでなにかしてるっぽい。
      ここまでにするのか・・・
#define LOCK_CONTENDED(_lock, try, lock)      \
do {                \
  if (!try(_lock)) {          \
    lock_contended(&(_lock)->dep_map, _RET_IP_);  \
    lock(_lock);          \
  }             \
  lock_acquired(&(_lock)->dep_map, _RET_IP_);     \ 
} while (0)