今天定位一个问题,本来是用ftrace查看调度轨迹,希望能看出有什么一场调度,结果偶然看到系统中存在两个swapper进程,一个进程号为0,一个进程号为3。进程号为0是正常情况下都应该有的,但是对于一个单核cpu来说,竟然还有一个3号swapper进程,就显得太奇怪了,于是看看代码,最后发现竟然是kernel_thread的问题。
为了定位问题,在初始化start_kernel中调用了一个函数,函数中使用了kernel_thread,创建一个新的内核线程,怀疑这个swapper就是创建的这个线程。于是查看kthread_create怎么给线程命名,代码如下:(所有代码内核版本均为3.12)
-
#define kthread_create(threadfn, data, namefmt, arg...) \
-
kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
继续查看kthread_create_on_node函数,如下:
-
/**
-
* kthread_create_on_node - create a kthread.
-
* @threadfn: the function to run until signal_pending(current).
-
* @data: data ptr for @threadfn.
-
* @node: memory node number.
-
* @namefmt: printf-style name for the thread.
-
*/
-
-
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
-
void *data, int node,
-
const char namefmt[],
-
...)
-
{
-
struct kthread_create_info create;
-
-
create.threadfn = threadfn;
-
create.data = data;
-
create.node = node;
-
init_completion(&create.done);
-
-
spin_lock(&kthread_create_lock);
-
list_add_tail(&create.list, &kthread_create_list);
-
spin_unlock(&kthread_create_lock);
-
-
wake_up_process(kthreadd_task);
-
wait_for_completion(&create.done);
-
-
if (!IS_ERR(create.result)) {
-
static const struct sched_param param = { .sched_priority = 0 };
-
va_list args;
-
-
va_start(args, namefmt);
-
vsnprintf(create.result->comm, sizeof(create.result->comm),
-
namefmt, args);
-
va_end(args);
-
/*
-
* root may have changed our (kthreadd
将name复制给了create.result->comm字段,那么create.result->comm又是什么呢?继续看代码,
-
struct kthread_create_info
-
{
-
/* Information passed to kthread() from kthreadd. */
-
int (*threadfn)(void *data);
-
void *data;
-
int node;
-
-
/* Result passed back to kthread_create() from kthreadd. */
-
struct task_struct *result;
-
struct completion done;
-
-
struct list_head list;
-
};
result字段是task_struct结构指针,看到这里,kthread_create怎样给新创建的函数取名流程也就一清二楚了。
那么kernel_thread又是怎么取名字的呢?为什么我们用kernel_thread创建的线程名字会是swapper呢?继续看代码:
-
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-
{
-
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
-
(unsigned long)arg, NULL, NULL);
-
}
可以看到kernel_thread直接调用do_fork函数,而do_fork函数我们知道,就是将父进程的地址空间直接复制给子进程,所以名字也是一样的,而我们当时调用kernel_thread的时间比较早,是在初始化时由swapper创建的,所以继承了swapper的名字,也就不足为奇了。
那么接下来的问题就是怎么给kernel_thread创建的线程取名呢?内核还有一个daemonize的接口,专门用来取名,在kernel_thread的函数指针所指向的函数中调用daemonize函数,然后重新编译内核,启动,发现3号线程的名字果然就是自己用daemonize所取得线程名字了。
阅读(3943) | 评论(0) | 转发(0) |