uevent应用:内核发送uevent,用户空间接收uevent

1,内核发送uevent

内核发送uevent的API由lib/kobject_event.c文件实现,include/linux/kobject.h是头文件。

enum kobject_action {
        KOBJ_ADD,
        KOBJ_REMOVE,
        KOBJ_CHANGE,
        KOBJ_MOVE,
        KOBJ_ONLINE,
        KOBJ_OFFLINE,
        KOBJ_MAX
};

/* kobject_uevent不能用在中断上下文 */
int kobject_uevent(struct kobject *kobj, enum kobject_action action);
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp[]);

在driver中可以调用kobject_uevent或者kobject_uevent_env来向用户空间发送uevent

kobject_uevent默认会发送”ACTION=xxx”,”DEVPATH=xxx”,”SUBSYSTEM=xxx”这三个uevent环境变量。

kobject_uevent_env可以发送一些如”xxx=xxx”的自定义的uevent环境变量。

static ssize_t esd_info_store(struct device *dev,
                    struct device_attribute *attr,
                    const char *buf, size_t count)
{
    if (!buf || count <= 0)
        return -EINVAL;

    kobject_uevent(&core_data->pdev->dev.kobj, KOBJ_CHANGE);

    return count;
}

static int test_uevent(struct device *dev,
                struct kobj_uevent_env *env)
{
        int ret = 0;

        ret = add_uevent_var(env,"COMMENT=%s", "test uevent message");

        if(ret)
            return ret;

    return 0;
}

const struct device_type my_dev_type ={
        .name ="william_ts",
        .uevent= test_uevent,
};

static int xxx_probe(struct platform_device *pdev)
{
    pdev->dev.type = &my_dev_type;
}

2,用户空间解析uevent

#define UEVENT_MSG_LEN 2048

static void uevent_event(uint32_t /*epevents*/, int event_fd)
{
    char msg[UEVENT_MSG_LEN + 2];
    int n;
    char *cp;

    n = uevent_kernel_multicast_recv(event_fd, msg, UEVENT_MSG_LEN);
    if (n <= 0)
        return;
    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
        return;

    msg[n] = '\0';
    msg[n + 1] = '\0';
    cp = msg;

    ALOGE("william get the uevent size n = %d, msg = %s", n, msg);
    while(*cp) {
        ALOGE("william receive the msg = %s", cp);
        /* advance to after the next \0 */
        while(*cp++)
            ;
    }

    ALOGE("william uevent received %s", msg);
}

void *MT::uevent_thread_loop(void)
{
    int epoll_fd, uevent_fd;
    struct epoll_event ev;
    int nevents = 0;

    ALOGE("creating uevent thread");

    uevent_fd = uevent_open_socket(64 * 1024, true);
    if (uevent_fd < 0) {
        ALOGE("uevent_init: uevent_open_socket failed\n");
        return NULL;
    }

    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);

    ev.events = EPOLLIN;
    ev.data.ptr = (void *)uevent_event;

    epoll_fd = epoll_create(64);
    if (epoll_fd == -1) {
        ALOGE("epoll_create failed; errno=%d", errno);
        goto error;
    }

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
        ALOGE("epoll_ctl failed; errno=%d", errno);
        goto error;
    }

    while (!destroyThread) {
        struct epoll_event events[64];

        nevents = epoll_wait(epoll_fd, events, 64, -1);
        if (nevents == -1) {
        if (errno == EINTR) continue;
            ALOGE("usb epoll_wait failed; errno=%d", errno);
            break;
        }

        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr)
                (*(void (*)(uint32_t, int event_fd))events[n].data.ptr)(
                    events[n].events, uevent_fd);
        }
    }

    ALOGI("exiting worker thread");
error:
    close(uevent_fd);

    if (epoll_fd >= 0)
        close(epoll_fd);

    return NULL;
}

void sighandler(int sig) {
  if (sig == SIGUSR1) {
    destroyThread = true;
    ALOGI("destroy set");
    return;
  }
  signal(SIGUSR1, sighandler);
}

3,测试结果

上报的event会通知到所有的用户进程,这里能够收到系统中所有的uevent消息,这里只打印了我们自己添加测试的event。

william get the uevent size n = 234, msg = change@/devices/platform/william_ts.0
william receive the msg = change@/devices/platform/william_ts.0
william receive the msg = ACTION=change
william receive the msg = DEVPATH=/devices/platform/william_ts.0
william receive the msg = SUBSYSTEM=platform
william receive the msg = DEVTYPE=william_ts
william receive the msg = DRIVER=william_ts
william receive the msg = MODALIAS=platform:william_ts
william receive the msg = MAC=05:04:03:02:01:00
william receive the msg = COMMENT=test uevent message
william receive the msg = SEQNUM=13492
william uevent received change@/devices/platform/william_ts.0

你可能感兴趣的:(kernel_basic,linux,uevent)