15年做那些网站能致富视频网站怎么建设
2026/5/18 20:44:18 网站建设 项目流程
15年做那些网站能致富,视频网站怎么建设,网站做友链盈利,公司备案号查询平台官网klist链表#x1f4a1;本文基于linux-v4.14.71. 概述 klist 是 Linux 内核中基于 list_head 扩展的链表结构#xff0c;提供了引用计数和线程安全的遍历机制。1.1 设计目的 klist 的设计目标是解决以下问题#xff1a; 安全遍历#xff1a;允许在遍历过程中安全地修改链表本文基于linux-v4.14.71. 概述klist是 Linux 内核中基于list_head扩展的链表结构提供了引用计数和线程安全的遍历机制。1.1 设计目的klist的设计目标是解决以下问题安全遍历允许在遍历过程中安全地修改链表插入、删除节点引用计数通过kref机制管理节点的生命周期延迟删除节点被标记删除后只有在引用计数为 0 时才真正移除线程安全使用自旋锁保护链表操作1.2 核心特性基于list_head的双向循环链表每个节点包含引用计数kref支持在遍历过程中安全删除节点提供get/put回调函数用于管理嵌入对象的引用计数2. 数据结构定义klist它表示的是一个对象的集合本质上是一个带锁带引用保护的双向链表。structklist{spinlock_tk_lock;// 保护链表的自旋锁structlist_headk_list;// 实际的链表头void(*get)(structklist_node*);// 获取节点时的回调void(*put)(structklist_node*);// 释放节点时的回调}__attribute__((aligned(sizeof(void*))));klist_node被挂到klist中的“某个对象”是链表里的一个成员。structklist_node{void*n_klist;// 指向所属的 klist低位用作删除标记structlist_headn_node;// 链表节点用于链入链表structkrefn_ref;// 引用计数当计数为0时节点被真正的删除};klist_iter用来表示一次klist遍历过程的状态上下文structklist_iter{structklist*i_klist;// 正在遍历的 kliststructklist_node*i_cur;// 当前所在的节点};klist_waiter用来等待某个节点引用计数归0structklist_waiter{structlist_headlist;/* 链表节点用于插入到klist_remove_waiters全局链表 */structklist_node*node;/* 等待的节点 */structtask_struct*process;/* 保存当前运行的进程用于后续被唤醒 */intwoken;};3. 核心操作函数源码分析3.1 初始化klist_init初始化整个klist容器get和put是获取和释放节点时的回调函数。voidklist_init(structklist*k,void(*get)(structklist_node*),void(*put)(structklist_node*)){INIT_LIST_HEAD(k-k_list);spin_lock_init(k-k_lock);k-getget;k-putput;}初始化klist某个节点它会初始化该对象的kref-refcount引用计数为1然后将klist_node绑定到指定的klist并且如果get存在的话则触发回调函数。staticvoidklist_node_init(structklist*k,structklist_node*n){INIT_LIST_HEAD(n-n_node);kref_init(n-n_ref);knode_set_klist(n,k);if(k-get)k-get(n);}3.2 添加节点klist_add_head在链表头部添加节点实现调用klist_node_init初始化改节点然后调用add_head将其添加到链表头。voidklist_add_head(structklist_node*n,structklist*k){klist_node_init(k,n);add_head(k,n);}klist_add_tail在链表尾部添加节点逻辑和klist_add_head一样只是节点插入的位置不一样。voidklist_add_tail(structklist_node*n,structklist*k){klist_node_init(k,n);add_tail(k,n);}klist_add_behind/klist_add_before在指定节点后/前添加节点逻辑也和上面一样只是节点插入的位置不一样。voidklist_add_behind(structklist_node*n,structklist_node*pos){structklist*kknode_klist(pos);klist_node_init(k,n);spin_lock(k-k_lock);list_add(n-n_node,pos-n_node);spin_unlock(k-k_lock);}voidklist_add_before(structklist_node*n,structklist_node*pos){structklist*kknode_klist(pos);klist_node_init(k,n);spin_lock(k-k_lock);list_add_tail(n-n_node,pos-n_node);spin_unlock(k-k_lock);}3.3 删除节点klist_del标记节点为删除状态并递减引用计数他不会立即从链表中移除节点只是标记节点为删除状态设置KNODE_DEAD标志递减引用计数当计数为 0 时才真正删除knode_kill函数核心作用是将knode所绑定n_klist指针设置为KNODE_DEAD。klist_dec_and_del函数内部会递减链表节点的引用计数当计数到0时会触发klist_release函数的调用。voidklist_del(structklist_node*n){klist_put(n,true);}staticvoidklist_put(structklist_node*n,bool kill){structklist*kknode_klist(n);/* 获取所属的klist */void(*put)(structklist_node*)k-put;spin_lock(k-k_lock);if(kill)knode_kill(n);if(!klist_dec_and_del(n))putNULL;spin_unlock(k-k_lock);if(put)put(n);/* 如果有put函数则触发 */}klist_release函数从klist中删除指定的klist_node节点然后唤醒对应的等待进程klist_remove_waiters是一个全局链表保存所有正在等待某个klist_node彻底释放的klist_waiter当对接节点被释放时就换唤醒对应klist_waiter保存的等待进程。staticvoidklist_release(structkref*kref){structklist_waiter*waiter,*tmp;/* 找到对应的klist_node节点 */structklist_node*ncontainer_of(kref,structklist_node,n_ref);WARN_ON(!knode_dead(n));list_del(n-n_node);/* 删除链表节点 */spin_lock(klist_remove_lock);/* 找到等待当前klist_node的waiter*/list_for_each_entry_safe(waiter,tmp,klist_remove_waiters,list){if(waiter-node!n)continue;/* 将该waiter节点从waiter链表中删除然后唤醒对应的等待进程 */list_del(waiter-list);waiter-woken1;mb();wake_up_process(waiter-process);}spin_unlock(klist_remove_lock);/* 将已删除的kist_node的绑定的n_klist设置为NULL */knode_set_klist(n,NULL);}klist_remove删除节点并等待其真正被移除调用klist_del标记删除阻塞等待直到节点引用计数为0并被真正移除适用于需要确保节点完全移除的场景。voidklist_remove(structklist_node*n){structklist_waiterwaiter;waiter.noden;/* 保存当前要删除的节点 */waiter.processcurrent;/* 保存当前运行的进程 */waiter.woken0;/* 将klist_waiter节点插入到全局等待链表 */spin_lock(klist_remove_lock);list_add(waiter.list,klist_remove_waiters);spin_unlock(klist_remove_lock);klist_del(n);/* 引用计数-1 *//* 让出CPU当节点被删除时会被唤醒 */for(;;){set_current_state(TASK_UNINTERRUPTIBLE);if(waiter.woken)break;schedule();}/* 恢复运行态 */__set_current_state(TASK_RUNNING);}3.4 遍历操作klist_iter_init用于初始化遍历器将i_klist指向k因为还未开始遍历c_cur设置为NULL。voidklist_iter_init(structklist*k,structklist_iter*i){klist_iter_init_node(k,i,NULL);}klist_iter_init_node初始化遍历器从指定节点开始遍历voidklist_iter_init_node(structklist*k,structklist_iter*i,structklist_node*n){i-i_klistk;i-i_curNULL;/* 引用计数不为0则增加节点的引用计数遍历器的当前遍历节点指向n */if(nkref_get_unless_zero(n-n_ref))i-i_curn;}klist_next获取下一个节点to_klist_node函数通过链表成员找到对应的klist_node节点。通过调用knode_dead来检查节点是否被标记为了KNODE_DEAD如果是则遍历器跳过该节点如果不是则返回该节点。klist_prev获取前一个节点实现机制类似klist_next。structklist_node*klist_next(structklist_iter*i){void(*put)(structklist_node*)i-i_klist-put;structklist_node*lasti-i_cur;structklist_node*next;spin_lock(i-i_klist-k_lock);if(last){/* 找到下一个klist_node节点 */nextto_klist_node(last-n_node.next);if(!klist_dec_and_del(last))/* 引用计数-1 */putNULL;/* 对象仍在使用 */}else/* 当遍历器没有当前节点last时从链表头获取第一个节点 */nextto_klist_node(i-i_klist-k_list.next);i-i_curNULL;/* 遍历到链表头则循环终止*/while(next!to_klist_node(i-i_klist-k_list)){/* 节点被标记了KNODE_DEAD时条件不成立 */if(likely(!knode_dead(next))){/* 引用计数1返回该节点 */kref_get(next-n_ref);i-i_curnext;break;}/* 找到下一个klist_node节点 */nextto_klist_node(next-n_node.next);}spin_unlock(i-i_klist-k_lock);/* 如果put存在则对上一个节点调用put */if(putlast)put(last);returni-i_cur;}klist_iter_exit结束遍历释放当前节点的引用计数必须调用此函数来正确释放引用计数。voidklist_iter_exit(structklist_iter*i){if(i-i_cur){/* 内部会递减该节点的引用计数 */klist_put(i-i_cur,false);i-i_curNULL;}}3.5 查询操作klist_node_attached检查节点是否已附加到某个klistintklist_node_attached(structklist_node*n){return(n-n_klist!NULL);}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询