信号量工作原理

一、内核相关文件为include/linux/semaphore.h和kernel/semaphore.c

二、主要结构体:

struct semaphore {
	raw_spinlock_t		lock;
	unsigned int		count;
	struct list_head	wait_list;
};

结构体成员变量解读:

1、lock主要用于保护count和wait_list链表的访问;

2、count记录信号量等待进程的计数;

3、wait_list用于记录等待信号量的进程,串成一个链表来统一管理;

三、相关接口

1、初始化接口

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);
}

接口主要完成互斥锁、信号量计数初始值、链表头结点的初始化操作;

2、down信号量接口

获取信号量接口总共有五个:

extern void down(struct semaphore *sem);
extern int __must_check down_interruptible(struct semaphore *sem);
extern int __must_check down_killable(struct semaphore *sem);
extern int __must_check down_trylock(struct semaphore *sem);
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);

1)down接口内核已不建议使用,按照内核发展趋势,将会逐步取消掉此接口;

2)down信号量接口,一般都建议使用down_interruptible,此接口将会把当前任务状态设置为TASK_INTERRUPTIBLE,意味着一旦满足条件,任务将会在设定的超时时间到来之前被调度;

3)down_killable:可被杀死地获取信号量。如果睡眠被致命信号中断,返回错误-EINTR;

4)down_trylock:此接口上来就去获取信号量,不会设置超时时间,不做任何等待,获取到就返回0,获取不到就返回1;

5)down_timeout:如果上来就获取到信号量,则直接返回,获取不到则睡眠等待设置的超时时间时长;

这五个接口,除了down_trylock,最终都调用了__down_common这个接口,只不过传入的参数不同而已

static noinline void __sched __down(struct semaphore *sem)
{
	__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

static noinline int __sched __down_interruptible(struct semaphore *sem)
{
	return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

static noinline int __sched __down_killable(struct semaphore *sem)
{
	return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT);
}

static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies)
{
	return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies);
}

我们可以看一下__down_common这个接口:首先会把当前进程挂接到信号量的Wait_list链表中,然后会通过schedule_timeout调度其他进程,当前任务挂起;

struct semaphore_waiter {
	struct list_head list;
	struct task_struct *task;
	int up;
};
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)
			return 0;
	}

 timed_out:
	list_del(&waiter.list);
	return -ETIME;

 interrupted:
	list_del(&waiter.list);
	return -EINTR;
}

3、释放信号量接口:此接口主要做了以下工作,首先判断当前信号量的wait_list是否为空,如果为空,即没有任何进程等待此信号量,则直接sem->count++,否则,则把wait_list中第一个节点摘除,通过wake_up_process放置到激活任务队列中,等待执行。

extern void up(struct semaphore *sem);
void up(struct semaphore *sem)
{
	unsigned long flags;

	raw_spin_lock_irqsave(&sem->lock, flags);
	if (likely(list_empty(&sem->wait_list)))
		sem->count++;
	else
		__up(sem);
	raw_spin_unlock_irqrestore(&sem->lock, flags);
}
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;
	wake_up_process(waiter->task);
}
时间: 2024-10-11 12:54:13

信号量工作原理的相关文章

Android ListView工作原理完全解析(转自 郭霖老师博客)

原文地址:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android所有常用的原生控件当中,用法最复杂的应该就是ListView了,它专门用于处理那种内容元素很多,手机屏幕无法展示出所有内容的情况.ListView可以使用列表的形式来展示内容,超出屏幕部分的内容只需要通过手指滑动就可以移动到屏幕内了. 另外ListView还有一个非常神奇的功能,我相信大家应该都体验过,即使在ListView中加载非常非常多的数据,比如达到

LVS集群之工作原理

  首先我们要了解LVS的工作机制: LVS里Director本身不响应请求,只是接受转发请求到后方,Realservers才是后台真正响应请求. LVS 工作原理基本类似DNAT,又不完全相像,它是一种四层交换,默认情况下通过用户请求的地址和端口来判断用户的请求,从而转发到后台真正提供服务的主机,而判断这种请求的是通过套接字来实现,所以四层就可以实现. 而且这个转发的过程对用户而言是透明的(简单的讲,就是用户访问DR的IP,而DR转发给RSS,而用户不知道这个过程) LVS的工作模式: 1.D

47 监控系统基础及zabbix介绍、zabbix工作原理及安装配置、zabbix on CentOS7、zabbix配置

02    zabbix工作原理及安装配置 配置环境 node1192.168.1.120CentOS6.7 node2192.168.1.121CentOS6.7 1.安装配置zabbix #安装前准备 [[email protected] ~]#yum -y install mysql-server mysq [[email protected] ~]# mysql mysql> CREATE DATABASE zabbix CHARACTER SET utf8; mysql> GRANT

inode工作原理及软连接与硬链接

 inode工作原理及软连接,硬链接 inode: 在linux文件系统中,不管什么类型的文件,保存在磁盘分区中时,系统都会分配一个编号,叫做索引节点index node,简称inode inode里面存储了文件的很多参数: 文件类型,权限.UID,GID,属主,属组 链接数(指向这个文件名路径名称个数) 该文件的大小和不同的时间戳 指向磁盘上文件的数据指针 .... 在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)

quarze的工作原理

quartz的工作原理 http://lavasoft.blog.51cto.com/62575/181907/ 几种定时任务的比較 http://blog.sina.com.cn/s/blog_6940cab30101a5pv.html

Java虚拟机工作原理详解

原文地址:http://blog.csdn.net/bingduanlbd/article/details/8363734 一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘当中.然后你在命令行中输入 [java] view plaincopy javac YourClassName.java 此时,你的java代码就被编译成字节码(.class).如果你是在Eclipse IDE或者其他开发工具中,你保存代码

HashMap工作原理、深入理解JVM、正则

HashMap工作原理: http://www.importnew.com/7099.html: http://blog.csdn.net/ghsau/article/details/16843543: http://blog.csdn.net/ghsau/article/details/16890151. 深入理解JVM: http://www.importnew.com/17770.html: http://www.cnblogs.com/dingyingsi/p/3760447.html.

[Java] SSH框架笔记_SSH三大框架的工作原理及流程

Hibernate工作原理及为什么要用? 原理:1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取并解析映射信息3.通过config.buildSessionFactory();//创建SessionFactory4.sessionFactory.openSession();//打

Servlet生命周期和工作原理

Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在下列时刻Servlet容器装载Servlet: 1,Servlet容器启动时自动装载某些Servlet,实现它只需要在web.XML文件中的<Servlet></Servlet>之间添加如下代码: <loadon-startup>1</loadon-startup&g