Aprendizaje integrado impulsado por LINUX 8 condiciones de carrera y problemas relacionados con la concurrencia (4) semáforo
El semáforo se ejecuta en el proceso y puede finalizar debido a un tiempo de espera o una señal de interrupción, y puede realizar la operación de suspensión.
1. Archivos de encabezado, funciones y descripciones
//源码位置:include/linux/semaphore.h
//结构体对象:struct semaphore {}
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
/*
初始化信号量函数:sema_init()
*/
static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}
#define __SEMAPHORE_INITIALIZER(name, n) \
{ \
.lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock), \
.count = n, \
.wait_list = LIST_HEAD_INIT((name).wait_list), \
}
/*
获取信号量函数:down()
函数实现源码位置:kernel/semaphore.c
*/
void down(struct semaphore *sem)
{
unsigned long flags;
raw_spin_lock_irqsave(&sem->lock, flags);
/*
判断是否还有信号量对象可以获取
如果有,执行 -1 操作,
如果没有,等待信号到来(但可以因超时或中断信号而结束)
关于__down()函数的实现,见源码附A.1
*/
if (likely(sem->count > 0))
sem->count--;
else
__down(sem);
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(down);
/*
释放信号量函数 :up()
实现源码位置:kernel/semaphore.c
*/
void up(struct semaphore *sem)
{
unsigned long flags;
raw_spin_lock_irqsave(&sem->lock, flags);
/*
判断信号量等待列表是否有对象:
如果没有对象(即:count =0),执行count ++ 操作
如果有对象,唤醒等待的对象;
*/
if (likely(list_empty(&sem->wait_list)))
sem->count++;
else
__up(sem);//实现方式,见源码,附A1.2
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(up);
Dos, ejemplo de código (espacio del kernel)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/semaphore.h>
static struct semaphore sema;
static int sema_open(struct inode * inode , struct file * file){
printk("文件将准备获取信号量......\n");
down(&sema);//获取信号量,如果没有,将执休眠等待操作
printk("获取信号量成功,打开文件成功\n");
return 0;
}
static int sema_close(struct inode * inode , struct file * file){
printk("准备关闭文件\n");
up(&sema);//释放信号量,并唤醒所有等待信号量的进程
printk("文件关闭完成,释放信号量\n");
return 0;
}
struct file_operations f_ops = {
.owner = THIS_MODULE,
.open = sema_open,
.release = sema_close
};
struct miscdevice misc_fops = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mysema_drv",
.fops = &f_ops
};
static int mysema_fops_init(void){
sema_init(&sema,1);//初始化信号量对象,每次只能1个进程打开文件
misc_register(&misc_fops);
return 0;
}
static void mysema_fops_exit(void){
misc_deregister(&misc_fops);
}
module_init(mysema_fops_init);
module_exit(mysema_fops_exit);
MODULE_LICENSE("GPL");
Tres, ejemplo de código (espacio de usuario)
include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc , char * argv[]){
int fp = open(argv[1],O_RDWR);
if(fp < 0)
goto err_file;
sleep(100);
close(fp)
return 0;
err_file :
printf("文件打开失败\n");
return -1;
}
Cuatro, prueba
#关闭超时功能
echo 0 > /proc/sys/kernel/hung_task_timeout_secs
/drivers/test # ./a /dev/mysema_drv &
/drivers/test # [ 594.834000] 文件将准备获取信号量......
[ 594.835000] 获取信号量成功,打开文件成功
/drivers/test # ./a /dev/mysema_drv &
/drivers/test # [ 598.652000] 文件将准备获取信号量......
/drivers/test # ./a /dev/mysema_drv &
/drivers/test #
/drivers/test # ./a /dev/mysema_drv &
[ 694.838000] 准备关闭文件
[ 694.838000] 文件关闭完成,释放信号量
[ 694.839000] 获取信号量成功,打开文件成功
[ 694.840000] 文件将准备获取信号量......
[ 794.838000] 准备关闭文件
[ 794.838000] 文件关闭完成,释放信号量
[ 794.839000] 获取信号量成功,打开文件成功
[ 794.840000] 文件将准备获取信号量......
[ 894.839000] 准备关闭文件
[ 894.839000] 文件关闭完成,释放信号量
[ 894.840000] 获取信号量成功,打开文件成功
[ 894.841000] 准备关闭文件
[ 894.842000] 文件关闭完成,释放信号量
Anexo A.1
/*
源码位置:kernel/semaphore.c
*/
static noinline void __sched __down(struct semaphore *sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
static inline int __sched __down_common(struct semaphore *sem, long state,
long timeout)
{
struct task_struct *task = current;
struct semaphore_waiter waiter;
list_add_tail(&waiter.list, &sem->wait_list);
waiter.task = task;
waiter.up = 0;
/*死循环,等待*/
for (;;) {
if (signal_pending_state(state, task))
goto interrupted;//因中断信号而结束
if (timeout <= 0)
goto timed_out; //因超时而结束
__set_task_state(task, state);
raw_spin_unlock_irq(&sem->lock);
timeout = schedule_timeout(timeout);
raw_spin_lock_irq(&sem->lock);
if (waiter.up) //当up()执行时,会将waiter.up =1;此时结束循环
return 0;
}
timed_out:
list_del(&waiter.list);
return -ETIME;
interrupted:
list_del(&waiter.list);
return -EINTR;
}
Apéndice 1.2
static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter, list);
list_del(&waiter->list);
waiter->up = 1;//此刻down()函数中的死循环会结束
wake_up_process(waiter->task);
}