linux 实现监听热插拔事件

在一些跑linux 系统的平台上,比如故事机,会支持sdcard 热插拔的功能,也就是在sdcard 插入后,把sdcard mount到文件系统中,sdcard拔出后移除。上层应用要怎么知道这个事件呢,应用层可以注册监听uevent 事件即可,下面给出对应的实现。

​
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define EPOLL_FD_SIZE     3   //需要监听的fd个数
#define EPOLL_EVENT_SIZE  2
#define EPOLL_TIMEOUT     1000  //等待的超时时间,1000ms 也就是1秒

#ifndef KERNEL_UEVENT_LEN
#define KERNEL_UEVENT_LEN      (4*1024)
#endif

typedef struct
{
    int epoll_fd;              //epoll 对应的fd
    int uevent_fd;             //热插拔节点的sock 句柄
    pthread_t hotplug_thread;  //对应的线程
    int is_start;              //线程是否已经创建
    int is_running;            //是否在while循环中运行
} hotplug_context_t;


static hotplug_context_t hotplug = {0};
static char uevent_buff[KERNEL_UEVENT_LEN];
static char card_node[32];

static int create_uevent_socket()
{
    int flags,retval;
    hotplug.uevent_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if(hotplug.uevent_fd<0)
    {
        printf("[hotplug] create_uevent_socket socket fail.\n");
        return -1;
    }
    flags = fcntl(hotplug.uevent_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(hotplug.uevent_fd, F_SETFL, flags);
    struct sockaddr_nl src_addr;
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();
    src_addr.nl_groups = 0xffffffff;
    retval = bind(hotplug.uevent_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
    if(retval < 0)
    {
        printf("[hotplug] create_uevent_socket bind fail.\n");
        close(hotplug.uevent_fd);
        hotplug.uevent_fd = 0;
        return -1;
    }
    return 0;
}

static void destroy_uevent_socket()
{
     if(hotplug.uevent_fd>0)
     {
         close(hotplug.uevent_fd);
         hotplug.uevent_fd = 0;
     }
}


static void hotplug_parse_uevent(char* recv_buff,int recv_size)
{
     //printf("[hotplug] recv_size = %d, recv_buff = %s.\n",recv_size,recv_buff);
     int i;
     char* p_str = recv_buff;
     for(i=0;i KERNEL_UEVENT_LEN)
               {
                   printf("[hotplug] receive overflow!\n");
                   continue;
               }
               hotplug_parse_uevent(uevent_buff,recv_size);
            }
        }
    }
    hotplug.is_start = 0;
    destroy_uevent_socket();
    close(hotplug.epoll_fd);
    return NULL;
}

///

int start_hotplug_monitor()
{
    if(hotplug.is_start)
    {
        printf("[hotplug] start_hotplug_monitor had start.\n");
        return 0;
    }
    hotplug.is_start = 1;      //先标志线程已经创建
    if(pthread_create(&(hotplug.hotplug_thread), NULL, hotplug_thread_loop, NULL)){
        printf("[hotplug] pthread_create hotplug_thread_loop fail.\n");
        hotplug.is_start = 0;  //线程创建失败
        return -1;
    }
    return 0;
}

int stop_hotplug_monitor()
{
    if(hotplug.is_start == 0) //如果线程还没有启动
    {
        printf("[hotplug] start_hotplug_monitor had not start.\n");
        return -1;
    }

    hotplug.is_running = 0; //让线程结束
    pthread_join(hotplug.hotplug_thread, NULL);   //等待线程运行结束
    return 0;
}

​

这个流程还是比较简单的,大概就是创建socket 连接,这不过最后一个参数是NETLINK_KOBJECT_UEVENT,然后绑定,然后用epoll 监听socket 是否可读(当然也可以用select实现),如果可读了,就从socket 里面读取对应的信息,重点在于读取到这些信息后怎么解析,不同的平台传递的信息内容可能不一样,根据实际情况去解析就可以了。

你可能感兴趣的:(linux,linux,hotplug,hotplug,event)