日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 手动睡眠

發(fā)布時間:2023/12/20 linux 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 手动睡眠 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在 Linux 內(nèi)核的之前的版本, 正式的睡眠要求程序員手動處理所有上面的步驟. 它是一 個繁瑣的過程, 包含相當(dāng)多的易出錯的樣板式的代碼. 程序員如果愿意還是可能用那種方 式手動睡眠; <linux/sched.h> 包含了所有需要的定義, 以及圍繞例子的內(nèi)核源碼. 但是, 有一個更容易的方式.

?

第一步是創(chuàng)建和初始化一個等待隊列. 這常常由這個宏定義完成: DEFINE_WAIT(my_wait);

其中, name 是等待隊列入口項的名子. 你可用 2 步來做:

?

wait_queue_t my_wait; init_wait(&my_wait);

?

但是常常更容易的做法是放一個 DEFINE_WAIT 行在循環(huán)的頂部, 來實現(xiàn)你的睡眠. 下一步是添加你的等待隊列入口到隊列, 并且設(shè)置進程狀態(tài). 2 個任務(wù)都由這個函數(shù)處理: void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);

這里, queue 和 wait 分別地是等待隊列頭和進程入口. state 是進程的新狀態(tài); 它應(yīng)當(dāng) 或者是 TASK_INTERRUPTIBLE(給可中斷的睡眠, 這常常是你所要的)或者 TASK_UNINTERRUPTIBLE(給不可中斷睡眠).

?

在調(diào)用 prepare_to_wait 之后, 進程可調(diào)用 schedule -- 在它已檢查確認(rèn)它仍然需要等 待之后. 一旦 schedule 返回, 就到了清理時間. 這個任務(wù), 也, 被一個特殊的函數(shù)處理:

?

void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait); 之后, 你的代碼可測試它的狀態(tài)并且看是否它需要再次等待.

我們早該需要一個例子了. 之前我們看了 給 scullpipe 的 read 方法, 它使用 wait_event. 同一個驅(qū)動中的 write 方法使用 prepare_to_wait 和 finish_wait 來實 現(xiàn)它的等待. 正常地, 你不會在一個驅(qū)動中象這樣混用各種方法, 但是我們這樣作是為了 能夠展示 2 種處理睡眠的方式.

?

為完整起見, 首先, 我們看 write 方法本身:

?

/* How much space is free? */

?

?

static int spacefree(struct scull_pipe *dev)

{

?

if (dev->rp == dev->wp)

return dev->buffersize - 1;

return ((dev->rp + dev->buffersize - dev->wp) % dev->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->private_data; int result;

if (down_interruptible(&dev->sem)) return -ERESTARTSYS;

?

/* Make sure there's space to write */ result = scull_getwritespace(dev, filp); if (result)

return result; /* scull_getwritespace called up(&dev->sem) */

/* ok, space is there, accept something */ count = min(count, (size_t)spacefree(dev)); if (dev->wp >= dev->rp)

count = min(count, (size_t)(dev->end - dev->wp)); /* to end-

of-buf */

else /* the write pointer has wrapped, fill up to rp-1 */ count = min(count, (size_t)(dev->rp - dev->wp - 1));

PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev-

>wp, buf);

if (copy_from_user(dev->wp, buf, count))

{

up (&dev->sem); return -EFAULT;

}

dev->wp += count;

if (dev->wp == dev->end)

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

?

/* finally, awake any reader */

wake_up_interruptible(&dev->inq); /* blocked in read() and select() */

?

/* and signal asynchronous readers, explained late in chapter 5 */ if (dev->async_queue)

?

?

kill_fasync(&dev->async_queue, SIGIO, POLL_IN); PDEBUG("\"%s\" did write %li bytes\n",current->comm, (long)count); return count;

}

?

這個代碼看來和 read 方法類似, 除了我們已經(jīng)將睡眠代碼放到了一個單獨的函數(shù), 稱為 scull_getwritespace. 它的工作是確保在緩沖中有空間給新的數(shù)據(jù), 睡眠直到有空間可 用. 一旦空間在, scull_p_write 可簡單地拷貝用戶的數(shù)據(jù)到那里, 調(diào)整指針, 并且喚醒 可能已經(jīng)在等待讀取數(shù)據(jù)的進程.

?

處理實際的睡眠的代碼是:

?

/* Wait for space for writing; caller must hold device semaphore. On

* error the semaphore will be released before returning. */

static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)

{

?

while (spacefree(dev) == 0)

{ /* full */

DEFINE_WAIT(wait);

?

up(&dev->sem);

if (filp->f_flags & O_NONBLOCK) return -EAGAIN;

?

PDEBUG("\"%s\" writing: going to sleep\n",current->comm); prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE); if (spacefree(dev) == 0)

schedule(); finish_wait(&dev->outq, &wait); if (signal_pending(current))

?

?

?

handle it */

?

?

}


return -ERESTARTSYS; /* signal: tell the fs layer to

?

if (down_interruptible(&dev->sem)) return -ERESTARTSYS;

?

return 0;

?

}

?

再次注意 while 循環(huán). 如果有空間可用而不必睡眠, 這個函數(shù)簡單地返回. 否則, 它必 須丟掉設(shè)備旗標(biāo)并且等待. 這個代碼使用 DEFINE_WAIT 來設(shè)置一個等待隊列入口并且 prepare_to_wait 來準(zhǔn)備好實際的睡眠. 接著是對緩沖的必要的檢查; 我們必須處理的情 況是在我們已經(jīng)進入 while 循環(huán)后以及在我們將自己放入等待隊列之前 (并且丟棄了旗 標(biāo)), 緩沖中有空間可用了. 沒有這個檢查, 如果讀進程能夠在那時完全清空緩沖, 我們

?

可能錯過我們能得到的唯一的喚醒并且永遠(yuǎn)睡眠. 在說服我們自己必須睡眠之后, 我們調(diào) 用 schedule.

?

值得再看看這個情況: 當(dāng)睡眠發(fā)生在 if 語句測試和調(diào)用 schedule 之間, 會發(fā)生什么? 在這個情況里, 都好. 這個喚醒重置了進程狀態(tài)為 TASK_RUNNING 并且 schedule 返回 -

- 盡管不必馬上. 只要這個測試發(fā)生在進程放置自己到等待隊列和改變它的狀態(tài)之后, 事 情都會順利.

?

為了結(jié)束, 我們調(diào)用 finish_wait. 對 signal_pending 的調(diào)用告訴我們是否我們被一個 信號喚醒; 如果是, 我們需要返回到用戶并且使它們稍后再試. 否則, 我們請求旗標(biāo), 并 且再次照常測試空閑空間.

轉(zhuǎn)載于:https://www.cnblogs.com/fanweisheng/p/11141869.html

總結(jié)

以上是生活随笔為你收集整理的linux 手动睡眠的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。