在 Linux 内核的之前的版本, 正式的睡眠要求程序员手动处理所有上面的步骤. 它是一 个繁琐的过程, 包含相当多的易出错的样板式的代码. 程序员如果愿意还是可能用那种方 式手动睡眠; <linux/sched.h> 包含了所有需要的定义, 以及围绕例子的内核源码. 但是, 有一个更容易的方式.

第一步是创建和初始化一个等待队列. 这常常由这个宏定义完成: DEFINE_WAIT(my_wait);

其中, name 是等待队列入口项的名子. 你可用 2 步来做:

wait_queue_t my_wait; init_wait(&my_wait);

但是常常更容易的做法是放一个 DEFINE_WAIT 行在循环的顶部, 来实现你的睡眠. 下一步是添加你的等待队列入口到队列, 并且设置进程状态. 2 个任务都由这个函数处理: void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);

这里, queue 和 wait 分别地是等待队列头和进程入口. state 是进程的新状态; 它应当 或者是 TASK_INTERRUPTIBLE(给可中断的睡眠, 这常常是你所要的)或者 TASK_UNINTERRUPTIBLE(给不可中断睡眠).

在调用 prepare_to_wait 之后, 进程可调用 schedule -- 在它已检查确认它仍然需要等 待之后. 一旦 schedule 返回, 就到了清理时间. 这个任务, 也, 被一个特殊的函数处理:

void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait); 之后, 你的代码可测试它的状态并且看是否它需要再次等待.

我们早该需要一个例子了. 之前我们看了 给 scullpipe 的 read 方法, 它使用 wait_event. 同一个驱动中的 write 方法使用 prepare_to_wait 和 finish_wait 来实 现它的等待. 正常地, 你不会在一个驱动中象这样混用各种方法, 但是我们这样作是为了 能够展示 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 方法类似, 除了我们已经将睡眠代码放到了一个单独的函数, 称为 scull_getwritespace. 它的工作是确保在缓冲中有空间给新的数据, 睡眠直到有空间可 用. 一旦空间在, scull_p_write 可简单地拷贝用户的数据到那里, 调整指针, 并且唤醒 可能已经在等待读取数据的进程.

处理实际的睡眠的代码是:

