加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 教程 > 正文

Linux 内核等待队列介绍

发布时间:2021-12-15 11:17:29 所属栏目:教程 来源:互联网
导读:在阅读Tun驱动时看到,有一些类似 add_wait_queue 的函数,这些函数正是执行等待队列的相关操作,要说等待队列还得从内核进程调度说起,内核调度系统内进程,分配时间片,但是有些进程如从网卡中读数据,在网卡有数据到达之前进程处于阻塞状态,如果此时给相

在阅读Tun驱动时看到,有一些类似 add_wait_queue 的函数,这些函数正是执行等待队列的相关操作,要说等待队列还得从内核进程调度说起,内核调度系统内进程,分配时间片,但是有些进程如从网卡中读数据,在网卡有数据到达之前进程处于阻塞状态,如果此时给相应进程分配时间片做调度,无疑是浪费系统资源,所以系统内每个进程都有自己的状态标志 task->state,这些状态定义于文件 include/linux/sched.h
 
#define TASK_RUNNING            0
#define TASK_INTERRUPTIBLE      1
#define TASK_UNINTERRUPTIBLE    2
...
 
内核只会调用标志是 TASK_RUNNING 的进程,如果需要等待资源,可以设置自己的进程标志为 TASK_INTERRUPTIBLE (可中断)或者 TASK_UNINTERRUPTIBLE (不可中断),然后调用 schedule();放弃CPU,此进程就不会被内核调度了,但随之而来的问题是,如果进程所需资源可以使用,如何唤醒进程呢,这就要依赖于等待队列了,进程在放弃控制权之前,把自己加入一个队列中,当所需条件满足,其他进程便可wakeup该队列,修改进程状态为 TASK_RUNNING,等待进程便可顺利往下执行了。
 
与等待队列相关的操作有如下几种:
 
/* 等待队列头声明 */
wait_queue_head_t simple_queue;
 
/* 初始化等待队列头 */
init_waitqueue_head(&simple_queue);
 
/* 定义等待队列项 */
DECLARE_WAITQUEUE (name, tsk);
 
/* 添加删除等待项 */
void fastcall add_wait_queue(wait_queue_head_t * q, wait_queue_t * wait);
void fastcall remove_wait_queue(wait_queue_head_t * q, wait_queue_t * wait);
 
/* 唤醒等待头中的所有项 */
void wake_up(wait_queue_head_t * queue);
void wake_up_interruptible(wait_queue_head_t * queue);
结合这些函数,再往simple驱动里添加一些简单的机制支持等待。在 simple_read 函数中修改当前进程状态,加入等待队列后,放弃控制权,另加入 simple_write 函数唤醒队列。
 
#include<linux/init.h>
#include<linux/module.h>
 
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/cdev.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<asm/io.h>
#include<asm/uaccess.h>
#include<asm/system.h>
 
#include<linux/device.h>
 
dev_t devno;
struct class * simple_class;
static struct cdev cdev;
 
wait_queue_head_t simple_queue;
 
char test_data[255];
int len;
 
ssize_t simple_read(struct file * pfile,
    char __user * buf, size_t size, loff_t * ppos)
{
    /* 定义一个等待项,添加到等待队列,并设置进程状态后放弃执行权 */
    DECLARE_WAITQUEUE (simple_item, current);
    add_wait_queue(&simple_queue, &simple_item);
    current->state = TASK_INTERRUPTIBLE;
    schedule();
    /* 被唤醒以后,从队列中移除 */
    remove_wait_queue(&simple_queue, &simple_item);
 
    if (copy_to_user(buf, test_data, len))
        return -EFAULT;
    else
        return len;
}
 
ssize_t simple_write(struct file * pfile, const char __user * buf, size_t count, loff_t * ppos)
{
    if (count > 255)
    {
        return -EFAULT;
    }
 
    if (!copy_from_user(test_data, buf, count))
    {
        len = count;
        /* 唤醒等待队列中所有进程 */
        wake_up(&simple_queue);
    }
    return len;
}
 
int simple_open(struct inode * pnode, struct file * pfile)
{
    printk(KERN_INFO "open simplen");
    return 0;
}
 
int simple_release(struct inode * pnode, struct file * pfile)
{
    printk(KERN_INFO "close simplen");
    return 0;
}
 
static struct file_operations simple_op =
{
    .owner = THIS_MODULE,
    .read = simple_read,
    .open = simple_open,
    .release = simple_release,
    .write = simple_write,
};
 
static int __init initialization(void)
{
    int result;
 
    result = alloc_chrdev_region(&devno, 0, 1, "simple");
    if (result < 0)
        return result;
 
    cdev_init(&cdev, &simple_op);
    result = cdev_add(&cdev, devno, 1);
 
    simple_class = class_create(THIS_MODULE, "simple");
    device_create(simple_class, NULL, devno, NULL, "simple");
 
    printk(KERN_INFO " init simplen");
 
    init_waitqueue_head(&simple_queue);
 
    return result;
}
 
static void __exit cleanup(void)
{
    device_destroy(simple_class, devno);
    class_destroy(simple_class);
 
    cdev_del(&cdev);
    unregister_chrdev_region(devno, 1);
    printk(KERN_INFO " cleanup simplen");
}
 
module_init(initialization);
module_exit(cleanup);
 
MODULE_AUTHOR("alloc cppbreak@gmail.com");
MODULE_DESCRIPTION("A simple linux kernel module");
MODULE_VERSION("V0.2");
MODULE_LICENSE("Dual BSD/GPL");
加载模块 insmod simple.ko 后,使用cat读取数据,cat /dev/simple, 会发现进程处于等待状态,不会输出任何信息,新打开一个终端,输入echo “test” > /dev/simple执行写操作,cat便会输出数据,紧接着再次处于等待状态。
 
insmod simple.ko
cat /dev/simple        --->    进程等待
first            --->    echo "first" > /dev/simple
cool            --->    echo "cool" > /dev/simple

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读