- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
semaphore的实现机制详解
semaphore的实现机制详解
semaphore是内核中比较重要和常用的同步方式之一,他主要的特点是实现了Sleep机制下的同步。也就是当获取一个semaphore但是又不能立刻获取的时候,他使当前的执行进程进入到Sleep状态中等待,当semaphore可以获取的时候,从新开始运行,而不像splin lock在获取锁的时候是BusyWait。
首先看其定义:
struct semaphore {
atomic_t count; // 原子变量,是后续的实际代码中,我们能看到其即为我们在初始化时所设置的信号量。
int sleepers; // 有几个等待者。
wait_queue_head_t wait; // 等待队列
};
初始化函数:
static inline void sema_init (struct semaphore *sem, int val)
{
atomic_set(sem-count, val); // 原子操作,把信号量的值设为原子操作的值。
sem-sleepers = 0; // 设为等待者为0。
init_waitqueue_head(sem-wait); // 初始化等待队列。
}
好看完了初始化函数,我们来看一下一个特例PV操作:
static inline void init_MUTEX (struct semaphore *sem)
{
sema_init(sem, 1);
}
static inline void init_MUTEX_LOCKED (struct semaphore *sem)
{
sema_init(sem, 0);
}
从中我们可以看到,其实我们所说的PV操作就是调用sema_init来把其中的原子变量分别置0或者1。
下面我们来看下具体的操作函数:
static inline void down(struct semaphore * sem)
{
might_sleep();
__asm__ __volatile__(
# atomic down operation\n\t
LOCK_PREFIX decl %0\n\t /* --sem-count */
jns 2f\n
\tlea %0,%%eax\n\t
call __down_failed\n
2:
:+m (sem-count)
:
:memory,ax);
}
关于might_sleep():
#define might_sleep() \
do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0)
从中可以看到其根本是调用might_resched():
#define might_resched() cond_resched()
其调用了cond_resched():
int __sched cond_resched(void)
{
if (need_resched() !(preempt_count() PREEMPT_ACTIVE)
system_state == SYSTEM_RUNNING) {
__cond_resched();
return 1;
}
return 0;
}
其中:
static inline int need_resched(void)
{
return unlikely(test_thread_flag(TIF_NEED_RESCHED));
// TIF_NEED_RESCHED 这个值在arm是2,在i386中是3。
}
其是判断进程的状态是否是需要调度。
其具体实现是:
#define test_thread_flag(flag) \
test_ti_thread_flag(current_thread_info(), flag)
得到当前进程的状态,然后和flag做位操作,判断是否可以做调度。
看下关于抢占机制的判断:
#define preempt_count() (current_thread_info()-preempt_count)
调用preempt_count()得到当前进程关于抢占的状态,preempt_count PREEMPT_ACTIVE 为TRUE,取反为当前不可以抢占,就不能调度,否则为可调度。
看些系统状态:system_state 为运行状态。
综合上面的几个条件,我们看出当前进程可以被调度或者说抢占,于是当前进程被调度放弃CPU资源。
might_sleep宏就是检查是否需要重新调度。
下面我们进入
文档评论(0)