/***************************************************************************************************
并发控制
信号量简介:
相关的主要API
struct semaphore sem; 定义信号量
void sema_init (struct semaphore *sem, int val); 初始化信号量 并设置信号量 sem 的值为 val
void init_MUTEX (struct semaphore *sem); 初始化一个互斥锁,即它把信号量 sem 的值设置为 1,等同于 sema_init (*sem, 1);
void init_MUTEX_LOCKED (struct semaphore *sem); 初始化一个互斥锁,但它把信号量 sem 的值设置为 0,等同于 sema_init (*sem, 0);
void down(struct semaphore * sem); 该函数用于获得信号量 sem,它会导致睡眠,因此不能在中断上下文使用;
int down_interruptible(struct semaphore * sem); 与down类似,down不能被信号打断,down_interruptible能被信号打断;
int down_trylock(struct semaphore * sem); 尝试获得信号量 sem,会立即获得信号量并返回0,否则返回非0。不会等待,可以在中断上下文使用。
void up(struct semaphore * sem); 该函数释放信号量 sem,唤醒等待者。
初始化自旋锁 (使用宏实现的)
spin_lock_init(lock) 动态初始化自旋锁lock
spin_lock(lock) 获得自旋锁lock,若获得锁,就马上返回,否则自旋,直到该锁被释放;
spin_trylock(lock) 获得自旋锁lock,若获得锁,返回真,否则立即返回假。
spin_unlock(lock) 释放自旋锁lock,与 spin_trylock 或 spin_lock 配对使用;
除此之外,还有一组自旋锁使用于中断情况下的 API。
***************************************************************************************************/
/***************************************************************************************************
操作流程:
终端1 # tail -f /var/log/message 用于查看信息
终端2 # make
# gcc usr.c
# insmod globalvar.ko
# mknod /dev/globalvar 1024 0
# ./a.out
# rmmod globalvar.ko
***************************************************************************************************/
/***************************************************************************************************
函 数:globalvar.c
功 能:并发控制验证--信号量的使用
***************************************************************************************************/
//#include <asm/semaphore.h> 找不到该文件,不包含也能编译过
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
#define MAJOR_NUM 1024 //主设备号
static ssize_t globalvar_read (struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);
static int global_var = 0; //设备的全局变量
static struct semaphore sem; //信号量
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
//获得信号量
if (down_interruptible(&sem))
{
return - ERESTARTSYS;
}
//将global_var从内核空间复制到用户空间
if ( copy_to_user(buf, &global_var, sizeof(int)))
{
up(&sem);
return - EFAULT;
}
printk(KERN_ALERT "globalvar_read enter ,the data is %d\n",global_var);
//释放信号量
up(&sem);
return sizeof(int);
}
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)
{
//获得信号量
if (down_interruptible(&sem))
{
return - ERESTARTSYS;
}
//将用户空间的数据复制到内核空间的global_var
if (copy_from_user(&global_var, buf, sizeof(int)))
{
up(&sem);
return - EFAULT;
}
printk(KERN_ALERT "globalvar_write enter ,the data is %d\n",global_var);
//释放信号量
up(&sem);
return sizeof(int);
}
struct file_operations globalvar_fops =
{
.write = globalvar_write,
.read = globalvar_read,
};
static int __init globalvar_init(void)
{
int ret;
ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops); //注册设备驱动
if (ret)
{
printk(KERN_ALERT "globalvar register failure\n");
}else
{
//init_MUTEX(&sem); 此函数已废弃使用sema_init()代替 init_MUTEX_LOCKED()用sema_init(&sem,0)代替
sema_init(&sem,1);
printk(KERN_ALERT "globalvar register success\n");
}
return ret;
}
static void __exit globalvar_exit(void)
{
printk(KERN_ALERT "globalvar exit success\n");
unregister_chrdev(MAJOR_NUM, "globalvar");
}
module_init(globalvar_init);
module_exit(globalvar_exit);
/***************************************************************************************************
用户使用函数
user.c
复制 LDD2的代码
***************************************************************************************************/
#include <stdio.h>
#include <sys/stat.h> //获得文件的属性,它可以返回一个结构,里面包含文件全部属性
#include <fcntl.h> //设备驱动程序接口是由结构说明,它定义在fcntl.h中
#include <sys/types.h> //类型 clock_t,dev_t,off_t,ptrdiff,size_t,ssize_t,time_t
int main(void)
{
int fd, num;
fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);
printf("fd = %d \n",fd);
if (fd != -1 )
{
read(fd, &num, sizeof(int));
printf("The globalvar is %d\n", num);
printf("Please input the num written to globalvar\n");
scanf("%d", &num);
write(fd, &num, sizeof(int));
read(fd, &num, sizeof(int));
printf("The globalvar is %d\n", num);
close(fd);
}else
{
printf("Device open failure\n");
}
return 0;
}
#/***************************************************************************************************
#Makefile
#复制 LDD2的代码
#***************************************************************************************************/
obj-m := globalvar.o #模块编译的目标必须以obj-m 这样的形式指出
KERNELDIR ?= /lib/modules/$(shell uname -r)/build #模块的编译必须指定内核源代码的路径
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules #本行开头必须使用 Tab 键
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clearn:
rm -rf *.o *.ko *mod.o [mM]odule* .*.cmd .tmp_versions