ZBLOG

使用poll机制从内核层通知应用层的代码示例

下面是一个使用 poll 机制从内核层通知应用层的简单示例。在这个示例中,我们将创建一个字符设备驱动程序,并在该驱动程序中实现对 poll 的支持,以便能够通过 poll() 系统调用从用户空间等待事件。

内核模块(字符设备)

首先,我们需要编写一个简单的字符设备驱动,它支持 poll

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/wait.h>

#define DEVICE_NAME "mychar"
#define BUFFER_SIZE 128

static int major_number;
static char message[BUFFER_SIZE] = {0};
static int message_length = 0;
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int data_available = 0;

static ssize_t mychar_read(struct file *file, char __user *buffer, size_t len, loff_t *offset) {
    if (data_available == 0) {
        // 如果没有数据可读,阻塞用户进程
        if (wait_event_interruptible(wq, data_available != 0)) {
            return -ERESTARTSYS; // 被信号中断
        }
    }

    // 拷贝数据到用户空间
    if (copy_to_user(buffer, message, message_length)) {
        return -EFAULT;
    }

    data_available = 0; // 重置标志
    return message_length; // 返回读取的字节数
}

static unsigned int mychar_poll(struct file *file, poll_table *wait) {
    poll_wait(file, &wq, wait); // 将当前文件描述符添加到等待队列

    if (data_available > 0) {
        return POLLIN | POLLRDNORM; // 表示有数据可读
    }
    
    return 0; // 没有数据可读
}

static ssize_t mychar_write(struct file *file, const char __user *buffer, size_t len, loff_t *offset) {
    if (len > BUFFER_SIZE) len = BUFFER_SIZE; // 限制写入长度

    if (copy_from_user(message, buffer, len)) {
        return -EFAULT;
    }

    message_length = len;
    data_available = 1; // 设置标志为有数据可读
    wake_up(&wq); // 唤醒所有在等待队列上的进程
    
    return len; // 返回写入的字节数
}

static struct file_operations fops = {
    .read = mychar_read,
    .write = mychar_write,
    .poll = mychar_poll,
};

static int __init mychar_init(void) {
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register a major number\n");
        return major_number;
    }

   printk(KERN_INFO "MyChar device registered with major number %d\n", major_number);
   return 0;
}

static void __exit mychar_exit(void) {
     unregister_chrdev(major_number, DEVICE_NAME);
     printk(KERN_INFO "MyChar device unregistered\n");
}

module_init(mychar_init);
module_exit(mychar_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple character device with poll support");

用户空间代码

下面是一个简单的用户空间程序,使用 poll() 等待字符设备的数据可用:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/poll.h>

#define DEVICE_FILE "/dev/mychar"

int main() {
    int fd = open(DEVICE_FILE, O_RDWR);
    
    if (fd == -1) {
        perror("Failed to open the device...");
        return errno;
    }
    
    struct pollfd fds[1];
    
    while (1) {
        fds[0].fd = fd;
        fds[0].events = POLLIN;

        printf("Waiting for input...\n");

        int ret = poll(fds, 1, -1); // 阻塞直到有事件发生
        
        if (ret == -1) {
            perror("poll error");
            close(fd);
            exit(EXIT_FAILURE);
        } else if (ret > 0 && fds[0].revents & POLLIN) { 
            char buffer[128] = {0};
            ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
            
            if (bytes_read >= 0) {
                printf("Read from device: %s\n", buffer);
            } else {
                perror("Read error");
                break;
            }
        }
        
      sleep(1); 
   }

   close(fd);
   return EXIT_SUCCESS;
}

编译与加载模块

确保安装了 Linux 开发工具,然后可以使用以下命令编译并加载内核模块:

# 保存上面的内核模块代码到 my_char_device.c 中,然后运行:
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

# 加载模块
sudo insmod my_char_device.ko

# 检查设备是否创建成功,应该在 /dev 下看到对应的设备文件:
ls /dev/mychar  

测试用户程序

运行用户程序之前,请确保您已经打开了终端以执行编译和加载操作。然后编译并运行上述用户空间代码:

gcc user_program.c -o user_program
./user_program &

现在您可以向 /dev/mychar 写入数据,例如通过另一个终端使用 echo 命令,如下所示:

echo "Hello World" > /dev/mychar 

这样会触发应用层中的 poll() 通知,输出读取到的数据。

注意:这是一个基本示例。在实际开发中,请确保处理好错误情况和资源释放,以免造成内存泄漏或其他问题。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=6231

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?