2012-04-23 106 views
1

因此,我有一个应用程序,我想在Linux上通知hotplug事件。当然,我看着libudev及其API。关于如何在libudev中使用select(),我还发现了一个有用的tutorial。在教程和掠过API后,我想出了这个示例程序,它等待热插拔事件,然后输出刚添加或删除的设备的一些基本信息。libudev如何使用轮询与文件描述符

#include <poll.h> 
#include <libudev.h> 
#include <stdexcept> 
#include <iostream> 

udev* hotplug; 
udev_monitor* hotplug_monitor; 

void init() 
{ 
    // create the udev object 
    hotplug = udev_new(); 
    if(!this->hotplug) 
    { 
    throw std::runtime_error("cannot create udev object"); 
    } 

    // create the udev monitor 
    hotplug_monitor = udev_monitor_new_from_netlink(hotplug, "udev"); 

    // start receiving hotplug events 
    udev_monitor_enable_receiving(hotplug_monitor); 
} 

void deinit() 
{ 
    // destroy the udev monitor 
    udev_monitor_unref(hotplug_monitor); 

    // destroy the udev object 
    udev_unref(hotplug); 
} 

void run() 
{ 
    // create the poll item 
    pollfd items[1]; 
    items[0].fd = udev_monitor_get_fd(hotplug_monitor); 
    items[0].events = POLLIN; 
    items[0].revents = 0; 

    // while there are hotplug events to process 
    while(poll(items, 1, 50) > 0) 
    { 
    // XXX 
    std::cout << "hotplug[ " << items[0].revents << " ]" << std::endl; 

    // receive the relevant device 
    udev_device* dev = udev_monitor_receive_device(hotplug_monitor); 
    if(!dev) 
    { 
     // error receiving device, skip it 
     continue; 
    } 

    // XXX 
    std::cout << "hotplug[" << udev_device_get_action(dev) << "] "; 
    std::cout << udev_device_get_devnode(dev) << ","; 
    std::cout << udev_device_get_subsystem(dev) << ","; 
    std::cout << udev_device_get_devtype(dev) << std::endl; 

    // destroy the relevant device 
    udev_device_unref(dev); 

    // XXX 
    std::cout << "done" << std::endl; 

    // clear the revents 
    items[0].revents = 0; 
    } 
} 

int main(int args, char* argv[]) 
{ 
    init(); 

    while(true) 
    { 
    run(); 
    } 

    deinit(); 
} 

嗯,它不起作用。这是我插入USB鼠标时获得的输出。

hotplug[ 1 ] 
hotplug[add] /dev/bus/usb/008/002,usb,usb_device 
done 
hotplug[ 1 ] 
hotplug[add] 

那时程序冻结了,我必须用Ctrl-C来停止它。我究竟做错了什么?

+0

我也不得不处理udev事件,但我选择了一条不同的路径 - 而不是直接使用libudev与udev交谈,我产生了一个通过stdout向我报告事件的“udevadm”进程。如果你使用我的事件循环(也可以在glib/gtk +之上工作),你可以使用我的udev事件监听器客户端实现。看例子http://code.google.com/p/badvpn/source/browse/trunk/examples/ncdudevmanager_test.c – 2012-04-23 21:07:48

+0

@AmbrozBizjak这很有趣,但我宁愿避免启动另一个进程,如果我可以帮助它。此外,如果我相信教程代码与select()一起工作,那么我不明白为什么我的代码不能使用poll()。但是,我记住这一点是一个备份计划。 – 2012-04-23 21:11:11

回答

4

该程序实际上并没有停止;它继续运行,但当您尝试打印空字符串时(不是所有事件都具有所有属性),std :: cout会变得混乱。一个解决办法是使三个打印(devnode,子系统,devtype)有条件。

+0

哦,我没有考虑到这一点。即时将要修改它,所以它只打印非空字符串,看看会发生什么。不过,你知道我为什么得到两个事件而不是两个? – 2012-04-24 14:20:24

+0

两个事件而不是两个?你的意思不是一个?你得到任何udevd发送。对于插入的大多数设备,它会针对设备的不同方面发送多个事件。您可以通过运行“/ sbin/udevadm monitor --udev --property”轻松观察整个事件(包括所有属性)。 – 2012-04-24 14:53:38

+0

是的,就是这样,我实际上得到更多像7,但我只看到前两个,之后,一个NULL搞乱了事情。我想我真的不明白udev事件是如何工作的。不过谢谢,救了我一些麻烦。 – 2012-04-24 14:59:48