(linux自学笔记)linux驱动并发控制、阻塞/非阻塞IO、异步通知

发布时间:2024-09-23  

1.关于并发控制


Linux 中多个进程对共享资源的并发访问,并发访问会导致竞态。



  在单 CPU范围内避免竞态的一种方法是在进入临界区之前屏蔽系统的中断。CPU一般都具备屏蔽中断和打开中断的功能,中断屏蔽将使得中断与进程之间的并发不再发生,由于Linux 内核的进程调度等操作都依赖中断来实现,内核抢占进程之间的并发也就得以避免了。


local_irq_disable() //屏蔽中断

...

critical section //临界区

...

local_irq_enable() //开中断



原子操作


原子操作指的是在执行过程中不会被别的代码路径所中断的操作。


原子操作驱动


#include

#include

#include

#include /* copy_to_user,copy_from_user */

#include

#include

#include

#include

#include

#include


#define LED_MAJOR 240

//原子变量

atomic_t atomic_led = ATOMIC_INIT(0);



int led_open (struct inode *inode,struct file *filp)

{

    unsigned tmp;

    //减1兼测试

    if (!atomic_dec_and_test(&atomic_led))

    {

        //加1

        atomic_inc(&atomic_led);

        return -1;

    }



    tmp = readl(S3C64XX_GPMDAT);

    tmp &= 0xffff0000;

    tmp |= 0x00001111;

    writel(tmp, S3C64XX_GPMCON);

    writel(0xffffffff, S3C64XX_GPMDAT);

    printk('<0>open ledn');

    return 0;

}


ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)

{

    return count;

}



ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)

{

    char wbuf[1];

    unsigned tmp;


    copy_from_user(wbuf,buf,count);


    tmp = readl(S3C64XX_GPMDAT);

    tmp &= 0xfffffff0;

    tmp |= wbuf[0];

    writel(tmp, S3C64XX_GPMDAT);


    return count;

}


int led_release (struct inode *inode, struct file *filp)

{

    atomic_inc(&atomic_led);


    return 0;

}



struct file_operations led_fops ={

    .owner = THIS_MODULE,

    .open = led_open,

    .read = led_read,

    .write = led_write,

    .release = led_release,


};


int __init led_init (void)

{

    int rc;

    printk ('<0>led initn');

    rc = register_chrdev(LED_MAJOR,'led',&led_fops);

    if (rc <0)

    {

        printk ('<0>register %s char dev errorn','led');

        return -1;

    }


    //atomic_t atomic_led = ATOMIC_INIT(0);

    //原子变量置1

    atomic_set(&atomic_led, 1);

    printk ('<0>successn');

    return 0;

}


void __exit led_exit (void)

{

    unregister_chrdev(LED_MAJOR,'led');

    printk ('<0>module exitn');

    return ;

}


module_init(led_init);

module_exit(led_exit);


测试程序


#include

#include 'stdio.h'

#include 'pthread.h'

#include 'stdlib.h'


void thread_one(void)

{

    int fd,count;

    char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};



    while((fd = open('/dev/my_led',O_RDWR))<0)

    {

        printf ('pthread_one:Open /dev/my_led file errorn');

        //pthread_exit(0);

        sleep(1);

    }

    for(count=0;count<3;count++)

    {

        write(fd,&buf[0],1);

        sleep(1);

        write(fd,&buf[5],1);

        sleep(1);

    }

    close (fd);

}


void thread_two(void)

{

    int fd,count;

    char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};



    while ((fd = open('/dev/my_led',O_RDWR)) < 0)

    {

        printf ('pthread_two:Open /dev/my_led file errorn');

        //pthread_exit(0);

    sleep(1);

    }

    for(count=0;count<3;count++)

    {

        write(fd,&buf[1],1);

        sleep(1);

        write(fd,&buf[5],1);

        sleep(1);

    }

    close(fd);

}


main()

