免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4567 | 回复: 9
打印 上一主题 下一主题

怎么获得内核线程的id,怎么撤销正在工作的work_struck [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-04-09 16:16 |只看该作者 |倒序浏览
本帖最后由 superlzdcn 于 2011-04-14 13:23 编辑

在一个工作队列调用的函数想打印出执行这个工作队列的线程的id,请问大家怎么办的呢
是否是用current?如果不是在进程上下文怎么打印?
请问如何cancel正在执行的工作函数,发现如果工作函数正在执行的话,cancel_delayed_work返回0,没有cancel成功
先谢谢大家

论坛徽章:
0
2 [报告]
发表于 2011-04-11 13:44 |只看该作者
工作队列一定在进程上下文中,这个不需要担心。

论坛徽章:
0
3 [报告]
发表于 2011-04-11 17:15 |只看该作者
如果在中断例程中调用的工作队列,那么current又是什么呢?

论坛徽章:
0
4 [报告]
发表于 2011-04-11 18:44 |只看该作者
兄弟,在中断例程中,你管线程干个鸟?它又不再中断上下文中。

况且,中断结束后,会发生调度的,这个没有任何意义

打印就用printk

论坛徽章:
2
申猴
日期:2013-12-26 22:11:31天秤座
日期:2014-12-23 10:23:19
5 [报告]
发表于 2011-04-11 18:51 |只看该作者
match_comm,循环遍历

论坛徽章:
0
6 [报告]
发表于 2011-04-12 06:05 |只看该作者
用CURRENT, 当前的如果不是你关心的线程(进程),就遍历一遍所有PROCESS,找到你要的那个,然后再打。。。

我好像在这里发过一个找CURRENT和所有线程的帖子,COPY如下:

======================================

QEMU小实验:手工遍历所有进程的方法

在内核中已经提供了遍历所有进程的方法,比如用for_each_process宏。但是如果你想加深对这部分的了解,那么可以不用这个宏,完全手工遍历一遍。下面介绍了在QEMU中,利用QEMU MONITOR,手工找出所有PROCESS的方法

环境:
QEMU 0.9.1
QEMU VM: CENT OS 5.3 (LINUX 2.6.18 )
ARCH :X86-32

主要思路:
我们已经知道LINUX中的所有进程都对应一个TASK_STRUCT. 同时这些TASK_STRUCT里面有一个成员叫做TASKS。它的类型是一个LIST_HEAD(有NEXT, PRE2个成员,构成一个双向链表)。所有的进程就是通过这个TASK_STRUCT里的TASKS连接在一起的。

想遍历进程的话,可以找到一个上面说的结构,然后顺着链表一个一个找下去。另外,还有一些重要的信息在TASK_STRUCT中。常用的有PID(线程ID), TGID(进程ID), COMM(进程的命令参数)。
(关于PID, TGID,可以看下面这个帖子:http://linux.chinaunix.net/bbs/thread-1155667-1-1.html

如果是在GDB里,那么找到了TASK_STRUCT之后,可以直接用 p task->pid 的方法来把PID之类的打印出来。但是我们的目的就是不用GDB的功能,而只用QEMU MONITOR的功能,纯手工的找出PID这些成员。

这样一来,我们需要自己计算下PID, TGID等成员在TASK_STRUCT中的偏移量。怎么算呢?最天真的办法是按照 .H 文件里TASK_STRUCT的声明,自己一个一个算过去,比如一个CHAR占一个字节,一个INT 4个字节等。但是由于TASK_STRUCT是一个很大的结构(包括几十或者上百个成员),同时考虑到编译的时候还有对齐的问题。这样手工算可以说既费力又不一定对。

最厉害的办法是自己写个类似的C编译器,直接把编译后的输出打印出来。感兴趣的可以看看CIL(C Intermediate Language)。但是CIL还是有点麻烦的。它是用OCAML语言写的。我不是很熟悉。

于是我采用了一个比较折中的办法:自己写个KERNEL MODULE, 在这个MODULE里直接定义一个TASK_STRUCT,然后把感兴趣的那些成员的地址和基地址都打印出来。或者直接把偏移量打印出来。

我就是用上述办法得到了几个关键成员的偏移量:
(前面是TASK_STRUCT里的成员,后面是它距离TASK_STRUCT基地址的偏移量)
pid = 0Xbc
tgid = 0Xc0
comm = 0X1AC
tasks = 0X80

还有一点,我们怎么找到第一个TASK_STRUCT呢?可以看这篇文章(如何找出CURRENT):
http://linux.chinaunix.net/bbs/v ... =1147973&extra=

好了,万事具备,开始行动吧。
1) 运行一个QEMU VM。我是在WINDOWS HOST上跑的QEMU. 在LINUX上也可以跑QEMU。但是LINUX上的QEMU有一点不好,那就是它的QEMU MONITOR的大小是固定的。太小了。而在WINDOWS上面,QEMU MONITOR可以变得很大。

2) 按ALT+CTRL+2, 切换到QEMU MONITOR. 输入STOP. 这样QEMU 就会暂停下来了。这样的好处是你可以花很多时间来遍历进程。而不用担心某个进程结束后,带来的地址无效的问题。

3) p $esp :找出当前的ESP。我实验的时的输出是 0xc3a94f78

4) 找出THREAD_INFO:也就是把ESP与上0XFFFFE000。得到0xc3a94000

5) x /20w 0xc3a94000。显示的这个内容的第一个指针(前4个字节)就是当前进程的TASK_STRUCT。因为THREAD_INFO里的第一个成员就是struct task_struct *task
我这里得到的结果是0xc3aaa370。

(注意:有的时候这个地方显示的数据全都是0。我怀疑是因为进程正在切换中,内核栈刚刚清空。碰到这种情况,可以在QEMU MONITOR里输入c, 让QEMU继续跑一段时间,然后输入stop. 从头开始。有时要多试几次)

6) 找到了TASK_STRUCT之后,根据前面找到的偏移量,可以方便的找到PID, TGID, COMM, TASKS 等成员的值。比如PID的位置在0xc3aaa42c (TASK+0XBC)。
注意,在看COMM的时候,要用下面这个命令: x /20b 0xc3aaa51c. 否则的话,QEMU会把数据当成DWORD处理,并自动转换Endian. 使得看到的字符串的顺序是反过来的。

7) 这样一来,当前进程的信息已经知道了 。在我的输出中,PID,TGID=0,COMM=SWAPPER. 我们开始找下一个。下一个进程是通过TASK_STRUCT->TASKS 连接在一起的。有一点要注意,TASK_STRUCT->TASKS->NEXT中的地址不是下个TASK_STRUCT的起始地址,而是下个TASK_STRUCT中的TASKS的地址。所以有了这个地址后,要先减去0X80才得到基地址。然后就可以用上面的方法找出PID, TGID, COMM来了。

论坛徽章:
0
7 [报告]
发表于 2011-04-12 09:48 |只看该作者
今天来看到大家回复的真不少,谢谢大家热心的回复啦

论坛徽章:
0
8 [报告]
发表于 2011-04-13 16:15 |只看该作者
期待高人。。。。

论坛徽章:
0
9 [报告]
发表于 2011-04-14 13:25 |只看该作者
尝试了cancel_delayed_work,直接返回0,work_struct还在运行
尝试了destroy_workqueue,这个函数会block直到work_struct结束
还有神马办法呀,高手在哪里呀?

论坛徽章:
0
10 [报告]
发表于 2011-04-14 19:06 |只看该作者
线程的ID不就是父进程的ID吗? 难道我记错了?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP