7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LinuxのRCUのコードを読んでみる (rcu_read_{lock,unlock}編)

Posted at

#はじめに

いまさらですが、Linuxの排他制御機構Read-copy Update (RCU)のコードを読んでみたいと思います。コードベースはLinux 4.3-rc7です。

RCUとはどういうものかについては説明しません。RCUの作者であるPaul E. McKenneyさんがたくさんドキュメントを書いてくれているので、そちらを読む方が正確で確実です。

#RCU
##rcu_read_lock, rcu_read_unlock

RCUのread側のためのAPIで、普通のロックと同じように、クリティカルセクションの最初でlockを、最後でunlockを実行します。lockと書いてありますが、ロックを取るわけではありません。

###rcu_read_lock
rcu_read_lockの実際のコードは以下のようになります。

include/linux/rcupdate.h
static inline void rcu_read_lock(void)
{
        __rcu_read_lock();
        __acquire(RCU);
        rcu_lock_acquire(&rcu_lock_map);
        RCU_LOCKDEP_WARN(!rcu_is_watching(),
                         "rcu_read_lock() used illegally while idle");
}

この中でRCUとして意味のあることをやっているのは__rcu_read_lockのみであとはデバッグ用のコードです。

__rcu_read_lockCONFIG_PREEMPT_RCUが有効か否かで動作が変わります。手元の環境では無効だったので、その前提で読んでいきます。

__rcu_read_lockpreempt_disableを呼ぶだけです。preempt_disableは名前の通り、コンテキスト切り替えを無効にします。これは無印RCUの制約である、read側のクリティカルセクションではコンテキスト切り替えが起きてはいけない、を満たすためのものだと思います1。クリティカルセクション内で自発的にスリープやブロックしないようにするのはプログラマの責任です。

###rcu_read_lockのデバッグコード
せっかくなので、他のデバッグ用コードも読んでいきます。

__acquire(RCU)はマクロで、デフォルトでは何もしません。__CHECKER__が定義されている場合は、__context__(RCU,1)に展開されます。

__CHECKER__はどうやらSparseという静的解析ツールを使うときに定義されるようです2。詳しい説明は省きますが、取っていないロックをアンロックしようとしたり、ロックをとったままコンテキスト切り替えをしようとするようなバグを検出できるようです。

rcu_lock_acquire(&rcu_lock_map)CONFIG_DEBUG_LOCK_ALLOCCONFIG_LOCKDEPが有効のときに、ロックのデバッグ機能(lockdep)のための処理を行ないます。詳しい説明は省きますが、lockdepは複雑なロックの依存関係のバグ(デッドロック等)を検出するためのものです。

最後のRCU_LOCKDEP_WARNはdynticks絡みのassertionのようですが、複雑な事情 [pdf]があるようで、正確なところはわかりません。時間があれば掘り下げるかもしれません。

###rcu_read_unlock

include/linux/rcupdate.h
static inline void rcu_read_unlock(void)
{
        RCU_LOCKDEP_WARN(!rcu_is_watching(),
                         "rcu_read_unlock() used illegally while idle");
        __release(RCU);
        __rcu_read_unlock();
        rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */
}

rcu_read_unlockは基本的にrcu_read_lockの逆操作をしているだけのようです。__rcu_read_unlockpreempt_enableしているだけです。

#おわりに

次は、synchronize_rcuあたりを読みたいと思います。

  1. CONFIG_PREEMPTなカーネルだとCPUが横取り可能性があり、横取りされるのは良いらしいです。一方で、自発的にスリープやブロックはしてはいけないみたいです。(rcu_read_lockのコメントより)

  2. Sparseの作者はLinusらしい

7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?