Samsung_tiny4412(笔记)-->spinlock,semaphore,atomic,mutex,completion,interrupt

/***********************************************************************************
 *
 *   Samsung_tiny4412(笔记)-->spinlock,semaphore,atomic,mutex,completion,interrupt
 *
 *   声明:
 *       1. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因;
 *       2. 基于1中的原因,本文借鉴了python中的缩进代码风格进行代码的体现:
 *           1. 有些代码中的"..."代表省略了不影响阅读的代码;
 *           2. 如下代码缩进代表在一个函数内部的代码,至于在什么函数里,不影响阅读:
 *               ... //省略代码
 *               struct test_s {
 *               };
 *               ... //省略代码
 *
 *                   //进入临界区之前加锁         }
 *                   spin_lock(&p->lock);     |
 *                                            |   |
 *                   /* 有效代码 */             |-->|采用缩进,代表在一个函数内
 *                                            |   |的代码
 *                   //出临界区之后解锁          |
 *                   spin_unlock(&p->lock);   }
 *
 *               ... //省略代码
 *               int __init test_init(void)
 *               {
 *                   ... //省略代码
 *               }
 *               ... //省略代码
 *
 *
 *                                          2015-3-13 阴 深圳 尚观 Var 曾剑锋
 **********************************************************************************/

                        \\\\\\\\--*目录*--////////
                        |  一. spinlock接口;
                        |  二. semaphore接口;
                        |  三. atomic接口;
                        |  四. mutex接口;
                        |  五. completion接口;
                        |  六. interrupt接口;
                        |  七. 按键驱动大致写法;
                        |  八. 测试按键驱动;
                        \\\\\\\\\\\\//////////////

一. spinlock接口:
    1. 声明:       spinlock_t lock;
    2. 初始化:     spin_lock_init(&test.lock);
    3. 获取自旋锁: spin_lock(&p->lock);
    4. 释放自旋锁: spin_unlock(&p->lock);
    5. spin_lock接口使用Demo:
        ...
        struct test_s {
            struct file_operations fops;
            spinlock_t lock;
            int major;
        };
        ...
            //进入临界区之前加锁
            spin_lock(&p->lock);
            for(i = 0; i < 3; i++)
            {
                printk("count = %d, %s", cnt++, kbuf);
                /*msleep(10);*/
                mdelay(10);
            }
            //出临界区之后解锁
            spin_unlock(&p->lock);
        ...
        int __init test_init(void)
        {
            int ret;
            // 初始化spin_lock
            spin_lock_init(&test.lock);

            ret = register_chrdev(test.major,
                    DEV_NAME, &test.fops);
            if(ret > 0)
            {
                test.major = ret;
                printk("major = %d\n", test.major);
                ret = 0;
            }

            return ret;
        }
        ...

二. semaphore接口:
    1. 定义: struct semaphore sem;
    2. 定义一个信号量,并初始化: DEFINE_SEMAPHORE(name);
    3. 初始化: sema_init(&test.sem, 1);
    4. 3种获取信号量:
        1. down(&p->sem);
        2. down_interruptible(&p->sem);
        3. down_trylock(&p->sem);
    5. 释放信号量: up(&p->sem);
    6. semaphore接口使用Demo:
        ...
        struct test_s {
            struct file_operations fops;
            /**
             * spinlock_t lock;
             * volatile int count;
             */
            struct semaphore sem;
            int major;
        };
        ...
            /**
             * spin_lock(&p->lock);
             * if(p->count <= 0)
             * {
             *     spin_unlock(&p->lock);
             *     return -EAGAIN;
             * }
             * p->count--;
             * spin_unlock(&p->lock);
             */

            //加不了锁,睡眠等待
            /*down(&p->sem);*/

            if(down_trylock(&p->sem))
                return -EAGAIN;

            for(i = 0; i < 3; i++)
            {
                printk("count = %d, %s", cnt++, kbuf);
                msleep(10);
            }

            up(&p->sem);

            /**
             * spin_lock(&p->lock);
             * p->count++;
             * spin_unlock(&p->lock);
             */
        ...
        int __init test_init(void)
        {
            int ret;

            /**
             * spin_lock_init(&test.lock);
             * test.count = 1;
             */

            sema_init(&test.sem, 1);

            ret = register_chrdev(test.major,
                    DEV_NAME, &test.fops);
            if(ret > 0)
            {
                test.major = ret;
                printk("major = %d\n", test.major);
                ret = 0;
            }

            return ret;
        }
        ...

