linux deepin内核头文件解析(二)——WRITE_ONCE函数和list.h

本文深入解析LinuxDeepin内核中的list.h文件,详细介绍了链表操作函数如添加、删除节点的实现原理,包括WRITE_ONCE和__write_once_size函数的作用,以及链表节点的删除和安全赋值机制。

前文书道:linux deepin内核头文件解析(一)——list.h

前文代码

static inline void __list_add(struct list_head *new,
			      struct list_head *prev,
			      struct list_head *next)
{
	if (!__list_add_valid(new, prev, next))
		return;
 
	next->prev = new;
	new->next = next;
	new->prev = prev;
	WRITE_ONCE(prev->next, new);
}

出现了函数WRITE_ONCE()来将prev->next和new链接,现在来仔细研究WRITE_ONCE函数。

函数定义在文件include/linux/compile.h

#define WRITE_ONCE(x, val) \
({							\
	union { typeof(x) __val; char __c[1]; } __u =	\
		{ .__val = (__force typeof(x)) (val) }; \
	__write_once_size(&(x), __u.__c, sizeof(x));	\
	__u.__val;					\
})

c源码为了高效率使用了宏定义的写法,现在为了提高可读性我来改写代码(降低了效率):

template<class T>
void WRITE_ONCE(T x, T var) {
    union { 
        typeof(x) __val; 
        char __c[1]; 
    } __u = { .__val = (__force typeof(x)) (val) };
    __write_once_size(&(x), __u.__c, sizeof(x));
    __u.__val;			
}

这里居然又出现了函数__write_once_size(),追根溯源把,转到__write_once_size的定义:

static __always_inline void __write_once_size(volatile void *p, void *res, int size)
{
	switch (size) {
	case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
	case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
	case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
	case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
	default:
		barrier();
		__builtin_memcpy((void *)p, (const void *)res, size);
		barrier();
	}
}

这里很容易可以看出函数__write_once_size(void *a, void *b, int size)目的是为了安全地使指针b赋值给指针a,而且不会出现指针类型错误,而且用了volatile关键字保证编译器不回因为优化而忽略这些代码,这很鲁棒!

所以语句

WRITE_ONCE(prev->next, new);

的真正作用就是安全地将prev->next指向new!

下一个函数

static inline void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

作用一目了然,也是链表添加节点,但参数只有两个,新节点地址和链表头emmmm,果然懒惰是人类进步的驱动力,双向链表嘛,不严谨的说每一个节点都可以是头节点。

下一个函数是往尾节点后添加新节点:

static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

下面进入节点的删除环节,注释是这么说的:

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * 通过给出prev和next来删除他们互相指向的入口(节点)
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 * 这是链表的内部操作,必须在我们已经知晓prev和next入口的前提下
 */
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
	next->prev = prev;
	WRITE_ONCE(prev->next, next);
}

 上图!

我执行代码__list_del(&n, &(n+2));

结果是什么呢,我把节点(n+2)的prev指向了节点n,把节点n的next指向了节点(n+2),现在节点(n+1)已经被孤立出链表的逻辑结构了!无论节点(n+1)还在不在内存里!

如下:

static inline void __list_del_entry(struct list_head *entry)
{
	if (!__list_del_entry_valid(entry))
		return;

	__list_del(entry->prev, entry->next);
}

__list_del_entry()函数传入一个节点(入口)地址,其中又出现新函数__list_del_entry_valid(),定位它:

static inline bool __list_del_entry_valid(struct list_head *entry)
{
	return true;
}

emmm,也就是说,如果传入的entry参数是list_head类型的指针,那么返回true,那上面的代码调用这个函数其实是确保安全性,保证不会传入野指针。

下一个函数

static inline void list_del(struct list_head *entry)
{
	__list_del_entry(entry);
	entry->next = LIST_POISON1;
	entry->prev = LIST_POISON2;
}

这个函数其实是对__list_del()函数的完善,__list_del函数虽然将节点entry孤立出链表体系之外,但是entry的prev和next依然指向链表,斩草要除根,这里的LIST_POISON1和LIST_POISON2定义在poison.h里,这里不展开讲,可以理解为在程序不会占用到的内存地址,把entry的头和脚都放逐到了程序之外,这才是斩草除根嘛。


