freepeople性欧美熟妇, 色戒完整版无删减158分钟hd, 无码精品国产vα在线观看DVD, 丰满少妇伦精品无码专区在线观看,艾栗栗与纹身男宾馆3p50分钟,国产AV片在线观看,黑人与美女高潮,18岁女RAPPERDISSSUBS,国产手机在机看影片

正文內(nèi)容

高級(jí)字符驅(qū)動(dòng)操作說(shuō)明(留存版)

  

【正文】 16:28) 分類: 第 6 章 高級(jí)字符驅(qū)動(dòng)操作在第 3 章, 我們建立了一個(gè)完整的設(shè)備驅(qū)動(dòng), 用戶可用來(lái)寫入和讀取. 但是一個(gè)真正的設(shè)備常常提供比同步讀和寫更多的功能. 現(xiàn)在我們已裝備有調(diào)試工具如果發(fā)生錯(cuò)誤, 并且一個(gè)牢固的并發(fā)的理解來(lái)幫助避免事情進(jìn)入錯(cuò)誤 我們可安全地前進(jìn)并且創(chuàng)建一個(gè)更高級(jí)的驅(qū)動(dòng).本章檢查幾個(gè)你需要理解的概念來(lái)編寫全特性的字符設(shè)備驅(qū)動(dòng). 我們從實(shí)現(xiàn) ioctl 系統(tǒng)調(diào)用開始, 它是用作設(shè)備控制的普通接口. 接著我們進(jìn)入各種和用戶空間同步的方法。 _IOC_READ 意思是從設(shè)備讀, 因此設(shè)備必須寫到用戶空間. 注意這個(gè)成員是一個(gè)位掩碼, 因此 _IOC_READ 和 _IOC_WRITE 可使用一個(gè)邏輯 AND 操作來(lái)抽取.size 涉及到的用戶數(shù)據(jù)的大小. 這個(gè)成員的寬度是依賴體系的, 但是常常是 13 或者 14 位. 你可為你的特定體系在宏 _IOC_SIZEBITS 中找到它的值. 你使用這個(gè) size 成員不是強(qiáng)制的 內(nèi)核不檢查它 但是它是一個(gè)好主意. 正確使用這個(gè)成員可幫助檢測(cè)用戶空間程序的錯(cuò)誤并使你實(shí)現(xiàn)向后兼容, 如果你曾需要改變相關(guān)數(shù)據(jù)項(xiàng)的大小. 如果你需要更大的數(shù)據(jù)結(jié)構(gòu), 但是, 你可忽略這個(gè) size 成員. 我們很快見到如何使用這個(gè)成員.頭文件 asm/, 它包含在 linux/ 中, 定義宏來(lái)幫助建立命令號(hào), 如下: _IO(type,nr)(給沒(méi)有參數(shù)的命令), _IOR(type, nre, datatype)(給從驅(qū)動(dòng)中讀數(shù)據(jù)的), _IOW(type,nr,datatype)(給寫數(shù)據(jù)), 和 _IOWR(type,nr,datatype)(給雙向傳送). type 和 number 成員作為參數(shù)被傳遞, 并且 size 成員通過(guò)應(yīng)用 sizeof 到 datatype 參數(shù)而得到.這個(gè)頭文件還定義宏, 可被用在你的驅(qū)動(dòng)中來(lái)解碼這個(gè)號(hào): _IOC_DIR(nr), _IOC_TYPE(nr), _IOC_NR(nr), 和 _IOC_SIZE(nr). 我們不進(jìn)入任何這些宏的細(xì)節(jié), 因?yàn)轭^文件是清楚的, 并且在本節(jié)稍后有例子代碼展示.這里是一些 ioctl 命令如何在 scull 被定義的. 特別地, 這些命令設(shè)置和獲得驅(qū)動(dòng)的可配置參數(shù)./* Use 39。int retval = 0。 在 scull 例子驅(qū)動(dòng)中, 任何用戶被許可來(lái)查詢 quantum 和 quantum 集的大小. 只有特權(quán)用戶, 但是, 可改變這些值, 因?yàn)椴贿m當(dāng)?shù)闹悼赡芎軌牡赜绊懴到y(tǒng)性能. 當(dāng)需要時(shí), ioctl 的 scull 實(shí)現(xiàn)檢查用戶的特權(quán)級(jí)別, 如下: if (! capable (CAP_SYS_ADMIN)) return EPERM。 tmp = scull_quantum。 /* Get by pointer */quantum = ioctl(fd,SCULL_IOCUANTUM)。my_queue)。 /* EOF */}ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos){ printk(KERN_DEBUG process %i (%s) awakening the readers...\n, currentpid, currentm)。 常常地硬件發(fā)出一個(gè)中斷來(lái)指示這樣一個(gè)事件, 并且驅(qū)動(dòng)喚醒等待的進(jìn)程作為處理這個(gè)中斷的一部分. scullpipe 驅(qū)動(dòng)不同, 以至于它可運(yùn)行而不需要任何特殊的硬件或者一個(gè)中斷處理. 我們選擇來(lái)使用另一個(gè)進(jìn)程來(lái)產(chǎn)生數(shù)據(jù)并喚醒讀進(jìn)程。 O_NONBLOCK) return EAGAIN。 PDEBUG(\%s\ did read %li bytes\n,currentm, (long)count)。手動(dòng)睡眠在 Linux 內(nèi)核的之前的版本, 正式的睡眠要求程序員手動(dòng)處理所有上面的步驟. 它是一個(gè)繁瑣的過(guò)程, 包含相當(dāng)多的易出錯(cuò)的樣板式的代碼. 程序員如果愿意還是可能用那種方式手動(dòng)睡眠。 if (result) return result。devasync_queue, SIGIO, POLL_IN)。wait)。wait, TASK_INTERRUPTIBLE)。devsem)。 if (down_interruptible(amp。 當(dāng)數(shù)據(jù)結(jié)構(gòu)改變時(shí)這樣的代碼會(huì)輕易地失效. 但是, 上面的代碼確實(shí)展示了自己改變一個(gè)進(jìn)程的當(dāng)前狀態(tài)不能使其睡眠. 通過(guò)改變 current 狀態(tài), 你已改變了調(diào)度器對(duì)待進(jìn)程的方式, 但是你還未讓出處理器.放棄處理器是最后一步, 但是要首先做一件事: 你必須先檢查你在睡眠的條件. 做這個(gè)檢查失敗會(huì)引入一個(gè)競(jìng)爭(zhēng)條件。 /* wrapped */ up (amp。devsem)) return ERESTARTSYS。 例如, 當(dāng)打開(為讀存取)一個(gè) 沒(méi)有寫者的(尚無(wú))FIFO, 或者存取一個(gè)磁盤文件使用一個(gè)懸掛鎖. 常常地, 打開一個(gè)設(shè)備或者成功或者失敗, 沒(méi)有必要等待外部的事件. 有時(shí), 但是, 打開這個(gè)設(shè)備需要一個(gè)長(zhǎng)的初始化, 并且你可能選擇在你的 open 方法中支持 O_NONBLOCK , 通過(guò)立刻返回 EAGAIN,如果這個(gè)標(biāo)志被設(shè)置. 在開始這個(gè)設(shè)備的初始化進(jìn)程之后. 這個(gè)驅(qū)動(dòng)可能還實(shí)現(xiàn)一個(gè)阻塞 open 來(lái)支持存取策略, 通過(guò)類似于文件鎖的方式. 我們將見到這樣一個(gè)實(shí)現(xiàn)在阻塞 open 作為對(duì) EBUSY 的替代一節(jié), 在本章后面.一些驅(qū)動(dòng)可能還實(shí)現(xiàn)特別的語(yǔ)義給 O_NONBLOCK。 wait_event_interruptible(wq, flag != 0)。 一個(gè)原子上下文只是一個(gè)狀態(tài), 這里多個(gè)步驟必須在沒(méi)有任何類型的并發(fā)存取的情況下進(jìn)行. 這意味著, 對(duì)于睡眠, 是你的驅(qū)動(dòng)在持有一個(gè)自旋鎖, seqlock, 或者 RCU 鎖時(shí)不能睡眠. 如果你已關(guān)閉中斷你也不能睡眠. 在持有一個(gè)旗標(biāo)時(shí)睡眠是合法的, 但是你應(yīng)當(dāng)仔細(xì)查看這樣做的任何代碼. 如果代碼在持有一個(gè)旗標(biāo)時(shí)睡眠, 任何其他的等待這個(gè)旗標(biāo)的線程也睡眠. 因此發(fā)生在持有旗標(biāo)時(shí)的任何睡眠應(yīng)當(dāng)短暫, 并且你應(yīng)當(dāng)說(shuō)服自己, 由于持有這個(gè)旗標(biāo), 你不能阻塞這個(gè)將最終喚醒你的進(jìn)程.另一件要記住的事情是, 當(dāng)你醒來(lái), 你從不知道你的進(jìn)程離開 CPU 多長(zhǎng)時(shí)間或者同時(shí)已經(jīng)發(fā)生了什么改變. 你也常常不知道是否另一個(gè)進(jìn)程已經(jīng)睡眠等待同一個(gè)事件。quantum)。 break。 返回值指出這個(gè)操作是否成功. 再次, __get_user 應(yīng)當(dāng)只用在已經(jīng)使用 access_ok 校驗(yàn)過(guò)的地址.如果做一個(gè)嘗試來(lái)使用一個(gè)列出的函數(shù)來(lái)傳送一個(gè)不適合特定大小的值, 結(jié)果常常是一個(gè)來(lái)自編譯器的奇怪消息, 例如coversion to nonscalar type requested. 在這些情況中, 必須使用 copy_to_user 或者 copy_from_user.. 當(dāng)用作一個(gè)設(shè)備文件, 但是, 它返回一個(gè) ENOTTY 錯(cuò)誤.FIONBIO File IOctl NonBlocking I/O(在阻塞和非阻塞操作一節(jié)中描述). 這個(gè)調(diào)用修改在 filpf_flags 中的 O_NONBLOCK 標(biāo)志. 給這個(gè)系統(tǒng)調(diào)用的第 3 個(gè)參數(shù)用作指示是否這個(gè)標(biāo)志被置位或者清除. (我們將在本章看到這個(gè)標(biāo)志的角色). 注意常用的改變這個(gè)標(biāo)志的方法是使用 ftl 系統(tǒng)調(diào)用, 使用 F_SETFL 命令.列表中的最后一項(xiàng)介紹了一個(gè)新的系統(tǒng)調(diào)用, ftl, 它看來(lái)象 ioctl. 事實(shí)上, ftl 調(diào)用非常類似 ioctl, 它也是獲得一個(gè)命令參數(shù)和一個(gè)額外的(可選地)參數(shù). 它保持和 ioctl 獨(dú)立主要是因?yàn)闅v史原因: 當(dāng) Unix 開發(fā)者面對(duì)控制 I/O 操作的問(wèn)題時(shí), 他們決定文件和設(shè)備是不同的. 那時(shí), 有 ioctl 實(shí)現(xiàn)的唯一設(shè)備是 ttys, 它解釋了為什么 ENOTTY 是標(biāo)準(zhǔn)的對(duì)不正確 ioctl 命令的回答. 事情已經(jīng)改變, 但是 ftl 保留為一個(gè)獨(dú)立的系統(tǒng)調(diào)用..inode 和 filp 指針是對(duì)應(yīng)應(yīng)用程序傳遞的文件描述符 fd 的值, 和傳遞給 open 方法的相同參數(shù). cmd 參數(shù)從用戶那里不改變地傳下來(lái), 并且可選的參數(shù) arg 參數(shù)以一個(gè) unsigned long 的形式傳遞, 不管它是否由用戶給定為一個(gè)整數(shù)或一個(gè)指針. 如果調(diào)用程序不傳遞第 3 個(gè)參數(shù), 被驅(qū)動(dòng)操作收到的 arg 值是無(wú)定義的. 因?yàn)轭愋蜋z查在這個(gè)額外參數(shù)上被關(guān)閉, 編譯器不能警告你如果一個(gè)無(wú)效的參數(shù)被傳遞給 ioctl, 并且任何關(guān)聯(lián)的錯(cuò)誤將難以查找.如果你可能想到的, 大部分 ioctl 實(shí)現(xiàn)包括一個(gè)大的 switch 語(yǔ)句來(lái)根據(jù) cmd 參數(shù), 選擇正確的做法. 不同的命令有不同的數(shù)值, 它們常常被給予符號(hào)名來(lái)簡(jiǎn)化編碼. 符號(hào)名通過(guò)一個(gè)預(yù)處理定義來(lái)安排. 定制的驅(qū)動(dòng)常常聲明這樣的符號(hào)在它們的頭文件中。 這個(gè)原型由于這些點(diǎn)而凸現(xiàn)于 Unix 系統(tǒng)調(diào)用列表, 這些點(diǎn)常常表示函數(shù)有數(shù)目不定的參數(shù). 在實(shí)際系統(tǒng)中, 但是, 一個(gè)系統(tǒng)調(diào)用不能真正有變數(shù)目的參數(shù). 系統(tǒng)調(diào)用必須有一個(gè)很好定義的原型, 因?yàn)橛脩舫绦蚩纱嫒∷鼈冎荒芡ㄟ^(guò)硬件的門. 因此, 原型中的點(diǎn)不表示一個(gè)變數(shù)目的參數(shù), 而是一個(gè)單個(gè)可選的參數(shù), 傳統(tǒng)上標(biāo)識(shí)為 char *argp. 這些點(diǎn)在那里只是為了阻止在編譯時(shí)的類型檢查. 第 3 個(gè)參數(shù)的實(shí)際特點(diǎn)依賴所發(fā)出的特定的控制命令( 第 2 個(gè)參數(shù) ). 一些命令不用參數(shù), 一些用一個(gè)整數(shù)值, 以及一些使用指向其他數(shù)據(jù)的指針. 使用一個(gè)指針是傳遞任意數(shù)據(jù)到 ioctl 調(diào)用的方法。 只對(duì)常規(guī)文件發(fā)出的那些.if (err) return EFAULT。 scull_quantum = arg。}return retval。阻塞 I/O回顧第 3 章, 我們看到如何實(shí)現(xiàn) read 和 write 方法. 在此, 但是, 我們跳過(guò)了一個(gè)重要的問(wèn)題:一個(gè)驅(qū)動(dòng)當(dāng)它無(wú)法立刻滿足請(qǐng)求應(yīng)當(dāng)如何響應(yīng)? 一個(gè)對(duì) read 的調(diào)用可能當(dāng)沒(méi)有數(shù)據(jù)時(shí)到來(lái), 而以后會(huì)期待更多的數(shù)據(jù). 或者一個(gè)進(jìn)程可能試圖寫, 但是你的設(shè)備沒(méi)有準(zhǔn)備好接受數(shù)據(jù), 因?yàn)槟愕妮敵鼍彌_滿了. 調(diào)用進(jìn)程往往不關(guān)心這種問(wèn)題。 實(shí)際上, 慣例是使用 wake_up 如果你在使用 wait_event , wake_up_interruptible 如果你在使用 wait_event_interruptible.我們現(xiàn)在知道足夠多來(lái)看一個(gè)簡(jiǎn)單的睡眠和喚醒的例子. 在這個(gè)例子代碼中, 你可找到一個(gè)稱為 sleepy 的模塊. 它實(shí)現(xiàn)一個(gè)有簡(jiǎn)單行為的設(shè)備:任何試圖從這個(gè)設(shè)備讀取的進(jìn)程都被置為睡眠. 無(wú)論何時(shí)一個(gè)進(jìn)程寫這個(gè)設(shè)備, 所有的睡眠進(jìn)程被喚醒. 這個(gè)行為由下面的 read 和 write 方法實(shí)現(xiàn):static DECLARE_WAIT_QUEUE_HEAD(wq)。 如果一個(gè)進(jìn)程調(diào)用 write 并且在緩沖中沒(méi)有空間, 這個(gè)進(jìn)程必須阻塞, 并且它必須在一個(gè)與用作 read 的不同的等待隊(duì)列中. 當(dāng)一些數(shù)據(jù)被寫入硬件設(shè)備, 并且在輸出緩沖中的空間變空閑, 這個(gè)進(jìn)程被喚醒并且寫調(diào)用成功, 盡管數(shù)據(jù)可能只被部分寫入如果在緩沖只沒(méi)有空間給被請(qǐng)求的 count 字節(jié).這 2 句都假定有輸入和輸出緩沖。 /* Char device structure */}。 return EFAULT。 當(dāng)然, 它們對(duì)應(yīng) 2 類的睡眠. 其他的狀態(tài)正常地和驅(qū)動(dòng)編寫者無(wú)關(guān).在 內(nèi)核, 對(duì)于驅(qū)動(dòng)代碼通常不需要直接操作進(jìn)程狀態(tài). 但是, 如果你需要這樣做, 使用的代碼是:void set_current_state(int new_state)。 return ((devrp + devbuffersize devwp) % devbuffersize) 1。 } devwp += count。 PDEBUG(\%s\ writing: going to sleep\n,currentm)。devsem)) return ERESTARTSYS。}這個(gè)代碼看來(lái)和 read 方法類似, 除了我們已經(jīng)將睡眠代碼放到了一個(gè)單獨(dú)的函數(shù), 稱為 scull_getwritespace. 它的工作是確保在緩沖中有空間給新的數(shù)據(jù), 睡眠直到有空間可用. 一旦空間在, scull_p_write 可簡(jiǎn)單地拷貝用戶的數(shù)據(jù)到那里, 調(diào)整指針, 并且喚醒可能已經(jīng)在等待讀取數(shù)據(jù)的進(jìn)程.處理實(shí)際的睡眠的代碼是:/* Wait for space for writing。 if (devwp = devrp) count = min(count, (size_t)(devend devwp))。init_wait(amp。 如果我們要持有它而睡眠, 就不會(huì)有寫者有機(jī)會(huì)喚醒我們. 一旦這個(gè)確保被丟掉, 我們做一個(gè)快速檢查來(lái)看是否用戶已請(qǐng)求非阻塞 I/O, 并且如果是這樣就返回. 否則, 是時(shí)間調(diào)用 wait_event_interruptible.一旦我們過(guò)了這個(gè)調(diào)用, 某些東東已經(jīng)喚醒了我們, 但是我們不知道是什么. 一個(gè)可能是進(jìn)程接收到了一個(gè)信號(hào). 包含 wait_event_interruptible
點(diǎn)擊復(fù)制文檔內(nèi)容
公司管理相關(guān)推薦
文庫(kù)吧 www.dybbs8.com
備案圖鄂ICP備17016276號(hào)-1