Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1204445
  • 博文数量: 185
  • 博客积分: 495
  • 博客等级: 下士
  • 技术积分: 1418
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-02 15:12
个人简介

治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu

文章分类

全部博文(185)

文章存档

2019年(1)

2018年(12)

2017年(5)

2016年(23)

2015年(1)

2014年(22)

2013年(82)

2012年(39)

分类: LINUX

2013-05-08 16:34:22

创建内核线程比较常用的接口有:kthread_create, kthread_run,这是kernel.h里面的两个宏,原型如下:
#define kthread_create(threadfn, data, namefmt, arg...) \
    kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
参数有四个:
threadfn---创建的线程需要执行的任务函数,类型是 int (*thread)(void *data)
data---传送给任务函数的参数
namefmt,arg---创建的内核线程的名字,也就是通过ps 看到的名字
这仅仅是创建一个线程实例,启动它还是需要wake_up_process来唤醒并运行它。

#define kthread_run(threadfn, data, namefmt, ...)               \
({                                       \
    struct task_struct *__k                           \
        = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
    if (!IS_ERR(__k))                           \
        wake_up_process(__k);                       \
    __k;                                   \
})
kthread_create的自启动版本,其实就是多了一个wake_up_process。

kthread_create其实是调用的函数:kthread_create_on_node,这是一个节点情缘性的函数,创建的节点将在指定的numa节点上分配内存,
这里需要注意的是内存分配在指定的numa节点上,但是cpu调度不是限定在此节点上的cpu上的。
这个在numa系统中是非常有用的,在用户态可以使用类似的numactl的功能将特定的进程绑定到对应的numa节点上。对于内核线程同样有这种需求,
例如数据库的后台日志线程就有可能使用这种方式创建的。
函数原型如下:
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's) priority or CPU mask.
         * The kernel thread should not inherit these properties.
         */
      /*这个是主动地去干预调度策略*/   
        sched_setscheduler_nocheck(create.result, SCHED_NORMAL, ¶m);
        set_cpus_allowed_ptr(create.result, cpu_all_mask);
    }
    return create.result;
}
这个函数是EXPORT_SYMBOL(kthread_create_on_node);在模块里面是可以使用的。


此外还有一个就是在指定的cpu上创建内核线程的函数:kthread_create_on_cpu,原型如下:
struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
                      void *data, unsigned int cpu,
                      const char *namefmt)
{
    struct task_struct *p;

   /*调用kthread_create_on_node在cpu所属的节点上创建线程*/
    p = kthread_create_on_node(threadfn, data, cpu_to_node(cpu), namefmt,
                   cpu);
    if (IS_ERR(p))
        return p;
    set_bit(KTHREAD_IS_PER_CPU, &to_kthread(p)->flags);
    /*设置线程的cpu*/
    to_kthread(p)->cpu = cpu;
    /* Park the thread to get it out of TASK_UNINTERRUPTIBLE state */
    /*设置线程到park状态,这样以后才能使用wake_up_on唤醒它*/
    kthread_park(p);
    return p;
}
此函数是内部函数,也就是说在模块内部是无法使用的。

此外还有一些非常有用的系统函数:
void kthread_bind(struct task_struct *p, unsigned int cpu)
{
    __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(kthread_bind);
绑定一个新创建的线程到指定的cpu上,这个跟kthread_create_on_cpu有点功能相似。

int kthread_park(struct task_struct *k)
{
    struct kthread *kthread = to_live_kthread(k);
    int ret = -ENOSYS;

    if (kthread) {
        if (!test_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
            set_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
            if (k != current) {
                wake_up_process(k);
                wait_for_completion(&kthread->parked);
            }
        }
        ret = 0;
    }
    return ret;
}
切换线程到park状态。


int kthread_stop(struct task_struct *k)
{
    struct kthread *kthread;
    int ret;

    trace_sched_kthread_stop(k);

    get_task_struct(k);
    kthread = to_live_kthread(k);
    if (kthread) {
        set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
        __kthread_unpark(k, kthread);
        wake_up_process(k);
        wait_for_completion(&kthread->exited);
    }
    ret = k->exit_code;
    put_task_struct(k);

    trace_sched_kthread_stop_ret(ret);
    return ret;
}
EXPORT_SYMBOL(kthread_stop);
停止一个使用kthread_create创建的线程。



阅读(3915) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~