17.completion机制

目录

completion:完成量

completion结构体

初始化

初始化完成量:init_completion()

静态定义并初始化

完成量休眠

wait_for_completion()函数

wait_for_completion_timeout()函数

wait_for_completion_interruptible()函数

完成量唤醒

complete()函数

complete_all()函数

实验环节

dts_led.c文件

app.c文件

Makefile文件

执行过程


completion:完成量

完成量用于进程 / 线程同步,与信号量 / 互斥量类似。

信号量 / 互斥量:资源对所有进程 / 线程是公平的,按先来后到顺序使用

完成量:一个线程的运行依赖另一个线程,那么它们使用临界资源时不再是公平的,被依赖方先使用

completion结构体

该结构体存放在内核/include/linux/completion.h文件。

struct completion {
	unsigned int done;        // 表示当前completion的状态
	wait_queue_head_t wait;   // 等待队列头
};

初始化

初始化完成量:init_completion()

// 注意x为 completion结构体指针
#define init_completion(x) __init_completion(x)

static inline void __init_completion(struct completion *x)
{
	x->done = 0;
	init_waitqueue_head(&x->wait);    // 初始化等待队列头
}

静态定义并初始化

#define DECLARE_COMPLETION(work) \
	struct completion work = COMPLETION_INITIALIZER(work)

#define COMPLETION_INITIALIZER(work) \
	{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }

完成量休眠

函数存放在内核/kernel/sched/completion.c文件。

wait_for_completion()函数

可能会使进程 / 线程一直休眠,休眠时进程 / 线程不接收中断信息。

// 完成量结构体指针
void __sched wait_for_completion(struct completion *x);

wait_for_completion_timeout()函数

限定了进程 / 线程的休眠时间,休眠时进程 / 线程不接收中断信息。

// x:完成量结构体指针
// timeout:超时时间
unsigned long __sched
wait_for_completion_timeout(struct completion *x, unsigned long timeout);

wait_for_completion_interruptible()函数

此函数引起进程 / 线程休眠时,进程 / 线程仍然能够响应外界发来的中断信号。

//  x:完成量结构体指针
int __sched wait_for_completion_interruptible(struct completion *x);

完成量唤醒

函数存放在内核/kernel/sched/completion.c文件。

complete()函数

注意:此函数只能唤醒一个进程 / 线程,之前的wait_for_completion()可以在多个进程 / 线程间休眠。

//  x:完成量结构体指针
void complete(struct completion *x);

complete_all()函数

唤醒所有在此完成量上休眠的进程 / 线程。

void complete_all(struct completion *x);

实验环节

dts_led.c文件

#include 
#include 
#include 
#include 
#include 
 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#include 
#include 
 
#include 
#include 
#include 
 
#define DEV_NAME        "rgb_led"
#define DEV_CNT         (1)
  
int rgb_led_red;
int rgb_led_green;
int rgb_led_blue;

struct completion rgb_wait;
unsigned int write_data = 0;
 
static dev_t led_devno;
static struct cdev led_chrdev;
struct class *class_led;
struct device *device;
struct device_node *rgb_led_device_node;
 
static int led_chrdev_open(struct inode *inode, struct file *filp)
{
        printk("open form driver\n");
        return 0;
}
 
static ssize_t led_chrdev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
        int ret, error;
        unsigned char receive_data[10];         //用于保存接收到的数据
 
        if(cnt > 10)    cnt = 10;
 
        error = copy_from_user(receive_data, buf, cnt);
        if(error < 0)   return -1;
 
        ret = kstrtoint(receive_data, 16, &write_data);
        if(ret)         return -1;
 
        if(write_data){
				complete_all(&rgb_wait);
                return cnt;
        }else{
				wait_for_completion(&rgb_wait);
        }
 
        /* 设置GPIO1_04输出电平 */
        if(write_data){
                gpio_set_value(rgb_led_red, 0);
        }
 
        return cnt;
}
 
static int led_chrdev_release(struct inode *inode, struct file *filp)
{
        printk(KERN_ALERT "finished!!!\n");
 
        return 0;
}
 
static struct file_operations led_chrdev_fops = {
        .owner = THIS_MODULE,
        .open = led_chrdev_open,
        .write = led_chrdev_write,
        .release = led_chrdev_release,
};
 
