【问题标题】:Listening for sysfs battery events监听 sysfs 电池事件
【发布时间】:2021-08-23 09:20:03
【问题描述】:

我正在编写一个检查电池容量的守护进程。这适用于运行 Linux 的太阳能嵌入式设备。我读过在守护进程中使用sleep() 是个坏主意,因此我正在尝试使用事件。所以我写了一些 PoC,但我没有收到任何事件!正如他们向我推荐的那样,我的第一个实现使用libudevpoll()

#include <fcntl.h>
#include <libudev.h>
#include <poll.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void)
{
    struct udev *udev;
    struct udev_monitor *mon;
    struct pollfd fds[1];
    int fd;
    udev = udev_new();
    if (udev == NULL)
        return 1;
    mon = udev_monitor_new_from_netlink(udev, "udev");
    udev_monitor_filter_add_match_subsystem_devtype(mon, "power_supply", NULL);
    udev_monitor_enable_receiving(mon);
    fd = udev_monitor_get_fd(mon);
    fds[0].fd = fd;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    if (poll(fds, 1, -1) > 0) {
        /* Never gets here! */
        struct udev_device *const dev = udev_monitor_receive_device(mon);
        if (dev != NULL) {
            puts(udev_device_get_sysname(dev));
            udev_device_unref(dev);
        }
        else
            fputs("udev_monitor_receive_device() failed\n", stderr);
    }
    udev_unref(udev);
    return 0;
}

我得到的唯一事件是我插入/拔出充电器时!然后我认为我在笔记本电脑安装中使用的状态栏确实显示了电池容量。我查看了source,他们使用inotify 监控电池的uevent。但是我到处读到我不应该将inotify 用于sysfs!尽管如此,我还是尝试了:

#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>

#define BAT_PATH "/sys/class/power_supply/BAT0"

int main(void)
{
    struct inotify_event ev = {0};
    int wd, ret = 1;
    ssize_t len;
    const int fd = inotify_init1(IN_CLOEXEC);
    if (fd < 0) {
        perror("inotify_init() failed");
        return ret;
    }
    /* else */
    wd = inotify_add_watch(fd, BAT_PATH "/uevent", IN_ACCESS);
    if (wd < 0)
        goto end;
    /* else */
    len = read(fd, &ev, sizeof(ev));
    /* Again... never gets here. */
    if (len > 0 && (ev.mask & IN_ACCESS))
        puts("It worked!");
    inotify_rm_watch(fd, wd);
    ret = 0;
end:
    close(fd);
    return ret;
}

事实证明这也行不通!它如何适用于我的状态栏但在我尝试时不起作用?我做错了什么可怕的事情吗?谢谢。

【问题讨论】:

  • poll()inotify_add_watch() 返回什么错误?您是否尝试过让 poll 手册页提供的示例发挥作用?
  • @fbynite 我没有收到任何错误!上面的程序只是阻塞(因为它们应该)等待事件,但没有找到任何事件。

标签: c linux inotify sysfs libudev


【解决方案1】:

关于您的第一个实现(会发表评论但没有足够的代表。因为我对 libudev 一无所知):我遵循的成功使用 sysfs 来 poll() GPIO 中断的指南建议寻找POLLPRI 事件,而不是的POLLIN,如您在第一个实现中所示(请参阅man poll 了解事件类型)。

更重要的是,您说连接/断开充电器时会收到一个事件,您的意思是每次软件执行都有一个事件吗?如果是这种情况,可能是因为您没有清除中断标志:在poll() 命中后,在 sysfs 中需要int len = read(fds[0].fd, *buf, SIZE); 将中断标记为已服务,并且还需要lseek(fds[0].fd, 0, 0); 在为了使下一个 read() 成功(有关代码示例,请参见我的其他答案 here)。

【讨论】:

  • 嗨,我试过POLLPRI,但我没有收到任何事件,即使是在插入/拔出充电器时!没错,我没有清除中断标志,但在这些示例中,我只寻找一个事件。请注意,我没有循环!谢谢!
【解决方案2】:

我不知道这个答案是否会帮助你,但我正在写答案,因为如果任何其他用户面临同样的问题,他们可以得到解决。 解决方案是: 您需要监视内核事件,因此您需要更改线路 表格

mon = udev_monitor_new_from_netlink(udev, "udev");

mon = udev_monitor_new_from_netlink(udev, "kernel");

然后你会得到事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2015-06-23
    • 2020-06-25
    • 2011-10-07
    • 1970-01-01
    相关资源
    最近更新 更多