三. atomic接口:
    1. 头文件:   linux-3.5/include/linux/atomic.h
    2. 声明定义: atomic_t val; atomic_t *v = &val;
    3. 读取原子变量的值:   atomic_read(v);
    4. 修改原子变量的值:   atomic_set(v, i);
    5. 原子变量自加1:      atomic_inc(v); --> v += 1;
    6. 原子变量自减1:      atomic_dec(v); --> v -= 1;
    7. 原子变量自加1并检测是否为0:       atomic_inc_and_test(v); v += 1,判断结果是否为0
    8. 原子变量自减1并检测是否为0:       atomic_dec_and_test(v); v -= 1,判断结果是否为0
    9. 原子变量自加1并返回原子变量的值:  atomic_inc_return(v)
    10. 原子变量自减1并返回原子变量的值: atomic_dec_return(v)
    11. 比较变量i和原子变量的值是否相等: atomic_sub_and_test(i, v)
    12. atomic接口使用Demo:
        ...
        struct test_s {
            struct file_operations fops;
            atomic_t v;
            int major;
        };
        typedef struct test_s test_t;

        static int test_open(struct inode *inode, struct file *file)
        {
            test_t *p;
            p = container_of(file->f_op, test_t, fops);

            file->private_data = p;

            if(!atomic_dec_and_test(&p->v))
            {
                atomic_inc(&p->v);
                return -EAGAIN;
            }

            printk("Open.\n");

            return 0;
        }

        static int test_close(struct inode *inode, struct file *file)
        {
            test_t *p = file->private_data;

            printk("Close.\n");
            atomic_inc(&p->v);

            return 0;
        }
        ...
        int __init test_init(void)
        {
            int ret;

            atomic_set(&test.v, 1);

            ret = register_chrdev(test.major,
                    DEV_NAME, &test.fops);
            if(ret > 0)
            {
                test.major = ret;
                printk("major = %d\n", test.major);
                ret = 0;
            }

            return ret;
        }
        ...

四. mutex接口:
    1. 定义: struct mutex lock;
    2. 定义一个互斥锁,并初始化: DEFINE_MUTEX(mutexname);
    3. 初始化: mutex_init(&lock);
    4. 3种加锁方式:
        1. mutex_lock(&lock);
        2. mutex_lock_interruptible(&lock);
        3. mutex_trylock(&lock);
    5. 解锁: mutex_unlock(&lock);
    6. mutex接口使用Demo:
        ...
        struct test_s {
            struct file_operations fops;
            /*struct semaphore sem;*/
            struct mutex lock;
            int major;
        };
        typedef struct test_s test_t;
        ...
            /*mutex_lock(&p->lock);*/

            /*
             *if(mutex_lock_interruptible(&p->lock))
             *    return -EINTR;
             */

            if(!mutex_trylock(&p->lock))
                return -EAGAIN;

            for(i = 0; i < 3; i++)
            {
                printk("count = %d, %s", cnt++, kbuf);
                msleep(10);
            }

            mutex_unlock(&p->lock);
        ...
        int __init test_init(void)
        {
            int ret;

            mutex_init(&test.lock);

            ret = register_chrdev(test.major, DEV_NAME, &test.fops);
            if(ret > 0)
            {
                test.major = ret;
                printk("major = %d\n", test.major);
                ret = 0;
            }

            return ret;
        }

