Mutex Subsystem
4336 ワード
supermircoサービス用のSuper IO w 83795の駆動を何とか理解しようとした時、私は不幸にもmutex_に陥った.lock :
具体的な設計ドキュメントはdocument/mutex-designを参照してください.私はここで演義を抜粋しただけです.
物語の始まり:
「なぜこの地球には新しいmutexサブシステムが必要なのか.
元のsemaphoreはどうしたの?
彼を懐かしむのを手伝ってあげましょう
struct semaphore {
spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
void down(struct semaphore *sem);//ldd
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem);
void up(struct semaphore *sem);
実は、間違いはsemaphoreではありません.私の心が変わったのです
今は簡単なmutexの意味が現れて、彼は私のコードの需要を完全に満たして、そしてsemaphoreは次の誘惑があります.
1つ目:
ほとんどのプラットフォームでは16バイトしかありませんが、あなたの'struct semaphore'には20バイトあります.
より小さな構造はより少ないRAM空間を意味し、CPU cacheによりよりよりよく利用されることを理解する必要がある.
2番目:
コンパクトなコードは、x 86上で、.textのサイズ比較:
と書く
text data bss dec hex filename
3280380 868188 396860 4545428 455b94 vmlinux-semaphore
3255329 865296 396732 4517357 44eded vmlinux-mutex
25051バイトのコードが小さなコードを節約されたことは、linuxカーネルの現在の最適化の主な目標であるより優れた命令キャッシュ占有を意味します.
3つ目は
mutexサブシステムは競争による負荷表現に対してより軽く、より拡張可能である(槍を考えてみる).8-wayのx 86システムでは、
mutexベースのカーネルテストcreat+unlink+close/tmpファイルシステムの下で16の並列タスク:
と書く
Semaphores: Mutexes:
$ ./test-mutex V 16 10 $ ./test-mutex V 16 10
8 CPUs, running 16 tasks. 8 CPUs, running 16 tasks.
checking VFS performance. checking VFS performance.
avg loops/sec: 34713 avg loops/sec: 84153
CPU utilization: 63% CPU utilization: 22%
結果は明らか~
4番目:
ファストパスのオーバーヘッドはありません(下を見てください)2つのアセンブリ命令だけでsemaphoraと同じです
c0377ccb <mutex_lock>:
c0377ccb: f0 ff 08 lock decl (%eax)
c0377cce: 78 0e js c0377cde <.text.lock.mutex>
c0377cd0: c3 ret
無視できないメリット:
struct mutexは良い意味で与えられています
*mutexを所有できるのは一度に1つのタスクのみです
*所有者のみがロックを解除できます
*複数回のロック解除は許可されていません
*再帰ロックも不可
*mutexオブジェクトはapiで初期化しなければなりませんmemsetなどできません
*mutexを持つタスクはexitできません
*ロックされたメモリ領域はfreeできません
*mutexは、ソフトウェアの割り込みまたはハードウェアの割り込みでは使用できません.
*taskletsソフトブレークまたはtimersのcontextで
(ps以上では3条目を除き、mutexattr_initが「PTHREAD_MUTEX_RECURSIVE_NP」の前のいくつかはpthread_mutexと同じです~)
カーネルのCONFIG_をコンパイルするとDEBUG_MUTEXESが開くとさらに強くなります
* - uses symbolic names of mutexes, whenever they are printed in debug output * - point-of-acquire tracking, symbolic lookup of function names * - list of all locks held in the system, printout of them * - owner tracking * - detects self-recursing locks and prints out all relevant info * - detects multi-task circular deadlocks and prints out all affected * locks and tasks (and only those tasks)
--------------------------------------------------------------------------------
もちろん彼にも欠点がある.
コンテキストを中断したり、異なるcontextでロックを解除したりすることはできませんが、semaphoreはできます.
いくつかの関数を簡単に見てみましょう
void __sched mutex_lock(struct mutex *lock)
{
might_sleep();
/*
* The locking fastpath is the 1->0 transition from
* 'unlocked' into 'locked' state.
*/
__mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
mutex_set_owner(lock);
}
ここにはライトがありますsleep();コンパイルカーネルがCONFIGを開いたらPREEMPT_VOLUNTARYマクロは、必要に応じてschedule()に直面します.
__mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
実は原子カウントconutを1から0に変えて、初期値が1でなければ、ここでは__を呼び出します.mutex_lock_slowpath関数
これでスローロックの経路に入りました(元々は速いのではないでしょうか、アーキテクチャ的にはアセンブリで書かれているものもあります)
static __used noinline void __sched//__used gcc __sched
__mutex_lock_slowpath(atomic_t *lock_count)
{
struct mutex *lock = container_of(lock_count, struct mutex, count);
__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, _RET_IP_);
}
まずcontainer_of対応する原子数のmutexを取得し、中断不可能な__を呼び出すmutex_lock_common()
続きを待つ