- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在编写 Linux 内核模块时,我遇到了一个 kthread 问题,在等待信号量解锁时我无法唤醒它。这会导致线程无法停止,并且 rmmod
在尝试卸载模块时卡住。
请注意:此模块在 3.10 内核上运行,我无法将其更新到更新的版本(客户要求在具有 3.10 内核的库存 CentOS 7 上运行)。
以下是模块源代码中有趣的部分。它代表了一个简单的生产者消费者问题,列表的大小没有限制(因此不需要生产者信号量)并且由互斥量保护。从列表中获取某些内容的函数由信号量保护,该信号量由生产者提高并由消费者降低。 producer 函数是从外部事件(实际上是一个字符设备)调用的,此代码片段中未显示,以保持尽可能小。除了模块卸载外,该过程运行完美。
导致卡顿的部分在代码片段中标有注释。我知道停止 kthread 的唯一方法是对其调用 kthread_stop
,在这种情况下失败,因为它显然无法唤醒 sleep 线程。因为它等待线程退出,调用永远不会返回,模块也不会卸载。
如何唤醒并停止kthread等待信号量成功卸载模块?
列表实现:
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/semaphore.h>
static LIST_HEAD(list);
DEFINE_MUTEX(list_lock);
DEFINE_SEMAPHORE(sem_list_consumer);
void add_to_list(struct *some_struct) {
int rv = mutex_lock_interruptible(&list_lock);
if(rv != 0) {
return;
}
list_add(&some_struct->list, &list);
mutex_unlock(&list_lock);
up(&sem_list_consumer);
}
struct some_struct * take_from_list() {
int rv;
some_struct *entry;
/* this is where the kthread will freeze when module is unloaded */
rv = down_interruptible(&sem_list_consumer);
if(rv != 0) {
return NULL;
}
rv = mutex_lock_interruptible(&list_lock);
if(rv != 0) {
up(&sem_list_consumer);
return NULL;
}
if (list_empty(&list)) {
mutex_unlock(&list_lock);
return NULL;
} else {
entry = list_last_entry(&list, struct some_struct, list);
if (entry) {
list_del(&entry->list);
}
}
mutex_unlock(&list_lock);
return entry;
}
消费者 kthread 实现:
#include <linux/kthread.h>
#include <linux/sched.h>
int consumer_kthread(void *data) {
struct some_struct *entry;
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
/* Here the function including the semaphore is called */
entry = take_from_list();
if(entry != NULL) {
/* Do something with 'entry' here */
} else {
/* Some handling of returned NULL pointers */
}
set_current_state(TASK_INTERRUPTIBLE);
}
set_current_state(TASK_RUNNING);
return 0;
}
模块实现:
#include <linux/init.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/sched.h>
static struct task_struct *consumer_task;
static int __init initModule(void) {
consumer_task = kthread_run(consumer_kthread, NULL, "list-consumer");
return 0;
}
static void __exit exitModule(void) {
/* this call will cause rmmod to freeze forever */
kthread_stop(consumer_task);
}
module_init(initModule);
module_exit(exitModule);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("My Module");
最佳答案
缺少代码意味着这个答案只能使用有根据的猜测。
以下是我对您丢失的代码的假设:
如果 take_from_list
返回一个有效的条目,consumer_kthread
对该条目做一些事情并调用 up(&sem_list_consumer)
来匹配调用到 take_from_list
中的 down_interruptible(&sem_list_consumer)
。
如果 take_from_list
返回 NULL
,consumer_kthread
会对 NULL
指针进行一些处理,并假定sem_list_consumer
信号量处于其原始状态。
鉴于这些假设,take_from_list
中存在一个错误,因为它有时返回 NULL
而没有先调用 up(&sem_list_consumer)
。这意味着对 take_from_list
的任何后续调用都将阻塞对 down_interruptible(&sem_list_consumer)
的调用,直到它们被信号中断。要修复该错误,请将 take_from_list
更改为在返回 NULL
时始终将信号量保持在它离开时的状态:
struct some_struct * take_from_list() {
int rv;
some_struct *entry;
rv = down_interruptible(&sem_list_consumer);
if(rv != 0) {
return NULL;
}
rv = mutex_lock_interruptible(&list_lock);
if(rv != 0) {
up(&sem_list_consumer);
return NULL;
}
if (list_empty(&list)) {
mutex_unlock(&list_lock);
up(&sem_list_consumer); /* <-- this line was missing */
return NULL;
} else {
entry = list_last_entry(&list, struct some_struct, list);
if (entry) {
list_del(&entry->list);
}
}
mutex_unlock(&list_lock);
return entry;
}
修改
如果 consumer_kthread
的缺失代码中有某个地方将自己添加到等待队列并进入休眠状态,则应包含对 kthread_should_stop()
的调用唤醒条件。唤醒条件应由其他条件满足 OR (||
) kthread_should_stop()
。
从 exitModule
函数调用 kthread_stop(consumer_task)
将唤醒消费者线程。如果它正在等待一个事件,它要做的第一件事就是检查唤醒条件,如果不满足则返回休眠状态。通过将 kthread_should_stop()
作为可能的唤醒条件之一,您可以确保使用者线程不会立即返回 sleep 状态。
关于c - Linux 内核 - 如何停止等待信号量的 kthread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40148586/
我正在使用 Tkinter 在 python 上写一个小游戏(顺便说一下,我不允许使用任何其他非内置模块)并且我想在主窗口上播放背景歌曲,这是那个包含标题,以及转到其他窗口和内容的按钮... 所以问题
我有一个 Azure WebJob,它在一个非常简单的应用服务标准:1 Small(计划)上运行。 现在,我的 WebJob(有 5 个函数正在运行)出现问题 - 我想停止 5 个正在运行的函数中的
我在 MacOS Lion 上使用 XCode 4.2。在模拟器中调试 iPhone/iPad 应用程序时,我使用 XCode 工具栏上的“停止”按钮(产品 | 停止)退出应用程序。在此之后,XCod
我刚刚下载了android开放源代码项目,并尝试使用make来构建它,我收到了以下消息: build/core/prebuilt.mk:91: *** recipe commences before
我以前从未制作过 makefile,但我们已经收到了这个,但是,如果我尝试运行它,它只会说, missing separator. stop. 我不知道可能出了什么问题 - 我已经确保空格只按制表符。
好吧,这段代码非常基本。用户将答案输入文本框,如果等于“第一+第二”,他们就得到一分。然后,他们有 5 秒钟的时间回答下一个数学问题。如果他们这样做了,函数“doCalculation”将再次运行,他
我在 viewController 中有一个循环动画 - (void)moveAnimating { [UIView animateWithDuration:2.0f animations:^
当我有一个待处理的 ASIFormDataRequest(作为异步任务启动)仍在执行并且用户按下后退按钮(为了弹出 View )时,我的 viewController 出现问题。 有什么方法可以停止该
我们正在使用 flashdevelop 和 flash CS 3 开发基于 flash 的游戏。我们正在使用 flash CS3 发布 swc,swc 将作为库在 flashdevlop 中使用。 一
我在线程中有一个连接,因此我将其添加到运行循环中以获取所有数据: [[NSRunLoop currentRunLoop] run]; [connection scheduleInRunLoop
你好,我做了一个 php 套接字服务器来从 plc 获取数据,plc 被配置为 tcp 套接字客户端。 我有一个严重的问题,如果本地网络出现故障,似乎功能 socket_accept 停止,plc 无
这个问题已经有答案了: How to stop a setTimeout loop? (10 个回答) 已关闭 8 年前。 请帮助获得正确的函数或方法来停止 setTimeout 函数。 我一直在尝试
我正在运行一个多项目SBT(v0.13)构建,并且希望它在子项目中遇到的第一个错误(编译)时快速失败(停止)。 当前的行为是,当某项无法在子项目中进行编译时,构建将继续(以编译所有其他子项目)。 一旦
我有播放.wav文件中声音的代码,但是我无法停止播放歌曲,甚至无法退出程序直到播放结束。因为这是一首5分钟的歌曲,所以这是一个问题。这是我如何播放wav的代码: public class EasySo
我正在寻找一种解决方案,该如何控制从JSF应用程序播放音频文件。 我不需要完整的解决方案,只需引用我可以用来控制播放音频文件(开始/停止/更改声音)的组件即可。 我尝试搜索过去的问题,但没有成功。 我
我已经在test.ps1中编写了以下函数,在运行该脚本以启动/停止/ ..时我想做一个选择: function getState($SeviceName) { $server = @('hos
我必须设置一个 10 分钟的计时器,它会重定向到主屏幕。此外,它必须在每个操作(例如按下按钮)时重置。我找到了这个计时器:https://github.com/fengyuanchen/vue-cou
我正在制作一个聊天应用程序,功能之一就是发送声音。发送的HTML如下: LOL Stop Play 第一次发送时,“自动播放”效果很好。因此,现在我
我基本上希望页面能够接受用户输入的时间(以秒为单位)。 之后我希望当用户按下“开始”按钮时开始倒计时按下暂停按钮时“暂停”。还有一个重置按钮,以便用户可以从头开始倒计时。 这是我到目前为止得到的:
我需要停止 $.each 循环,加载图像,然后继续循环。我有 Canvas ,可以在其中加载对象图像。对象以正确的顺序排列在数组中。现在,当我尝试从数组加载对象时,存在一个问题:由于尺寸不同,并且它们
我是一名优秀的程序员,十分优秀!