日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux设备驱动开发-linux驱动中的阻塞访问方式

發(fā)布時間:2024/9/21 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux设备驱动开发-linux驱动中的阻塞访问方式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

阻塞與非阻塞是設(shè)備訪問的兩種不同的模式。什么是阻塞操作呢?其是指在執(zhí)行設(shè)備操作的時候,如果不能獲得資源,則掛起進程直到滿足可操作的條件后再進行操作.而非阻塞操作則是在進程不能進行設(shè)備操作時,并不掛起到等待隊列,而是放棄或者不斷的查詢,直到能夠進行操作。

應(yīng)用程序以阻塞的方式進行read操作的時候,會調(diào)用一個system call,將系統(tǒng)的控制權(quán)交給kernel后就進入等待狀態(tài),等kernel將這個system執(zhí)行完成后向應(yīng)用程序返回響應(yīng),應(yīng)用程序的得到響應(yīng)后,就推出阻塞狀態(tài),并進行后面的工作。

應(yīng)用程序以非阻塞的方式進行write操作的時候,通過設(shè)置文件描述符的屬性O(shè)_NONBLOCK使其進入非阻塞的訪問狀態(tài),這時進程也會調(diào)用相應(yīng)的system call,但是system call會立即從kernel中返回。

從表面上看,阻塞狀態(tài)貌似沒有非阻塞的訪問方式效率高,事實上卻不是這樣,非阻塞的訪問方式雖然不用等待,會立即返回,可是他不一定就完成了相應(yīng)的工作,比如上面的例子里面,雖然立即返回,但是數(shù)據(jù)可能還沒有真正的寫入文件中,所以說效率的高低并不是表面看上去的那樣。

在linux驅(qū)動中,可以使用等待隊列來實現(xiàn)阻塞進程的喚醒。wait queue以隊列為基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),與進程調(diào)度機制緊密結(jié)合,能夠用于實現(xiàn)內(nèi)核中的異步事件通知機制等。下面就先看下一些關(guān)于等待隊列的基本的操作。

定義一個等待隊列頭并初始化:

[cpp]?view plaincopy
  • wait_queue_head_t?my_queue;??
  • init_waitqueue_head(&my_queue);??
  • 或者

    [cpp]?view plaincopy
  • DECLARE_WAIT_QUEUE_HEAD(my_queue);??
  • 下面來看下wait_queue_head_t這個結(jié)構(gòu)體,其中t的意思就是typedef的意思,是linux中的一種命名規(guī)則。

    [cpp]?view plaincopy
  • struct?__wait_queue_head?{??
  • ????????spinlock_t?lock;??
  • ????????struct?list_head?task_list;??
  • };??
  • typedef?struct?__wait_queue_head?wait_queue_head_t;??
  • 首先是定義了一個lock的自旋鎖,后面定義了一個鏈表。其中看下init_waitqueue_head函數(shù),通過wait_queue_head_t結(jié)構(gòu)體成員,就不難想象里面大概的函數(shù)實現(xiàn):

    [cpp]?view plaincopy
  • extern?void?__init_waitqueue_head(wait_queue_head_t?*q,?struct?lock_class_key?*);??
  • ??
  • #define?init_waitqueue_head(q)??????????????????????????\??
  • ????????do?{????????????????????????????????????????????\??
  • ????????????????static?struct?lock_class_key?__key;?????\??
  • ????????????????????????????????????????????????????????\??
  • ????????????????__init_waitqueue_head((q),?&__key);?????\??
  • ????????}?while?(0)??
  • 而__init_waitqueue_head()函數(shù)是:

    [cpp]?view plaincopy
  • void?__init_waitqueue_head(wait_queue_head_t?*q,?struct?lock_class_key?*key)??
  • {??
  • ????????spin_lock_init(&q->lock);??
  • ????????lockdep_set_class(&q->lock,?key);??
  • ????????INIT_LIST_HEAD(&q->task_list);??
  • }??
  • 其大概也就是初始化自旋鎖以及鏈表等單元。而DECLARE_WAIT_QUEUE_HEAD的函數(shù)原型是:

    [cpp]?view plaincopy
  • #define?DECLARE_WAIT_QUEUE_HEAD(name)?\??
  • ????????wait_queue_head_t?name?=?__WAIT_QUEUE_HEAD_INITIALIZER(name)??
  • [cpp]?view plaincopy
  • #define?__WAIT_QUEUE_HEAD_INITIALIZER(name)?{???????????????????????????\??
  • ????????.lock???????????=?__SPIN_LOCK_UNLOCKED(name.lock),??????????????\??
  • ????????.task_list??????=?{?&(name).task_list,?&(name).task_list?}?}??
  • 定義等待隊列用DECLARE_WAITQUEUE函數(shù)來實現(xiàn)

    [cpp]?view plaincopy
  • DECLARE_WAITQUEUE(name,tsk);??
  • 其定義了一個名為name的等待隊列

    [cpp]?view plaincopy
  • #define?DECLARE_WAITQUEUE(name,?tsk)????????????????????????????????????\??
  • ????????wait_queue_t?name?=?__WAITQUEUE_INITIALIZER(name,?tsk)??
  • 其中

    [cpp]?view plaincopy
  • typedef?struct?__wait_queue?wait_queue_t;??
  • ??
  • struct?__wait_queue?{??
  • ????????unsigned?int?flags;??
  • #define?WQ_FLAG_EXCLUSIVE???????0x01??
  • ????????void?*private;??
  • ????????wait_queue_func_t?func;??
  • ????????struct?list_head?task_list;??
  • };??
  • [cpp]?view plaincopy
  • #define?__WAITQUEUE_INITIALIZER(name,?tsk)?{????????????????????????????\??
  • ????????.private????????=?tsk,??????????????????????????????????????????\??
  • ????????.func???????????=?default_wake_function,????????????????????????\??
  • ????????.task_list??????=?{?NULL,?NULL?}?}??
  • flag:它的值有WQ_FLAG_EXCLUSIVE或者0,他說明等待的進程是否是互斥的。當(dāng)為WQ_FLAG_EXCLUSIVE表示互斥;

    private:一般用來指向等待進程的task_struct實例;

    func:其喚醒等待進程;

    task_list:用于鏈接等待隊列中的進程

    下面看下添加和移除等待隊列的API函數(shù):

    [cpp]?view plaincopy
  • void?add_wait_queue(wait_queue_head_t?*q,?wait_queue_t?*wait)??
  • {??
  • ????????unsigned?long?flags;??
  • ??
  • ????????wait->flags?&=?~WQ_FLAG_EXCLUSIVE;??
  • ????????spin_lock_irqsave(&q->lock,?flags);??
  • ????????__add_wait_queue(q,?wait);??
  • ????????spin_unlock_irqrestore(&q->lock,?flags);??
  • }??
  • EXPORT_SYMBOL(add_wait_queue);??
  • 其意思就是將wait等待隊列加入到q的等待隊列頭中。再看其中的__add_wait_queue函數(shù):

    [cpp]?view plaincopy
  • static?inline?void?__add_wait_queue(wait_queue_head_t?*head,?wait_queue_t?*new)??
  • {??
  • ????????list_add(&new->task_list,?&head->task_list);??
  • }??
  • 這樣很容易看出,wait是如何掛到q上面去的。同樣的:

    [cpp]?view plaincopy
  • void?remove_wait_queue(wait_queue_head_t?*q,?wait_queue_t?*wait)??
  • {??
  • ????????unsigned?long?flags;??
  • ??
  • ????????spin_lock_irqsave(&q->lock,?flags);??
  • ????????__remove_wait_queue(q,?wait);??
  • ????????spin_unlock_irqrestore(&q->lock,?flags);??
  • }??
  • EXPORT_SYMBOL(remove_wait_queue);??
  • 而__remove_wait_queue函數(shù)

    [cpp]?view plaincopy
  • static?inline?void?__remove_wait_queue(wait_queue_head_t?*head,??
  • ????????????????????????????????????????????????????????wait_queue_t?*old)??
  • {?????????
  • ????????list_del(&old->task_list);??
  • }?????????
  • 這樣看就很簡單了。

    下面介紹的是等待事件函數(shù),其就是依據(jù)condition條件是否滿足來選擇是否返回或者阻塞等待。

    [cpp]?view plaincopy
  • wait_event(wq,?condition)??
  • wait_event_timeout(wq,?condition,?timeout)???
  • wait_event_interruptible(wq,?condition)???
  • wait_event_interruptible_timeout(wq,?condition,?timeout)??
  • 下面以此來看上面函數(shù)的實現(xiàn)過程:

    [cpp]?view plaincopy
  • /**?
  • ?*?wait_event?-?sleep?until?a?condition?gets?true?
  • ?*?@wq:?the?waitqueue?to?wait?on?
  • ?*?@condition:?a?C?expression?for?the?event?to?wait?for?
  • ?*?
  • ?*?The?process?is?put?to?sleep?(TASK_UNINTERRUPTIBLE)?until?the?
  • ?*?@condition?evaluates?to?true.?The?@condition?is?checked?each?time?
  • ?*?the?waitqueue?@wq?is?woken?up.?
  • ?*?
  • ?*?wake_up()?has?to?be?called?after?changing?any?variable?that?could?
  • ?*?change?the?result?of?the?wait?condition.?
  • ?*/??
  • #define?wait_event(wq,?condition)???????????????????????????????????????\??
  • do?{????????????????????????????????????????????????????????????????????\??
  • ????????if?(condition)??????????????????????????????????????????????????\??
  • ????????????????break;??????????????????????????????????????????????????\??
  • ????????__wait_event(wq,?condition);????????????????????????????????????\??
  • }?while?(0)??
  • 其不難看出,當(dāng)condition為真時,函數(shù)立即返回,否則等待條件為真。

    [cpp]?view plaincopy
  • #define?__wait_event(wq,?condition)?????????????????????????????????????\??
  • do?{????????????????????????????????????????????????????????????????????\??
  • ????????DEFINE_WAIT(__wait);????????????????????????????????????????????\??
  • ????????????????????????????????????????????????????????????????????????\??
  • ????????for?(;;)?{??????????????????????????????????????????????????????\??
  • ????????????????prepare_to_wait(&wq,?&__wait,?TASK_UNINTERRUPTIBLE);????\??
  • ????????????????if?(condition)??????????????????????????????????????????\??
  • ????????????????????????break;??????????????????????????????????????????\??
  • ????????????????schedule();?????????????????????????????????????????????\??
  • ????????}???????????????????????????????????????????????????????????????\??
  • ????????finish_wait(&wq,?&__wait);??????????????????????????????????????\??
  • }?while?(0)??
  • 這里首先是定義了一個等待隊列項__wait:

    [cpp]?view plaincopy
  • #define?DEFINE_WAIT(name)?DEFINE_WAIT_FUNC(name,?autoremove_wake_function)??
  • [cpp]?view plaincopy
  • #define?DEFINE_WAIT_FUNC(name,?function)????????????????????????????????\??
  • ????????wait_queue_t?name?=?{???????????????????????????????????????????\??
  • ????????????????.private????????=?current,??????????????????????????????\??
  • ????????????????.func???????????=?function,?????????????????????????????\??
  • ????????????????.task_list??????=?LIST_HEAD_INIT((name).task_list),?????\??
  • ????????}??
  • 其中,.private ?= current表示等待隊列項指向當(dāng)前的進程;.func ?= function 其就是的喚醒函數(shù)。

    下面就進入循環(huán),開始是prepare_to_wait函數(shù),這個函數(shù)的作用是將等待隊列項__wait插入到等待隊列透wq中,然后設(shè)置為TASK_UNINTERRUPTIBLE,即改阻塞狀態(tài)不能被信號打斷,而TASK_INTERRUPTIBLE狀態(tài)可以被信號打斷喚醒。然后再檢查一次condition,當(dāng)condition剛好為真時函數(shù)立即返回,否則調(diào)用schedule()函數(shù)使得進程睡眠,執(zhí)行schedule()進行了進程的切換以后,直到進程被喚醒才會調(diào)度該進程。for循環(huán)是等進程被喚醒后再一次檢查condition條件是否滿足,防止同時喚醒的進程已經(jīng)搶先占據(jù)了資源。最后finish_wait將進程狀態(tài)屬性改為TASK_RUNNING,并且將進程從等待隊列中刪除。下面看下實現(xiàn)過程:

    [cpp]?view plaincopy
  • prepare_to_wait(wait_queue_head_t?*q,?wait_queue_t?*wait,?int?state)??
  • {??
  • ????????unsigned?long?flags;??
  • ??
  • ????????wait->flags?&=?~WQ_FLAG_EXCLUSIVE;??
  • ????????spin_lock_irqsave(&q->lock,?flags);??
  • ????????if?(list_empty(&wait->task_list))??
  • ????????????????__add_wait_queue(q,?wait);??
  • ????????set_current_state(state);??
  • ????????spin_unlock_irqrestore(&q->lock,?flags);??
  • }??
  • EXPORT_SYMBOL(prepare_to_wait);??
  • [cpp]?view plaincopy
  • void?finish_wait(wait_queue_head_t?*q,?wait_queue_t?*wait)??
  • {??
  • ????????unsigned?long?flags;??
  • ??
  • ????????__set_current_state(TASK_RUNNING);??
  • ????????/*?
  • ?????????*?We?can?check?for?list?emptiness?outside?the?lock?
  • ?????????*?IFF:?
  • ?????????*??-?we?use?the?"careful"?check?that?verifies?both?
  • ?????????*????the?next?and?prev?pointers,?so?that?there?cannot?
  • ?????????*????be?any?half-pending?updates?in?progress?on?other?
  • ?????????*????CPU's?that?we?haven't?seen?yet?(and?that?might?
  • ?????????*????still?change?the?stack?area.?
  • ?????????*?and?
  • ?????????*??-?all?other?users?take?the?lock?(ie?we?can?only?
  • ?????????*????have?_one_?other?CPU?that?looks?at?or?modifies?
  • ?????????*????the?list).?
  • ?????????*/??
  • ????????if?(!list_empty_careful(&wait->task_list))?{??
  • ????????????????spin_lock_irqsave(&q->lock,?flags);??
  • ????????????????list_del_init(&wait->task_list);??
  • ????????????????spin_unlock_irqrestore(&q->lock,?flags);??
  • ????????}??
  • }??
  • EXPORT_SYMBOL(finish_wait);??
  • 下面看一下wait_event_timeout()函數(shù)的實現(xiàn),timeout就是阻塞等待的超時時間,單位是jiffy,當(dāng)timeout達到以后,不論condition是否滿足函數(shù)都會返回。

    [cpp]?view plaincopy
  • #define?wait_event_timeout(wq,?condition,?timeout)??????????????????????\??
  • ({??????????????????????????????????????????????????????????????????????\??
  • ????????long?__ret?=?timeout;???????????????????????????????????????????\??
  • ????????if?(!(condition))???????????????????????????????????????????????\??
  • ????????????????__wait_event_timeout(wq,?condition,?__ret);?????????????\??
  • ????????__ret;??????????????????????????????????????????????????????????\??
  • })??
  • [cpp]?view plaincopy
  • #define?__wait_event_timeout(wq,?condition,?ret)????????????????????????\??
  • do?{????????????????????????????????????????????????????????????????????\??
  • ????????DEFINE_WAIT(__wait);????????????????????????????????????????????\??
  • ????????????????????????????????????????????????????????????????????????\??
  • ????????for?(;;)?{??????????????????????????????????????????????????????\??
  • ????????????????prepare_to_wait(&wq,?&__wait,?TASK_UNINTERRUPTIBLE);????\??
  • ????????????????if?(condition)??????????????????????????????????????????\??
  • ????????????????????????break;??????????????????????????????????????????\??
  • ????????????????ret?=?schedule_timeout(ret);????????????????????????????\??
  • ????????????????if?(!ret)???????????????????????????????????????????????\??
  • ????????????????????????break;??????????????????????????????????????????\??
  • ????????}???????????????????????????????????????????????????????????????\??
  • ????????finish_wait(&wq,?&__wait);??????????????????????????????????????\??
  • }?while?(0)??
  • 其和前面的區(qū)別就在于多了一個timeout條件,schedule_timeout()函數(shù)設(shè)置了一個ret的時鐘值,他首先調(diào)用schedule()函數(shù),進程睡眠,但是每次時鐘中斷的時候它都會檢測時鐘值是否到期,當(dāng)時鐘到期后則返回,正常的返回值是0。

    剩余的兩個wait()函數(shù)過程都一樣,這里列出實現(xiàn)過程:

    [cpp]?view plaincopy
  • #define?wait_event_interruptible(wq,?condition)?????????????????????????\??
  • ({??????????????????????????????????????????????????????????????????????\??
  • ????????int?__ret?=?0;??????????????????????????????????????????????????\??
  • ????????if?(!(condition))???????????????????????????????????????????????\??
  • ????????????????__wait_event_interruptible(wq,?condition,?__ret);???????\??
  • ????????__ret;??????????????????????????????????????????????????????????\??
  • })??
  • [cpp]?view plaincopy
  • #define?__wait_event_interruptible(wq,?condition,?ret)??????????????????\??
  • do?{????????????????????????????????????????????????????????????????????\??
  • ????????DEFINE_WAIT(__wait);????????????????????????????????????????????\??
  • ????????????????????????????????????????????????????????????????????????\??
  • ????????for?(;;)?{??????????????????????????????????????????????????????\??
  • ????????????????prepare_to_wait(&wq,?&__wait,?TASK_INTERRUPTIBLE);??????\??
  • ????????????????if?(condition)??????????????????????????????????????????\??
  • ????????????????????????break;??????????????????????????????????????????\??
  • ????????????????if?(!signal_pending(current))?{?????????????????????????\??
  • ????????????????????????schedule();?????????????????????????????????????\??
  • ????????????????????????continue;???????????????????????????????????????\??
  • ????????????????}???????????????????????????????????????????????????????\??
  • ????????????????ret?=?-ERESTARTSYS;?????????????????????????????????????\??
  • ????????????????break;??????????????????????????????????????????????????\??
  • ????????}???????????????????????????????????????????????????????????????\??
  • ????????finish_wait(&wq,?&__wait);??????????????????????????????????????\??
  • }?while?(0)??
  • 其中wait_event_interruptible()函數(shù)是將進程屬性設(shè)置為TASK_INTERRUPTIBLE,可以被信號喚醒,signal_pending(current)函數(shù)是判斷是否是信號喚醒的。是的話直接返回-ERESTARTSYS。

    [cpp]?view plaincopy
  • #define?wait_event_interruptible_timeout(wq,?condition,?timeout)?\??
  • ({?\??
  • ????????long?__ret?=?timeout;?\??
  • ????????if?(!(condition))?\??
  • ????????????????__wait_event_interruptible_timeout(wq,?condition,?__ret);?\??
  • ????????__ret;?\??
  • })??
  • [cpp]?view plaincopy
  • #define?__wait_event_interruptible_timeout(wq,?condition,?ret)?\??
  • do?{?\??
  • ????????wait_queue_t?__wait;?\??
  • ????????init_waitqueue_entry(&__wait,?current);?\??
  • ????????add_wait_queue(&wq,?&__wait);?\??
  • ????????for?(;;)?{?\??
  • ????????????????set_current_state(TASK_INTERRUPTIBLE);?\??
  • ????????????????if?(condition)?\??
  • ????????????????????????break;?\??
  • ????????????????if?(!signal_pending(current))?{?\??
  • ????????????????????????ret?=?schedule_timeout(ret);?\??
  • ????????????????????????if?(!ret)?\??
  • ????????????????????????????????break;?\??
  • ????????????????????????continue;?\??
  • ????????????????}?\??
  • ????????????????ret?=?-ERESTARTSYS;?\??
  • ????????????????break;?\??
  • ????????}?\??
  • ????????current->state?=?TASK_RUNNING;?\??
  • ????????remove_wait_queue(&wq,?&__wait);?\??
  • }?while?(0)??
  • [cpp]?view plaincopy
  • static?inline?void?init_waitqueue_entry(wait_queue_t?*q,?struct?task_struct?*p)??
  • {??
  • ????????q->flags?=?0;??
  • ????????q->private?=?p;??
  • ????????q->func?=?default_wake_function;??
  • }??
  • default_wake_function是內(nèi)核中的一個默認的喚醒函數(shù)。

    下面來看一下喚醒函數(shù),常用的有:

    [cpp]?view plaincopy
  • #define?wake_up(x)??????????????????????__wake_up(x,?TASK_NORMAL,?1,?NULL)??
  • #define?wake_up_interruptible(x)????????__wake_up(x,?TASK_INTERRUPTIBLE,?1,?NULL)??
  • 喚醒函數(shù)主要是喚醒屬于指定等待隊列頭的所有等待隊列中等待進程??梢钥闯?#xff0c;其實質(zhì)都是調(diào)用__wake_up()函數(shù),只是傳遞的參數(shù)不同而已。

    [cpp]?view plaincopy
  • void?__wake_up(wait_queue_head_t?*q,?unsigned?int?mode,??
  • ????????????????????????int?nr_exclusive,?void?*key)??
  • {??
  • ????????unsigned?long?flags;??
  • ??
  • ????????spin_lock_irqsave(&q->lock,?flags);??
  • ????????__wake_up_common(q,?mode,?nr_exclusive,?0,?key);??
  • ????????spin_unlock_irqrestore(&q->lock,?flags);??
  • }??
  • EXPORT_SYMBOL(__wake_up);??
  • 其中

    [cpp]?view plaincopy
  • static?void?__wake_up_common(wait_queue_head_t?*q,?unsigned?int?mode,??
  • ????????????????????????int?nr_exclusive,?int?wake_flags,?void?*key)??
  • {??
  • ????????wait_queue_t?*curr,?*next;??
  • ??
  • ????????list_for_each_entry_safe(curr,?next,?&q->task_list,?task_list)?{??
  • ????????????????unsigned?flags?=?curr->flags;??
  • ??
  • ????????????????if?(curr->func(curr,?mode,?wake_flags,?key)?&&??
  • ????????????????????????????????(flags?&?WQ_FLAG_EXCLUSIVE)?&&?!--nr_exclusive)??
  • ????????????????????????break;??
  • ????????}??
  • }??
  • list_for_each_entry_safe將遍歷整個等待隊列鏈表,在if語句中,func是默認的喚醒函數(shù),是將curr進程通過mode方式喚醒,然后再比較是否是互斥形式,如果是的話在判斷需要喚醒的互斥進程的數(shù)量(nr_exclusive是需喚醒的互斥進程的數(shù)量),通過if語句可以看出,在遍歷的過程中首先先會喚醒非互斥的,然后才會喚醒互斥進程(可以通過if語句中&&的順序判斷)。

    通過上面的分析,對于等待隊列的阻塞以及喚醒已經(jīng)很清楚了,下面還有一套sleep()函數(shù),其目的是使進程在等待隊列上睡眠,如:

    [cpp]?view plaincopy
  • sleep_on(wait_queue_head_t?*q)??
  • interruptible_sleep_on(wait_queue_head_t?*q)??
  • sleep_on函數(shù)是將進程的狀態(tài)設(shè)置為TASK_UMINTERRUPTIBLE,并且將它附屬到等待隊列頭q上,知道獲得資源,q引導(dǎo)的等待隊列被喚醒。

    而interruptible_sleep_on函數(shù)是將進程設(shè)置為TASK_INTERRUPTIBLE。

    sleep_on與wake_up、interruptible_sleep_on與wake_up_interruptible都是成對出現(xiàn)使用的。

    [cpp]?view plaincopy
  • void?__sched?sleep_on(wait_queue_head_t?*q)??
  • {??
  • ????????sleep_on_common(q,?TASK_UNINTERRUPTIBLE,?MAX_SCHEDULE_TIMEOUT);??
  • }??
  • EXPORT_SYMBOL(sleep_on);??
  • [cpp]?view plaincopy
  • void?__sched?interruptible_sleep_on(wait_queue_head_t?*q)??
  • {??
  • ????????sleep_on_common(q,?TASK_INTERRUPTIBLE,?MAX_SCHEDULE_TIMEOUT);??
  • }??
  • EXPORT_SYMBOL(interruptible_sleep_on);??
  • 其核心都是sleep_on_common()函數(shù),只是傳遞的參數(shù)不同。

    [cpp]?view plaincopy
  • static?long?__sched??
  • sleep_on_common(wait_queue_head_t?*q,?int?state,?long?timeout)??
  • {??
  • ????????unsigned?long?flags;??
  • ????????wait_queue_t?wait;??
  • ??
  • ????????init_waitqueue_entry(&wait,?current);??
  • ??
  • ????????__set_current_state(state);??
  • ??
  • ????????spin_lock_irqsave(&q->lock,?flags);??
  • ????????__add_wait_queue(q,?&wait);??
  • ????????spin_unlock(&q->lock);??
  • ????????timeout?=?schedule_timeout(timeout);??
  • ????????spin_lock_irq(&q->lock);??
  • ????????__remove_wait_queue(q,?&wait);??
  • ????????spin_unlock_irqrestore(&q->lock,?flags);??
  • ??
  • ????????return?timeout;??
  • }??
  • 實現(xiàn)思想與前面所說的都差不多,代碼也比較簡單,這里就不詳細分析了。

    在許多的設(shè)備驅(qū)動中,并不調(diào)用sleep_on()或interruptible_sleep_on(),而是親自進行進程的狀態(tài)改變和切換,這樣代碼的效率比較高,下面我們根據(jù)前面的globlemem虛擬字符設(shè)備驅(qū)動的例子來進行改進,增加隊列等待機制,可以對照之前的代碼來看加入阻塞訪問前后的區(qū)別。

    首先定義設(shè)備結(jié)構(gòu)體,添加了r_wait和w_wait兩個讀寫的等待隊列頭:

    [cpp]?view plaincopy
  • struct?globalmem_dev{??
  • ????????struct?cdev?cdev;??
  • ????unsigned?int?current_len;??
  • ????????unsigned?char?mem[GLOBALMEM_SIZE];??
  • ????struct?semaphore?sem;??
  • ????wait_queue_head_t?r_wait;??
  • ????wait_queue_head_t?w_wait;??
  • };??
  • 自然還需要在初始化模塊里面進行初始化:

    [cpp]?view plaincopy
  • int?globalmem_init(void)??
  • {??
  • ????????int?result;??
  • ????????dev_t?devno=MKDEV(globalmem_major,0);??
  • ??
  • ????????if(globalmem_major)??
  • ????????????????result=register_chrdev_region(devno,1,"globalmem");??
  • ????????else{??
  • ????????????????result=alloc_chrdev_region(&devno,0,1,"globalmem");??
  • ????????????????globalmem_major=MAJOR(devno);??
  • ????????}??
  • ????????if(result<0)??
  • ????????????????return?result;??
  • ??
  • ????????globalmem_devp?=?kmalloc(sizeof(struct?globalmem_dev),GFP_KERNEL);??
  • ????if(!globalmem_devp){??
  • ????????result?=?-ENOMEM;??
  • ????????goto?fail_malloc;??
  • ????}??
  • ??
  • ????memset(&globalmem_devp,0,sizeof(struct?globalmem_dev));??
  • ??
  • ????????globalmem_setup_cdev(&globalmem_devp,0);??
  • ????init_MUTEX(&globalmem_devp->sem);??
  • ????init_waitqueue_head(&globalfifo_devp->r_wait);?????//初始化讀等待隊列??
  • ????init_waitqueue_head(&globalfifo_devp->w_wait);????//初始化寫等待隊列??
  • ??
  • ????????return?0;??
  • ??
  • fail_malloc:??
  • ????unregister_chrdev_region(devno,1);??
  • ????return?result;??
  • }??
  • 下面在繼續(xù)修改讀寫模塊:

    [cpp]?view plaincopy
  • static?ssize_t?globalmem_read(struct?file?*filp,char?__user?*buf,size_t?count,loff_t?*ppos)??
  • {??
  • ????unsigned?long?p?=?*ppos;??
  • ????int?ret?=?0;??
  • ????struct?globalmem_dev?*dev?=?filp->private_data;??
  • ????DECLARE_WAITQUEUE(wait,cuerrent);??????
  • ??????
  • ????down(&dev->sem);??
  • ????add_wait_queue(&dev->r_wait,&wait);??
  • ??
  • ????while(dev->current_len==0){??
  • ????????if(filp->f_flags?&?O_NONBLOCK){??
  • ????????????ret?=?-EAGAIN;??
  • ????????????goto?out;?????????
  • ????????}??
  • ????????__set_current_state(TASK_INTERRUPTIBLE);??
  • ????????up(&dev->sem);??
  • ??
  • ????????schedule();??
  • ????????if(signal_pending(current)){??
  • ????????????ret?=?-ERESTARTSYS;??
  • ????????????goto?out2;????
  • ????????}?????
  • ??????????
  • ????????down(&dev->sem);??
  • ????}??
  • ??????
  • ????if(count?>?dev->current_len)??
  • ????????count?=?dev->current_len;??
  • ????if(copy_to_user(buf,dev->mem,count)){??
  • ????????ret?=?-EFAULT;??
  • ????????goto?out;?????
  • ????}else{??
  • ????????memcpy(dev->mem,dev->mem+count,dev->current_len-count);??
  • ????????dev->current_len?-=?count;??
  • ????????printk(KERN_INFO?"read?%d?bytes(s),current_len:%d\n",count,dev->current_len);??
  • ??
  • ????????wake_up_interruptible(&dev->w_wait);??
  • ??????????
  • ????????ret?=?count;??????????????
  • ????}??
  • ????out:up(&dev->sem);??
  • ????out2:remove_wait_queue(&dev->r_wait,&wait);??
  • ????set_current_state(TASK_RUNNING);??
  • ????return?ret;??
  • }??
  • [cpp]?view plaincopy
  • static?ssize_t?globalmem_write(struct?file?*filp,const?char?__user?*buf,size_t?count,loff_t?*ppos)??
  • {??
  • ????unsigned?long?p?=?*ppos;??
  • ????int?ret?=?0;??
  • ????struct?globalmem_dev?*dev?=?filp->private_data;??
  • ????DECLARE_WAITQUEUE(wait,cuerrent);??????
  • ??????
  • ????down(&dev->sem);??
  • ????add_wait_queue(&dev->w_wait,&wait);??
  • ??
  • ????while(dev->current_len==GLOBALFIFO_SIZE){??
  • ????????if(filp->f_flags?&?O_NONBLOCK){??
  • ????????????ret?=?-EAGAIN;??
  • ????????????goto?out;?????????
  • ????????}??
  • ????????__set_current_state(TASK_INTERRUPTIBLE);??
  • ????????up(&dev->sem);??
  • ??
  • ????????schedule();??
  • ????????if(signal_pending(current)){??
  • ????????????ret?=?-ERESTARTSYS;??
  • ????????????goto?out2;????
  • ????????}?????
  • ??????????
  • ????????down(&dev->sem);??
  • ????}??
  • ??????
  • ????if(count?>?GLOBALFIFO_SIZE-dev->current_len)??
  • ????????count?=?GLOBALFIFO-dev->current_len;??
  • ????if(copy_from_user(dev->mem+dev->current_len,buf,count)){??
  • ????????ret?=?-EFAULT;??
  • ????????goto?out;?????
  • ????}else{??
  • ????????dev->current_len?+=?count;??
  • ????????printk(KERN_INFO?"written?%d?bytes(s),current_len:%d\n",count,dev->current_len);??
  • ??
  • ????????wake_up_interruptible(&dev->r_wait);??
  • ??????????
  • ????????ret?=?count;??????????????
  • ????}??
  • ????out:up(&dev->sem);??
  • ????out2:remove_wait_queue(&dev->w_wait,&wait);??
  • ????set_current_state(TASK_RUNNING);??
  • ????return?ret;??
  • }??
  • 其并沒有調(diào)用seelp_on()等函數(shù),選擇自己設(shè)置狀態(tài)以及進程的切換等動作。將上述的過程用wait_event_interruptible()函數(shù)替換的話,可能會出現(xiàn)死鎖的狀態(tài),可以自己思考一下這個過程。上面讀緩沖區(qū)的數(shù)據(jù)需要在寫函數(shù)中喚醒r_wait,才可以進行讀的操作,而進行寫的過程需要在讀函數(shù)中喚醒w_wait才可以寫入。

    總結(jié)

    以上是生活随笔為你收集整理的Linux设备驱动开发-linux驱动中的阻塞访问方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。