Linux-内核模块开发


前言:最近在做入职公司的操作系统培训作业,其中第三个作业是关于Linux内核模块开发的,于是乎又重新拿起了Linux设备驱动程序这本书,看起了申嵌视频,在CSDN上写写学习笔记,在校的最后一个月蛋疼中。。。。。。

首先来看两段最基础的代码,一个可以动态加载进内核的代码和一个Makefile:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#define DRIVER_AUTHOR "sty"
#define DRIVER_DESC "HELLO DRIVER"

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

int __init hello_init(void)
{
	printk(KERN_INFO "HELLO WORLD\n");
	return 0;
}

void __exit hello_exit(void)
{
	printk(KERN_INFO "goodbye world\n");
}

module_init(hello_init);
module_exit(hello_exit);

ifeq ($(KERNELRELEASE),)#假如变量$(KERNELRELEASE)不等于空,执行下面的语句,否则执行else下面的语句

KERNELDIR ?=/lib/modules/$(shell uname -r)/build#内核源代码的路径,build这个其实是个连接文件,会连接到源代码目录(需要变)

PWD := $(shell pwd)#表示内核模块在当前目录下,modules表示编译的是内核

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules#进入到$(KDIR)目录下使用它自己的makefile

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
    obj-m := hello.o
endif

三个常用命令:加载 insmod (insmod hello.ko),装载时会调用module_init指定函数;卸载 rmmod (rmmod hello),卸载也会调用指定函数;查看 lsmod加载 modprobe (modprobe hello)。

modprobe如同insmod,也是加载一个模块到内核。它的不同之处在于它会根据文件/lib/modules/<$version>/modules.dep查看要加载的模块,看它是否还依赖于其他模块,如果是,modprobe会首先找到这些模块,把它们加载到内核。

而printk()是调试内核的常用手段,打印信息会在dmesg,而不是在终端上,调试前最好用dmesg -c清除掉以前历史信息。


与应用程序对比。内核模块有以下不同:

应用程序从头(main)到尾执行任务,执行结束后从内存中消失。内核模块则是先在内核中注册自己以便于服务将来的某个请求,然后它的初始化函数结束,此时模块仍然存在于内核中,直到卸载函数被调用,模块才从内核中消失。模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。

     


                                                                                


                                          

内核线程模块程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/completion.h>       // for DECLARE_COMPLETION()
#include <linux/jiffies.h>
#include <linux/param.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>            
#include <linux/delay.h>            // mdelay()
#include <linux/kthread.h> 
#include <linux/cdev.h>

static int kthread_major = 0;
static struct cdev kThreadDevs;//表示的是字符设备的内核的内部结构

#define DRIVER_AUTHOR "sty"
#define DRIVER_DESC "KTHREAD DRIVER"
#define BEEP_MAGIC 'k'

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

static struct task_struct *task;
int flag = 0;

/*
 * Open the device; in fact, there's nothing to do here.
 */
int k_thread_open (struct inode *inode, struct file *filp)
{
	printk(KERN_INFO "k_thread_open!!!\n");
	return 0;
}
ssize_t k_thread_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
{
	printk(KERN_INFO "k_thread_read!!!\n");
	return 0;
}
ssize_t k_thread_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
	printk(KERN_INFO "k_thread_write!!!\n");
	return 0;
}
static long k_thread_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	printk(KERN_INFO "k_thread_unlock_ioctl!!!\n");
	return 0;
}
static int k_thread_release(struct inode *node, struct file *file)
{
	printk(KERN_INFO "k_thread_release!!!\n");
	return 0;
}

/*
 * Our various sub-devices.
 */
/* Device 0 uses remap_pfn_range */
static struct file_operations kThread_remap_ops = {  //这种结构将设备节点与驱动程序关联起来,实现了系统调用
	.owner   = THIS_MODULE,
	.open    = k_thread_open,
	.release = k_thread_release,
	.read    = k_thread_read,
	.write   = k_thread_write,
	.unlocked_ioctl   = k_thread_ioctl,	
};

