concurrency control of Linux drivers (semaphore)

Source: Internet
Author: User
Tags semaphore

Absrtact: Concurrency control is a problem that multi-tasking operating system must face and solve. Concurrency and mutual exclusion are primarily used to protect critical resources, and it is difficult to understand the concepts and applications of concurrency and mutual exclusion without standing in the operating system process scheduling perspective. Both preemptive operating system and time-sharing operating system, the protection of critical resources, must adopt mutually exclusive mechanism. In the Linux kernel, there are several mechanisms for concurrency control: spin locks, atomic variables, semaphores, read-write locks, and so on. The different concurrency mechanisms correspond to different applications, for example, the spin lock can be applied to the interrupt processing function, and the semaphore can not. This paper mainly discusses the use of semaphores from a globalmem_lock example. Note: This example was taken from the Linux device driver development details, and made some changes to the compilation alarm.

Reference Code

/*====================================================================== A Globalmem Driver as an example of Char Devic E Drivers This example are to introduce what to use locks to avoid race conditions the initial developer of the Original code is ZP1015 <[email][email protected][/email]>. All rights reserved.======================================================================*/#include <linux/ module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include < linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h>/* global memory 4K */#define GLOBALMEM_SIZE 0x  1000/* Clear 0 global memory */#define MEM_CLEAR 0x1//#define GLOBALMEM_MAJOR 254/* Preset GLOBALMEM main device number */#define Globalmem_major 0//[color=red] I set this to 0, mainly to let the system automatically assign the main device number, if not, some systems may insmod unsuccessful [/color]static globalmem_major = globalmem_mAjor;/*globalmem device Structural body */struct Globalmem_dev { struct Cdev Cdev; /*cdev Structural Body */unsigned char mem[globalmem_size]; /* Global Memory */struct semaphore sem; /* Signal volume for concurrent control */};struct Globalmem_dev *GLOBALMEM_DEVP; /* Device struct pointer *//* file Open function */int globalmem_open (struct inode *inode, struct file *filp) {/* assign device struct pointer to file private data pointer */filp-> Private_data = Globalmem_devp;return 0;} /* File release function */int globalmem_release (struct inode *inode, struct file *filp) {return 0;} /* IOCTL device control function */static int globalmem_ioctl (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) {struct Globalmem_dev *dev = filp->private_data;/* Gets the device struct pointer */switch (cmd) {case Mem_clear:if (down_interruptible ( &dev->sem)) {Return-erestartsys;} memset (dev->mem, 0, globalmem_size); up (&dev->sem); Releases the semaphore printk (kern_info "Globalmem is set to zero\n"); break;default:return-einval;} return 0;} /* Read function */static ssize_t globalmem_read (struct file *filp, char __user *buf, size_t size, loff_t *ppos) {unsigned long p = *ppos;unsigned int count = size;int ret = 0;struct Globalmem_dev *dev = filp->private_data;  /* Get device struct pointer *//* analysis and get valid write length */if (P >= globalmem_size) return count? -Enxio:0;if (Count > Globalmem_size-p) Count = Globalmem_size-p;if (down_interruptible (&AMP;DEV-&GT;SEM))//get semaphore {R Eturn-erestartsys;} /* Kernel space-User space */if (Copy_to_user (buf, (void*) (Dev->mem + P), count)) {ret =-efault;} Else{*ppos + = Count;ret = COUNT;PRINTK (kern_info "read%u bytes (s) from%lu\n", Count, p);} Up (&dev->sem); Release the semaphore return ret;}  /* Write function */static ssize_t globalmem_write (struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {unsigned long p = *ppos;unsigned int count = size;int ret = 0;struct Globalmem_dev *dev = filp->private_data;  /* Get device struct pointer *//* analysis and get valid write length */if (P >= globalmem_size) return count? -Enxio:0;if (Count > Globalmem_size-p) Count = Globalmem_sizE-p;if (Down_interruptible (&AMP;DEV-&GT;SEM))//gain semaphore {Return-erestartsys;} /* User space, kernel space */if (copy_from_user (Dev->mem + p, buf, count)) ret =-Efault;else{*ppos + = Count;ret = COUNT;PRINTK (KE Rn_info "written%u bytes (s) from%lu\n", Count, p);} Up (&dev->sem); Release the semaphore return ret;} /* Seek file Locator function */static loff_t globalmem_llseek (struct file *filp, loff_t offset, int orig) {loff_t ret = 0;switch (orig) {CA SE 0:/* Relative file start position offset */if (offset < 0) {ret =-einval;break;} if ((unsigned int) offset > globalmem_size) {ret =-einval;break;} Filp->f_pos = (unsigned int) Offset;ret = filp->f_pos;break;case 1:/* Relative to file current position offset */if ((Filp->f_pos + offset) ; globalmem_size) {ret =-einval;break;} if ((Filp->f_pos + offset) < 0) {ret =-einval;break;} Filp->f_pos + = Offset;ret = Filp->f_pos;break;default:ret =-Einval;break;} return ret;} /* File operation struct */static const struct file_operations globalmem_fops ={.owner = This_module,.llseek = Globalmem_llseek,.read = G Lobalmem_reAd,.write = Globalmem_write,.ioctl = Globalmem_ioctl,.open = Globalmem_open,.release = globalmem_release,};/* Initialize and register cdev*/static void Globalmem_setup_cdev (struct globalmem_dev *dev, int index) {int err, Devno = MKDEV (globalmem_ Major, index); Cdev_init (&dev->cdev, &globalmem_fops);d Ev->cdev.owner = This_module;dev->cdev.ops = &globalmem_fops;err = Cdev_add (&dev->cdev, Devno, 1); if (err) PRINTK (kern_notice "Error%d adding led%d", err, index);} /* Device driver module load function */int globalmem_init (void) {int result;dev_t devno = MKDEV (globalmem_major, 0);/* Request device number */if (globalmem_ Major) result = Register_chrdev_region (Devno, 1, "Globalmem"), else/* Dynamic Request device Number */{result = Alloc_chrdev_region (&devno  , 0, 1, "Globalmem"); globalmem_major = major (Devno);} if (Result < 0) return result;/* dynamic request device structure Memory */GLOBALMEM_DEVP = kmalloc (sizeof (struct globalmem_dev), gfp_kernel); !GLOBALMEM_DEVP)/* Application Failed */{result =-Enomem;goto fail_malloc;} memset (GLOBALMEM_DEVP, 0, sizeof (struct Globalmem_dev)); Globalmem_setup_cdev (GLOBALMEM_DEVP, 0); Init_mutex (&globalmem_devp->sem); /* Initialize semaphore */PRINTK ("register Globalmem success\n"); return 0;fail_malloc:unregister_chrdev_region (Devno, 1); return Result;}   /* Module unload function */void globalmem_exit (void) {Cdev_del (&globalmem_devp->cdev);     /* Write-off cdev*/kfree (GLOBALMEM_DEVP); /* Release the device structure body storage */unregister_chrdev_region (MKDEV (globalmem_major, 0), 1); /* Release the device number */PRINTK ("Unregister globalmem success\n");} Module_author ("ZP1015"); Module_license ("Dual BSD/GPL"); Module_param (globalmem_major, int, s_irugo); Module_init (globalmem_init); module_ Exit (Globalmem_exit);



