亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? ch06s02.html

?? 驅動程序在 Linux 內核里扮演著特殊的角色. 它們是截然不同的"黑盒子", 使硬件的特殊的一部分響應定義好的內部編程接口. 它們完全隱藏了設備工作的細節. 用戶的活動通過一套標準化的調用來進行,
?? HTML
?? 第 1 頁 / 共 3 頁
字號:
        { /* nothing to read */
                up(&dev->sem); /* release the lock */
                if (filp->f_flags & O_NONBLOCK)

                        return -EAGAIN;
                PDEBUG("\"%s\" reading: going to sleep\n", current->comm);
                if (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 (down_interruptible(&dev->sem))
                        return -ERESTARTSYS;
        }
        /* ok, data is there, return something */

        if (dev->wp > dev->rp)
                count = min(count, (size_t)(dev->wp - dev->rp));
        else /* the write pointer has wrapped, return data up to dev->end */
                count = min(count, (size_t)(dev->end - dev->rp));
        if (copy_to_user(buf, dev->rp, count))
        {
                up (&dev->sem);
                return -EFAULT;
        }
        dev->rp += count;
        if (dev->rp == dev->end)

                dev->rp = dev->buffer; /* wrapped */
        up (&dev->sem);

        /* finally, awake any writers and return */
        wake_up_interruptible(&dev->outq);
        PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count);
        return count;
}
</pre>
<p>如同你可見的, 我們在代碼中留有一些 PDEBUG 語句. 當你編譯這個驅動, 你可使能消息機制來易于跟隨不同進程間的交互.</p>
<p>讓我們仔細看看 scull_p_read 如何處理對數據的等待. 這個 while 循環在持有設備旗標下測試這個緩沖. 如果有數據在那里, 我們知道我們可立刻返回給用戶, 不必睡眠, 因此整個循環被跳過. 相反, 如果這個緩沖是空的, 我們必須睡眠. 但是在我們可做這個之前, 我們必須丟掉設備旗標; 如果我們要持有它而睡眠, 就不會有寫者有機會喚醒我們. 一旦這個確保被丟掉, 我們做一個快速檢查來看是否用戶已請求非阻塞 I/O, 并且如果是這樣就返回. 否則, 是時間調用 wait_event_interruptible.</p>
<p>一旦我們過了這個調用, 某些東東已經喚醒了我們, 但是我們不知道是什么. 一個可能是進程接收到了一個信號. 包含 wait_event_interruptible 調用的這個 if 語句檢查這種情況. 這個語句保證了正確的和被期望的對信號的反應, 它可能負責喚醒這個進程(因為我們處于一個可中斷的睡眠). 如果一個信號已經到達并且它沒有被這個進程阻塞, 正確的做法是讓內核的上層處理這個事件. 到此, 這個驅動返回 -ERESTARTSYS 到調用者; 這個值被虛擬文件系統(VFS)在內部使用, 它或者重啟系統調用或者返回 -EINTR 給用戶空間. 我們使用相同類型的檢查來處理信號, 給每個讀和寫實現.</p>
<p>但是, 即便沒有一個信號, 我們還是不確切知道有數據在那里為獲取. 其他人也可能已經在等待數據, 并且它們可能贏得競爭并且首先得到數據. 因此我們必須再次獲取設備旗標; 只有這時我們才可以測試讀緩沖(在 while 循環中)并且真正知道我們可以返回緩沖中的數據給用戶. 全部這個代碼的最終結果是, 當我們從 while 循環中退出時, 我們知道旗標被獲得并且緩沖中有數據我們可以用.</p>
<p>僅僅為了完整, 我們要注意, scull_p_read 可以在另一個地方睡眠, 在我們獲得設備旗標之后: 對 copy_to_user 的調用. 如果 scull 當在內核和用戶空間之間拷貝數據時睡眠, 它在持有設備旗標中睡眠. 在這種情況下持有旗標是合理的因為它不能死鎖系統(我們知道內核將進行拷貝到用戶空間并且在不加鎖進程中的同一個旗標下喚醒我們), 并且因為重要的是設備內存數組在驅動睡眠時不改變.</p>
</div>
<div class="sect2" lang="zh-cn">
<div class="titlepage"><div><div><h3 class="title">
<a name="AdvancedSleeping.sect2"></a>6.2.5.&#160;高級睡眠</h3></div></div></div>
<p>許多驅動能夠滿足它們的睡眠要求, 使用至今我們已涉及到的函數. 但是, 有時需要深入理解 Linux 等待隊列機制如何工作. 復雜的加鎖或者性能需要可強制一個驅動來使用低層函數來影響一個睡眠. 在本節, 我們在低層看而理解在一個進程睡眠時發生了什么.</p>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="Howaprocesssleeps.sect3"></a>6.2.5.1.&#160;一個進程如何睡眠</h4></div></div></div>
<p>如果我們深入 &lt;linux/wait.h&gt;, 你見到在 wait_queue_head_t 類型后面的數據結構是非常簡單的; 它包含一個自旋鎖和一個鏈表. 這個鏈表是一個等待隊列入口, 它被聲明做 wait_queue_t. 這個結構包含關于睡眠進程的信息和它想怎樣被喚醒.</p>
<p>使一個進程睡眠的第一步常常是分配和初始化一個 wait_queue_t 結構, 隨后將其添加到正確的等待隊列. 當所有東西都就位了, 負責喚醒工作的人就可以找到正確的進程.</p>
<p>下一步是設置進程的狀態來標志它為睡眠. 在 &lt;linux/sched.h&gt; 中定義有幾個任務狀態. TASK_RUNNING 意思是進程能夠運行, 盡管不必在任何特定的時刻在處理器上運行. 有 2 個狀態指示一個進程是在睡眠: TASK_INTERRUPTIBLE 和 TASK_UNTINTERRUPTIBLE; 當然, 它們對應 2 類的睡眠. 其他的狀態正常地和驅動編寫者無關.</p>
<p>在 2.6 內核, 對于驅動代碼通常不需要直接操作進程狀態. 但是, 如果你需要這樣做, 使用的代碼是:</p>
<pre class="programlisting">
void set_current_state(int new_state); 
</pre>
<p>在老的代碼中, 你常常見到如此的東西:</p>
<pre class="programlisting">
current-&gt;state = TASK_INTERRUPTIBLE; 
</pre>
<p>但是象這樣直接改變 current 是不鼓勵的; 當數據結構改變時這樣的代碼會輕易地失效. 但是, 上面的代碼確實展示了自己改變一個進程的當前狀態不能使其睡眠. 通過改變 current 狀態, 你已改變了調度器對待進程的方式, 但是你還未讓出處理器.</p>
<p>放棄處理器是最后一步, 但是要首先做一件事: 你必須先檢查你在睡眠的條件. 做這個檢查失敗會引入一個競爭條件; 如果在你忙于上面的這個過程并且有其他的線程剛剛試圖喚醒你, 如果這個條件變為真會發生什么? 你可能錯過喚醒并且睡眠超過你預想的時間. 因此, 在睡眠的代碼下面, 典型地你會見到下面的代碼:</p>
<pre class="programlisting">
if (!condition)
    schedule();
