首先来区分一下进程和线程,新手上路,各位大神多多指教;
在中断服务程序、内核软中断服务程序以及其他设备驱动程序的设计中,注意不能让这些函数嵌套太深,不宜使用太多、太大的局部变量,入以下例子;
int function()
{
char buf [1024]; //buf为局部变量,在堆栈中消耗了1KB
...............
}
进程task_struct结构以及系统空间堆栈的特殊安排,决定了内核中的一些宏定义;
#define THREAD_SIZE (2*PAGE_SIZE)
//2的1次方个PAGE_SIZE
#define alloc_task_struct() (struct_task_struct*)get_free_pages(GFP_KERNEL,1);
#define free_task_struct(p) free_pages((unsigned long) (p), 1);
static __always_inline struct task_struct *get_current(void)
{
unsigned long sp_el0;
asm ("mrs %0, sp_el0" : "=r" (sp_el0));
return (struct task_struct *)sp_el0;
}
#define current get_current()
current.h定义了一个宏操作指向当前进程的task_struct结构的指针;
AND指令需要4个CPU时钟周期,从寄存器到寄存器MOV指令只需要2个时钟周期;
task_struct结构体在include/linux/sched.h中给出定义,太大了就不往这里粘贴了,一起学一学重要的数据结构;
#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
* For reasons of header soup (see current_thread_info()), this
* must be the first element of task_struct.
*/
struct thread_info thread_info;
#endif
/* -1 unrunnable, 0 runnable, >0 stopped: */
volatile long state;
/* Used in tsk->state: */
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define __TASK_STOPPED 4
#define __TASK_TRACED 8
/* Used in tsk->exit_state: */
#define EXIT_DEAD 16
#define EXIT_ZOMBIE 32
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
/* Convenience macros for the sake of set_current_state: */
#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)
#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)
state表示进程的当前状态,其各自含义如下所示;
代码中的flag也反映进程管理有关的其他信息sched.h;
/*
* Per process flags
*/
#define PF_IDLE 0x00000002 /* I am an IDLE thread */
#define PF_EXITING 0x00000004 /* Getting shut down */
#define PF_EXITPIDONE 0x00000008 /* PI exit done on shut down */
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */
#define PF_FORKNOEXEC 0x00000040 /* Forked but didn't exec */
#define PF_MCE_PROCESS 0x00000080 /* Process policy on mce errors */
#define PF_SUPERPRIV 0x00000100 /* Used super-user privileges */
#define PF_DUMPCORE 0x00000200 /* Dumped core */
#define PF_SIGNALED 0x00000400 /* Killed by a signal */
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
#define PF_NPROC_EXCEEDED 0x00001000 /* set_user() noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH 0x00002000 /* If unset the fpu must be initialized before use */
#define PF_USED_ASYNC 0x00004000 /* Used async_schedule*(), used by module init */
#define PF_NOFREEZE 0x00008000 /* This thread should not be frozen */
#define PF_FROZEN 0x00010000 /* Frozen for system suspend */
#define PF_KSWAPD 0x00020000 /* I am kswapd */
#define PF_MEMALLOC_NOFS 0x00040000 /* All allocation requests will inherit GFP_NOFS */
#define PF_MEMALLOC_NOIO 0x00080000 /* All allocation requests will inherit GFP_NOIO */
#define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
#define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK 0x80000000 /* This thread called freeze_processes() and should not be frozen */
除了state和flag之外,反映当前状态的还有一些,比如说sigpending、counter、nee_sched、add_limit、Personality等;
说了这么多,我在内核驱动中如何获取线程的状态呢?
从简单到复杂吧,先看看怎么遍历所有的线程;
//thread.c
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // KERN_INFO
#include <linux/sched.h> // for_each_process, pr_info
void procs_info_print(void)
{
struct task_struct* task_list;
size_t process_counter = 0;
for_each_process(task_list) {
pr_info("== %s [%d]\n", task_list->comm, task_list->pid);
++process_counter;
}
printk(KERN_INFO "== Number of process: %zu\n", process_counter);
}
int init_module(void)
{
printk(KERN_INFO "[ INIT ==\n");
procs_info_print();
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "== CLEANUP ]\n");
}
MODULE_LICENSE("GPL");
Makefile:
obj-m += thread.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
实际效果:
............................
[10585.922885] == telepathy-indic [2210]
[10585.922885] == mission-control [2218]
[10585.922886] == zeitgeist-daemo [2246]
[10585.922886] == zeitgeist-fts [2252]
[10585.922887] == zeitgeist-datah [2254]
[10585.922888] == cat [2265]
[10585.922888] == cupsd [2279]
[10585.922889] == update-notifier [2311]
[10585.922890] == deja-dup-monito [2333]
[10585.922891] == gnome-terminal [2341]
[10585.922891] == gnome-pty-helpe [2351]
[10585.922892] == bash [2352]
[10585.922893] == kworker/u256:1 [3710]
[10585.922893] == kworker/u256:2 [3908]
[10585.922894] == sudo [4776]
[10585.922894] == insmod [4777]
[10585.922895] == Number of process: 226
那怎么根据输入的进程名得到task_struct结构体呢;
//thread.c
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // KERN_INFO
#include <linux/sched.h> // for_each_process, pr_info
#include <linux/pid.h> //find_get_pid
#include <linux/string.h>
struct task_struct *find_task(char *find_name)
{
struct task_struct* task_list;
size_t process_counter = 0;
for_each_process(task_list) {
// pr_info("== %s [%d]\n", task_list->comm, task_list->pid);
if(!strcmp(task_list->comm,find_name)){
printk("%s (pid=%d, comm=%s)\n", __func__, task_list->pid, task_list->comm);
return task_list;
}
else{
++process_counter;
}
}
printk(KERN_INFO "== Number of process: %zu\n", process_counter);
return 0;
}
static int __init thread_init(void)
{
char *find_name = "kthreadd";
struct task_struct* task;
printk(KERN_INFO "[ INIT ==\n");
printk("%s (pid=%d, comm=%s)\n", __func__, current->pid, current->comm);
task = find_task(find_name);
// printk("%s (pid=%d, comm=%s)\n", __func__, task->pid, task->comm);
printk("the thread state is: %lu %d\n",task->state,task->flags);
return 0;
}
static void __exit thread_exit(void)
{
printk(KERN_INFO "== CLEANUP ]\n");
}
module_init(thread_init);
module_exit(thread_exit);
// 模块信息
MODULE_LICENSE("GPL");
MODULE_AUTHOR("curtis li");
效果如下,成功将task_struckt指针返回到thread_init:
[16924.131582] [ INIT ==
[16924.131584] thread_init (pid=14615, comm=insmod)
[16924.131586] find_task (pid=2, comm=kthreadd)
[16924.131586] the thread state is: 1 2129984
[17549.520333] == CLEANUP ]
我们之前的提的问题,如何知晓某一特定进程的状态;
对dmesg信息进行分析,此进程的状态为(1 --> #define TASK_INTERRUPTIBLE 1 )也就是说当前出于stop的状态,可以被唤醒;flags的值为 2129984 --> 0x208040,对号入座查找flags的宏;
#define PF_FORKNOEXEC 0x00000040 /* Forked but didn't exec */
#define PF_NOFREEZE 0x00008000 /* This thread should not be frozen */
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
到这里怎么获取一个进程的状态就告一段落了;