前者是一种异步方式,call_rcu会将释放老指针的回调函数放入一个结点中,然后将该结点加入到当前正在运行call_rcu的处理器的本地链表中,在时钟中断的 softirq部分(RCU_SOFTIRQ), rcu软中断处理函数rcu_process_callbacks会检查当前处理器是否经历了一个休眠期(quiescent,此处涉及内核进程调度等方面的内容),rcu的内核代码...
对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它,但写者在访问它时首先拷贝一个副本,然后对副本进行修改,最后使用一个回调(callback)机制在适当的时机把指向原来数据的指针替换为新的被修改的数据。这个时机就是所有引用该数据的CPU都退出对共享数据的访问。 RCU的优点? 在面对内核中需要频繁读但是不...
rcu_read_lock() / rcu_read_unlock():用于进入和离开RCU读取段,保证了在这两个函数调用内的读取不会看到中间状态的数据。 synchronize_rcu():等待一个RCU宽限期的结束,确保之前的所有RCU读者都已经完成。 call_rcu():将一个回调函数传递给RCU,该函数会在RCU宽限期之后被调用,用于释放老的数据结构。 kfree_...
在回收的时候,分别用了synchronize_rcu同步回收和call_rcu异步回收两种机制; 为了简化代码,基本的容错判断都已经省略了; 没有考虑多个Updater的机制,因此,也省略掉了Updater之间的互斥操作; #include<linux/module.h>#include<linux/init.h>#include<linux/slab.h>#include<linux/kthread.h>#include<linux/rcupdate...
Updater使用synchronize_rcu或call_rcu来启动Reclaimer,对旧的临界资源进行回收,其中synchronize_rcu表示同步等待回收,call_rcu表示异步回收; Reclaimer Reclaimer回收的是旧的临界资源; 为了确保没有读者正在访问要回收的临界资源,Reclaimer需要等待所有的读者退出临界区,这个等待的时间叫做宽限期(Grace Period); ...
对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它,但写者在访问它时首先拷贝一个副本,然后对副本进行修改,最后使用一个回调(callback)机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据。这个时机就是所有引用该数据的CPU都退出对共享数据的操作。
//指向特定RCU类型的call_rcu函数:call_rcu_sched, call_rcu_bh等int ncpus;// 处理器数量unsigned long gpnum;//当前宽限期编号,gpnum > completed,表明正处在宽限期内unsigned long completed;//上一个结束的宽限期编号,如果与gpnum相等,表明RCU空闲...unsigned long gp_max;//最长的宽限期时间,...
在实时RCU、SRCU或QRCU中,被抢占的读者将阻止正在进行中的优雅周期的完成,即使有高优先级的任务在等待优雅周期完成时也是如此。实时RCU可以通过用call_rcu()替换synchronize_rcu()来避免此问题,或者采用RCU优先级提升来避免。 除了那些“玩具”RCU实现,RCU优雅周期可能会延续好几个毫秒。这使得RCU更适于使用在读数据...
在释放老指针方面,Linux内核提供两种方法供使用者使用,一个是调用call_rcu,另一个是调用synchronize_rcu。前者是一种异步 方式,call_rcu会将释放老指针的回调函数放入一个结点中,然后将该结点加入到当前正在运行call_rcu的处理器的本地链表中,在时钟中断的 softirq部分(RCU_SOFTIRQ), rcu软中断处理函数rcu_process_...
因为,这时候读操作可能还在读取旧数据,所以,必须等到所有的可能的读操作执行rcu_read_unlock()离开临界代码段后,旧数据的存储空间才能被释放。 (4)调用call_rcu(),完成旧数据存储空间的回收工作。该函数的参数是类型为rcu_head的描述符的地址。该描述符嵌入在要回收的数据结构的内部。该函数还有一个参数就是一个...