自旋锁是一直循环检查, 直到锁上为止(锁不上也不会让进程休眠)。自旋锁只有两种状态,可锁上和锁不上. 锁上后确保执行的代码为原子操作, 直到解锁为止. 注意不能长时间锁上自旋锁, 不能在临界区里休眠.
spinlock_t 自旋锁
#include
spinlock_t mylock;
spin_lock_init(&mylock); //初始化自旋锁, 初始化过后是可锁上状态.
上锁:
spin_lock(&mylock); //spin_lock_irq 不让中断打断执行
...
保护执行的代码 //临界区, 在临界区里不能执行会休眠的代码
...
spin_unlock(&mylock); //spin_unlock_irq
当自旋锁锁上后, 拥有此锁的进程不能进入休眠. 自旋锁只适用于保护执行时间较短的代码.
//
如用于前面的计数例子.
test.c
#include
#include
#include
#include
#include
#include
#include
int count = 0;
spinlock_t mylock;
ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off)
{
printk("pid = %d, %s, count = %d\n", current->pid, current->comm, count);
return 0;
}
ssize_t mywrite(struct file *fl, const char __user *buf, size_t len, loff_t *off)
{
spin_lock(&mylock);
count++; //保护对count变量的操作.
spin_unlock(&mylock);
return len; //表示写操作成功
}
struct file_operations fops = {
.owner = THIS_MODULE,
.read = myread,
.write = mywrite,
};
struct miscdevice mymdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mymdev",
.fops = &fops,
};
static int __init test_init(void)
{
spin_lock_init(&mylock);
return misc_register(&mymdev);
}
static void __exit test_exit(void)
{
misc_deregister(&mymdev);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
//
信号量, 当锁不上时, 当前进程会进入睡眠状态, 直到被up唤醒为止.
信号量可用于生产/消费的模型. 信号量的状态可有多种,一个锁可被锁上多次, 只要有资源都可以上锁.
#include
struct semaphore {
spinlock_t lock; //用于保护对count, wait_list的操作
unsigned int count; //当锁上时,count的值减1. 当解锁时,count的值加1. 如count的值为10表示此锁可被锁上10次.
//count的值当大于0时表示可锁, 等于0时表示没有资源分配(不可以锁上,再锁的话, 进程会被安排进入休眠)
struct list_head wait_list; //等待操作进程的链表
};
void sema_init(struct semaphore *sem, int val);//初始化信号量,count成员的值设为val
void down(struct semaphore *sem); //上锁 count--
int down_interruptible(struct semaphore *sem); //能被中断信号打断的上锁
int down_trylock(struct semaphore *sem);
int down_timeout(struct semaphore *sem, long jiffies); // down_timeout(&sem, HZ);
void up(struct semaphore *sem); //解锁 count++
如用信号量实现生产/消费的模型. 一个进程读取驱动里的数据(消费), 另一个进程写入数据到驱动(生产).在驱动源码里把写入的数据用内核存放起来,当读进程获取数据后,还需从内核链表里移除数据.
test.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
spinlock_t mylock; //用于保护链表的操作
struct semaphore sem;
static LIST_HEAD(dlist); //用于存放数据的链表
typedef struct {
char data[1000];
int len;
struct list_head list;
}data_t;
ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off)
{
int ret;
data_t *data;
struct list_head *tmp;
ret = down_interruptible(&sem);
if (ret < 0)
return -ERESTART;
tmp = dlist.next;
if (tmp == &dlist)
return -ENODATA;
data = container_of(tmp, data_t, list);
ret = copy_to_user(buf, data->data, data->len);
ret = data->len - ret;
spin_lock(&mylock);
list_del(tmp);
spin_unlock(&mylock);
kfree(data);
printk("after down: pid = %d, %s\n", current->pid, current->comm);
return ret;
}
ssize_t mywrite(struct file *fl, const char __user *buf, size_t len, loff_t *off)
{
data_t *data = kzalloc(sizeof(data_t), GFP_KERNEL);
int ret;
ret = copy_from_user(data->data, buf, len);
data->len = len-ret;
spin_lock(&mylock);
list_add_tail(&data->list, &dlist);
spin_unlock(&mylock);
up(&sem); // count++;
return len;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.read = myread,
.write = mywrite,
};
struct miscdevice mymdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mymdev",
.fops = &fops,
};
static int __init test_init(void)
{
sema_init(&sem, 0); //初始化count的值为0
spin_lock_init(&mylock);
return misc_register(&mymdev);
}
static void __exit test_exit(void)
{
misc_deregister(&mymdev);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");