使用 Linux sysfs_notify 调用 [英] Using the Linux sysfs_notify call

查看:17
本文介绍了使用 Linux sysfs_notify 调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在内核驱动程序和用户空间程序之间进行异步通信(我知道这里有很多问题需要类似的信息,但我找不到与 sysfs_notify 相关的问题).

I am trying to communicate asynchronously between a kernel driver and a user-space program (I know there are lots of questions here that ask for similar information, but I could find none that deal with sysfs_notify).

我将 Vilhelm 的编辑留在这里,但是将源添加到一个使用 sysfs 的简单驱动程序和一个用户空间程序来轮询它.驱动程序工作正常(我从网上获得了大部分内容;它缺少信用,但当我回去添加它们时找不到它们).不幸的是,轮询程序不起作用.它总是立即返回成功.有趣的是,如果我在轮询之前不执行两次读取,则 revents 成员将设置为 POLLERR |POLLIN 而不仅仅是程序输出中的 POLLIN.

I am leaving Vilhelm's edit here, but adding the source to both a simple driver utilizing sysfs and a user-space program to poll it. The driver works fine (I got most of it from the net; it is missing the credits, but I couldn't find them when I went back to add them). Unfortunately, the polling program does not work. It always returns success immediately. Interestingly, if I don't perform the two reads prior to the poll, the revents members are set to POLLERR | POLLIN instead of just POLLIN as seen in the program output.

程序输出:

root@ubuntu:/home/wmulcahy/demo# ./readhello
触发
属性文件值:74 (t) [0]
revents[0]: 00000001
revents[1]: 00000001

root@ubuntu:/home/wmulcahy/demo# ./readhello
triggered
Attribute file value: 74 (t) [0]
revents[0]: 00000001
revents[1]: 00000001

这是驱动程序:hello.c(你可以看到我从哪里开始......)

Here is the driver: hello.c (you can see where I started out...)

#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[] = {
    &notify.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)
", a->attr.name );
    return scnprintf(buf, PAGE_SIZE, "%s: %d
", 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
", 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
");
    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
");
             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
");
}

module_init(hello_module_init);
module_exit(hello_module_exit);
MODULE_LICENSE("GPL");

这里是轮询程序:readhello.c

And here is the poll program: 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!
");
    }
    else if (ufds[0].revents & POLLIN)
    {
        printf("triggered
");
        cnt = read( notifyFd, attrData, 1 );
        printf( "Attribute file value: %02X (%c) [%d]
", attrData[0], attrData[0], cnt );
    }
    printf( "revents[0]: %08X
", ufds[0].revents );
    printf( "revents[1]: %08X
", ufds[1].revents );

    close( triggerFd );
    close( notifyFd );
}

一些即将推出的 sysfs 增强功能.

在内部,补丁为每个 kobject 添加了一个等待队列头系统;该队列被插入到轮询表中以响应轮询()调用.sysfs 代码无法知道,但是,当任何给定 sysfs 属性的值已更改,因此子系统实现可轮询属性必须显式调用:

Internally, the patch adds a wait queue head to every kobject on the system; that queue is inserted into a poll table in response to a poll() call. The sysfs code has no way of knowing, however, when the value of any given sysfs attribute has changed, so the subsystem implementing a pollable attribute must make explicit calls to:

void sysfs_notify(struct kobject *kobj, char *dir, char *attr);

谢谢,李

推荐答案

阻塞轮询来自用户端.用户代码可以简单地告诉内核它对哪些属性感兴趣,然后阻塞在 poll() 中,直到其中一个发生更改.

The blocking poll is from the user side. User code can simply tell the kernel which attributes it's interested in, then block in a poll() until one of them has changed.

sysfs_notify() 是内核端调用,用于释放用户空间poll().调整内核属性值后,只需调用 sysfs_notify() 以允许任何用户空间应用程序响应其未完成的 poll().

The sysfs_notify() is a kernel-side call that releases the user-space poll(). After you adjust your kernel attribute value, just call sysfs_notify() to allow any user-space applications to respond to their outstanding poll().

poll() 视为订阅"感兴趣的属性更改的通知,而 sysfs_notify() 将更改视为发布"到任何订阅者.

Think of the poll() as "subscribing" to notices of a change in an attribute of interest, and sysfs_notify() as "publishing" the change to any subscribers.

这篇关于使用 Linux sysfs_notify 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