Linux設備驅(qū)動程序?qū)W習(5)-高級字符驅(qū)動程序操作[(2)阻塞型IO和休眠]_第1頁
Linux設備驅(qū)動程序?qū)W習(5)-高級字符驅(qū)動程序操作[(2)阻塞型IO和休眠]_第2頁
Linux設備驅(qū)動程序?qū)W習(5)-高級字符驅(qū)動程序操作[(2)阻塞型IO和休眠]_第3頁
Linux設備驅(qū)動程序?qū)W習(5)-高級字符驅(qū)動程序操作[(2)阻塞型IO和休眠]_第4頁
Linux設備驅(qū)動程序?qū)W習(5)-高級字符驅(qū)動程序操作[(2)阻塞型IO和休眠]_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、Linux 設備驅(qū)動程序?qū)W習(5 )-高級字符驅(qū)動程序操作(2 )阻塞型I/O和休眠Linux設備驅(qū)動程序?qū)W習(5)-高級字符驅(qū)動程序操作(2 )阻塞型I/O和休眠這一部分主要討論:如果驅(qū)動程序無法立即滿足請求,該如何響應?(65865346 ),、休眠進程被置為休眠,意味著它被標識為處于一個特殊的狀態(tài)并且從調(diào)度器的運行隊列中移走。這個進程將不被在任何 CPU上調(diào)度,即將不會運行。直到發(fā)生某些事情改變了那個狀態(tài)。安全地進入休眠的兩條規(guī)則:(1)永遠不要在原子上下文中進入休眠,即 當驅(qū)動在持有一個自旋鎖、seqlock或者RCU鎖時不能睡眠;關(guān)閉中斷也不能睡眠。持有一個信號量時休眠是合法的,但你

2、應當仔細查看代碼:如果代碼在持有一個信號量時睡眠,任何其他的等待這個信號量的線程也會休眠。因此發(fā)生在持有信號量時的休眠必須短暫, 而且決不能阻塞那個將最終喚醒你的進程。(2)當進程被喚醒,它并不知道休眠了多長時間以及休眠時發(fā)生什么;也不知道是否另有進程也在休眠等待同一事件,且那個進程可能在它之前醒來并獲取了所等待的資源。所以不能對喚醒后的系統(tǒng)狀態(tài)做任何的假設,并必須重新檢查等待條件來確保正確的響應。除非確信其他進程會在其他地方喚醒休眠的進程,否則也不能睡眠。使進程可被 找到意味著:需要維護一個稱為等待隊列的數(shù)據(jù)結(jié)構(gòu)。它是一個進程鏈表,其中飽含了等待某個特定事件的所有進程。在Linux中,一個等

3、待隊列由一個wait_queue_head_t結(jié)構(gòu)體來管理,其定義在 <linux/wait.h>中。wait_queue_head_t 類型的數(shù)據(jù)結(jié)構(gòu)非常簡單:struct _wait_queue_head spinl ock_t lock ;struct list_head task_list ;typedef struct _wait_queue_head wait_queue_head_t它包含一個自旋鎖和一個鏈表。 這個鏈表是一個等待隊列入口,它被聲明做 wait_queue_t 。wait_queue_head_t包含關(guān)于睡眠進程的信息和它想怎樣被喚醒.簡單休眠(其實是

4、高級休眠的宏)Linux內(nèi)核中最簡單的休眠方式是稱為wait_event的宏(及其變種),它實現(xiàn)了休眠和進程等待的條件的檢查。形式如下:wait_event (queue, condition )/* 不可中斷休眠,不推薦*/wait_event_interruptible(queue, condition )/* 推薦,返回非零值意味著休眠被中斷,且驅(qū)動應返回-ERESTARTSYS*/wait_event_timeout (queue, condition , timeout )wait_event_interruptible_timeout(queue, condition , time

5、out )/*有限的時間的休眠;若超時,則不管條件為何值 返回0,*/喚醒休眠進程的函數(shù)稱為 wake_up ,形式如下:void wake_up( wait_queue_head_t * queue);void wake_up_interruptible(wait_queue_head_t *queue);慣例:用 wake_up 喚醒 wait_event ;用 wake_up_interruptible喚醒 wait_event_interruptible。簡單休眠實驗模塊程序鏈接:模塊測試程序鏈接:sbepy test實驗現(xiàn)象:Tekkaman244OSBC2440V4d / lib