</pre>
<p>通過在設置了進程狀態后檢查我們的條件, 我們涵蓋了所有的可能的事件進展. 如果我們在等待的條件已經在設置進程狀態之前到來, 我們在這個檢查中注意到并且不真正地睡眠. 如果之后發生了喚醒, 進程被置為可運行的不管是否我們已真正進入睡眠.</p>
<p>調用 schedule , 當然, 是引用調度器和讓出 CPU 的方式. 無論何時你調用這個函數, 你是在告訴內核來考慮應當運行哪個進程并且轉換控制到那個進程, 如果必要. 因此你從不知道在 schedule 返回到你的代碼會是多長時間.</p>
<p>在 if 測試和可能的調用 schedule (并從其返回)之后, 有些清理工作要做. 因為這個代碼不再想睡眠, 它必須保證任務狀態被重置為 TASK_RUNNING. 如果代碼只是從 schedule 返回, 這一步是不必要的; 那個函數不會返回直到進程處于可運行態. 如果由于不再需要睡眠而對 schedule 的調用被跳過, 進程狀態將不正確. 還有必要從等待隊列中去除這個進程, 否則它可能被多次喚醒.</p>
</div>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="Manualsleeps.sect3"></a>6.2.5.2.&#160;手動睡眠</h4></div></div></div>
<p>在 Linux 內核的之前的版本, 正式的睡眠要求程序員手動處理所有上面的步驟. 它是一個繁瑣的過程, 包含相當多的易出錯的樣板式的代碼. 程序員如果愿意還是可能用那種方式手動睡眠; &lt;linux/sched.h&gt; 包含了所有需要的定義, 以及圍繞例子的內核源碼. 但是, 有一個更容易的方式.</p>
<p>第一步是創建和初始化一個等待隊列. 這常常由這個宏定義完成:</p>
<pre class="programlisting">
DEFINE_WAIT(my_wait); 
</pre>
<p>其中, name 是等待隊列入口項的名子. 你可用 2 步來做:</p>
<pre class="programlisting">
wait_queue_t my_wait;
init_wait(&amp;my_wait);
</pre>
<p>但是常常更容易的做法是放一個 DEFINE_WAIT 行在循環的頂部, 來實現你的睡眠.</p>
<p>下一步是添加你的等待隊列入口到隊列, 并且設置進程狀態. 2 個任務都由這個函數處理:</p>
<pre class="programlisting">
void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state); 
</pre>
<p>這里, queue 和 wait 分別地是等待隊列頭和進程入口. state 是進程的新狀態; 它應當或者是 TASK_INTERRUPTIBLE(給可中斷的睡眠, 這常常是你所要的)或者 TASK_UNINTERRUPTIBLE(給不可中斷睡眠).</p>
<p>在調用 prepare_to_wait 之后, 進程可調用 schedule -- 在它已檢查確認它仍然需要等待之后. 一旦 schedule 返回, 就到了清理時間. 這個任務, 也, 被一個特殊的函數處理:</p>
<pre class="programlisting">
void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait); 
</pre>
<p>之后, 你的代碼可測試它的狀態并且看是否它需要再次等待.</p>
<p>我們早該需要一個例子了. 之前我們看了 給 scullpipe 的 read 方法, 它使用 wait_event. 同一個驅動中的 write 方法使用 prepare_to_wait 和 finish_wait 來實現它的等待. 正常地, 你不會在一個驅動中象這樣混用各種方法, 但是我們這樣作是為了能夠展示 2 種處理睡眠的方式.</p>
<p>為完整起見, 首先, 我們看 write 方法本身:</p>
<pre class="programlisting">
/* How much space is free? */
static int spacefree(struct scull_pipe *dev)
{

        if (dev-&gt;rp == dev-&gt;wp)
                return dev-&gt;buffersize - 1;
        return ((dev-&gt;rp + dev-&gt;buffersize - dev-&gt;wp) % dev-&gt;buffersize) - 1;
}

