Mutex Subsystem

 

在我想辦法弄懂supermirco 服務用的Super IO w83795的驅動的時候 ,我不幸又陷入了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 有下面的誘惑.

 

第一:

'struct mutex'  在大多數的平臺上他更小 只有16字節 而你 'struct semaphore' 有20個字節

要知道更小的結構意味着 更少的 RAM空間 ,能更好的被CPU cache利用

 

第二:

緊湊的代碼, 在x86上, .text的大小比較:

 

寫道
text data bss dec hex filename
3280380 868188 396860 4545428 455b94 vmlinux-semaphore
3255329 865296 396732 4517357 44eded vmlinux-mutex

 

 

 

你看 25051字節的代碼被節省了  小代碼意味着更優越的指令高速緩衝存儲器佔用 ,這是linux 內核當前優化的主要目標

 

第三:

mutex 子系統 對於競爭帶來的負載 表現的更輕盈更可擴展(想想長矛).  在一個8-way的 x86系統上,允許一個

基於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%

 

 


結果顯而易見 ~

 

第四:

 

沒有快路徑的開銷(看下面) 只要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

*   只有擁有者可以解鎖

*  多次解鎖是不允許的

*  遞歸加鎖也是不可以的

*  一個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);
}

 

這裏有一個  might_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()

 

待續

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章