Linux那些事兒之我是U盤 24 心鎖

2021-08-22 09:32:59 字數 3171 閱讀 6504

如果大家沒意見的話,我們繼續usb_stor_acquire_resources函式.

761至764行,這沒啥好說的吧.就是剛才urb申請了之後判斷是否申請成功了,如果指標為null那麼就是失敗了.直接返回-enomem.別往下了.

767行,哦,又乙個傢伙閃亮登場了,dev_semaphore,這是乙個訊號量,在storage_probe的最初始階段我們曾經見過,當時有這麼一句話,這就是呼叫乙個巨集init_mutex來初始化乙個訊號量,

943 init_mutex(&(us->dev_semaphore));

我們當時說了,等到用的時候再講.不過現在的確是到用的時候了,不過,我還不想講.曾經我天真的以為,只要學了譚浩強的那本c程式設計,即便不能寫**,也應該能夠看懂**.然而,後來我發現事實並非如此,世界沒錯,我錯了.

首先,什麼是訊號量?畢業的時候,校園招聘中常常筆試面試會考訊號量,會考死鎖,不過通常考的會比較簡單,更多的情況是考察一些基本概念,印象中曾經在sun中國工程研究院的面試中被問起過,當然也有比較複雜一點的,要求結合具體的問題對某種演算法進行合理性分析,比如intel某年在上海交大的筆試題,考到了經典的哲學家進餐問題,不過幸運的是這種**的筆試題我沒遇上,我進intel的時候只被問起解釋氣泡排序法...

我們整個故事中有兩個訊號量,它們都是us的成員,乙個是這個dev_semaphore,另乙個是sema,在定義struct us_data的時候我們已經看到過,

111struct semaphore

dev_semaphore;

/* protect pusb_dev */

156struct semaphore

sema;

/* to sleep thread on

*/sema也同樣是在storage_probe的一開始就做了初始化,

944 init_mutex_locked(&(us->sema));

裝置驅動中最難的部分在於三個方面,乙個是涉及到記憶體管理的**,乙個是涉及到程序管理的**,另乙個就是訊號量和互斥鎖或者別的鎖的**.這些部分如果不合理將容易導致系統崩潰,而訊號量最容易導致的就是死鎖.

網名為賣血上網的哥們說話了,那麼到底什麼是訊號量?或者什麼是互斥鎖?

先說互斥鎖.它誕生於這樣乙個背景.這個世界上,有些東西只能屬於某乙個人,或者說在乙個時間裡只能屬於乙個人,這你承認吧,比如乙個女孩的心.當你要追求乙個女孩時,你首先會去了解其人是否名花有主,若是否,你才會去追求,若已然有主,那麼你只能放棄,或者準確的說,你只能等待.當然你可以很激昂的說,如果等待可以換來奇蹟的話,我寧願等下去,哪怕一年,抑或一生!然而,她愛的是他,終究不是你,所以你傷悲,流淚,卻打不開她心中那把鎖.這裡你應該就能感覺到什麼是互斥鎖了,乙個女孩如果心有所屬,那麼對你來說,就彷彿已有人在你之前給她上了一把鎖,而鑰匙,不在你這裡.

那麼你問**中為什麼要鎖?ok,我告訴你,如果你正在操作乙個佇列,比如乙個佇列一百個元素,你想把第七十個讀出來,於是你去遍歷這個佇列,可是如果沒有鎖,那麼可能你遍歷的時候別人也可以操作這個佇列,比如你馬上就要找到第七十個了,可是,可是,注意了,可是,這個時候,說不定哪位哥們兒缺德,把第七十個數給刪除了,那你不是白忙活了?所以,怎麼辦?設乙個鎖,每個人要想操作這個佇列就得先獲得這把鎖,而一旦你獲得了這把鎖,你在操作這把鎖期間,別人就不能操作,因為他要操作他就得先獲得鎖,而這個時候鎖在你這裡,所以他只能等待,等你結束了,釋放了鎖,他才可以去操作.那麼互斥鎖指的就是這種情況,乙個資源只能同時被乙個程序操作,互斥的字面意思也正是如此.互相排斥,就像愛情是自私的一樣.