static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,
                             loff_t *f_pos)
{

        struct scull_pipe *dev = filp-&gt;private_data;
        int result;
        if (down_interruptible(&amp;dev-&gt;sem))
                return -ERESTARTSYS;

        /* Make sure there's space to write */
        result = scull_getwritespace(dev, filp);
        if (result)
                return result; /* scull_getwritespace called up(&amp;dev-&gt;sem) */
        /* ok, space is there, accept something */
        count = min(count, (size_t)spacefree(dev));
        if (dev-&gt;wp &gt;= dev-&gt;rp)
                count = min(count, (size_t)(dev-&gt;end - dev-&gt;wp)); /* to end-of-buf */
        else /* the write pointer has wrapped, fill up to rp-1 */
                count = min(count, (size_t)(dev-&gt;rp - dev-&gt;wp - 1));
        PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev-&gt;wp, buf);
        if (copy_from_user(dev-&gt;wp, buf, count))
        {
                up (&amp;dev-&gt;sem);
                return -EFAULT;
        }
        dev-&gt;wp += count;
        if (dev-&gt;wp == dev-&gt;end)
                dev-&gt;wp = dev-&gt;buffer; /* wrapped */
        up(&amp;dev-&gt;sem);

        /* finally, awake any reader */
        wake_up_interruptible(&amp;dev-&gt;inq); /* blocked in read() and select() */

        /* and signal asynchronous readers, explained late in chapter 5 */
        if (dev-&gt;async_queue)
                kill_fasync(&amp;dev-&gt;async_queue, SIGIO, POLL_IN);
        PDEBUG("\"%s\" did write %li bytes\n",current-&gt;comm, (long)count);
        return count;
}

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
在线免费不卡电影| 欧美高清dvd| 欧美日本精品一区二区三区| 337p粉嫩大胆色噜噜噜噜亚洲| 国产午夜精品一区二区三区嫩草 | 日本美女一区二区| av不卡免费在线观看| 欧美一级爆毛片| 亚洲男人的天堂在线aⅴ视频| 免费成人在线观看视频| 99精品视频一区二区| 精品国产一区二区国模嫣然| 中文字幕在线一区免费| 久久成人免费电影| 欧美日韩亚洲不卡| 亚洲欧美色图小说| 国产99精品在线观看| 欧美大度的电影原声| 亚洲午夜三级在线| 99久久婷婷国产综合精品电影| 欧美成人video| 天堂蜜桃一区二区三区| 91国偷自产一区二区三区观看| 久久久噜噜噜久噜久久综合| 日韩高清不卡一区二区三区| 色噜噜久久综合| 中文字幕视频一区| 国产69精品久久777的优势| 欧美成人精品福利| 蜜桃视频在线观看一区| 欧美日韩国产片| 亚洲福中文字幕伊人影院| 色综合久久综合中文综合网| 国产精品成人午夜| 成人在线一区二区三区| 国产亚洲精久久久久久| 国产精品99久久久久久有的能看 | 91黄色免费看| 自拍偷拍欧美激情| 99视频热这里只有精品免费| 久久亚洲欧美国产精品乐播| 久久成人麻豆午夜电影| 亚洲精品一区二区三区影院| 久久国产欧美日韩精品| 精品欧美乱码久久久久久| 久久99在线观看| 日韩免费性生活视频播放| 久久99久久久久久久久久久| 日韩精品一区二区三区swag| 国产一区在线精品| 国产精品欧美久久久久无广告| 不卡视频在线观看| 玉米视频成人免费看| 精品视频一区二区不卡| 日韩成人一区二区| 欧美精品一区二区精品网| 国产精品一区二区在线播放 | 精品久久久三级丝袜| 国产九色sp调教91| 1区2区3区精品视频| 在线观看欧美精品| 蜜桃av一区二区三区电影| 精品噜噜噜噜久久久久久久久试看 | 夫妻av一区二区| 亚洲欧美一区二区三区久本道91| 欧美吞精做爰啪啪高潮| 久久精品久久99精品久久| 国产亚洲综合在线| 91国产免费观看| 青青草原综合久久大伊人精品优势 | 国产日韩欧美综合一区| a级精品国产片在线观看| 亚洲午夜在线视频| 精品久久人人做人人爰| av中文字幕在线不卡| 日韩精品91亚洲二区在线观看| 久久精品免视看| 67194成人在线观看| 成人a免费在线看| 蜜芽一区二区三区| 亚洲三级视频在线观看| 日韩免费看的电影| 日本道色综合久久| 国产大片一区二区| 日韩电影免费一区| 一区二区三区四区不卡在线| 国产亚洲精品久| 欧美一区二区三区在| 91亚洲大成网污www| 国产一区二区三区免费在线观看 | 麻豆国产精品官网| 亚洲乱码国产乱码精品精可以看 | 99re6这里只有精品视频在线观看 99re8在线精品视频免费播放 | 欧美日韩国产综合一区二区| 午夜精品久久久久久久99樱桃| 精品国产1区2区3区| 一本久久a久久精品亚洲| 麻豆精品新av中文字幕| ●精品国产综合乱码久久久久| 欧美另类久久久品| 丁香婷婷深情五月亚洲| 久久狠狠亚洲综合| 午夜久久电影网| 国产精品网站在线| 7799精品视频| 99国产精品久久久久| 精久久久久久久久久久| 国产精品色呦呦| 国产夜色精品一区二区av| 欧美性大战久久| 成人夜色视频网站在线观看| 蜜桃一区二区三区四区| 亚洲一区二区精品久久av| 国产欧美精品国产国产专区| 精品久久久久av影院| 欧美视频在线一区二区三区 | 精品日本一线二线三线不卡 | 国产成人亚洲精品狼色在线| 亚洲18色成人| 亚洲精品一二三| 日本一二三四高清不卡| 欧美另类变人与禽xxxxx| 欧美日韩黄视频| 欧美色视频在线观看| 91在线丨porny丨国产| 国产福利精品一区| 久久99国产精品久久99果冻传媒| 亚洲成人免费视| 美女视频黄久久| 免费不卡在线观看| 日本欧美一区二区| 日韩精品91亚洲二区在线观看| 亚洲一区二区三区中文字幕| 亚洲欧美另类图片小说| 亚洲香肠在线观看| 五月天网站亚洲| 亚洲一区二区在线播放相泽| 一区二区三区免费网站| 亚洲欧美日韩中文字幕一区二区三区 | 91麻豆免费观看| 欧美午夜不卡在线观看免费| 欧美主播一区二区三区美女| 91久久精品日日躁夜夜躁欧美| 91久久精品一区二区三区| 欧日韩精品视频| 精品视频1区2区3区| 国内成人精品2018免费看| 成人黄页毛片网站| 97aⅴ精品视频一二三区| 成人教育av在线| 91美女视频网站| 欧美日韩精品久久久| 日韩一区二区三区免费观看| 久久综合丝袜日本网| 欧美韩国日本一区| 天堂在线一区二区| 国产中文一区二区三区| 国产电影一区在线| 色综合久久66| 91精品欧美福利在线观看| 91精品国产色综合久久不卡电影 | 色国产精品一区在线观看| 在线精品视频免费播放| 91精品免费在线| 久久久蜜桃精品| 亚洲激情成人在线| 日韩有码一区二区三区| 国产九色精品成人porny| 欧美人狂配大交3d怪物一区| 欧美不卡123| 亚洲欧美日韩国产成人精品影院| 午夜欧美大尺度福利影院在线看| 久久99国产精品成人| 成人免费视频播放| 日韩欧美在线一区二区三区| 欧美激情一区三区| 香蕉加勒比综合久久| 久久99热国产| 欧美在线视频你懂得| 欧美丰满美乳xxx高潮www| 中文字幕日本不卡| 日韩电影在线一区| 岛国av在线一区| 制服丝袜中文字幕一区| 中文字幕欧美日韩一区| 国产精品久久免费看| 国产真实乱对白精彩久久| 色综合天天综合给合国产| 精品欧美乱码久久久久久1区2区 | 久久蜜臀中文字幕| 亚洲色图.com| 99re成人在线| 久久久国产精品不卡| 日韩高清欧美激情| 色88888久久久久久影院按摩| 91精品国产91久久久久久一区二区 | 欧美国产欧美亚州国产日韩mv天天看完整| 亚洲国产三级在线| 99精品欧美一区二区三区小说| 精品成人一区二区三区|