concurrency vs. race State
reason: SMP, process preemption, interrupts,
local_irq_disable () can only prohibit interrupts on this CPU
Local_irq_save (Flags) also saves CPU interrupt bit information (?)
If you want to disable only the bottom half of the interrupt, local_bh_disable ()


Atomic Operation
void Atomic_set (atomic_t *v, int i);
atomic_t v=atomic_init (0);
Atomic_read (atomic_t *v);
void Atomic_add (int i, atomic_t *v);
void atomic_sub (int i, atomic_t *v);
void Atomic_inc (atomic_t *v);
void Atomic_dec (atomic_t *v);
int atomic_inc_and_test (atomic_t *v);
int atomic_dec_and_test (atomic_t *v); test is 0
int atomic_sub_and_test (int i, atomic_t *v);
int Atomic_add_return (int i, atomic_t *v); return new value
int Atomic_sub_return (int i, atomic_t *v)
int Atomic_inc_return (atomic_t *v);
int Atomic_dec_return (atomic_t *v);
void Set_bit (nr, void *addr) set nr bit
void Clear_bit (nr, void *addr)
int test_bit (nr, void * addr);
int test_and_set_bit (nr, void *addr);
int test_and_clear_bit (nr, void *addr);
int test_and_change_bit (nr,void *addr);


Spin lock
primarily for SMP and kernel preemption scenarios
single CPU and kernel can be preempted, preemption will be banned during spin lock hold
You cannot call Copy_to_user () Copy_from_user Kmalloc () and other functions that may cause blocking during a spin lock call
spinlock_t spin;
Spin_lock_init (lock);
Spin_lock (lock);
Spin_try_lock (lock);
combination: Spin_lock_irq () =spin_lock () +local_irq_disable () Spin_unlock_irq ()
Spin_lock_irqsave () Spin_unlock_irqstore ( )
spin_lock_bh () spin_unlock_bh ( )

concurrency control of Linux drivers (semaphore)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.