報告者 : 彭敏君 ANT 實驗室 2011/03/24 Concurrency and Race Conditions
outline 5.0. 引言 5.1. scull 缺陷 5.2. Concurrency and Its Management 5.3. Semaphores and Mutex 5.4. Completions 機制 5.5. Spinlocks 5.6. 鎖定機制的使用準則 5.7. 鎖定機制外的選擇
引言 Scull 存在缺陷的原因 早期 Linux 不支援 SMP 只有在 hardware interrupt 會發生 concurrency
Scull 以下是 Scull 中的一段程式碼 if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); if (!dptr->data[s_pos]) goto out; } 假設有兩個 process (A and B) 都執行到 if (!dptr->data[s_pos]) 則 ?
Concurrency and Its Managemen Linux 自 2.6 版本後加入了可插隊 目前的系統大多都是 SMP 架構 熱插拔
Semaphores and Mutex void sema_init(struct semaphore *sem, int val); DECLARE_MUTEX(name); //1 DECLARE_MUTEX_LOCKED(name);//0 void init_MUTEX(struct semaphore *sem); void init_MUTEX_LOCKED(struct semaphore *sem);
Semaphores and Mutex Down up void down(struct semaphore *sem); int down_interruptible(struct semaphore *sem); int down_trylock(struct semaphore *sem); void up(struct semaphore *sem);
Semaphores and Mutex 複習一下 Scull_dev 的結構 struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the current array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */ };
Semaphores and Mutex Scull 初始化 for (i = 0; i < scull_nr_devs; i++) { scull_devices[i].quantum = scull_quantum; scull_devices[i].qset = scull_qset; sema_init(&scull_devices[i].sem, 1); scull_setup_cdev(&scull_devices[i], i); }
Semaphores and Mutex Reader void init_rwsem(struct rw_semaphore *sem); void down_write(struct rw_semaphore *sem); int down_write_trylock(struct rw_semaphore *sem); void up_write(struct rw_semaphore *sem); void downgrade_write(struct rw_semaphore *sem);
Semaphores and Mutex Writer void down_write(struct rw_semaphore *sem); int down_write_trylock(struct rw_semaphore *sem); void up_write(struct rw_semaphore *sem); void downgrade_write(struct rw_semaphore *sem);
Completions 等候完成 完成通知 DECLARE_COMPLETION(my_completion); void wait_for_completion(struct completion *c); void complete(struct completion *c); void complete_all(struct completion *c);
Completions Read Write ssize_t complete_read (struct file *filp, char __user *buf, size_t count, loff_t *pos){ printk(KERN_DEBUG "process %i (%s) going to sleep\n",current->pid, current- >comm); wait_for_completion(&comp); printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); ] return 0; /* EOF */ } ssize_t complete_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) awakening the readers...\n", current- >pid, current->comm); complete(&comp); return count; /* succeed, to avoid retrial */ }
Spinlocks spinlock_t my_lock = SPIN_LOCK_UNLOCKED; void spin_lock_init(spinlock_t *lock); Lock void spin_lock(spinlock_t *lock); unLock void spin_unlock(spinlock_t *lock);
Spinlocks Lock void spin_lock(spinlock_t *lock); void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); void spin_lock_irq(spinlock_t *lock); void spin_lock_bh(spinlock_t *lock) unLock void spin_unlock(spinlock_t *lock); void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); void spin_unlock_irq(spinlock_t *lock); void spin_unlock_bh(spinlock_t *lock);
Spinlocks tryLock int spin_trylock(spinlock_t *lock); int spin_trylock_bh(spinlock_t *lock);
Spinlocks Read void read_lock(rwlock_t *lock); void read_lock_irqsave(rwlock_t *lock, unsigned long flags); void read_lock_irq(rwlock_t *lock); void read_lock_bh(rwlock_t *lock); void read_unlock(rwlock_t *lock); void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags); void read_unlock_irq(rwlock_t *lock); void read_unlock_bh(rwlock_t *lock);
Spinlocks Write void write_lock(rwlock_t *lock); void write_lock_irqsave(rwlock_t *lock, unsigned long flags); void write_lock_irq(rwlock_t *lock); void write_lock_bh(rwlock_t *lock); int write_trylock(rwlock_t *lock); void write_unlock(rwlock_t *lock); void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags); void write_unlock_irq(rwlock_t *lock); void write_unlock_bh(rwlock_t *lock);
鎖定機制的使用準則 規則明確 不同時鎖定多個資源 規劃時仔細考慮鎖定的區間
鎖定機制外的選擇 無所演算法 連動運算 位元運算 Ready-Copy-Upate (RCU)