6、/ modules/ Tekkaman244OSBC2440#Vnsmod sleepy . ko Tekkama n244OSBC2440V4d / dev/Tekkaman244OSBC2440#V4at / proc / devicesCharacter devices :1 mem2 pty3 ttyp4 / dev/ vc/ 04 tty4 ttyS5 / dev/ tty5 / dev/ con sole5 / dev/ ptmx7 vcs10 misc13 in put14 sound81 video4li nux89 i2c90 mtd116 alsa128 ptm136 pt

7、s180 usb189 usb_device204 s3c2410_serial252 sleepy253 usb_e ndpo int254 rtcBlock devices :1 ramdisk256 rfd7 loop31 mtdblock93 nftl96 inftl179 mmcTekkaman244OSBC2440V4nknod - m 666 sleepy c 252 0Tekkama n244OSBC2440V4d / tmp/Tekkaman244OSBC2440V4 sleepy_testr &Tekkaman244OSBC2440#V4 sleepy_testr

8、&Tekkama n244OSBC2440VpsPID Uid VSZ Stat Comma nd1 root 1744 S init2 root SW< kthreadd 3 root SWNksoftirqd / 04 root SW< watchdog/ 05 root SW< events / 06 root SW< khelper 59 root SW< kblockd / 060 root SW< ksuspend_usbd63 root SW< khubd65 root SW< kseriod 77 root SWpdflu

9、sh 78 root SWpdflush 79 root SW< kswapdq80 root SW< aio / 0707 root SW< mtdblockd 708 root SW< nftld 709 root SW< inftld710 root SW< rfdd 742 root SW < kpsmoused751 root SW < kmmcfl769 root SW < rpciod / 0778 root 1752 S - sh779 root 1744 S init781 root 1744 S init783 root

10、 1744 S init787 root 1744 S init799 root 1336 S ./sleepy_testr800 root 1336 S ./sleepy_testr802 root 1744 R psTekkaman244OSBC2440V4 sleepy_testw read code =0write code =02 + Done ./ sleepy_testrTekkama n244OSBC2440VpsPID Uid VSZ Stat Comma nd1 root 1744 S init2 root SW< kthreadd 3 root SWNksoftir

11、qd / 04 root SW< watchdog/ 05 root SW< events / 06 root SW< khelper 59 root SW< kblockd / 060 root SW< ksuspend_usbd63 root SW< khubd65 root SW< kseriod 77 root SWpdflush 78 root SWpdflush 79 root SW < kswapdq80 root SW < aio/ 0707 root SW < mtdblockd 708 root SW < n

12、ftld 709 root SW < inftld 710 root SW < rfdd 742 root SW < kpsmoused751 root SW < kmmcd769 root SW < rpciod / 0778 root 1752 S - sh779 root 1744 S init781 root 1744 S init783 root 1744 S init787 root 1744 S init799 root 1336 S ./sleepy_testr804 root 1744 R psTekkaman2440SBC2440V4 slee

13、py_testwwrite code =0Tekkama n2440SBC2440Vrfead code =01 + Done ./ sleepy_testr Tekkama n2440SBC2440VpsPID Uid VSZ Stat Comma nd1 root 1744 S init2 root SW < kthreadd 3 root SWN ksoftirqd / 04 root SW < watchdog/ 05 root SW < events / 0root SW < khelper 59 root SW60 root SW63 root SW65 r

14、oot SW77 root SW78 root SW79 root SW80 root SW707 root SW708 root SW709 root SW710 root SW742 root SW751 root SW769 root SW< kblockd / 0< ksuspend_usbd< khubd< kseriod pdflush pdflush < kswapdq< aio / 0< mtdblockd < nftld < inftld < rfdd < kpsmoused< kmmcd< rpc

