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

正文內(nèi)容

高級字符驅(qū)動操作說明(留存版)

2025-06-02 04:29上一頁面

下一頁面
  

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