Linux-休眠与唤醒

Linux-休眠与唤醒

前言

当应用程序必须等待某个时间发生,比如必须等待按键被按下时,可以使用“休眠-唤醒”机制,这一机制近似于,你是个早起困难户,想要早起,必须等待闹钟响了,才会起床。

提示:以下是本篇文章正文内容,下面案例可供参考

一、“休眠-唤醒”机制

当应用程序调用read等函数读取数据时->应用程序进入内核驱动,调用驱动中对应的函数,若有数据则复制到应用空间,并且立刻返回->但是若没有数据,应用程序就会进入休眠->当有数据的时候,即按下按键,驱动程序中的中断服务函数就会被调用,在这个函数中,会记录数据,同时唤醒应用程序->唤醒应用程序之后,应用程序继续运行内核中对应的代码,也就是驱动中对应的函数,将数据复制到应用空间,并且立刻返回。

二、重要的函数及其数据结构

wait内核函数

休眠,直到 condition 为真;休眠期间是可被打断的,可以被信号打断

wait_event_interruptible(wq, condition)

参数1:等待队列,休眠的时候,会将进程/线程放入等待队列中,中断服务程序会从 wq 中把它取出来唤醒。

参数2:一直等待,直到 condition为真

休眠,直到 condition 为真;退出的唯一条件是 condition 为真,信号也不好使

wait_event(wq, condition)

休眠,直到 condition 为真或超时;休眠期间是可被打断的,可以被信号打断

wait_event_interruptible_timeout(wq,condition, timeout)

休眠,直到 condition 为真;退出的唯一条件是 condition 为真,信号也不好使

wait_event_timeout(wq, condition,

timeout)

唤醒函数

唤醒 x 队列中状态为“ TASK_INTERRUPTIBLE”的线程,只唤

醒其中的一个线程

wake_up_interruptible(x)

唤醒 x 队列中状态为“ TASK_INTERRUPTIBLE”的线程,只唤

醒其中的 nr 个线程

wake_up_interruptible_nr(x, nr)

唤 醒 x 队 列 中 状 态 为 “ TASK_INTERRUPTIBLE ” 或

“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中的一个线程

wake_up(x)

唤醒 x 队列中状态为“ TASK_INTERRUPTIBLE”的线程,唤醒

其中的所有线程

wake_up_interruptible_all(x)

唤 醒 x 队 列 中 状 态 为 “ TASK_INTERRUPTIBLE ” 或

“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中 nr 个线程

wake_up_interruptible_all(x)

唤 醒 x 队 列 中 状 态 为 “ TASK_INTERRUPTIBLE ” 或

“TASK_UNINTERRUPTIBLE”的线程,唤醒其中的所有线程

wake_up_all(x)

三.驱动编程步骤

1.初始化等待队列wq

2.read函数中调用wait_event_interruptible

它本身会判断 event 是否为 FALSE,如果为 FASLE 表示无数据,则休眠。

当从 wait_event_interruptible 返回后,把数据复制回用户空间。

3.在中断服务程序里:

设置 event 为 TRUE,并调用 wake_up_interruptible 唤醒线程。

附录(源码)

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

struct gpio_key {

int gpio;

struct gpio_desc *gpiod;

int flag;

int irq;

};

static struct gpio_key *gpio_key_imx6ull;

/*

*创建设备号需要的一些参数

*/

static int major = 0;//主设备号

static struct class *cls;//类

static struct device *dev;//设备

/* 创建环形缓冲区

*用于保存数据,防止数据丢失

*/

#define BUF_LEN 128

static int g_keys[BUF_LEN];//环形缓冲区的大小

static int r, w;

#define NEXT_POS(x) ((x+1) % BUF_LEN)//指向缓冲区的下一位

//队列为空

static int is_key_buf_empty(void)

{

return (r == w);

}

//队列满

static int is_key_buf_full(void)

{

return (r == NEXT_POS(w));

}

//入队列write

static void put_key(int key)

{

if (!is_key_buf_full())

{

g_keys[w] = key;

w = NEXT_POS(w);

}

}

//出队列read

static int get_key(void)

{

int key = 0;

if (!is_key_buf_empty())

{

key = g_keys[r];

r = NEXT_POS(r);

}

return key;

}

//定义gpio_key_wait等待队列,并初始化

static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);

//中断服务1程序,用于唤醒队列

