我正在编写一些内核驱动程序,我需要检查哪个线程正在另一个核心上的某个点上运行。我的驱动程序在每个核心上运行一个内核线程,我需要不时地同步一些线程来执行某些任务。我从调试日志中可以看到的是,有时一个线程会等待一些其他线程太多。我做了一些补丁,我将__preempt_count
存储在其他核心上,以检查是否有任何softirq / hardirq或preemption禁用延迟我的线程。
我还使用FTRACE来检查irqsoff和preemptirqsoff,以确保关闭IRQ和禁用抢占的最大持续时间。
直到现在我能够发现kerneloops线程,它禁止中断最多20毫秒,我发现太长了。
做了systemctl disable kerneloops
并摆脱了这个问题。
现在我似乎处理了一些抢先禁用的窗口。为了将来分析这个驱动程序,我需要一种方法来确定在其他核心上的特定时间点正在执行哪些线程。我尝试使用FTRACE主要用于IRQ进入/退出的事件,我还使用trace_printk
在ftrace缓冲区中推送一些调试日志,以便在一个日志中包含所有内容等。
但是,我想要做的一件事是访问其他核心的current_task
结构(current
ptr)并打印comm
字段,该字段给出了任务(或pid值)。
但是我很难完成这件事。
对于__preempt_count
我没有问题:
int *p = per_cpu_ptr(&__preempt_count,cpu);
pr_info("Preempt count of cpu%u is 0x%08x\n",cpu,*p);
到目前为止,我没有声明或访问每个cpu变量的问题,但由于某种原因,current_task
指针在尝试访问时会触发页面错误。
char buf[10];
struct task_struct *task = per_cpu_ptr(current_task,cpu);
snprintf(buf,8,"%s",task->comm);
pr_info("Task name: %s",buf);
上面的代码触发总是页面错误,NULL ptr bla bla。
到目前为止我无法找到原因。我试图打印task
的指针值,我得到了相同的页面错误。
可能是因为其他核心无法访问该地址吗?在内核空间不应该是afaik的情况。到目前为止,我对每个核心变量也没有任何问题,而且我在这方面发挥了很多作用。
结论:访问current_task
其他核心并打印comm / pid字段的正确方法是什么?
非常感谢,
丹尼尔
答案 0 :(得分:0)
我终于弄清楚出了什么问题。
__preempt_count
和current_task
之间的区别在于第一个被定义为int变量,而第二个被定义为结构的指针。换句话说,第一个被定义为变量而第二个被定义为指针。
现在,深入研究每个cpu变量,它们只是编译器在单独的内存位置(如数组)分配的变量。当调用变量Foo的per_cpu_ptr
时,宏会计算类似Foo[cpu]
的内容,但这意味着per_cpu_ptr
需要变量的实际基址,这意味着&
这样它就可以从这开始计算相对地址值。
声明:foo = per_cpu_ptr(&__preempt_count,cpu)
时,此地址已被赋予= &__preempt_count
在声明:bar = per_cpu_ptr(current_task,cpu)
时,未提供此地址,因为此处缺少&
。 current_task是一个指针,但不是current_task数组的基地址。
在上述两种情况下,per_cpu_ptr
的参数都是一个指针,但在这里我的理解是错误的,我不清楚实际上我需要传递的变量的指针是什么,现在它是'清楚:我必须传递变量的基址(var或指针不重要),以便宏可以计算该cpu的相对地址。
因此正确的方法是:
bar = per_cpu(current_task,cpu)
转换为*per_cpu_var(¤t_task,cpu)
或
bar = *per_cpu_var(¤t_task,cpu);