首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux 2.6内核中新的锁机制--RCU(3)API

Linux 2.6内核中新的锁机制--RCU(3)API

四、RCU APIrcu_read_lock()
读者在读取由RCU保护的共享数据时使用该函数标记它进入读端临界区。
rcu_read_unlock()
该函数与rcu_read_lock配对使用,用以标记读者退出读端临界区。夹在这两个函数之间的代码区称为"读端临界区"(read-side critical section)。读端临界区可以嵌套,如图3,临界区2被嵌套在临界区1内。
图 3  嵌套读端临界区示例synchronize_rcu()
该函数由RCU写端调用,它将阻塞写者,直到经过grace period后,即所有的读者已经完成读端临界区,写者才可以继续下一步操作。如果有多个RCU写端调用该函数,他们将在一个grace period之后全部被唤醒。注意,该函数在2.6.11及以前的2.6内核版本中为synchronize_kernel,只是在2.6.12才更名为synchronize_rcu,但在2.6.12中也提供了synchronize_kernel和一个新的函数synchronize_sched,因为以前有很多内核开发者使用synchronize_kernel用于等待所有CPU都退出不可抢占区,而在RCU设计时该函数只是用于等待所有CPU都退出读端临界区,它可能会随着RCU实现的修改而发生语意变化,因此为了预先防止这种情况发生,在新的修改中增加了专门的用于其它内核用户的synchronize_sched函数和只用于RCU使用的synchronize_rcu,现在建议非RCU内核代码部分不使用synchronize_kernel而使用synchronize_sched,RCU代码部分则使用synchronize_rcu,synchronize_kernel之所以存在是为了保证代码兼容性。
synchronize_kernel()
其他非RCU的内核代码使用该函数来等待所有CPU处在可抢占状态,目前功能等同于synchronize_rcu,但现在已经不建议使用,而使用synchronize_sched。
synchronize_sched()
该函数用于等待所有CPU都处在可抢占状态,它能保证正在运行的中断处理函数处理完毕,但不能保证正在运行的softirq处理完毕。注意,synchronize_rcu只保证所有CPU都处理完正在运行的读端临界区。注:在2.6.12内核中,synchronize_kernel和synchronize_sched都实际使用synchronize_rcu,因此当前它们的功能实际是完全等同的,但是将来将可能有大的变化,因此务必根据需求选择恰当的函数。
1
2
3
4
5
6
void fastcall call_rcu(struct rcu_head *head,
                                void (*func)(struct rcu_head *rcu))
struct rcu_head {
        struct rcu_head *next;
        void (*func)(struct rcu_head *head);
};




函数 call_rcu 也由 RCU 写端调用,它不会使写者阻塞,因而可以在中断上下文或 softirq 使用,而 synchronize_rcu、synchronize_kernel 和synchronize_shced 只能在进程上下文使用。该函数将把函数 func 挂接到 RCU回调函数链上,然后立即返回。一旦所有的 CPU 都已经完成端临界区操作,该函数将被调用来释放删除的将绝不在被应用的数据。参数 head 用于记录回调函数 func,一般该结构会作为被 RCU 保护的数据结构的一个字段,以便省去单独为该结构分配内存的操作。需要指出的是,函数 synchronize_rcu 的实现实际上使用函数call_rcu。
1
2
void fastcall call_rcu_bh(struct rcu_head *head,
                                void (*func)(struct rcu_head *rcu))




函数call_ruc_bh功能几乎与call_rcu完全相同,唯一差别就是它把softirq的完成也当作经历一个quiescent state,因此如果写端使用了该函数,在进程上下文的读端必须使用rcu_read_lock_bh。
1
2
3
4
5
#define rcu_dereference(p)     ({ \
                                typeof(p) _________p1 = p; \
                                smp_read_barrier_depends(); \
                                (_________p1); \
                                })




该宏用于在RCU读端临界区获得一个RCU保护的指针,该指针可以在以后安全地引用,内存栅只在alpha架构上才使用。
除了这些API,RCU还增加了链表操作的RCU版本,因为对于RCU,对共享数据的操作必须保证能够被没有使用同步机制的读者看到,所以内存栅是非常必要的。
static inline void list_add_rcu(struct list_head *new, struct list_head *head)该函数把链表项new插入到RCU保护的链表head的开头。使用内存栅保证了在引用这个新插入的链表项之前,新链表项的链接指针的修改对所有读者是可见的。
1
2
static inline void list_add_tail_rcu(struct list_head *new,
                                        struct list_head *head)




该函数类似于list_add_rcu,它将把新的链表项new添加到被RCU保护的链表的末尾。
1
static inline void list_del_rcu(struct list_head *entry)




该函数从RCU保护的链表中移走指定的链表项entry,并且把entry的prev指针设置为LIST_POISON2,但是并没有把entry的next指针设置为LIST_POISON1,因为该指针可能仍然在被读者用于便利该链表。
1
static inline void list_replace_rcu(struct list_head *old, struct list_head *new)




该函数是RCU新添加的函数,并不存在非RCU版本。它使用新的链表项new取代旧的链表项old,内存栅保证在引用新的链表项之前,它的链接指针的修正对所有读者可见。
1
list_for_each_rcu(pos, head)




该宏用于遍历由RCU保护的链表head,只要在读端临界区使用该函数,它就可以安全地和其它_rcu链表操作函数(如list_add_rcu)并发运行。
1
list_for_each_safe_rcu(pos, n, head)




该宏类似于list_for_each_rcu,但不同之处在于它允许安全地删除当前链表项pos。
1
list_for_each_entry_rcu(pos, head, member)




该宏类似于list_for_each_rcu,不同之处在于它用于遍历指定类型的数据结构链表,当前链表项pos为一包含struct list_head结构的特定的数据结构。
1
list_for_each_continue_rcu(pos, head)




该宏用于在退出点之后继续遍历由RCU保护的链表head。
1
static inline void hlist_del_rcu(struct hlist_node *n)




它从由RCU保护的哈希链表中移走链表项n,并设置n的ppre指针为LIST_POISON2,但并没有设置next为LIST_POISON1,因为该指针可能被读者使用用于遍利链表。
1
2
static inline void hlist_add_head_rcu(struct hlist_node *n,
                                        struct hlist_head *h)




该函数用于把链表项n插入到被RCU保护的哈希链表的开头,但同时允许读者对该哈希链表的遍历。内存栅确保在引用新链表项之前,它的指针修正对所有读者可见。
1
hlist_for_each_rcu(pos, head)




该宏用于遍历由RCU保护的哈希链表head,只要在读端临界区使用该函数,它就可以安全地和其它_rcu哈希链表操作函数(如hlist_add_rcu)并发运行。
1
hlist_for_each_entry_rcu(tpos, pos, head, member)




类似于hlist_for_each_rcu,不同之处在于它用于遍历指定类型的数据结构哈希链表,当前链表项pos为一包含struct list_head结构的特定的数据结构。
返回列表