static irqreturn_t gpio_key_isr(int irq, void *dev_id)

{

struct gpio_key *gpio_key = dev_id;

int val;

int key;

val = gpiod_get_value(gpio_key->gpiod);

printk("key %d %d\n", gpio_key->gpio, val);

key = (gpio_key->gpio << 8) | val;

put_key(key);

wake_up_interruptible(&gpio_key_wait);//唤醒等待队列

return IRQ_HANDLED;

}

static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)

{

int err;

int key;

//如果!is_key_buf_empty()为假,则休眠,否则就是有数据

wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());

key = get_key();

err = copy_to_user(buf, &key, 4);

return 4;

}

static struct file_operations gpio_key_drv = {

.owner = THIS_MODULE,

.read = gpio_key_drv_read,

};

//设备匹配成功后执行

static int gpio_key_drv_probe(struct platform_device *pdev)

{

int count;

int i;

int err;

int ret;

struct device_node *node = pdev->dev.of_node;

enum of_gpio_flags flag;

//创建设备号

major = register_chrdev(0, "gpio_key", &gpio_key_drv);

//创建类

cls = class_create(THIS_MODULE, "gpio_key_class");

if(IS_ERR(cls)){

printk("class_create failed\n");

ret = PTR_ERR(cls);

goto err_0;

}

//创建设备

dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "gpio_key"); /* /dev/100ask_gpio_key */

if (IS_ERR(dev)) {

printk( "device_create failed\n");

ret = PTR_ERR(dev);

goto err_1;

}

count = of_gpio_count(node);

if (!count)

{

printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);

return -1;

}

//获取设备树中的信息

gpio_key_imx6ull = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);

for (i = 0; i < count; i++)

{

gpio_key_imx6ull[i].gpio = of_get_gpio_flags(node, i, &flag);

if (gpio_key_imx6ull[i].gpio < 0)

{

printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);

return -1;

}

gpio_key_imx6ull[i].gpiod = gpio_to_desc(gpio_key_imx6ull[i].gpio);

gpio_key_imx6ull[i].flag = flag & OF_GPIO_ACTIVE_LOW;

gpio_key_imx6ull[i].irq = gpio_to_irq(gpio_key_imx6ull[i].gpio);

}

for (i = 0; i < count; i++)

{

err = request_irq(gpio_key_imx6ull[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_key_imx6ull[i]);

}

return 0;

err_0:

unregister_chrdev(major, "gpio_key");

return ret;

err_1:

class_destroy(cls);

return ret;

}

static int gpio_key_drv_remove(struct platform_device *pdev)

{

int count;

int i;

struct device_node *node = pdev->dev.of_node;

count = of_gpio_count(node);

for (i = 0; i < count; i++)

{

free_irq(gpio_key_imx6ull[i].irq, &gpio_key_imx6ull[i]);

}

kfree(gpio_key_imx6ull);

return 0;

device_destroy(cls, MKDEV(major, 0));

class_destroy(cls);

unregister_chrdev(major, "gpio_key");

}

//匹配列表

static const struct of_device_id gpio_key_device[] = {

{ .compatible = "atkalpha-key" },

{ },

};

//platform驱动结构体

static struct platform_driver gpio_key_driver = {

.probe = gpio_key_drv_probe,

.remove = gpio_key_drv_remove,

.driver = {

.name = "imx6ull_gpio_key",//驱动名字,用于和设备匹配

.of_match_table = gpio_key_device,//设备树匹配

},

};

static int __init gpio_key_drv_init(void)

{

printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

return platform_driver_register(&gpio_key_driver);

}

static void __exit gpio_key_drv_exit(void)

{

platform_driver_unregister(&gpio_key_driver);

}

module_init(gpio_key_drv_init);

module_exit(gpio_key_drv_exit);

MODULE_LICENSE("GPL");

相关数据

网上处理违章用什么软件哪个好时间:2020-01-07
365bet体育投注网

网上处理违章用什么软件哪个好时间:2020-01-07

⌚ 07-27 👁️‍🗨️ 7121
血气唤醒徽章提升大吗
365bet体育投注网

血气唤醒徽章提升大吗

⌚ 06-29 👁️‍🗨️ 2347
上厕所腿麻了怎么快速恢复
365bet体育比分直播

上厕所腿麻了怎么快速恢复

⌚ 01-20 👁️‍🗨️ 9378