Android2.3及Linux2.6.29内核模拟器版本编译与调试
一、前言
1.自旋锁与信号量
自旋锁:当不能获得自旋锁时一直忙等待,既不睡眠、也不执行调度;在SMP中使用自旋锁。
信号量:当不能获得信号量时,系统睡眠或执行调度(进程上下文中)。
2.自旋锁
在内核非抢占时,自旋锁相当于空操作、不起任何作用。
二、实例分析
1.Linux2.6.29内核开启内核抢占
make menuconfig
Kernel Features->Preemptible Kernel
如果不开启内核抢占,本试验将没有任何异常!
对比下开启前后内核模块的魔术字。
modinfo test_driver.ko
未开启内核抢占:
filename: test_driver.ko license: GPL author: tank depends: vermagic: 2.6.29-gb0d93fb-dirty mod_unload ARMv5开启内核抢占:
filename: test_driver.ko license: GPL author: tank depends: vermagic: 2.6.29-gb0d93fb-dirty preempt mod_unload ARMv52.程序
内核模块:
test_driver.c
#include <linux/module.h> #include <linux/types.h> #include <linux/uaccess.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/delay.h> #define TEST_MAJOR 240 //static DEFINE_SPINLOCK(write_lock); //static DEFINE_SPINLOCK(read_lock); static spinlock_t write_lock; static spinlock_t read_lock; static DEFINE_MUTEX(write); static DEFINE_MUTEX(read); //动态设备节点 struct class *mymodule_class; //结束 static int test_led_open(struct inode *inode, struct file *file) { printk("#########open######\n"); return 0; } static int test_led_close(struct inode *inode, struct file *file) { printk("#########release######\n"); return 0; } static int test_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) { printk("############read##000000000####\n"); unsigned long flags; down(&read);//spin_lock_init(&read_lock); spin_lock(&read_lock); spin_lock(&read_lock); //两次获得“自旋锁”,导致内核crash!!!!!!!!! printk("#########read######\n"); //msleep(10000); down(&write);//spin_lock(&write_lock); printk("#########read#11111#####\n"); //msleep(10000); up(&read);//spin_unlock_irqrestore(&read_lock,flags); printk("#########read##22222####\n"); //msleep(10000); up(&write);//spin_unlock(&write_lock); printk("#########read##33333####\n"); return count; } static int test_led_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { printk("########write#000000########\n"); unsigned long flags; down(&write);//spin_lock(&write_lock); printk("#########write######\n"); //msleep(10000); down(&read);//spin_lock(&read_lock); printk("#########write#11111#####\n"); //msleep(10000); up(&write);//spin_unlock(&write_lock); printk("#########write##22222####\n"); //msleep(10000); up(&read);//spin_unlock(&read_lock); printk("#########write##33333####\n"); return count; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = test_led_open, .release = test_led_close, .read = test_led_read, .write = test_led_write, }; static int __init test_drv_init(void) { int rc; printk("test_driver dev\n"); //注册设备 rc = register_chrdev(TEST_MAJOR,"test_dev",&led_fops); if (rc <0){ printk ("register %s char dev error\n","led"); return -1; } //实现动态创建 mymodule_class = class_create(THIS_MODULE, "test_dev"); device_create(mymodule_class, NULL, MKDEV(TEST_MAJOR, 0), NULL, "tankai_dev"); //结束 printk ("ok!\n"); return 0; out_chrdev: unregister_chrdev(TEST_MAJOR, "mymodule"); out: return -1; } static void __exit test_drv_exit(void) { //动态设备节点 device_destroy(mymodule_class, MKDEV(TEST_MAJOR, 0)); class_destroy(mymodule_class); //结束 unregister_chrdev(TEST_MAJOR, "test_dev"); } module_init(test_drv_init); module_exit(test_drv_exit); MODULE_AUTHOR("tank"); MODULE_LICENSE("GPL");Makefile
obj-m := test_driver.o PWD := $(shell pwd) #KERNELDIR := /usr/src/linux-headers-3.0.0-26-generic/ KERNELDIR := /home/android2.3/android2.3_kernel/ default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules # cp -rf mini.ko ../module/ # cp -rf lddbus.ko ../module/ clean: rm *.mod.c *.o *.ko *.bak modules.* Module.*
make生成test_driver.ko
用户测试程序:testread.c
#include <fcntl.h> #include <stdlib.h> #include <sys/mman.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> int main(){ int fd = open("/dev/tankai_dev",O_RDWR,0); if(fd < 0) perror("testdriver"); printf("TK------->>>fd is %d\n",fd); char buf[20]; int result = read(fd,&buf,3); printf("TK------->>>readresult is %d,buf is %s\n",result,buf); strcpy(buf,"123"); //result = write(fd,&buf,3); printf("TK------->>>writeresult is %d,buf is %s\n",result,buf); close(fd); return 0; }
Android.mk
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ testread.c LOCAL_SHARED_LIBRARIES := \ libutils LOCAL_MODULE:= testread LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE)mm编译后生成testread
3.操作
insmod test_driver.ko
./testread
4.结果死锁
串口终端操作没有任何反映,手机界面也无法在操作;系统内核挂掉,死机。
#########open###### ############read##000000000#### #########read###### #########read#11111##### #########read##22222#### #########read##33333#### #########release###### Unable to handle kernel paging request at virtual address 40008084 pgd = c8e18000 [40008084] *pgd=0a685031, *pte=0bb1934f, *ppte=0bb19aae Internal error: Oops: 81f [#1] PREEMPT Modules linked in: test_driver CPU: 0 Not tainted (2.6.29-gb0d93fb-dirty #93) PC is at 0xafd1c9d2 LR is at 0xafd1c9cf pc : [<afd1c9d2>] lr : [<afd1c9cf>] psr: 60000030 sp : beebebb8 ip : 00009118 fp : 00000000 r10: 00000000 r9 : 00000000 r8 : 00000000 r7 : beebebd4 r6 : afd424f8 r5 : 40008000 r4 : 40008084 r3 : 40008088 r2 : 00000003 r1 : 00001000 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode USER_32 ISA Thumb Segment user Control: 00093177 Table: 08e18000 DAC: 00000015 Process testread (pid: 373, stack limit = 0xca5b2268) Kernel panic - not syncing: Fatal exception