五. completion接口:
    1. 定义: struct completion com;
    2. 定义一个完成量,并初始化: DECLARE_COMPLETION(work)
    3. 初始化: init_completion(&com);
    4. 2种等待完成:
        1. wait_for_completion(&com);
        2. wait_for_completion_interruptible(&com);
    5. 2种通知完成量:
        1. complete(&com);
        2. complete_all(&com);
    6. mutex接口使用Demo:
        ...
        struct test_s {
            struct file_operations fops;
            struct completion com;
            int major;
        };
        typedef struct test_s test_t;
        ...
        static ssize_t test_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
        {
            test_t *p = file->private_data;

            //在完成量com上阻塞
            /*wait_for_completion(&p->com);*/

            if(wait_for_completion_interruptible(&p->com))
                return -ERESTARTSYS;

            printk("Read data.\n");

            return count;
        }

        static ssize_t test_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
        {
            test_t *p = file->private_data;

            printk("Write data.\n");

            /*complete(&p->com);*/

            //通知所有阻塞的进程
            complete_all(&p->com);

            return count;
        }
        ...
        int __init test_init(void)
        {
            int ret;

            init_completion(&test.com);
            ret = register_chrdev(test.major,
                                  DEV_NAME, &test.fops);
            if(ret > 0)
            {
                test.major = ret;
                printk("major = %d\n", test.major);
                ret = 0;
            }

            return ret;
        }
        ...
六. interrupt接口:
    1. 查看系统中断处理信息: cat /proc/interrupts
    2. 申请并注册中断处理函数:
        static inline int __must_check request_irq( unsigned int irq, irq_handler_t handler,
                                      unsigned long flags, const char *name, void *dev_data);
    3. 释放中断,并取消中断处理函数:
        void free_irq(unsigned int irq, void *dev_data);
    4. 代码执行环境:
        1. 中断上下文:         in_interrupt(); ---> 判断执行环境是否是中断上下文
            1. 软中断上下文:   in_softirq();   ---> 判断执行环境是否是soft irq
            2. 外部中断上下文: in_irq();       ---> 判断执行环境是否是硬件中断处理环境
        2. 进程上下文.
    5. 共享中断方法:
        1. request_irq()指定共享标志 IRQF_SHARED;
        2. request_irq()最后一个参数不能传递NULL,传递当前驱动全局变量地址;
    6. 将系统gpio编号转换成对应的外部中断: gpio_to_irq();
    7. spinlock中断中使用Demo:
        ...
        struct test_s {
            struct file_operations fops;
            spinlock_t lock;
            int major;
        };
        typedef struct test_s test_t;
        ...
        int critical(const char *s, spinlock_t *lock)
        {
            int i;
            unsigned long flag;
            static int cnt = 0;

            /*spin_lock(lock);*/
            /*local_irq_disable();*/
            /*local_irq_save(flag);*/
            /*spin_lock_irq(lock);*/
            spin_lock_irqsave(lock, flag);

            for(i = 0; i < 3; i++)
            {
                printk("count = %d, %s", cnt++, s);
                mdelay(1000);
            }

            spin_unlock_irqrestore(lock, flag);
            /*spin_unlock_irq(lock);*/
            /*local_irq_restore(flag);*/
            /*local_irq_enable();*/
            /*spin_unlock(lock);*/

            return 0;
        }

        static irqreturn_t irq_handler(int irq, void *arg)
        {
            test_t *p = arg;

            critical("irq\n", &p->lock);

            return IRQ_HANDLED;
        }

        static ssize_t test_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
        {
            int ret;
            char kbuf[count + 1];
            test_t *p = file->private_data;

            ret = copy_from_user(kbuf, buf, count);
            if(ret)
                return -EFAULT;
            kbuf[count] = ‘\0‘;

            if(critical(kbuf, &p->lock))
                return -EAGAIN;

            return count;
        }
        ...
        int __init test_init(void)
        {
            int ret;

            spin_lock_init(&test.lock);

            ret = register_chrdev(test.major,
                    DEV_NAME, &test.fops);
            if(ret > 0)
            {
                test.major = ret;
                printk("major = %d\n", test.major);
                ret = 0;
            }

            ret = request_irq(IRQ_EINT(26), irq_handler,
                              IRQF_TRIGGER_FALLING,
                              "key1", &test);
            if(ret)
                unregister_chrdev(test.major, DEV_NAME);

            return ret;
        }
        ...

