深入理解RCU实现
RCU链表操作为了操作链表,在include/linux/rculist.h有一套专门的RCU API。如:list_entry_rcu、list_add_rcu、list_del_rcu、list_for_each_entry_rcu等。即对所有kernel 的list的操作都有一个对应的RCU操作。那么这些操作和原始的list操作有哪些不同呢?我们先对比几个看下。 l list_entry_rcu #define list_entry_rcu(ptr, type, member) container_of(rcu_dereference(ptr), type, member) #define list_entry(ptr, type, member) container_of(ptr, type, member) l __list_for_each_rcu #define __list_for_each_rcu(pos, head) for (pos = rcu_dereference((head)->next); pos != (head); pos = rcu_dereference(pos->next)) #define __list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next) 从__list_for_each_rcu和list_entry_rcu的实现可以看出,其将指针的获取替换为使用rcu_dereference。 l list_replace_rcu static inline void list_replace_rcu(struct list_head *old, struct list_head *new) {
} static inline void list_replace(struct list_head *old, struct list_head *new) {
} 从list_replace_rcu的实现可以看出,RCU API的实现将指针的赋值替换为rcu_assign_pointer。 l list_del_rcu static inline void list_del_rcu(struct list_head *entry) {
} static inline void list_del(struct list_head *entry) {
} 从list_del_rcu的实现,可以看出RCU API的实现没有将删除项的next指针置为无效。这样实现是为了防止删除节点时,读者还在遍历该节点。 RCU链表API使用下面看下RCU list API的几个应用示例。 只有增加和删除的链表操作在这种应用情况下,绝大部分是对链表的遍历,即读操作,而很少出现的写操作只有增加或删除链表项,并没有对链表项的修改操作,这种情况使用RCU非常容易,从rwlock转换成RCU非常自然。路由表的维护就是这种情况的典型应用,对路由表的操作,绝大部分是路由表查询,而对路由表的写操作也仅仅是增加或删除,因此使用RCU替换原来的rwlock顺理成章。系统调用审计也是这样的情况。 这是一段使用rwlock的系统调用审计部分的读端代码: static enum audit_state audit_filter_task(struct task_struct *tsk) { struct audit_entry *e; enum audit_state state; read_lock(&auditsc_lock); /* Note: audit_netlink_sem held by caller. */ list_for_each_entry(e, &audit_tsklist, list) { (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |