《Linux内核并发与竞态》分析Linux2.6.29内核死锁

时间:2022-10-08 15:46:20

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 ARMv5
2.程序

内核模块:

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