一,内核实例分析
先来分析一下一个实例,这个例子主要是创建一个内核线程,用来打印GPIO信息,当线程没有收到停止的指令时,一直打印。
int config_gpio_thread(void *tmp_gpio_num) //回调函数,返回值必须是int ,且参数必须是void *
{
int gpio_num = *((int *)tmp_gpio_num);//类型强转,由void*转成int*,取值
while(!kthread_should_stop()) //当kthread_should_stop()函数没有被调用的时候,就一直打印。
{
gpio_direction_output(gpio_num, 0);
printk("the gpio get a value of :%d:=========buqing.wang test \n",__gpio_get_value(gpio_num));
msleep(500);
gpio_direction_output(gpio_num, 2);
printk("the gpio get a value of :%d:=============buqing.wang test \n",__gpio_get_value(gpio_num));
msleep(500);
}
return 0;
}
//具体的操作部分
int handle_gpio_thead(int num)
{
struct task_struct * gpio_thread; //任务结构体
void* gpio_num;
gpio_num=#
gpio_thread=kthread_create(config_gpio_thread,&gpio_num,"gpio_thread");//第二个参数是回调函数的参数,必须是void*
wake_up_process(gpio_thread); //唤醒线程开始工作
msleep(5000); //5s后,叫停线程
kthread_stop(gpio_thread);//这个函数调用后,kthread_should_stop()返回值由false变成true
return 0;
}
二,关于线程创建相关的API
创建Kthread主要有两种方法
第一种就是如上所述:
kthread_create(threadfn, data, namefmt, arg…),宏,返回一个task_struct *类型的数据址。创建线程任务,threadfn 线程的回调函数,data是参数,那么format是线程名字。
回调函数返回值必须是int,参数必须是void*
wake_up_process(gpio_thread),启动线程
第二种方法:
kthread_run(threadfn, data, namefmt, …) 直接创建线程并且启动
其他线程相关的API:
int kthread_stop(struct task_struct *k); //让线程结束
bool kthread_should_stop(void); //判断线程状态
参考文件:
kernel/include/linux/kthread.h
#ifndef _LINUX_KTHREAD_H
#define _LINUX_KTHREAD_H
/* Simple interface for creating and stopping kernel threads without mess. */
#include <linux/err.h>
#include <linux/sched.h>
__printf(4, 5)
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data,
int node,
const char namefmt[], ...);
#define kthread_create(threadfn, data, namefmt, arg...) \
kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
void *data,
unsigned int cpu,
const char *namefmt);
/**
* kthread_run - create and wake a thread.
* @threadfn: the function to run until signal_pending(current).
* @data: data ptr for @threadfn.
* @namefmt: printf-style name for the thread.
*
* Description: Convenient wrapper for kthread_create() followed by
* wake_up_process(). Returns the kthread or ERR_PTR(-ENOMEM).
*/
#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; \
})
void kthread_bind(struct task_struct *k, unsigned int cpu);
int kthread_stop(struct task_struct *k);
bool kthread_should_stop(void);
bool kthread_should_park(void);
bool kthread_freezable_should_stop(bool *was_frozen);
void *kthread_data(struct task_struct *k);
void *probe_kthread_data(struct task_struct *k);
int kthread_park(struct task_struct *k);
void kthread_unpark(struct task_struct *k);
void kthread_parkme(void);
int kthreadd(void *unused);
extern struct task_struct *kthreadd_task;
extern int tsk_fork_get_node(struct task_struct *tsk);
/*
* Simple work processor based on kthread.
*
* This provides easier way to make use of kthreads. A kthread_work
* can be queued and flushed using queue/flush_kthread_work()
* respectively. Queued kthread_works are processed by a kthread
* running kthread_worker_fn().
*/
st