30 spinlock_t自旋锁和semaphore信号量

自旋锁是一直循环检查, 直到锁上为止(锁不上也不会让进程休眠)。自旋锁只有两种状态,可锁上和锁不上. 锁上后确保执行的代码为原子操作, 直到解锁为止. 注意不能长时间锁上自旋锁, 不能在临界区里休眠.

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");

你可能感兴趣的:(OrangePi,H3,Linux设备驱动开发,semaphore,spinlock)