Dig*_*lee 7 linux kernel polling linux-kernel sysfs
我试图在内核驱动程序和用户空间程序之间异步通信(我知道这里有很多问题需要类似的信息,但我找不到任何处理sysfs_notify的问题).
我将离开Vilhelm的编辑,但是将源添加到使用sysfs的简单驱动程序和用户空间程序进行轮询.驱动程序工作正常(我从网上得到了大部分;它缺少了学分,但是当我回去添加它们时我找不到它们).不幸的是,投票计划不起作用.它总是立即返回成功.有趣的是,如果我在轮询之前不执行两次读取,则revents成员将设置为POLLERR | 如程序输出中所见,POLLIN而不仅仅是POLLIN.
节目输出:
root @ ubuntu:/ home/wmulcahy/demo#./ readhello
triggered
属性文件值:74(t)[0]
revents [0]:00000001
revents [1]:00000001
这是驱动程序:hello.c(你可以看到我开始的地方......)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
struct my_attr {
    struct attribute attr;
    int value;
};
static struct my_attr notify = {
    .attr.name="notify",
    .attr.mode = 0644,
    .value = 0,
};
static struct my_attr trigger = {
    .attr.name="trigger",
    .attr.mode = 0644,
    .value = 0,
};
static struct attribute * myattr[] = {
    ¬ify.attr,
    &trigger.attr,
    NULL
};
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
{
    struct my_attr *a = container_of(attr, struct my_attr, attr);
    printk( "hello: show called (%s)\n", a->attr.name );
    return scnprintf(buf, PAGE_SIZE, "%s: %d\n", a->attr.name, a->value);
}
static struct kobject *mykobj;
static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len)
{
    struct my_attr *a = container_of(attr, struct my_attr, attr);
    sscanf(buf, "%d", &a->value);
    notify.value = a->value;
    printk("sysfs_notify store %s = %d\n", a->attr.name, a->value);
    sysfs_notify(mykobj, NULL, "notify");
    return sizeof(int);
}
static struct sysfs_ops myops = {
    .show = show,
    .store = store,
};
static struct kobj_type mytype = {
    .sysfs_ops = &myops,
    .default_attrs = myattr,
};
static struct kobject *mykobj;
static int __init hello_module_init(void)
{
    int err = -1;
    printk("Hello: init\n");
    mykobj = kzalloc(sizeof(*mykobj), GFP_KERNEL);
    if (mykobj) {
        kobject_init(mykobj, &mytype);
        if (kobject_add(mykobj, NULL, "%s", "hello")) {
             err = -1;
             printk("Hello: kobject_add() failed\n");
             kobject_put(mykobj);
             mykobj = NULL;
        }
        err = 0;
    }
    return err;
}
static void __exit hello_module_exit(void)
{
    if (mykobj) {
        kobject_put(mykobj);
        kfree(mykobj);
    }
    printk("Hello: exit\n");
}
module_init(hello_module_init);
module_exit(hello_module_exit);
MODULE_LICENSE("GPL");
以下是民意调查程序:readhello.c
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <poll.h>
#define TEST_SYSFS_TRIGGER  "/sys/hello/trigger"
#define TEST_SYSFS_NOTIFY   "/sys/hello/notify"
int main(int argc, char **argv)
{
    int cnt, notifyFd, triggerFd, rv;
    char attrData[100];
    struct pollfd ufds[2];
    // Open a connection to the attribute file.
    if ((notifyFd = open(TEST_SYSFS_NOTIFY, O_RDWR)) < 0)
    {
        perror("Unable to open notify");
        exit(1);
    }
    // Open a connection to the attribute file.
    if ((triggerFd = open(TEST_SYSFS_TRIGGER, O_RDWR)) < 0)
    {
        perror("Unable to open trigger");
        exit(1);
    }
    ufds[0].fd = notifyFd;
    ufds[0].events = POLLIN;
    ufds[1].fd = triggerFd;
    ufds[1].events = POLLIN;
    // Someone suggested dummy reads before the poll() call
    cnt = read( notifyFd, attrData, 100 );
    cnt = read( triggerFd, attrData, 100 );
    ufds[0].revents = 0;
    ufds[1].revents = 0;
    if (( rv = poll( ufds, 2, 10000)) < 0 )
    {
        perror("poll error");
    }
    else if (rv == 0)
    {
        printf("Timeout occurred!\n");
    }
    else if (ufds[0].revents & POLLIN)
    {
        printf("triggered\n");
        cnt = read( notifyFd, attrData, 1 );
        printf( "Attribute file value: %02X (%c) [%d]\n", attrData[0], attrData[0], cnt );
    }
    printf( "revents[0]: %08X\n", ufds[0].revents );
    printf( "revents[1]: %08X\n", ufds[1].revents );
    close( triggerFd );
    close( notifyFd );
}
在内部,补丁将等待队列头添加到系统上的每个kobject; 该队列被插入轮询表以响应poll()调用.但是,当任何给定sysfs属性的值发生更改时,sysfs代码无法知道,因此实现pollable属性的子系统必须显式调用:
Run Code Online (Sandbox Code Playgroud)void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
谢谢,李
Pet*_*ter 10
阻止轮询来自用户方.用户代码可以简单地告诉内核它感兴趣的属性,然后阻止poll()直到其中一个属性发生了变化.
这sysfs_notify()是一个释放用户空间的内核端调用poll().调整内核属性值后,只需调用sysfs_notify()以允许任何用户空间应用程序响应其未完成的内容poll().
可以将poll()"订阅"视为感兴趣属性更改的通知,并将sysfs_notify()更改"发布"给任何订阅者.