c - 使用 libevent 读取 chardevice
问题描述
我编写了一个 chardevice 将从网络接收到的一些消息传递给用户空间应用程序。用户空间应用程序必须读取 chardevice 并通过 TCP 套接字向其他用户空间应用程序发送/接收消息。读取和接收都应该是阻塞的。
由于 Libevent 能够同时处理多个事件,我认为为 chardevice 创建的文件注册一个事件并为套接字注册一个事件就可以了,但我错了。但是 chardevice 会创建一个“字符特殊文件”,而 libevent 似乎无法阻止。如果我在 chardevice 内部实现了阻塞机制,即互斥锁或信号量,那么套接字事件也会阻塞,应用程序无法接收消息。
用户空间应用程序必须随时接受外部连接。
你知道如何让它工作吗?也许还使用另一个库,我只想要套接字和文件阅读器的阻塞行为。
先感谢您。
更新:感谢@Ahmed Masud 的帮助。这就是我所做的
内核模块 chardevice:
实现一个轮询函数,等待新数据可用
struct file_operations fops = {
...
.read = kdev_read,
.poll = kdev_poll,
};
如果用户空间必须停止,我有一个全局变量要处理,还有一个等待队列:
static working = 1;
static wait_queue_head_t access_wait;
这是读取函数,如果 copy_to_user 中有错误,我返回 -1,如果一切顺利,则返回 > 0,如果模块必须停止,则返回 0。used_buff 是原子的,因为它处理由用户应用程序读取并由内核模块写入的共享缓冲区的大小。
ssize_t
kdev_read(struct file* filep, char* buffer, size_t len, loff_t* offset)
{
int error_count;
if (signal_pending(current) || !working) { // user called sigint
return 0;
}
atomic_dec(&used_buf);
size_t llen = sizeof(struct user_msg) + msg_buf[first_buf]->size;
error_count = copy_to_user(buffer, (char*)msg_buf[first_buf], llen);
if (error_count != 0) {
atomic_inc(&used_buf);
paxerr("send fewer characters to the user");
return error_count;
} else
first_buf = (first_buf + 1) % BUFFER_SIZE;
return llen;
}
当有数据要读取时,我只需递增used_buf
并调用wake_up_interruptible(&access_wait)
. 这是 poll 函数,我只是等到 used_buff > 0
unsigned int
kdev_poll(struct file* file, poll_table* wait)
{
poll_wait(file, &access_wait, wait);
if (atomic_read(&used_buf) > 0)
return POLLIN | POLLRDNORM;
return 0;
}
现在,这里的问题是,如果我在用户空间应用程序等待时卸载模块,后者将进入阻塞状态并且无法停止它。这就是为什么我在卸载模块时唤醒应用程序
void
kdevchar_exit(void)
{
working = 0;
atomic_inc(&used_buf); // increase buffer size to application is unlocked
wake_up_interruptible(&access_wait); // wake up application, but this time read will return 0 since working = 0;
... // unregister everything
}
用户空间应用程序
Libevent 默认使用轮询,因此只需创建一个 event_base 和一个 reader 事件。
base = event_base_new();
filep = open(fname, O_RDWR | O_NONBLOCK, 0);
evread = event_new(base, filep, EV_READ | EV_PERSIST,
on_read_file, base);
其中 on_read_file 只是读取文件,不进行轮询调用(libevent 处理):
static void
on_read_file(evutil_socket_t fd, short event, void* arg)
{
struct event_base* base = arg;
int len = read(...);
if (len < 0)
return;
if (len == 0) {
printf("Stopped by kernel module\n");
event_base_loopbreak(base);
return;
}
... // handle message
}
解决方案
推荐阅读
- ios - 如何在一个 ViewController 中打开多个文件?
- android - 当用户在android中卸载我的应用程序时如何得到通知
- swift - 与泛型类型和协议关联的类型约束允许绕过 WHERE 子句
- asp.net-core - 如何使用其他表的属性动态获取表中的属性?
- datetime - 如何在vim中新创建的文件中插入日期?
- html - 显示问题:阻止影响周围 div 的 css
- django - 无法将 Django 项目导入其他计算机
- reactjs - 反应原生的私有路由不适用于页面更改。带有有效负载 {"name":"Home"} 的操作 'NAVIGATE' 未被任何导航器处理
- html - 如何在图像上显示文本并在我的页面中正确定位该图像?
- firebase - 将 React Native 连接到 firebase 给了我错误