线程同步第一篇
completion
数据结构
struct swait_queue_head {
raw_spinlock_t lock;
struct list_head task_list;
};
struct completion {
unsigned int done;
struct swait_queue_head wait;
};
Linux APIs
static inline void init_completion(struct completion *x);
void wait_for_completion(struct completion *);
int __sched wait_for_completion_interruptible(struct completion *x);
void complete(struct completion *);
bool completion_done(struct completion *x);
在Linux驱动器中的应用
imx SPI 驱动器
变量定义
在结构中,定义两个completion 变量,dma_rx_completion 和 dma_tx_completion。
struct spi_imx_data {
...
struct completion dma_rx_completion;
struct completion dma_tx_completion;
...
};
初始化
在sdma初始化程序中,调用init_completion函数初始化这两个变量。见下列的程序代码段。
static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
struct spi_master *master)
{
...
init_completion(&spi_imx->dma_rx_completion);
init_completion(&spi_imx->dma_tx_completion);
...
}
等待任务完成
在触发sdma传送之后,调用wait_for_completion_interruptible函数等待sdma传送结束。
static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
struct spi_transfer *transfer)
{
...
spi_imx->devtype_data->trigger(spi_imx);
if (wait_for_completion_interruptible(&spi_imx->dma_tx_completion) ||
spi_imx->slave_aborted) {
dev_dbg(spi_imx->dev,
"I/O Error in DMA TX interrupted\n");
dmaengine_terminate_all(master->dma_tx);
dmaengine_terminate_all(master->dma_rx);
return -EINTR;
}
if (wait_for_completion_interruptible(&spi_imx->dma_rx_completion) ||
spi_imx->slave_aborted) {
dev_dbg(spi_imx->dev,
"I/O Error in DMA RX interrupted\n");
dmaengine_terminate_all(master->dma_tx);
dmaengine_terminate_all(master->dma_rx);
return -EINTR;
}
...
}
通知任务完成
在sdma完成回调函数中,使用complete API,通知任务已经完成。
static void spi_imx_dma_rx_callback(void *cookie)
{
struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
complete(&spi_imx->dma_rx_completion);
}
static void spi_imx_dma_tx_callback(void *cookie)
{
struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
complete(&spi_imx->dma_tx_completion);
}
spin_lock
数据结构
typedef volatile int pthread_spinlock_t;
typedef pthread_spinlock_t spinlock_t;
APIs
spin_lock_init(spinlock_t *lock);
int spin_is_locked(spinlock_t *lock)
void spin_lock(spinlock_t *lock);
void spin_unlock(spinlock_t *lock);
int spin_trylock(spinlock_t *lock);
spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_unlock_irq(spinlock_t *lock);
int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
int atomic_dec_and_lock_irqsave((atomic_t *atomic, spinlock_t *lock, unsigned long *flags);
在Linux内核中的应用
AT91 SPI 驱动器
在设备探测代码中,初始化
int at91_usart_spi_probe(struct platform_device *pdev) {
...
spin_lock_init(&aus->lock);
....
}
在中断处理程序中使用
该中断处理程序是不可重入代码,在多CPU核心的系统中,这是必要的。
在加入中断处理代码时,使用spinlock给这个代码加锁,在执行完代码,返回之前,解锁。
irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id) {
...
spin_lock(&aus->lock);
...
if (at91_usart_spi_rx_ready(aus)) {
at91_usart_spi_rx(aus);
spin_unlock(&aus->lock);
return IRQ_HANDLED;
}
spin_unlock(&aus->lock);
return IRQ_NONE;
}