未完,下面还有list.h的查找和更改部分,涉及到了linux内核设计最精彩的算法部分,下章再说

<think>我们正在处理用户的问题:如何在Linux终端安装特定版本的QQ(3.2.18_250710_amd64)。 注意:Linux系统上安装QQ通常不是通过官方仓库直接安装的,因为官方可能不提供。常见的做法是使用Wine运行Windows版QQ,或者使用第三方打包的版本。 根据用户提供的引用,我们并没有直接关于QQ安装的信息。引用[1]提到了lrzsz(一个文件传输工具),引用[2]是关于虚拟机安装CentOS的步骤。因此,我们需要根据一般经验来回答。 步骤: 1. 确认用户系统:由于用户没有明确说明,我们需要考虑不同的Linux发行版(如Ubuntu、CentOS等)。 2. 安装方法:由于是特定版本,我们可能需要下载该版本的安装包(通常是.deb或.rpm),然后使用包管理器安装。或者,如果只有Windows版本,则使用Wine。 但是,请注意,QQ的Linux版本官方已经停止更新,且官方提供的版本很旧(比如QQ for Linux v1.0)。用户提到的版本号(3.2.18_250710_amd64)看起来像是第三方基于Wine打包的版本,比如Deepin-wine环境下的QQ。 因此,我们可以推荐用户使用Deepin-wine环境来安装QQ。Deepin-wine是深度操作系统(Deepin)团队开发的Wine优化版本,用于运行Windows应用程序。 具体步骤(以Ubuntu为例): 步骤1:添加Deepin-wine仓库并安装 步骤2:下载特定版本的QQ安装包(.deb格式) 步骤3:使用dpkg安装,并解决依赖问题。 注意:由于用户要求特定版本(3.2.18_250710_amd64),我们需要确保下载到该版本的安装包。 如果用户使用的是CentOS,可能需要转换包格式(如使用alien)或者使用其他方法。 考虑到用户要求的是在终端安装,所以我们将使用命令行。 以下是一个详细的步骤指南(假设用户使用Ubuntu或Debian系):</think>在Linux系统上安装特定版本的QQ(如3.2.18_250710_amd64),通常需要借助第三方兼容方案(如Wine或Deepin-wine环境),因为腾讯官方已停止维护Linux版QQ。以下是具体步骤: --- ### **安装方法(以Ubuntu/Debian为例)** #### 1. **安装Wine环境** ```bash sudo dpkg --add-architecture i386 # 启用32位支持 sudo apt update sudo apt install wine64 wine32 # 安装Wine ``` #### 2. **下载QQ安装包** 从可信源获取特定版本安装包(如`QQ_3.2.18_250710_amd64.deb`): ```bash wget https://example-path/QQ_3.2.18_250710_amd64.deb # 替换为实际下载链接 ``` #### 3. **安装依赖与QQ** ```bash sudo apt install -f ./QQ_3.2.18_250710_amd64.deb # 自动解决依赖 ``` #### 4. **启动QQ** ```bash wine ~/.wine/drive_c/Program\ Files/Tencent/QQ/Bin/QQ.exe # 通过Wine运行 ``` --- ### **替代方案:Deepin-wine(更稳定)** 若上述方法失败,可使用深度社区封装的Deepin-wine环境: ```bash # 添加Deepin仓库 echo "deb [by-hash=force] https://community-packages.deepin.com/deepin apricot main" | sudo tee /etc/apt/sources.list.d/deepin.list sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 425956BB3E31DF51 # 安装Deepin-wineQQ sudo apt update sudo apt install deepin-wine5 com.qq.im.deepin # 自动安装适配版本 ``` --- ### **注意事项** 1. **兼容性问题** Wine可能无法完美运行最新版QQ,建议优先使用Deepin-wine方案。 2. **安全风险** 非官方源可能存在安全隐患,请从可信渠道下载安装包(如[深度社区](https://www.deepin.org)或[Ubuntu Kylin](https://www.ubuntukylin.com))。 3. **依赖冲突** 若安装失败,尝试修复依赖: ```bash sudo apt --fix-broken install ``` ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值