聊cmpxchg的楔子
近些日子,一直埋头于进程上下文/软中断对TCP传输控制块的访问,总想着在这个点里为TCP传输优化做点事。
原因也很简单,因为进程上下文/软中断的锁。
对于这种锁,最常见的就是TCP发送数据的入口。
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
{
int ret;
lock_sock(sk);
ret = tcp_sendmsg_locked(sk, msg, size);
release_sock(sk);
return ret;
}
EXPORT_SYMBOL(tcp_sendmsg);
简单明了,lock_sock 上锁,release_sock 解锁。
而对于TCP的所有,都需要等待上层的解锁操作,才能继续自己的工作,定时器、TSQ、DelayACK和PMTU都不例外。像极了被地主强取豪夺的佃农,但TCP生下来就得吃这碗饭,所以TCP传输优化也应将关注点放一些在进程上下文/软中断的锁上,毕竟地主少克扣点,佃农的日子也会好过很多。
这几天,往复看了很多遍lock_sock和release_sock。虽然更多是在lock_sock上下功夫,但对release_sock也执念颇深。
release_sock 的回调是tcp_release_cb ,函数名也简单易懂,释放TCP传输控制块的函数功能。
在这里,我第N次见到了老面孔cmpxchg。
宏定义cmpxchg
cmpxchg(void *ptr, unsigned long old, unsigned long new) :将ptr指针指向的内容和old比较,当值相同,将new的值写入ptr指向的内容,并返回没有变动的old值表示成功;当值不同,将ptr指向的内容写入old,并返回变动的old值表示失败。ptr指向的是内存对象存储的值。
宏定义cmpxchg是纯汇编实现的函数体,也在函数体前保证了原子性,这使得cmpxchg函数强大,其他一切实现的都不如它,它高效、安全、不会牵引出更多的问题,除了晦涩。
Linux里有很多地方有cmpxchg的身影,以至于我对它的存在不能视而不见。
为什么宏定义cmpxchg那么经常的被使用,那就得聊聊它的能力。但我并不愿撸源码的实现,晦涩的,除了让人厌恶,也让我觉得恶心。
于是,我打算换一种方式,比强撸代码有用的多。
在开始之前,还是得对cmpxchg的功能有个印象,才好让我继续发挥。
cmpxchg的关键,功能实现的函数。对,又一层宏定义,具体实现是__raw_cmpxchg。
/*
- Atomic compare and exchange. Compare OLD with MEM, if identical,
- store NEW in MEM. Return the initial value in MEM. Success is
- indicated by comparing RETURN with OLD.
*/ #define __raw_cmpxchg(ptr, old, new, size, lock)
cmpxchg能干什么,我这么解释,想必就都明白了。 对于 *ptr和old相同的,好比*ptr找到了对应的条目,那么交换成新条目(*ptr==old2,*ptr==new2);而*ptr和old不同的,就好比没有条目,那该做的是将这个条目记录下来(*ptr !=old4,old4==*ptr);返回OLD,可以让调用方得到结果。
宏定义cmpxchg和网络的路径交换简直一摸一样。
其实上,现实的交易所也是这样运转的,能兑换的,你可以去交易所按汇率去兑换; 不能兑换的,交易所也会记录下你要交易的信息。
cmpxchg也得益于这类交换机制的应用。
至于汇编指令,延展出来又是一堆废话,本意并不在此,写到大半作罢。
至此,门外的吵闹声已经打乱了我的思绪,我只好加入他们。
|