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 (&DEV->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 (&DEV->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);
|