static int led_probe(struct platform_device *pdv)
{
        int ret = -1;   //保存错误状态码
        unsigned int register_data = 0;
 
        printk(KERN_ALERT "match successed!\n");
 
        /* 获取rgb_led的设备树节点 */
        rgb_led_device_node = of_find_node_by_path("/rgb_led");
        if(rgb_led_device_node == NULL){
                printk(KERN_ERR "get rgb_led failed!\n");
                return -1;
        }
 
        /* 获取red led GPIO 引脚号 */
        rgb_led_red = of_get_named_gpio(rgb_led_device_node, "rgb_led_red", 0);
        if(rgb_led_red < 0){
                printk(KERN_ERR "rgb_led_red failed!\n");
                return -1;
        }
 
        /* 获取green led GPIO 引脚号 */
        rgb_led_green = of_get_named_gpio(rgb_led_device_node, "rgb_led_green", 0);
        if(rgb_led_green < 0){
                printk(KERN_ERR "rgb_led_green failed!\n");
                return -1;
        }
 
                /* 获取blue led GPIO 引脚号 */
        rgb_led_blue = of_get_named_gpio(rgb_led_device_node, "rgb_led_blue", 0);
        if(rgb_led_blue < 0){
                printk(KERN_ERR "rgb_led_blue failed!\n");
                return -1;
        }
 
        /* 设置GPIO为输出模式,并默认高电平 */
        gpio_direction_output(rgb_led_red, 1);
        gpio_direction_output(rgb_led_green, 1);
        gpio_direction_output(rgb_led_blue, 1);
 
        /* 第一步
         * 采用动态分配的方式获取设备编号,次设备号为0
         * 设备名称为rgb-leds,可通过命令cat /proc/devices查看
         * DEV_CNT为1,当前只申请一个设备编号
         */
        ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);
		if(ret < 0){
                printk("fail to alloc led_devno\n");
                goto alloc_err;
        }
 
        /* 第二步
         * 关联字符设备结构体cdev与文件操作结构体file_operations
         */
        led_chrdev.owner = THIS_MODULE;
        cdev_init(&led_chrdev, &led_chrdev_fops);
 
        /* 第三步
         * 添加设备到cdev_map哈希表中
         */
        ret = cdev_add(&led_chrdev, led_devno, DEV_CNT);
        if(ret < 0){
                printk("fail to add cdev\n");
                goto add_err;
        }
 
        /* 第四步:创建类 */
        class_led = class_create(THIS_MODULE, DEV_NAME);
 
        /* 第五步:创建设备 */
        device = device_create(class_led, NULL, led_devno, NULL, DEV_NAME);
 
        return 0;
 
alloc_err:
        return -1;
add_err:
        //添加设备失败时,需要注销设备号
        unregister_chrdev_region(led_devno, DEV_CNT);
        printk("error!\n");
}
 
static const struct of_device_id rgb_led[] = {
        {.compatible = "fire,rgb_led"},
        {/* sentinel */}
};
 
/* 定义平台设备结构体 */
struct platform_driver led_platform_driver = {
        .probe = led_probe,
        .driver = {
                .name = "rgb-leds-platform",
                .owner = THIS_MODULE,
                .of_match_table = rgb_led,
        }
};
 
static int __init led_platform_driver_init(void)
{
        int DriverState;

		init_completion(&rgb_wait);
        DriverState = platform_driver_register(&led_platform_driver);
        printk(KERN_ALERT "DriverState is %d\n", DriverState);
 
        return 0;
}
 
static void __exit led_platform_driver_exit(void){
        /* 销毁设备 */
        device_destroy(class_led, led_devno);
        /* 删除设备号 */
        cdev_del(&led_chrdev);
        /* 取消注册字符设备 */
        unregister_chrdev_region(led_devno, DEV_CNT);
        /* 销毁类 */
        class_destroy(class_led);
 
        platform_driver_unregister(&led_platform_driver);
 
        printk(KERN_ALERT "led_platform_driver exit\n");
}
 
module_init(led_platform_driver_init);
module_exit(led_platform_driver_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("couvrir");
MODULE_DESCRIPTION("led module");
MODULE_ALIAS("led module");

app.c文件

#include 
#include 
#include 
#include 
 
int main(int argc, char *argv[])
{
        if(argc != 2){
                printf("commend error!\n");
                return -1;
        }
 
        int fd = open("/dev/rgb_led", O_RDWR);
        if(fd < 0){
                printf("open file:/dev/rgb_led failed!!!\n");
                return -1;
        }
 
        int error = write(fd, argv[1], sizeof(argv[1]));
        if(error < 0){
                printf("write file error!\n");
                close(fd);
        }
 
        error = close(fd);
        if(error < 0){
                printf("close file error!\n");
        }
 
        return 0;
}

Makefile文件

照旧

执行过程

虚拟机:

执行make和make copy。生成.ko文件。

开发板(在挂载目录下执行):

sudo insmod dts_led.ko

sudo ./App 0 &(进程休眠)

sudo ./App 1(唤醒app进程,app进程继续点亮灯)

sudo rmmod dts_led.ko

你可能感兴趣的:(#,野火i.mx,6ull内核驱动进阶,linux)