七. 按键驱动大致写法:
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/gpio.h>
    #include <linux/delay.h>
    #include <linux/interrupt.h>
    #include <linux/uaccess.h>
    #include <linux/sched.h>

    #define DEV_NAME    "test"

    struct timer_list timer;
    struct btn_desc {
        int gpio;
        int num;
        char *name;
    };

    int ev_key = 0;
    char key_state[] = {0, 0, 0, 0};
    DECLARE_WAIT_QUEUE_HEAD(wq);

    struct btn_desc btn[] = {
        { EXYNOS4_GPX3(2), 0, "key1" },
        { EXYNOS4_GPX3(3), 1, "key2" },
        { EXYNOS4_GPX3(4), 2, "key3" },
        { EXYNOS4_GPX3(5), 3, "key4" }
    };

    void timer_main(unsigned long data)
    {
        ev_key = 1;
        wake_up_interruptible(&wq);
        printk("timer_main.\n");
    }

    static irqreturn_t irq_handler(int irq, void *arg)
    {
        struct btn_desc *key = arg;

        key_state[key->num] = 1;

        mod_timer(&timer, jiffies + 20);

        return IRQ_HANDLED;
    }

    static int test_open(struct inode *inode, struct file *file)
    {
        int i, irq, ret;

        for(i = 0; i < ARRAY_SIZE(btn); i++)
        {
            //irq = IRQ_EINT(26+i); //irq可以通过这种方法获得
            irq = gpio_to_irq(btn[i].gpio);
            ret = request_irq(irq, irq_handler, IRQF_TRIGGER_FALLING | IRQF_SHARED,
                        btn[i].name, &btn[i]);
            if(ret)
                break;
        }

        if(ret)
        {
            for(--i; i >= 0; i--)
            {
                irq = gpio_to_irq(btn[i].gpio);
                free_irq(irq, &btn[i]);
            }
            return ret;
        }

        return 0;
    }

    static int test_close(struct inode *inode, struct file *file)
    {
        int i, irq;

        for(i = 0; i < ARRAY_SIZE(btn); i++)
        {
            irq = gpio_to_irq(btn[i].gpio);
            free_irq(irq, &btn[i]);
        }

        return 0;
    }

    static ssize_t test_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
    {
        int ret;

        if(count > ARRAY_SIZE(key_state))
            count = ARRAY_SIZE(key_state);

        while(!ev_key)
        {
            if(file->f_flags & O_NONBLOCK)
                return -EAGAIN;

            if(wait_event_interruptible(wq, ev_key))
                return -ERESTARTSYS;
        }

        ret = copy_to_user(buf, key_state, count);
        if(ret)
            return -EFAULT;

        memset(key_state, 0, sizeof(key_state));
        ev_key = 0;

        return count;
    }

    static struct file_operations fops = {
        .owner      = THIS_MODULE,
        .open       = test_open,
        .release    = test_close,
        .read       = test_read,
    };

    int major;
    int __init test_init(void)
    {
        int ret;

        setup_timer(&timer, timer_main, 11223344);
        ret = register_chrdev(major,
                              DEV_NAME, &fops);
        if(ret > 0)
        {
            major = ret;
            printk("major = %d\n", major);
            ret = 0;
        }

        return ret;
    }

    void __exit test_exit(void)
    {
        del_timer_sync(&timer);
        unregister_chrdev(major, DEV_NAME);
    }

    module_init(test_init);
    module_exit(test_exit);

    MODULE_LICENSE("GPL");