int kthread_sendmsg(void *arg)
{
	printk(" in %s()\n", __FUNCTION__);
	allow_signal(SIGKILL); //使得线程可以接收SIGKILL信号
	mdelay(2000);
	printk("should stop: %d\n",kthread_should_stop());
	while (!signal_pending(current) && !kthread_should_stop()) 
	{
		//使得线程可以可以被杀死,也可以再rmmod的时候结束
		printk(" jiffies is %lu\n", jiffies);
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(HZ * 5);   
		printk("should stop: %d\n",kthread_should_stop());
	}
	printk("Leaving kthread_function\n");
	flag = 1; //flag很关键!
	return 0;
}


/*
 * Set up the cdev structure for a device.
 */
static void kthread_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
	int err, devno = MKDEV(kthread_major, minor);
    
	cdev_init(dev, fops);
	dev->owner = THIS_MODULE;
	dev->ops = fops;
	err = cdev_add (dev, devno, 1);
	/* Fail gracefully if need be */
	if (err)
		printk (KERN_NOTICE "Error %d adding beep%d", err, minor);
}
int __init kthread_init(void)
{
	int result;
	dev_t dev = MKDEV(kthread_major, 0);//dev_t是一个32位类型,前12位表示主号,后20位表示次号
	char dev_name[]="kThread";
	printk(KERN_INFO "CREATE KTHREAD!!!\n");
	/* Figure out our device number. */
	if (kthread_major)
		result = register_chrdev_region(dev, 1, dev_name);
	else {
		result = alloc_chrdev_region(&dev, 0, 1, dev_name);//动态分配设备号
		kthread_major = MAJOR(dev);
	}
	if (result < 0) {
		printk(KERN_WARNING "beep: unable to get major %d\n", kthread_major);//打印主设备号
		return result;
	}
	if (kthread_major == 0)
		kthread_major = result;	
	/* Now set up cdev. */
	kthread_setup_cdev(&kThreadDevs, 0, &kThread_remap_ops);
	printk("kthread device installed, with major %d\n", kthread_major);
	printk("The device name is: %s\n", dev_name);

	task = kthread_run(kthread_sendmsg,NULL,"kthread_sendmsg");
	return 0;
}

void __exit kthread_exit(void)
{
	/* 卸载驱动程序 */
	cdev_del(&kThreadDevs);
	unregister_chrdev_region(MKDEV(kthread_major, 0), 1);
	printk(KERN_INFO "RELEASE KTHREAD!!!\n");
        if(!flag)
        {
                 if (!IS_ERR(task))
                 {  
                      int ret = kthread_stop(task);  
                      printk(KERN_INFO "First thread function has stopped ,return %d\n", ret);  
                 }                  
       }
       printk("task_struct: 0x%x",task);
       printk(" Goodbye\n");
}

module_init(kthread_init);
module_exit(kthread_exit);


用户空间程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>

#define BEEP_MAGIC 'k'
#define MAX_PAYLOAD 1024 /* maximum payload size*/

struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;

void *recvMsg(void *args);
void service();

int main()
{
	int i = 0;
	int dev_fd;
	dev_fd = open("/dev/kThread",O_RDWR | O_NONBLOCK);
	if ( dev_fd == -1 ) 
	{
		printf("Cann't open file /dev/kThread\n");
		exit(1);
	}
	ioctl(dev_fd,1,1); 
	service();
	printf("This is main Thread!\n");
	sleep(3);
	close(dev_fd);
	return 0;
}

void *recvMsg(void *args)
{
   	int t_id;
	t_id = (int) args;
	printf("pthread %d create!!!\n",t_id);
	while(1)
	{
		printf("pthread!!!\n");
		sleep(1);
	}		
}

void service()
{
	int i, ret;
	pthread_t  tid;
	for(i = 0; i < 2; i++) 
	{	
        	ret = pthread_create(&tid,NULL,(void *) recvMsg,(void *)i);
		if(ret != 0)//error 
		{
			perror("fail to created consumer thread\n");
			return;
		}
	   	if(pthread_detach(tid) != 0) //将子进程的状态设置为分离的,这样该线程运行结束后会自动释放所有资源
		{
			perror("fail to detach consumer pthread \n");
			return;
		}
	}
}



Linux内核线程之深入浅出:http://blog.163.com/jiams_wang/blog/static/303391492012103010374038/

Linux内核多线程(一):http://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545624.html

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值