{

    pthread_t thread_one_id,thread_two_id;

    int resurt;

    pthread_attr_t thread_one_attr,thread_two_attr;

    int thread_one_priority,thread_two_priority;




    thread_one_priority = 11;

    thread_two_priority = 11;


    pthread_attr_init(&thread_one_attr);

    pthread_attr_init(&thread_two_attr);


    //设置为指定调度算法

    pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED);

    pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED);


    //指定调度算法

    pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR);

    pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR);


    pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority);


    pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority);


    pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE);

    //sleep(1);

    if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1)

    {

        perror('ss');

        printf('thread one creat errorn %d',resurt);

        exit(1);

    }



    if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1)

    {

        printf('thread two creat errorn');

        exit(1);

    }



    //sleep(1);

    pthread_join(thread_one_id, NULL);

    pthread_join(thread_two_id, NULL);

}


运行结果


自旋锁


自旋锁是一种对临界资源进行互斥手访问的典型手段。为了获得一个自旋锁,在某CPU 上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其他执行单元不可能访问这个内存变量。


自旋锁保护临界段


    spinlock(&lock_led);

    if (count)/*已经打开*/

    {

        spin_unlock(&lock_led);

        return -1;

    }


    spin_unlock(&lock_led);


信号量


//获得信号量


void down(struct semaphore * sem);


//释放信号量


void up(struct semaphore * sem);


2 .关于阻塞/非阻塞IO



阻塞和非阻塞I/O 是设备访问的两种不同模式,驱动程序可以灵活地支持用户空间对设备的这两种访问方式。

阻塞操作是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。而非阻塞操作的进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。


阻塞一个线程,直至另一个线程运行完。


include

#include

#include

#include /* copy_to_user,copy_from_user */

#include

#include

#include

#include

#include

#include

#include

#include


#define LED_MAJOR 240


struct my_queue

{

    //定义等待列对头

    wait_queue_head_t queue_head;

    //定义自旋锁

    spinlock_t lock;

    //文件打开标志

    int file_flag;

}led_queue;



int led_open (struct inode *inode,struct file *filp)

{

    unsigned tmp;

    struct my_queue * dev = &led_queue;

    //自旋锁 临界段

    spin_lock(&dev->lock);


    //定义等待列对

    DECLARE_WAITQUEUE(wait,current);

    //进入等待列对头

    add_wait_queue(&dev->queue_head, &wait);

    dev->file_flag--;

    spin_unlock(&dev->lock);

    while(dev->file_flag < 0)

    {

        //改变进程状态

         __set_current_state(TASK_INTERRUPTIBLE);

        //

        schedule();

    }


    spin_lock(&dev->lock);

    dev->file_flag = 0;

    spin_unlock(&dev->lock);



    tmp = readl(S3C64XX_GPMDAT);

    tmp &= 0xffff0000;

    tmp |= 0x00001111;

    writel(tmp, S3C64XX_GPMCON);

    writel(0xffffffff, S3C64XX_GPMDAT);

    printk('<0>open ledn');

    //移除

    remove_wait_queue(&dev->queue_head, &wait);

    return 0;

}


ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)

{

    return count;

}



ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)

{

    char wbuf[1];

    unsigned tmp;


    copy_from_user(wbuf,buf,count);


    tmp = readl(S3C64XX_GPMDAT);

    tmp &= 0xfffffff0;

    tmp |= wbuf[0];

    writel(tmp, S3C64XX_GPMDAT);

    return count;

}


int led_release (struct inode *inode, struct file *filp)

{

    struct my_queue * dev = &led_queue;

    spin_lock(&dev->lock);

    dev->file_flag = 1;

    spin_unlock(&dev->lock);


    wake_up_interruptible(&dev->queue_head);


    return 0;

}



struct file_operations led_fops ={

    .owner = THIS_MODULE,

    .open = led_open,

    .read = led_read,

    .write = led_write,

    .release = led_release,


};


int __init led_init (void)

{

    int rc;

    struct my_queue * dev = &led_queue;


    printk ('<0>led initn');

    rc = register_chrdev(LED_MAJOR,'led',&led_fops);

    if (rc <0)

    {

        printk ('<0>register %s char dev errorn','led');

        return -1;

    }

    //初始化列对头

    init_waitqueue_head(&dev->queue_head);

    //初始化自旋锁

    spin_lock_init(&dev->lock);

    //文件打开标志

    dev->file_flag = 1;

    printk ('<0>successn');

    return 0;

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>