LDD3源码学习日记<六>

简单休眠实验(sleepy.c)

#include <linux/module.h>
#include <linux/init.h>

#include <linux/sched.h>  /* current and everything */
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h>     /* everything... */
#include <linux/types.h>  /* size_t */
#include <linux/wait.h>

MODULE_LICENSE("GPL");

static int sleepy_major = 0;

static DECLARE_WAIT_QUEUE_HEAD(wq);	//定义并初始化一个等待队列头
static int flag = 0;

ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
	printk(KERN_DEBUG "process %i (%s) going to sleep\n",
			current->pid, current->comm);
	wait_event_interruptible(wq, flag != 0);	//如果flag != 0条件成立,程序继续执行,否则保持休眠
	flag = 0;					//flag重新归零
	printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
	return 0; /* 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",
			current->pid, current->comm);
	flag = 1;
	wake_up_interruptible(&wq);	//执行写操作时,队列头wq所在队列的所有进程
	return count; /* succeed, to avoid retrial */
}


struct file_operations sleepy_fops = {
	.owner = THIS_MODULE,
	.read =  sleepy_read,
	.write = sleepy_write,
};


int sleepy_init(void)
{
	int result;
	result = register_chrdev(sleepy_major, "sleepy", &sleepy_fops);
	if (result < 0)
		return result;
	if (sleepy_major == 0)
		sleepy_major = result; /* dynamic */
	return 0;
}

void sleepy_cleanup(void)
{
	unregister_chrdev(sleepy_major, "sleepy");
}

module_init(sleepy_init);
module_exit(sleepy_cleanup);
代码结构很简单,file_operation要求只完成了读和写。代码的作用是,在调用read函数时,进程会进入休眠状态,在write函数里,休眠的进程将被唤醒。

为了管理休眠进程,需要建立等待队列,等待队列就是一个进程链表,其中包含等待某个特定事件的所有进程。等待队列通过“等待队列头”来管理,等待队列头是一个类型为wait_queue_head_t的结构体。可以静态初始化一个等待队列头:
DECLARE_WAIT_QUEUE_HEAD(name);
也可以动态初始化一个等待队列头:
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
一个进程要进入休眠,最常用的函数是:
wait_event_interruptible(queue, condition);
queue是等待队列头,condition是一个条件表达式,进程进入休眠前和被唤醒后,都会检查condition的值是否为真,如果不为真,则进程会进入休眠。
对应wait_event_interruptible的唤醒函数是:
wake_up_interruptible(wait_queue_head_t *queue)
下面测试一下这个小模块:

首先看他的装载和卸载脚本:

#!/bin/sh  
# $Id: complete_load,v 1.4 2004/11/03 06:19:49 rubini Exp $  
module="sleepy"  
device="sleepy"  
mode="666"  
  
# Group: since distributions do it differently, look for wheel or use staff  
if grep -q '^staff:' /etc/group; then  
    group="staff"  
else  
    group="wheel"  
fi  
  
# invoke insmod with all arguments we got  
# and use a pathname, as insmod doesn't look in . by default  
/sbin/insmod ./$module.ko $* || exit 1  
  
# retrieve major number  
major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)  
  
# Remove stale nodes and replace them, then give gid and perms  
# Usually the script is shorter, it's scull that has several devices in it.  
  
rm -f /dev/${device}  
mknod /dev/${device} c $major 0  
  
chgrp $group /dev/${device}   
chmod $mode  /dev/${device}  

#!/bin/sh  
module="sleepy"  
device="sleepy"  
  
# invoke rmmod with all arguments we got  
/sbin/rmmod $module $* || exit 1  
  
# Remove stale nodes  
  
rm -f /dev/${device}  


这个程序的测试需要用两个端口,开发板上只能支持一个,所以我把它放在了红帽子五自带的内核上运行,结果如下图:


左端的窗口用cat命令从sleepy设备读取数据时,会导致进程休眠,当在另一个窗口向/dev/sleepy中写入数据时,进程又会被唤醒。


参考博客:http://blog.csdn.net/liuhaoyutz/article/details/7388163

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值