/* 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 循环. 如果有空间可用而不必睡眠, 这个函数简单地返回. 否则, 它必 须丢掉设备旗标并且等待. 这个代码使用 DEFINE_WAIT 来设置一个等待队列入口并且 prepare_to_wait 来准备好实际的睡眠. 接着是对缓冲的必要的检查; 我们必须处理的情 况是在我们已经进入 while 循环后以及在我们将自己放入等待队列之前 (并且丢弃了旗 标), 缓冲中有空间可用了. 没有这个检查, 如果读进程能够在那时完全清空缓冲, 我们

可能错过我们能得到的唯一的唤醒并且永远睡眠. 在说服我们自己必须睡眠之后, 我们调 用 schedule.

值得再看看这个情况: 当睡眠发生在 if 语句测试和调用 schedule 之间, 会发生什么? 在这个情况里, 都好. 这个唤醒重置了进程状态为 TASK_RUNNING 并且 schedule 返回 -

- 尽管不必马上. 只要这个测试发生在进程放置自己到等待队列和改变它的状态之后, 事 情都会顺利.

为了结束, 我们调用 finish_wait. 对 signal_pending 的调用告诉我们是否我们被一个 信号唤醒; 如果是, 我们需要返回到用户并且使它们稍后再试. 否则, 我们请求旗标, 并 且再次照常测试空闲空间.

转载于:https://www.cnblogs.com/fanweisheng/p/11141869.html

linux 手动睡眠相关推荐

  1. linux手动释放内存的方法

    Linux手动释放缓存的方法 Linux释放内存的命令: sync echo 1 > /proc/sys/vm/drop_caches drop_caches的值可以是0-3之间的数字,代表不同 ...

  2. Linux手动释放缓存的方法

    Linux手动释放缓存的方法 1. 错误状态 2. 解决办法 1. 错误状态 这一年为什么文章少了呢,因为开发一直没停过,开发遇到的问题经常让人头大. 比如今天遇到个问题,启动一个服务去编译文件,直接 ...

  3. Linux进程睡眠状态disk sleep

    Linux进程睡眠状态disk sleep <Linux-进程管理> 1. Linux进程状态 Running(R):运行或将要运行 Interruptible(S):被阻断而等待一个事件 ...

  4. Linux手动部署MoguBlog 博客微服务 Springalibaba

    Linux手动部署MoguBlog微服务 安装docker 使用官方安装脚本自动安装 安装命令如下: curl -fsSL https://get.docker.com | bash -s docke ...

  5. Linux内核睡眠唤醒调试

    本文基于RockPI 4A单板Debian系统Linux4.4内核介绍下睡眠唤醒(suspend/resume)的一些调试方法. 一.参数设置 1.关闭串口睡眠 在Linux内核睡眠过程中,会先调用s ...

  6. 腾讯云服务器CVM(CentOS 7、Tencent Linux)手动搭建LNMP环境(linux+Nginx+Mariadb+PHP)

    手动搭建云服务器运行环境就是喜欢折腾,如果觉得麻烦的网友可以使用LNMP镜像直接启动CVM实例,以便快速建站. 腾讯云服务器CVM(CentOS 7.Tencent Linux)手动搭建LNMP环境( ...

  7. 清理linux服务器缓存,详解Linux手动释放缓存的方法

    详解Linux手动释放缓存的方法 发布时间:2020-08-20 07:53:27 来源:脚本之家 阅读:87 作者:闪电王国 栏目:服务器 Linux释放内存的命令: sync echo 1 > ...

  8. linux 手动释放内存

    当在Linux下 频繁存取文件 或者 程序测试频繁崩溃后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching 因此我们很有必要手动清理系统缓存释放内存. 我们在清理缓存 ...

  9. linux 手动添加 swap 分区

    为什么需要swap 根据Redhat公司的建议,Linux系统swap分区最适合的大小是物理内存的1-2倍.不过Linux上有些软件对swap分区得需求较大,例如要顺利执行Oracle数据库软件,sw ...

最新文章

  1. CKEditor的安装与基本使用
  2. python3环境下 tensorflow环境中经常遇到'*' has type str, but expected one of: bytes问题的解决
  3. mysql数据库的常用操作-索引
  4. cocos2d-x 2.x版本使用uiwidget需要注意的几点
  5. Qt中的QFormLayout
  6. C语言实例第3期:在控制台打印出著名的杨辉三角
  7. 【正视CSS 06】构建我们自己的世界观!
  8. symantec antivirus 10.0服务器通讯问题
  9. Win11系统语言修改不了中文怎么办
  10. 文件上传限制文件类型
  11. python paramiko并发_Python之paramiko
  12. asp.net服务器控件开发-学习之路(一)
  13. 关于几款系统恢复常用工具的用法介绍
  14. [计算机网络]RJ45直通线和交叉线的连接方式和设备类型解析
  15. HTML文本框不能复制粘贴,word文本框无法复制粘贴
  16. ardupilot 关于设备车Rover的学习《3》------模式控制
  17. 选择器的权重中对交集选择器,分组(并集)选择器,以及关系选择器的理解
  18. 【Flink】Flink SQL 读取 CSV 文件
  19. C语言中删除重复字母,删除C ++中的重复字母
  20. 拒酒词,社交必备!!!

热门文章

  1. 关于mysql优化之个人见解
  2. 基于OSSIM的漏洞***测试视频教程
  3. 结对项目 - 词频统计
  4. DIOCP 运作核心探密
  5. OC类导入Swift工程演示
  6. JVM空间申请流程图
  7. 静态库和动态库(转)
  8. intellij中重命名一个文件
  9. opencv书籍调研
  10. Running /usr/bin/wineserver -w. This will hang until all wine processes XXXX terminate