15、iod / 0778 root 1752 S - sh779 root 1744 S init781 root 1744 S init783 root 1744 S init787 root 1744 S init806 root 1744 R ps阻塞和非阻塞操作全功能的read和write 方法涉及到進程可以決定是進行非阻塞I/O還是阻塞I/O操作。明確的非阻塞I/O由filp->f_flags 中的O_NONBLOCK 標志來指示(定義再<linux/fcntl.h> ,被<linux/fs.h>自動包含)。瀏覽源碼,會發(fā)現(xiàn)O_NON BLOCK的另一個名字

16、:O_N DELAY,這是為了兼容 SystemV代碼。O_NON BLOCK標志缺省地被清除,因為等待數(shù)據(jù)的進程的正常行為只是睡眠.其實不一定只有read和write方法有阻塞操作,open也可以有阻塞操作。后面會見到。而我的項目有一個和CPLD的接口的驅(qū)動,我決定要在ioctl中使用阻塞。while (dev->rp = dev -> wp»/* nothing to read */up (& dev-> sem); /* release the lock */if (filp ->f_flags & O_NONBLOCKreturn -

17、EAGAINPDEBUG (""%s" reading: going to sleep'n", current ->comrmif (wait_event_interruptible(dev->inq, (dev->rp != dev->wp»)return - ERESTARTSYS* signal: tell the fs layer to handle it */* otherwise loop, but first reacquire the lock */if (dow nn terruptible(&

18、amp; dev->sem)return - ERESTARTS;YS/* ok, data is there, retur n someth ing */咼級休眠步驟:(1) 分配和初始化一個 wait_queue_t 結(jié)構(gòu),隨后將其添加到正確的等待隊 列。(2) 設置進程狀態(tài),標記為休眠。在<linux/sched.h>中定義有幾個任務狀態(tài):TASK_RUNNING意思是進程能夠運行。有 2個狀態(tài)指示一個進程是在睡眠:TASK_INTERRUPTIBLE 和 TASK_UNTINTERRUPTIBLE 。2.6 內(nèi)核 的驅(qū)動代碼通常不需要直接操作進程狀態(tài)。但如果需要這樣做

19、使用的代碼是:void set_current_state(int new_state );在老的代碼中,你常常見到如此的東西:current->state = TASK_INTERRUPTIBLE;但是象這樣直接改變current是不推薦的,當數(shù)據(jù)結(jié)構(gòu)改變時這樣的代碼將會失效。通過改變 current狀態(tài),只改變了調(diào)度器對待進程的方式,但進程還未讓出處理器。(3) 最后一步是放棄處理器。但必須先檢查進入休眠的條件。如果不做檢查會引入競態(tài):如果在忙于上面的這個過程時有其他的線程剛剛試圖喚醒你,你可能錯過喚醒且長時間休眠。因此典型的代碼下:if (! condition )(2)當wake

20、_up 被在一個等待隊列上調(diào)用,它在喚醒第一個有 WQ_FLAG_EXCLUSIVE 標志的進程后停止喚醒.但內(nèi)核仍然每次喚醒所有的非獨占等待。schedule ();如果代碼只是從schedule 返回,則進程處于TASK_RUNNING 狀態(tài)。如果不需睡眠而跳過對 schedule 的調(diào)用,必須將任務狀態(tài)重置為TASK_RUNNING,還必要從等待隊列中去除這個進程,否則它可能被多次喚醒。手工休眠/*( 1)創(chuàng)建和初始化一個等待隊列。常由宏定義完成:*/DEFINE_WA(Tny_wait);/*name是等待隊列入口項的名字.也可以用2步來做:*/wait_queue_t my_wait

21、 ;ini t_wait(&m y_wait);/*常用的做法是放一個DEFINE_WAIT在循環(huán)的頂部,來實現(xiàn)休眠。*/*(2)添加等待隊列入口到隊列,并設置進程狀態(tài):*/void prepare_to_wait (wait_queue_head_t * queue , wait_queue_t *wait , int state );/*queue 和wait分別地是等待隊列頭和進程入口。 state 是進程的新狀態(tài):TASK_INTERRUPTIBLE( 可中斷休眠,推薦)或TASK_UNINTERRUPTIBLE( 不可中斷休眠,不推薦)。*/*(3)在檢查確認仍然需要休眠之后

22、調(diào)用 schedule*/schedule ();/*( 4)schedule 返回,就到了清理時間:*/void finish_wait (wait_queue_head_t *queu e, wait_queue_t *wait );認真地看簡單休眠中的wait_eve nt (queue con diti on )和wait_eve nt_in terruptible(queue, con diti on )底層源碼會發(fā)現(xiàn),其實他們只是手工休眠中的函數(shù)的組合。所以怕麻煩的話還是用 wait event比較好。獨占等待當一個進程調(diào)用 wake_up 在等待隊列上,所有的在這個隊列上等待的進

23、程被置為可運行的。 這在許多情況下是正確的做法。但有時,可能只有一個被喚醒的進程將成功獲得需要的資源,而其余的將再次休眠。這時如果等待隊列中的進程數(shù)目大,這可能嚴重降低系統(tǒng)性能。為此,內(nèi)核開發(fā)者增加了一個獨占等待"選項。它與一個正常的睡眠有2個重要的不同:采用獨占等待要滿足2個條件:(1) 希望對資源進行有效競爭;(2) 當資源可用時,喚醒一個進程就足夠來完全消耗資源。使一個進程進入獨占等待,可調(diào)用:void prepare_to_wait_exclusive (wait_queue_head_t *queue, wait_queue_t *wait , int state );注意

24、:無法使用 wait_eve nt和它的變體來進行獨占等待喚醒的相關(guān)函數(shù)很少會需要調(diào)用wake_up_interruptible之外的喚醒函數(shù),但為完整起見,這里是整個集合:wake_up( wait_queue_head_t *queue);wake_up_interruptible (wait_queue_head_t * queue);/*wake_up喚醒隊列中的每個非獨占等待進程和一個獨占等待進程。 wake_up_interruptible 同樣,除了它跳過處于不可中斷休眠的進程。它 們在返回之前,使一個或多個進程被喚醒、被調(diào)度(如果它們被從一個原子 上下文調(diào)用,這就不會發(fā)生).*

25、/wake_up_nr( wait_queue_head_t * queue, int nr );wake_up_interruptible_nr(wait_queue_head_t *queue, int nr );/*這些函數(shù)類似wake_up,除了它們能夠喚醒多達 nr個獨占等待者,而 不只是一個.注意傳遞0被解釋為請求所有的互斥等待者都被喚醒*/wake_up_all (wait_queue_head_t *queue); wake_up_interruptible_all(wait_queue_head_t * queue);/*這種wake_up喚醒所有的進程,不管它們是否進行獨占

26、等待(可中斷的 類型仍然跳過在做不可中斷等待的進程)*/wake_up_interruptible_sync(wait_queue_head_t * queue);/* 一個被喚醒的進程可能搶占當前進程,并且在wake_up返回之前被調(diào)度 到處理器。但是,如果你需要不要被調(diào)度出處理器時,可以使用wake_up_interruptible的"同步"變體.這個函數(shù)最常用在調(diào)用者首先要完成剩下的少量工作,且不希望被調(diào)度出處理器時。*/poll禾口select當應用程序需要進行對多文件讀寫時,若某個文件沒有準備好,則系統(tǒng)會處于讀寫阻塞的狀態(tài),并影響了其他文件的讀寫。為了避免這種情況

27、,在必須使用多輸入輸出流又不想阻塞在它們?nèi)魏我粋€上的應用程序常將非阻塞I/O和poll ( System V )、select ( BSD Unix )、 epoll(linux2.5.45開始)系統(tǒng)調(diào)用配合使用。當poll函數(shù)返回時,會給出一個文件是否可讀寫的標志,應用程序根據(jù)不同的標志讀寫相應的文件,實現(xiàn)非阻塞的讀寫。這些系統(tǒng)調(diào)用功能相同:允許進程來決定它是否可讀或?qū)懸粋€或多個文件而不阻塞。這些調(diào)用也可阻塞進程直到任何一個給定集合的文件描述符可用來讀或?qū)憽_@些調(diào)用都需要來自設備驅(qū)動中poll方法的支持,poll返回不同的標志,告訴主進程文件是否可以讀寫,其原型(定義在<linuxpo

28、ll.h> ):unsigned int (* poll ) (struct file *filp , poll_table *wait);實現(xiàn)這個設備方法分兩步:1.在一個或多個可指示查詢狀態(tài)變化的等待隊列上調(diào)用poll_wait.如果沒有文件描述符可用來執(zhí)行I/O,內(nèi)核使這個進程在等待隊列上等待所有的傳遞給系統(tǒng)調(diào)用的文件描述符.驅(qū)動通過調(diào)用函數(shù)poll_wait增加一個等待隊列到portable結(jié)構(gòu),原型:void poll_wait (struct file *, wait_queue_head_t *, poll_table *);2.返回一個位掩碼:描述可能不必阻塞就立刻進行的

29、操作,幾個標志(通過<linux/poll.h> 定義)用來指示可能的操作標志含義POLLIN如果設備無阻塞的讀,就返回該值POLLRDNORM通常的數(shù)據(jù)已經(jīng)準備好,可以讀了,就返回該值。通常的做法是會返回(POLLLIN|POLLRDNORA )POLLRDBAND如果可以從設備讀出帶外數(shù)據(jù),就返回該值,它只可在 linux內(nèi)核的某些網(wǎng)絡代碼中使用,通常不用在設備驅(qū)動 程序中POLLPRI如果可以無阻塞的讀取高優(yōu)先級(帶外)數(shù)據(jù),就返回該值,返回該值會導致select報告文件發(fā)生異常,以為select八帶外數(shù)據(jù)當作異常處理POLLHUP當讀設備的進程到達文件尾時,驅(qū)動程序必須返回

30、該值,依照select的功能描述,調(diào)用select的進程被告知進程時可讀的。POLLERR如果設備發(fā)生錯誤,就返回該值。POLLOUT如果設備可以無阻塞地些,就返回該值POLLWRNORM設備已經(jīng)準備好,可以寫了,就返回該值。通常地做法是(POLLOUT|POLLNORM )POLLWRBAND于 POLLRDBAND 類似考慮poll方法的scullpipe 實現(xiàn):staticunsigned int scull_p_poll(struct file *filp , poll_table*wait)struct scull_pipe *dev = filp -> private_dat

31、a ;unsigned int mask = 0 ;/* The buffer is circular; it is con sidered full* if "wp" is right behind "rp" and empty if the* two are equal.*/dow n(& dev->sem);poll_wait(filp , &dev->inq, wait );poll_wait(filp , &dev-> outq , wait );if (dev-> rp != dev ->

32、wp)mask|= POLLIN | POLLRDNORM* readable */if (spacefree (dev)mask|= POLLOUT| POLLWRNORIW writable */up (& dev-> sen);return mask;與read 和 write 的交互正確實現(xiàn)poll調(diào)用的規(guī)則從設備讀取數(shù)據(jù):(1)如果在輸入緩沖中有數(shù)據(jù),read調(diào)用應當立刻返回,即便數(shù)據(jù)少于應用程序要求的,并確保其他的數(shù)據(jù)會很快到達。如果方便,可一直返回小于請求的數(shù)據(jù),但至少返回一個字節(jié)。在這個情況下,poll應當返回POLLIN|POLLRDNORM 。(2)如果在輸入

33、緩沖中無數(shù)據(jù),read默認必須阻塞直到有一個字節(jié)。若O NONBLOCK 被置位,read立刻返回-EAGIN 。在這個情況下,poll必須報告這個設備是不可讀(清零POLLIN|POLLRDNORM )的直到至少一個字節(jié)到達。(3)若處于文件尾,不管是否阻塞,read應當立刻返回0,且poll應該返回POLLHUP。向設備寫數(shù)據(jù)(1) 若輸出緩沖有空間,write應立即返回。它可接受小于調(diào)用所請求的數(shù)據(jù),但至少必須接受一個字節(jié)。在這個情況下,poll應返回POLLOUT|POLLWRNORM 。(2) 若輸出緩沖是滿的,write默認阻塞直到一些空間被釋放。若O_NOBLOCK被設置,wri

34、te立刻返回一個-EAGAIN。在這些情況下,poll應當報告文件是不可寫的(清零POLLOUT|POLLWRNORM ).若設備不能接受任何多余數(shù)據(jù),不管是否設置了 O_NON BLOCK , write應返回-ENOSPC("設備上沒有空間")。(3) 永遠不要讓write在返回前等待數(shù)據(jù)的傳輸結(jié)束,即使 O_NONBLOCK被清除。若程序想保證它加入到輸出緩沖中的數(shù)據(jù)被真正傳送,驅(qū)動必須提供一 個fsync方法。刷新待處理輸出若一些應用程序需要確保數(shù)據(jù)被發(fā)送到設備, 就實現(xiàn)必須fsync方法。對fsync的調(diào)用只在設備被完全刷新時(即輸出緩沖為空)才返回,不管O_NO

35、NBLOCK 是否被設置,即便這需要一些時間。其原型是:int (* fsync) (struct file *file , struct dentry*dentry , intdatas ync);底層數(shù)據(jù)結(jié)構(gòu)只要用戶應用程序調(diào)用 poll、select、或epoll_ctl,內(nèi)核就會調(diào)用這個系統(tǒng)調(diào)用所引用的所有文件的poll方法,并向他們傳遞同一個poll_table 。poll_table結(jié)構(gòu)只是構(gòu)成實際數(shù)據(jù)結(jié)構(gòu)的簡單封裝:struct poll_table_struct ;/* structures and helpers for f_op->poll impleme ntati

36、 ons*/typedef void (* poll_queue_proc )( struct file *, wait_queue_head_t *, struct poll_table_struct*);typedef struct poll_table_struct poll_queue_proc qproc; poll_table ;對于poll和select系統(tǒng)調(diào)用,poll_table 是一個包含 poll_table_entry 結(jié)構(gòu)內(nèi)存頁鏈表。struct poll_table_e ntrystruct file * filp ;wait_queue_t wait ;wait_

37、queue_head_t * wait_address ;對poll_wait 的調(diào)用有時還會將進程添加到給定的等待隊列。整個的結(jié)構(gòu)必須由內(nèi)核維護,在poll或者select返回前,進程可從所有的隊列中去除如果被輪詢的驅(qū)動沒有一個驅(qū)動程序指明可進行非阻塞 I/O,poll調(diào)用會簡單地睡眠,直到一個它所在的等待隊列 (可能許多)喚醒它.當poll調(diào)用完成,poll_table 結(jié)構(gòu)被重新分配,所有的之前加入到poll表的等待隊列入口都會從表和它們的等待隊列中移出.struct poll_wqueues poll_table pt ;struct poll_table_page * table ;

38、int error ;int inline_index;struct poll_table_e ntryinline entries N INLINE POLL ENTRIES;struct poll_table_page struct poll_table_page * next ;struct poll_table_entry * entry ;struct poll_table_e ntry en tries 0;;A阿就d胡w琲曲曲 in'rfi itjwal t_q u<?ue_he3d_ tfk丿An袖 anattiYep i'IhestFiicrpoll_t

39、able_struct異步通知通過使用異步通知,應用程序可以在數(shù)據(jù)可用時收到一個信號,而無需不停地輪詢啟用步驟:知道信號到達時該通知哪個進程。(2)使用fcntl系統(tǒng)調(diào)用,通過F_SETFL命令設置FASYNC標志。內(nèi)核操作過程1. F_SETOWN 被調(diào)用時 filp->f_owner被賦值。2. 當F_SETFL被執(zhí)行來打開FASYNC,驅(qū)動的fasync方法被調(diào)用.這個標志在文件被打開時缺省地被清除。3. 當數(shù)據(jù)到達時,所有的注冊異步通知的進程都會被發(fā)送一個SIGIO信號Linux提供的通用方法是基于一個數(shù)據(jù)結(jié)構(gòu)和兩個函數(shù),定義在<linux/fs.h>數(shù)據(jù)結(jié)構(gòu):str

40、uct fasync_structintmagic ;intfa_fd;structfasync_struct*fa_next; /* singly linked list */struct file*fa_file ;;驅(qū)動調(diào)用的兩個函數(shù)的原型:int fasync_helper (int fd , struct file *filp , int mode, structfasyn c_struct * fa);void kill_fasync(struct fasync_struct * fa , int sig , int band);當一個打開的文件的FASYNC標志被修改時,調(diào)用fa

41、sync_helper 來從相關(guān)的進程列表中添加或去除文件。除了最后一個參數(shù) ,其他所有參數(shù)都時被提供給fasync方法的相同參數(shù)并被直接傳遞。當數(shù)據(jù)到達時,kill_fasync 被用來通知相關(guān)的進程,它的參數(shù)是被傳遞的信號(常常是SIGIO)和band (幾乎都是POLL_IN )。這是scullpipe 實現(xiàn)fasync方法的:static int scull_p_fasync(int fd , struct file *filp , int mode)struct scull_pipe *dev = filp -> private_data ;return fasync_help

42、er (fd , filp , mode, &dev->async_queue);當數(shù)據(jù)到達,下面的語句必須被執(zhí)行來通知異步讀者.因為對sucllpipe讀者的新數(shù)據(jù)通過一個發(fā)岀 write的進程被產(chǎn)生,這個語句岀現(xiàn)在scullpipe 的write 方法中:if (dev-> asyn c_queue)kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 注意,一些設備也針對設備可寫而實現(xiàn)了異步通知,在這個情況,kill_fas nyc必須以POLL_OUT模式調(diào)用.*/當文件被關(guān)閉時必須調(diào)用fasync方法,

43、來從活動的異步讀取進程列表中刪除該文件。盡管這個調(diào)用僅當filp->f_flags 被設置為FASYNC時才需要,但不管什么情況,調(diào)用這個函數(shù)不會有問題,并且是普遍的實現(xiàn)方法。以下是scullpipe的release 方法的一部分:/* remove this filp from the asynchronously notified filp's */scull_p_fasync (- 1, filp , 0);異步通知使用的數(shù)據(jù)結(jié)構(gòu)和 struct wait_queue幾乎相同,因為他們都涉及等待事件。區(qū)別異步通知用struct file 替代struct task_stru

44、ct.隊列中的file用獲取f_owner, 一邊給進程發(fā)送信號。scullpipe 的實驗(poll和fasync 方法的實現(xiàn))模塊程序鏈接:scullpipe模塊測試程序鏈接:scullpipe-testARM9實驗板的實驗現(xiàn)象是:Tekkaman244OSBC2440V4d / lib / modules/Tekkaman244OSBC2440Vinsmod pipe . koTekkaman244OSBC2440V4at / proc / devicesCharacter devices :1 mem2 pty3 ttyp4 / dev/ vc/ 04 tty4 ttyS5 / dev

45、/ tty5 / dev/ con sole5 / dev/ ptmx7 vcs10 misc13 in put14 sound81 video4li nux89 i2c90 mtd116 alsa128 ptm136 pts180 usb189 usb_device204 s3c2410_serial252 pipe253 usb_e ndpo int254 rtcBlock devices :1 ramdisk256 rfd7 loop31 mtdblock93 nftl96 inftl179 mmcTekkama n244OSBC2440V4d / dev/Tekkama n244OSB

46、C2440V4Tekkama n244OSBC2440V4d / tmp/Tekkaman244OSBC2440V4 pipe_test &Tekkama n244OSBC2440V4pe n scullpipe0!ope n scullpipe1!SCULL_P_IOCTSIZE scull_p_bufferO=21 !SCULL_PO CTSIZE: scull_p_buffer1=21 !close pipetestO!close pipetest1!reope n scullpipeO!reope n scullpipe1!Tekkama n2440SBC2440V4cho 1

47、2345678901234567890 > /dev/ scullpipeOTekkama n244OSBC2440Vrfead from pipetestO code=200=1 1=2 2=3 3=4 4=55=6 6=7 7=8 8=9 9=010=1 11= 2 12= 3 13= 4 14= 515= 6 16= 7 17= 8 18= 9 19= 0read from pipetestO code =10=1=2 2=3 3=4 4=55=6 6=7 7=8 8=9 9=010=1 11=2 12= 3 13= 4 14= 515= 6 16= 7 17= 8 18= 9 19= 0/ dev/ scullpipe1=15Tekkama n244OSBC2440V4cho 12345678901234 >Tekkama

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論