八. 测试按键驱动:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>

    int main(int argc, char **argv)
    {
        int fd, i, ret;
        char buf[4];

        fd = open(argv[1], O_RDWR);
        if(-1 == fd)
        {
            perror("open");
            exit(1);
        }

        while(1)
        {
            ret = read(fd, buf, sizeof(buf));
            if(4 != ret)
                continue;

            for(i = 0; i < sizeof(buf); i++)
            {
                if(buf[i] == 1)
                    printf("key%d down.\n", i + 1);
            }
        }

        close(fd);
        return 0;
    }
时间: 2024-08-05 01:49:40

Samsung_tiny4412(笔记)-->spinlock,semaphore,atomic,mutex,completion,interrupt的相关文章

Samsung_tiny4412(笔记)--&gt;jiffies,timer,kthread,workqueue,tasklet

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->jiffies,timer,kthread,workqueue,tasklet * * 声明: * 1. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因; * 2. 基于1中的原因,本文借鉴了python中的缩进代码风格进行代码的体现: * 1. 有些代码中的"

Samsung_tiny4412(笔记)--&gt;linux 3.5,U-Boot,Busybox,SD卡启动环境搭建

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->linux 3.5,U-Boot,Busybox,SD卡启动环境搭建 * * 声明: * 1. 以下所有的shell命令都是在root权限下运行的; * 2. minicom(U-Boot)指的是用minicom连接开发板作为U-Boot的终端; * 3. 文中在需要往文件中

Samsung_tiny4412(笔记)--&gt;volatile,container_of,file_operations,file,inode

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->volatile,container_of,file_operations,file,inode * * 声明: * 本文的结构体的注释主要是参考网络上的解释,几乎无任何个人理解,主要是为后续 * 代码编辑提供参考. * * 2015-3-8 阴 深圳 尚观 Etc 曾剑锋

Samsung_tiny4412(笔记)--&gt;Makefile,open,read,write,lseek,poll,ioctl,fasync

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->Makefile,open,read,write,lseek,poll,ioctl,fasync * * * 2015-3-9 阴 深圳 尚观 Var 曾剑锋 **********************************************************

Samsung_tiny4412(笔记)--&gt;ASM with C,MMU,Exception,GIC

/**************************************************************************** * Samsung_tiny4412(笔记)-->ASM with C,MMU,Exception,GIC * * 声明: * 1. 以下所有的shell命令都是在root权限下运行的; * 2. 文中在需要往文件中写入内容的时候使用了如下2方式: * 1.如果文件不存在,创建文件;如果存在,以覆盖的方式往文件中添加内容: * cat >

Samsung_tiny4412(笔记)--&gt;字符设备驱动基本操作及调用流程

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->字符设备驱动基本操作及调用流程 * * 声明: * 以下所有的shell命令都是在root权限下运行的; * * 2015-3-7 阴 深圳 尚观 Sbin 曾剑锋 *******************************************************

Samsung_tiny4412(笔记)--&gt;list_head,proc file system,GPIO,ioremap

/**************************************************************************** * Samsung_tiny4412(笔记)-->list_head,proc file system,GPIO,ioremap * * * 2015-3-11 阴 深圳 尚观 Var 曾剑锋 ***************************************************************************

Samsung_tiny4412(笔记)--&gt;alloc_pages,kmalloc,vmalloc,kmem_cache,class

/*********************************************************************************** * * Samsung_tiny4412(笔记)-->alloc_pages,kmalloc,vmalloc,kmem_cache,class * * 声明: * 1. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因; * 2. 基于1中的原因,本文借鉴了python中的缩进代码风格进行代码的体现: * 1. 有些代码

spinlock,mutex,semaphore,critical section

critical section(临界区) 在任意时刻只允许一个线程对共享资源进行访问.如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开.临界区包含两个操作原语: EnterCriticalSection() 进入临界区 LeaveCriticalSection() 离开临界区. 优点:速度快.因为Critical Section不是内核对象,函数EnterCriticalSection()和LeaveCritica