网页开发和网站开发,网站模板织梦,用帝国软件做网站的心得,用vis做的简单网站sysfs 是 Linux userspace 和 kernel 进行交互的一个媒介。通过 sysfs#xff0c;userspace 可以主动去读写 kernel 的一些数据#xff0c;同样的#xff0c; kernel 也可以主动将一些“变化”告知给 userspace。也就是说#xff0c;通过sysfs#xff0c;userspace 和 ker… sysfs 是 Linux userspace 和 kernel 进行交互的一个媒介。通过 sysfsuserspace 可以主动去读写 kernel 的一些数据同样的 kernel 也可以主动将一些“变化”告知给 userspace。也就是说通过sysfsuserspace 和 kernel 的交互本质上是双向的 userspace 通过 sysfs 访问 kernel 数据的方法便是大名鼎鼎的 show() / store() 方法 uevent是通过netlink实现的首先在内核中调用netlink_kernel_create函数创建一个socket套接字当有事件发生时通过kobject_uevent函数最终调用netlink_broadcast_fillted函数向用户发送数据同时在用户空间有监听事件则kernel的变化用户空间即刻知晓 uevent初始化 uevent_net_init()创建类型为NETLINK_KOBJECT_UEVENT的socket并将其放入uevent_sock_list链表上。uevent_net_exit()则将其从uevent_socket_list中摘除并且释放socket相关资源 对uevent_helper设置 Linux下热插拔通知用户空间 对uevent_helper设置可以对/proc/sys/kernel/hotplug写可执行文件路径即可。然后在内核触发uevent事件的之后调用相关可执行文件进行处理 或者还可以对/proc/kernel/uevent_helper写入可执行文件路径 usermode helper用于帮助在内核空间启动一个用户空间程序
1、kernel中uevent主要调用函数 通过内核发送uevent很简单将数据代表环境变量的字符串组装好后选择合适的action指定对应的kobject设备即可 kobject_uevent(drv-p-kobj, KOBJ_ADD); kobject_uevent_env(kobj, action, NULL); retval netlink_broadcast_filtered(uevent_sock, skb,0, 1, GFP_KERNEL,kobj_bcast_filter,kobj); uevent发送可以通过kobject_uevent()或者通过kobject_uevent_env()附加更多uevent信息。 kobject_uevent_env()主要分为两部分一是通过netlink_broadcast_filtered()将socket信息发出去另一个是通过uevent helper将uevent调用指定的uevent_helper进行处理通常是热插拔程序mdev、udevd等 其中kobject_uevent函数中的action对应 KOBJ_ADD, KOBJ_REMOVE, KOBJ_CHANGE, KOBJ_MOVE, KOBJ_ONLINE, KOBJ_OFFLINE, 而 kobject_uevent() 其实就是直接调用了 kobject_uevent_env() 函数。一切的操作将在该函数中完成比如 kset uevent ops (struct kset_uevent_ops)的获取、字符串的填充组合、netlink message 的发送等,这些 uevent ops 在 start_kernel() 就会被注册 发送格式一般为actiondevpatch change/devices/virtual/thermal/cooling_device0 ACTIONchange DEVPATH/devices/virtual/thermal/cooling_device0 SUBSYSTEMthermal NAMEuser_cooling STATE1 TEMP90 SEQNUM747
2、userspace用户空间的实现使用
用户空间会首先创建一个socket并绑定到AF_NETLINK地址族上然后recv接收消息处理内核传递上来的message 创建socket——》recv接收uevent信息——》解析接收到的uevent信息——》地址族是AF_NETLINK类型的socket协议类型是NETLINK_KOBJECT_UEVENT——》将当前socket绑定到AFNETLINK上并设置本进程为处理消息的进程
3、mdev kmod
busybox下的mdev
mdev是一种附加“-s”主动遍历/sys/dev下设备另一种是作为hotplug处理程序被内核uevent helper调用到mdev作为hotplug程序处理时从环境变量中获取参数创建或删除设备 /etc/mdev.con文件配置
4、mdev和udev区别
udev和mdev都是通过uevent机制处理热插拔的用户程序udev在用户空间监听内核uevent消息然后解析uevent消息进行相应的热插拔事件处理mdev是基于uevent-helper机制内核在发送uevent的时同时调用uevent-helper指向的用户空间程序进行热插拔处理udev是作为一个demo常驻内存的mdev是在需要时被调用
5、总结
uevent是内核发送消息到用户空间的一种途径通过netlink实现 内核中通过kobject_uevent、kobject_uevent_env发送uevent消息用户空间使用标准的socket接口来监听接收uevent消息或者通过uevent-helper调用用户空间进程mdev来进行热插拔动作处理方式遵循mdev.conf规则而 uevent 把事件上报给用户空间有两种途径 通过 kmod 模块直接调用用户空间的可执行程序或脚本 通过 netlink 通信机制将事件从内核空间传递到用户空间
6、通过 uevent 上报电池电量
内核
drivers/power/supply/power_supply_core.c drivers/power/supply/power_supply_sysfs.c power_supply_init power_supply_class-dev_uevent power-suply_uevent 初始化workqueue后续用于调度 INIT_WORK(psy-changed_work, power_supply_changed-work) 驱动中检测到硬件发生变化时调用power_supply_changed函数进而调用changed_work schedule_work(psy-changed_work); 添加环境变量回调kset中注册的power-supply-uevent将msg以socketbuffer的格式打包 power_supply_changed-work kobject-uevent(psy-dev.kobj, KOBJ_CHANGE); kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]) if(envp_ext ! NULL) add_uevent_var(env, “%s”, envp_ext[i]); if(uevent_ops uevent_ops-uevent) // uevent_ops kset-uevent_ops; uevent_ops-uevent dev_uevent uevent_ops-uevent(kset, kobj, env); // power_supply_class-dev_uevent power_supply_uevent; class类kset power_supply_uevent; add_uevent-var(env, “ACTION%s”, action_string); add_uevent_var(env, “DEVPATH%s”, devpath); add_uevent_var(env, “SUBSYSTEM%s”, subsystem); kobject_uevent_net_boardcast(kobj, env, action_string, devpath); alloc_uevent_skb // sockect buffer的放置有关 header: actiondevpath socket_buffer scratch skb_put(skb, len); /add header/ sprintf(scratch, “%s%s”, action_string, devpath); skb_put_data(skb, env-buf, env_buflen);
用户
hardware/interfaces/health/utils/libhealthloop/HealthLoop.cpp
power_supply通过调用kobject_uevent envp_ext为NULL, 会回调class的dev_uevent并且使用的是默认的add_uevent_varACTIONaction_string DEVPATHdevpath SUBSYSTEMsubsystem电池上层接受的时候会通过SUBSYSTEM进行过滤 StartLoop epollfd.reset(epoll_create1(EPOLL_CLOEXEC)); // 进程被替换时会关闭文件描述符 uevent_fd.reset(uevent_open_socket(64 * 1024, true)); // uevent_fd ev.events EPOLLIN; // 1 新的请求 2 接收到普通数据缓冲未满 3 正常关闭连接 ev.events | EPOLLWAKEUP // 1 唤醒源 系统会保持唤醒 epoll_ctl(epollfd_, EPOLL_CTRL_ADD, uevent_fd_, ev); // ADD表示绑定事件 MainLoop - while(1) epoll_wait(wpollfd_, events, eventctl, timeout); // epoll等待uevent事件 uevent_kernel_multicast_recv // 接收uevent事件 strcmp(cp, “SUBSYSTEM” POWER_SUPPLY_SUBSYSTEM); // 判断subsystembattery power_supply ScheduleBatteryUpdate(); // 更新上报电池细节