除了对缓冲区管理的巧妙, usb_skeleton.c中对于并发控制技术的使用也值得学习, 在构造资源对象usb_skel的时候, 这个驱动使用了semaphore ,spinlock,mutex三种常用的并发控制锁机制, 接下来我们讨论一下内核大牛们是如何在不同应用场景中使用这些技术的.
semaphoresemaphore是以进程为单位的, 其典型特点就是当一个进程不能获取信号量的时候, 会进陷入睡眠让出CPU, 所以中断上下文不能使用semaphore。在usb_skeleton.c中,semaphore在如下场景中被使用
335 static void skel_write_bulk_callback(struct urb *urb) 336 { 358 up(&dev->limit_sem); 359 } 361 static ssize_t skel_write(struct file *file, const char *user_buffer, 362 size_t count, loff_t *ppos) 363 { 376 /* 377 * limit the number of URBs in flight to stop a user from using up all 378 * RAM 379 */ 380 if (!(file->f_flags & O_NONBLOCK)) { 381 if (down_interruptible(&dev->limit_sem)) { 382 retval = -ERESTARTSYS; 383 goto exit; 384 } 385 } else { 386 if (down_trylock(&dev->limit_sem)) { 387 retval = -EAGAIN; 388 goto exit; 389 } 390 } 467 return retval; 468 } spinlock当不能获取临界资源时,使用spinlock的进程不会陷入睡眠, 而是忙等,所以spinlock可以用在中断上下文,但是如果不能获取资源又不出让CPU,会浪费系统资源,所以被spinlock保护的临界区不能太长。usb_skeleton主要在以下场景中使用了spinlock
226 static ssize_t skel_read(struct file *file, char *buffer, size_t count, 227 loff_t *ppos) 228 { 250 retry: 251 spin_lock_irq(&dev->err_lock); 252 ongoing_io = dev->ongoing_read; 253 spin_unlock_irq(&dev->err_lock); 332 return rv; 333 } mutexmutex只是用来保证互斥,在不使用trylock的时候,和semaphore一样会在得不到锁的时候进入睡眠。usb_skeleton在以下场景中使用mutex
226 static ssize_t skel_read(struct file *file, char *buffer, size_t count, 227 loff_t *ppos) 228 { 239 /* no concurrent readers */ 240 rv = mutex_lock_interruptible(&dev->io_mutex); 330 exit: 331 mutex_unlock(&dev->io_mutex); 332 return rv; 333 }