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

正文內容

高級字符驅動操作說明(文件)

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

下一頁面
 

【正文】 出命令的程序甚至常常不需要運行在和它要控制的設備所在的同一個系統上.例如, setterm 程序作用于控制臺(或者其他終端)配置, 通過打印 escape 序列. 控制程序可位于和被控制的設備不同的一臺計算機上, 因為一個簡單的數據流重定向可完成這個配置工作. 這是每次你運行一個遠程 tty 會話時所發(fā)生的事情: escape 序列在遠端被打印但是影響到本地的 tty。阻塞 I/O回顧第 3 章, 我們看到如何實現 read 和 write 方法. 在此, 但是, 我們跳過了一個重要的問題:一個驅動當它無法立刻滿足請求應當如何響應? 一個對 read 的調用可能當沒有數據時到來, 而以后會期待更多的數據. 或者一個進程可能試圖寫, 但是你的設備沒有準備好接受數據, 因為你的輸出緩沖滿了. 調用進程往往不關心這種問題。 那個進程可能在你之前醒來并且獲取了你在等待的資源. 結果是你不能關于你醒后的系統狀態(tài)做任何的假設, 并且你必須檢查來確保你在等待的條件是, 確實, 真的.一個另外的相關的點, 當然, 是你的進程不能睡眠除非確信其他人, 在某處的, 將喚醒它. 做喚醒工作的代碼必須也能夠找到你的進程來做它的工作. 確保一個喚醒發(fā)生, 是深入考慮你的代碼和對于每次睡眠, 確切知道什么系列的事件將結束那次睡眠. 使你的進程可能被找到, 真正地, 通過一個稱為等待隊列的數據結構實現的. 一個等待隊列就是它聽起來的樣子:一個進程列表, 都等待一個特定的事件.在 Linux 中, 一個等待隊列由一個等待隊列頭來管理, 一個 wait_queue_head_t 類型的結構, 定義在linux/中. 一個等待隊列頭可被定義和初始化, 使用:DECLARE_WAIT_QUEUE_HEAD(name)。我們將很快返回到等待隊列結構, 但是我們知道了足夠多的來首先看看睡眠和喚醒.. 一個非零值意味著你的睡眠被某些信號打斷, 并且你的驅動可能應當返回 ERESTARTSYS. 最后的版本(wait_event_timeout 和 wait_event_interruptible_timeout)等待一段有限的時間。 實際上, 慣例是使用 wake_up 如果你在使用 wait_event , wake_up_interruptible 如果你在使用 wait_event_interruptible.我們現在知道足夠多來看一個簡單的睡眠和喚醒的例子. 在這個例子代碼中, 你可找到一個稱為 sleepy 的模塊. 它實現一個有簡單行為的設備:任何試圖從這個設備讀取的進程都被置為睡眠. 無論何時一個進程寫這個設備, 所有的睡眠進程被喚醒. 這個行為由下面的 read 和 write 方法實現:static DECLARE_WAIT_QUEUE_HEAD(wq)。 flag = 0。 flag = 1。 /* succeed, to avoid retrial */}注意這個例子里 flag 變量的使用. 因為 wait_event_interruptible 檢查一個必須變?yōu)檎娴臈l件, 我們使用 flag 來創(chuàng)建那個條件.有趣的是考慮當 sleepy_write 被調用時如果有 2 個進程在等待會發(fā)生什么. 因為 sleepy_read 重置 flag 為 0 一旦它醒來, 你可能認為醒來的第 2 個進程會立刻回到睡眠. 在一個單處理器系統, 這幾乎一直是發(fā)生的事情. 但是重要的是要理解為什么你不能依賴這個行為. wake_up_interruptible 調用將使 2 個睡眠進程醒來. 完全可能它們都注意到 flag 是非零, 在另一個有機會重置它之前. 對于這個小模塊, 這個競爭條件是不重要的. 在一個真實的驅動中, 這種競爭可能導致少見的難于查找的崩潰. 如果正確的操作要求只能有一個進程看到這個非零值, 它將必須以原子的方式被測試. 我們將見到一個真正的驅動如何處理這樣的情況. 但首先我們必須開始另一個主題.. 如果一個進程調用 write 并且在緩沖中沒有空間, 這個進程必須阻塞, 并且它必須在一個與用作 read 的不同的等待隊列中. 當一些數據被寫入硬件設備, 并且在輸出緩沖中的空間變空閑, 這個進程被喚醒并且寫調用成功, 盡管數據可能只被部分寫入如果在緩沖只沒有空間給被請求的 count 字節(jié).這 2 句都假定有輸入和輸出緩沖。 例如, 一個磁帶設備的 open 常常阻塞直到插入一個磁帶. 如果這個磁帶驅動器使用 O_NONBLOCK 打開, 這個 open 立刻成功, 不管是否介質在或不在.只有 read, write, 和 open 文件操作受到非阻塞標志影響.. 類似地, 讀進程被用來喚醒正在等待緩沖空間可用的寫者進程.這個設備驅動使用一個設備結構, 它包含 2 個等待隊列和一個緩沖. 緩沖大小是以常用的方法可配置的(在編譯時間, 加載時間, 或者運行時間).struct scull_pipe{ wait_queue_head_t inq, outq。 /* where to read, where to write */ int nreaders, nwriters。 /* Char device structure */}。 while (devrp == devwp) { /* nothing to read */ up(amp。 PDEBUG(\%s\ reading: going to sleep\n, currentm)。 } /* ok, data is there, return something */ if (devwp devrp) count = min(count, (size_t)(devwp devrp))。 return EFAULT。devsem)。 return count。 只有這時我們才可以測試讀緩沖(在 while 循環(huán)中)并且真正知道我們可以返回緩沖中的數據給用戶. 全部這個代碼的最終結果是, 當我們從 while 循環(huán)中退出時, 我們知道旗標被獲得并且緩沖中有數據我們可以用.僅僅為了完整, 我們要注意, scull_p_read 可以在另一個地方睡眠, 在我們獲得設備旗標之后: 對 copy_to_user 的調用. 如果 scull 當在內核和用戶空間之間拷貝數據時睡眠, 它在持有設備旗標中睡眠. 在這種情況下持有旗標是合理的因為它不能死鎖系統(我們知道內核將進行拷貝到用戶空間并且在不加鎖進程中的同一個旗標下喚醒我們), 并且因為重要的是設備內存數組在驅動睡眠時不改變.. 當然, 它們對應 2 類的睡眠. 其他的狀態(tài)正常地和驅動編寫者無關.在 內核, 對于驅動代碼通常不需要直接操作進程狀態(tài). 但是, 如果你需要這樣做, 使用的代碼是:void set_current_state(int new_state)。 如果在你忙于上面的這個過程并且有其他的線程剛剛試圖喚醒你, 如果這個條件變?yōu)檎鏁l(fā)生什么? 你可能錯過喚醒并且睡眠超過你預想的時間. 因此, 在睡眠的代碼下面, 典型地你會見到下面的代碼:if (!condition) schedule()。 linux/ 包含了所有需要的定義, 以及圍繞例子的內核源碼. 但是, 有一個更容易的方式.第一步是創(chuàng)建和初始化一個等待隊列. 這常常由這個宏定義完成:DEFINE_WAIT(my_wait)。但是常常更容易的做法是放一個 DEFINE_WAIT 行在循環(huán)的頂部, 來實現你的睡眠.下一步是添加你的等待隊列入口到隊列, 并且設置進程狀態(tài). 2 個任務都由這個函數處理:void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state)。 return ((devrp + devbuffersize devwp) % devbuffersize) 1。devsem)) return ERESTARTSYS。 /* scull_getwritespace called up(amp。 PDEBUG(Going to accept %li bytes to %p from %p\n, (long)count, devwp, buf)。 } devwp += count。 /* finally, awake any reader */ wake_up_interruptible(amp。 PDEBUG(\%s\ did write %li bytes\n,currentm, (long)count)。 up(amp。 PDEBUG(\%s\ writing: going to sleep\n,currentm)。 if (spacefree(dev) == 0) schedule()。 if (signal_pending(current)) return ERESTARTSYS。}再次注意 while 循環(huán). 如果有空間可用而不必睡眠, 這個函數簡單地返回. 否則, 它必須丟掉設備旗標并且等待. 這個代碼使用 DEFINE。devsem)) return ERESTARTSYS。devoutq, amp。devoutq, amp。 if (filpf_flags amp。}這個代碼看來和 read 方法類似, 除了我們已經將睡眠代碼放到了一個單獨的函數, 稱為 scull_getwritespace. 它的工作是確保在緩沖中有空間給新的數據, 睡眠直到有空間可用. 一旦空間在, scull_p_write 可簡單地拷貝用戶的數據到那里, 調整指針, 并且喚醒可能已經在等待讀取數據的進程.處理實際的睡眠的代碼是:/* Wait for space for writing。 /* blocked in read() and select() */ /* and signal asynchronous readers, explained late in chapter 5 */ if (devasync_queue) kill_fasync(amp。 /* wrapped */ up(amp。devsem)。 if (devwp = devrp) count = min(count, (size_t)(devend devwp))。s space to write */ result = scull_getwritespace(dev, filp)。 int result。 它應當或者是 TASK_INTERRUPTIBLE(給可中斷的睡眠, 這常常是你所要的)或者 TASK_UNINTERRUPTIBLE(給不可中斷睡眠).在調用 prepare_to_wait 之后, 進程可調用 schedule 在它已檢查確認它仍然需要等待之后. 一旦 schedule 返回, 就到了清理時間. 這個任務, 也, 被一個特殊的函數處理:void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait)。init_wait(amp。 那個函數不會返回直到進程處于可運行態(tài). 如果由于不再需要睡眠而對 schedule 的調用被跳過, 進程狀態(tài)將不正確. 還有必要從等待隊列中去除這個進程, 否則它可能被多次喚醒.. 但是象這樣直接改變 current 是不鼓勵的。一個進程如何睡眠如果我們深入 linux/, 你見到在 wait_queue_head_t 類型后面的數據結構是非常簡單的。 如果我們要持有它而睡眠, 就不會有寫者有機會喚醒我們. 一旦這個確保被丟掉, 我們做一個快速檢查來看是否用戶已請求非阻塞 I/O, 并且如果是這樣就返回. 否則, 是時間調用 wait_event_interruptible.一旦我們過了這個調用, 某些東東已經喚醒了我們, 但是我們不知道是什么. 一個可能是進程接收到了一個信號. 包含 wait_event_interruptible 調用的這個 if 語句檢查這種情況. 這個語句保證了正確的和被期望的對信號的反應, 它可能負責喚醒這個進程(因為我們處于一個可中斷的睡眠). 如果一個信號已經到達并且它沒有被這個進程阻塞, 正確的做法是讓內核的上層處理這個事件. 到此, 這個驅動返回 ERESTARTSYS 到調用者。devoutq)。 if (devrp == devend) devrp = devbuffer。 if (copy_to_user(buf, devrp, count)) {
點擊復制文檔內容
公司管理相關推薦
文庫吧 www.dybbs8.com
備案圖鄂ICP備17016276號-1