那什麼是訊號量?訊號量和互斥鎖略有不同.它允許乙個時間裡有幾個程序同時訪問一段資源.到底允許幾個可以設定,這稱為設定訊號量的初值,如設定為1,那就說明是同一時間只有乙個程序可以訪問,那麼這就是互斥鎖了,不過有的時候乙個資源確實可以讓幾個程序訪問,特別是讀訪問,你想乙個檔案可以被兩個程序同時讀,這不要緊吧,各讀各的,誰也影響不了誰,只要大家都不寫就是了.設定訊號量的初值,比如設定5,那麼就是說,同一時間你就讓最多5個程序同時去讀這個檔案.每個程序獲取了訊號量就把訊號量的值減一,到第六個程序了,它去判斷,發現值已經等於0了,於是它不能訪問了,只能等待,等待別的程序釋放鎖.

不過也許,一把鑰匙只能開一把鎖,更能代表愛情的專一.所以實際上,linux核心**中鎖用得更多,而初值不為1的訊號量用得相對來說不多.比如我們剛才看到的這兩個訊號量,都是屬於當作互斥鎖在用.因為他們的初值乙個被設定成了1(init_mutex),乙個被設定成了0(init_mutex_locked).設定成一很好理解,就是一把互斥鎖,只能容許乙個程序去獲得它,設定成0呢,就表示這把鎖已經被鎖住了,得有程序釋放它才可以.我們這裡767行這句down(&us->dev_semaphore)和up(&us->dev_semaphore)是一對,乙個是獲得鎖,乙個是釋放鎖.它們就是為了保護中間那段**.我剛才說我不想講這段**,的確,現在講為什麼這裡要用鎖還為時過早,整個故事中us->dev_semaphore出現的次數不是很多,但是我們必須對整個**都熟悉了才可能理解為什麼要用這把鎖,因為這些**都是環環相扣的,不能孤立來看.所以,我們將在故事的收尾階段來一次性來以高屋建瓴的方式看每一處down(&us->dev_semaphore)和up(&us->dev_semaphore)的使用原因.接下來我們看到了這把鎖的時候,也將一併跳過不提.到最後再來看.需要說的是這裡down和up這兩個函式的作用分別就是去獲得鎖和釋放鎖.對於down來說,它每次判斷一下訊號量的值是否大於0,若是,就進入下面的**,同時將訊號量的值減一,若否,就等待,或者說專業一點,進入睡眠.對於down(),我們小時候那部《揮劍問情》的歌詞很形象的描述了其行為,

男:揮劍問情,如果問是有情,也願以身相許,以身相殉;

女:揮劍問情,如果問是無情,又怕回首別是一種傷心.

不過,我們這裡看到了兩把鎖,除了us->dev_semaphore以外,另乙個是us->sema,現在還沒有使用它,但是我們可以先說一下,us->sema在整個故事中出現的次數不多,總共只有三次.加上這裡提到的這句初始化為0的語句,乙個出現了四次.所以我們在遇到它的時候不需要跳過,會詳細的講.因為很容易理解它為什麼會用在那裡.請你記住,這個訊號量或者說這把鎖是被初始化為0了,不是1,它一開始就處於鎖住的狀態,到時候你就會知道為什麼了.我們邊走邊看.

另外乙個需要說一下的是,與down ()相似的有乙個叫做down_interruptible ()的函式,它們的區別在於後者可被訊號打斷,而前者不可被訊號打斷,而一旦問是無情,那麼他們將進入等待,或者專業一點說,進入睡眠,直到某一天...

我們將看到的獲取us->sema的函式正是down_interruptible.而釋放鎖的函式仍然可以用up.

讀Linux那些事兒之我是U盤筆記(一)

我是u盤 1 模組 insmod 裝置插入,module init 被稱為驅動程式的初始化入口 rmmod 裝置拔出,module exit 2 usb core 什麼是usb core?她負責實現一些核心的功能,為別的裝置驅動程式提供服務,比如申請記憶體,比如實現一些所有的裝置都會需要的公共的函式...

讀Linux那些事兒之我是U盤筆記(八)

37 錯誤處理 device reset 在這裡對應的就是登出,bus reset 對應的就是重起 功能 給裝置傳送乙個 reset 的 request,然後clear掉halt feature,保證裝置的端點沒有停止.就這些,這就夠了.bus reset usb lock device for r...

Linux那些事兒之我是U盤 5 外面的世界很精彩

看 之前,我曾經認真的思考過這麼乙個問題,我需要關注的僅僅是drivers usb storage 目錄下面那相關的3000多行 嗎?就是這樣幾個檔案就能讓乙個個不同的u盤在linux下面工作起來嗎?像一開始那樣把這個目錄比作乙個小城的話,也許,城裡的月光很漂亮,她能夠把人的夢照亮,能夠溫暖人的心房...