2011/3

我错过了太多

如果当初我勇敢,结局是不是不一样。如果当时你坚持,回忆会不会不一般。最终我还是没说,你还是忽略。这是不是最好的结局,我们都已经不计较。——岩井俊二《情书》
现在才发现,在不知不觉中,我竟然错过了那么的人,那么多的风景……

离开北京之前,有好几个朋友都说要给我介绍对象,我都没怎么答应,答应的也只是因为关系好,其实我还是抱着做朋友的心态,根本就没指望能做恋人。临走之前给我送行的一个姑娘,那天告诉我,如果不是我当初那句开玩笑的“不许流泪也不能反对”,她也许就不会让我走,也许我们还可能会在一起。一句不经意间的话就错过了一个人,或许是一辈子。如果当初我没有执意离开北京,结局会不会不这样?

现在来到西安一个星期了,见到了很多以前的老师。见面之后他们都要问我的一个问题是,你谈对象了吗?看来是真的到了该谈婚论嫁的年纪,可我还是觉得结婚这种事儿离我很远。有个老师还张罗着给我介绍对象,还当着老系主任的面,搞得我很不好意思。我当然也不会答应,因为我不会留在西安。现在一直在路上,漂泊不定,这个问题比以前还要没谱。

今天和小公子一起吃饭,看看他和他女朋友,我发现年龄不是问题。再看看 cocobear 和他那个女朋友,我发现距离也不是问题。可为什么到了我这里什么都是问题了呢?倒不是我把年龄什么的看得太重,而是我觉得人家姑娘会看重这些。我认识的姑娘也不少,可真谈得来的没几个,可在这少有的几个中,可能因为做朋友时间长了都不会去想做恋人,久而久之,我也只能看着姑娘们一个个被别人带走。不过,到现在我们还是很好的朋友,所以这样不也挺好的吗?

而且,我人长得一点儿都不帅,平时还根本不注意外表穿着,用一个哥们的话说是,“一看你这身打扮就知道你是搞计算机的。” 自然不能博得姑娘们的青睐。虽然我平时脾气很好,基本上不会生气,可是一旦我拧巴起来,谁都不拗不过我,性格使然。这也决定了我不能很好地和姑娘相处,尤其是做恋人吵架的时候,所以我也没正儿八经地谈过几次恋爱。可是,还是有姑娘追我的,虽然连我自己都不太相信。对此我感激不尽,感谢姑娘你的赏识,可我这个人没什么好的,不值得你留恋,我和姑娘都这么说,亦是拒人于千里之外。

现在想想,一直到今天都没女朋友,纯属他妈的自己活该。别人给我介绍的我不要,追我的我又不答应,非得是自己认识的、自己喜欢的才行,可是自己又找不到,这不纯属自作自受么?有时候真想自己狠狠抽自己两巴掌……也就是这样,在一错再错的过程中,一步一步地走到了今天,这世界上没有卖后悔药的,对此我没什么可抱怨的,而且抱怨也没有用。

我这个人愤世嫉俗,有时候很拧巴,又喜欢四处漂泊,浪迹天涯,所以我觉得不太可能会有哪个姑娘愿意死心踏地跟着我,而且我总是觉得她跟别人或许会过得更好!如果哪一天她真出现了,真觉得非我不跟了,我一定要告诉她:我给不了你什么车子房子,但我可以帮你实现自己的梦想!我也给不了你一个固定的住所,但我可以给你幸福!因为,我走到哪里,家就在哪里!

API 与 ABI

(本文亦是《C语言编程艺术》中的一部分,所以请勿用于商业用途。)

一些程序员居然对API和ABI这两个概念都不清楚,我感到有些惊讶。这里以 Linux 内核为例简单解释一下。

API,顾名思义,是编程的接口,换句话说也就是你编写“应用程序”时候调用的函数之类的东西。对于内核来说,它的“应用程序”有两种:一种是在它之上的,用户空间的真正的应用程序,内核给它们提供的是系统调用这种接口,比如 read(2),write(2);另一种就是内核模块了,它们和内核处于同一层,内核给它们提供的是导出的内核函数,比如 kmalloc(),printk()。这些接口都是你可以在编写程序的时候直接看到的,可以直接拿来用的。

而 ABI 是另一种形式的接口,二进制接口。除非你直接使用汇编语言,这种接口一般是不能直接拿来用的。比如,内核系统调用用哪些寄存器或者干脆用堆栈来传递参数,返回值又是通过哪个寄存器传递回去,内核里面定义的某个结构体的某个字段偏移是多少等等,这些都是二进制层面上的接口。这些接口是直接给编译好的二进制用的。换句话说,如果 ABI 保持稳定的话,你在之前版本上编译好的二进制应用程序、内核模块,完全可以无须重新编译直接在新版本上运行。另一种比较特殊的 ABI 是像 /proc,/sys 目录下面导出的文件,它们虽然不是直接的二进制形式,但也会影响编译出来的二进制,如果它里面使用到它们的话,因此这些“接口”也是一种 ABI。

你平时看到的什么 POSIX 标准啊,C99 标准啊,都是对 API 的规定。而规定 ABI 的标准就不多,而且也没那么强势,Linux 上面的 ABI 标准似乎只有 Linux Foundation 提供的一些标准

好了,从上面我们可以看出,其实保持一个稳定的 ABI 要比保持稳定的 API 要难得多。比如,在内核中 int register_netdevice(struct net_device *dev) 这个内核函数原型基本上是不会变的,所以保持这个 API 稳定是很简单的,但它的 ABI 就未必了,就算是这个函数定义本身没变,即 API 没变,而 struct net_device 的定义变了,里面多了或者少了某一个字段,它的 ABI 就变了,你之前编译好的二进制模块就很可能会出错了,必须重新编译才行。

你可能会感到意外,上游的 Linux 内核其实不光不保持稳定的 ABI,它就连稳定的 API 都不会保持!而且还牛逼哄哄地写了一个文档,叫 stable_api_nonsense.txt。这么做的道理是,内核一直在向前推进,而且速度很快,内核开发者们并不想因为 API 的限制而阻碍前进的脚步!毕竟我们不想成为下一个 Windows!:-)

所以,你的驱动在不同版本的内核上不经修改直接运行那几乎是不太可能的,就算是你允许重新编译也未必就能不经修改编译成功。即使在同一个大版本的不同发行版上也可能不行。

那你应该怎么办?最好的办法莫过于把你的驱动贡献到社区,汇入内核源代码树中,这样一旦内核的 API 有改动,改动这个 API 的人就有义务替你修改你的驱动的代码,你只需要 review 一下(或者这个也会有人帮你),也省去你不少时间,何乐而不为呢?另一种办法就是基于某个提供稳定 ABI 的内核,比如红帽的 RHEL (认为这是广告的人请使用 CentOS,谢谢!),红帽的企业版内核保证有稳定的 ABI,只要你没有跨大的版本,因为我们的源代码里会检测 ABI 的变化,为此我们实在付出了不少努力。

当然了,如何检查 ABI 变化那就是另一个有意思的话题了,以后有机会慢慢说这个问题。

斯为常识

最近国外不安宁,可国内比国外还热闹,每天看国内各种时政新闻跟娱乐新闻似得。如此下去,人家娱乐圈怎么办?你们再这么演下去,人家演员怎么办?迟早有一天奥斯卡会被你们拿走!

言归正传。梁文道写过一本书,叫《常识》,封面即提到“本书所集,无甚高论,多为常识而已。若觉可怪,是因为此乃一个常识稀缺的时代。”愚以为,我们不是缺常识,而是有太多的混淆常识的论调,使得常识变得不那么显而易见。

列举如下。

1. 人类发展到今天依然是贪婪、自私,否则我们全都实现共产主义了。因此,权力越大的人越有可能滥用权力,尤其是在不受监督的情况下。所以,不管他们把牛逼吹上天,把话说得比唱歌还好听,想要不受约束和监督就能清白,那是不可能的。

2. 我们首先是人,其次才是中国人。所以,如果我们在这个国家连做人最基本的尊严都没有,凭什么还要做中国人?你还有什么更高尚的理由去迫使人家留下来?所以我旗帜鲜明地支持移民。同理,日本地震,如果你连最起码的人的同情心都没有,怎么好意思说自己是中国人?

3. 看一个人交什么样的朋友就能知道他是什么样的人,国家亦如此,看它把什么样的国家视为“老朋友”就知道它想成为一个什么样的国家。其实,那些被我们视为“万恶”的国家大都对我们挺不错的,美国也好,现在的日本也罢,比起那些“老朋友”来说真不知道要好多少倍。

4. 从来都是人民养的政府,没有政府养人民这一说,因为政府的收入是靠每一个公民的纳税。纳税说白了不就是花钱买服务么!只不过这个花钱是一种义务,可得到服务也得是权利才行啊!花钱能买到服务,那是正常社会。花钱买不到服务,那是流氓。不服务还要你花钱,那是土匪。

5. 纵观人类历史,人类社会一直都是向更自由、更平等的方向发展。可有几个国家就是偏偏逆势而行,简直就是展示人类丑陋灵魂的活的博物馆。我都怀疑他们是不是照着《动物庄园》上写的去做的呢?怪不得这书还没被禁啊。

6. 不管他们说得多么好听,多么动人,如果连孩子都不放过,如果连孩子的教育都不舍得投入,那这个国家一定没有希望,毫无疑问。

7. 他们总以为别的国家也像他们一样,做事没有原则,没有价值观,打仗一定是为了利益,其实他们才是这样,为了利益不惜一切手段,更过分的是,还是从自己的人民身上。要知道“虎毒不食子”啊。

民主的国家各有各的民主,独裁的国家却总是相似的。

请勿自觉对号入座!

That is love

“爱不是千言万语,也不是朝朝暮暮。爱是每当午夜梦醒时,发现内心牵挂的依然是远方的你。”

On love

What is love?

That must be love…

(图片选自 9gag.com。这个网站不错,每天都有很多很有意思的图片。)

又开始周游全国了

在家里待了有些日子了,整天过着“饭来张口,衣来伸手”的日子,上周愣是在家里待了六天连门都迈出去一步。其实在家里上班比在办公室都累,以前是八小时办公,回家之后成十二小时了,前些天还经常在夜里一两点回复邮件,估计大家都感觉我移民美国了好像……

现在家里没什么事儿了,爸妈都过得挺好的。我在家也憋不住了,开始收拾行李,准备再次出发远行了。

其实,在此期间我去了一趟杭州,在济南机场和杭州机场候机时我都能专心地看代码,看来我已经能适应这种漂泊的生活。所以万事俱备,只欠东风,周末就动身出发下江南了。

第一站是苏州,都说“烟花三月下扬州”,我说我这是去苏州看丫头!因为还有“南京看坟头,苏州看丫头”一说,去南京的时候确实是看坟头去了,不知道苏州的丫头会不会比杭州的还漂亮?而我路过江南小镇的时候,会不会也惹上一个江南的丫头?

从苏州出发向西行,回到阔别两年的西安,你们谁也阻止不了我去南稍门建基吃牛肉泡馍,你们谁也阻止不了我去小寨吃那家我至爱的米皮!今天的西安已非当年的西安,只是不知道,当年学校里面的那个小吃街的砂锅西施,而今安在哉?

从西安南下就到了四川,吃着火锅还唱着歌。这里山好,水好,妹子好!你看,我走过全国那么多地方,还是最喜欢四川重庆的妹子了!“少不入蜀”大抵就是这个道理。尤其是那个叫雅安的地方,人都说雅安有三雅:雅鱼,是说鱼好吃;雅雨,是说雨水好;雅女,是说那儿的姑娘们漂亮!更何况人家还有打箭炉和理塘这两个地方呢!这次去要看望一下小佳妹子,我说等我到了咱们一起吃一起唱!可是,你也知道,在四川,叫小佳的妹子何止万千!

从四川走就向东了,到了以前从未去过的广西,都说桂林山水甲天下,这个我不清楚,可是我知道它旁边有个地方叫阳朔,和丽江一样出名的地方……

在桂林待到四月中旬,然后就得动身赶往福州参加小林子的婚礼了,途经广州中转,拜见一下老大和他那小女朋友。到了四月底的时候我就能到达厦门了,终于可以去鼓浪屿转一下了。等参加完小林子的婚礼我就该踏上回来的旅途了,如果有机会去一下江西婺源,然后借道南昌就回北京了。

此次回京是为办签证,无意久留。所以等签证一办好就会回家,或者直接去我向往的那个南方小城,漂泊暂时结束,新的旅途等到了七月,到了葡萄牙再开始…… Eu estarei de volta para a Europa!

PS1 上面的图是我闲着无聊的时候手工画的,很坑爹是吧。

PS2 有人说我这样简直就是流窜犯……其实呐,我充其量也就只是个流氓!

PS3 有好几个人诅咒我,说我很快就会回北京的。靠,就冲你们这句话我也不回去……

他们要结婚了

今年结婚的同学真不少,是不是大家都看着2012快来了,想赶紧将错就错地把生米煮成熟饭呢?还是上了车之后现在才开始补票呢?

光我目前知道的今年要结婚的就有三对,按照时间的先后顺序如下。

首先是简佳同学,没错,就是上次提到的去非洲的那个妞儿!人家这次从非洲大草原回来硬是带来一本结婚证,还得瑟地说是从大使馆领的。姑娘,可是你不知道嘛,我们这边虽然神马都在涨价可唯独结婚证却是在降价……

我离开北京之前她请我吃饭,我还专门给她准备了一个红包,塞了一个吉利数字的钱。我觉得没机会去参加她的婚礼了,可咱也得先把红包送到啊。结果她看到红包之后眼睛都发绿,然后拆开红包之后两眼放光,再看到红包背面写的那句话之后气得脸都绿了。你猜我写的什么?——“祝您丫好运!”

其次是小林子同学,当时怎么也不会想到这个87年的小朋友会突然就要结婚了,因为听说他找对象的事还是在不久之前,这让我们这些连对象都没有的人只能去挠墙了……我和他关系不错,所以我决定亲自前往福州参加他的婚礼,其实主要还是想看看那个传说中的新娘子到底啥样!所以4月底我会到达福建,因为福州之前去过,到了先去厦门转一圈。

然后是Wendy同学,毕业后留在了生活安逸的西安,后来找了个对象,然后今年十月也要结婚了。比较八卦的是,这位同学和前面那位同学在大学期间曾经谈过恋爱……所以我觉得这俩人今年都要结婚不是简单的巧合……

我还知道两对,虽然今年不太可能会结婚,但是都是谈了挺长时间了,一直还没舍得结!或许是还腼腆害羞内向!一对是我们老大和那个小大嫂,其实我本以为最可能结婚的是他们两个,结果半路杀出来一个小林子。另一个是我在济南的高中同学飞哥,这次从北京回来还特意去济南和飞哥飞嫂一起吃了顿饭,用我当时的话说是,你们都谈了六年了,是我们的榜样啊!

严肃地讲,其实我觉得结婚这事儿挺美好的,两个人从陌生到相识、到相恋、到最后结婚,每一步都不容易,有道是”百年修得同船渡,千年修得共枕眠”!婚姻并不是结束,而是开始,那“识人间烟火”的生活这才刚刚开始!衷心祝愿上面的同学生活美满幸福!

兄弟姐妹们,你们不要害怕!点播一首《结了》送给你们!

关于 /proc/mounts

现在的 Linux 系统里一般都有这么三个文件:/etc/fstab,/etc/mtab,和 /proc/mounts,比较容易让人迷惑。简单解释一下。

/etc/fstab 是只读不写的,它提供的是系统上挂载设备的静态信息,比如 mount -a 就会挂载 /etc/fstab 里面指定的文件系统。

/etc/mtab 是供 mount/umount 进行读写的,是相对动态的。读的话,比如你在挂载一个文件系统时缺少一个参数,它就会自动去/etc/mtab 或者 /etc/fstab 里去查,如果找到的话,只要一个参数也够。写的话,比如你umount了一个文件系统,umount 就会删掉/etc/mtab 里面的相关记录。

看似上面的这两个文件已经够用了,但是新的情况出现了。Linux 内核引入了一个 mount namespace,是给container用的。因为这个的出现,Linux 不得不引入 /proc/mounts。为什么呢?因为记录 mount 信息的 /etc/mtab 是全局的,也就是说,就算你的某个进程有自己的 namespace,但只要还和外面共享同一个 /etc/mtab,那么,里面进行umount/mount操作的信息也会被记录到/etc/mtab里,外面也会看到!凌乱了!由此可见,我们不能有全局的mtab,肿么办呢?/proc/mounts 出来了,有人可能觉得它也是全局的啊!可你仔细看一下的话会发现,它其实是到 /proc/self/mounts 的一个符号链接!如此以来,container 里面的 /proc/mounts 和外面的当然就不会一样了!聪明啊!

所以,/etc/mtab 已经过时了,应该被抛弃,或者直接符号链接到/proc/mounts。同理,查看系统上挂载的文件系统的话,直接调用无参数的mount也是不妥的,因为那样也是读 /etc/mtab。我们应该使用 util-linux-ng 提供的一个新命令: findmnt,它是读的 /proc/self/mountinfo。

Fedora 上那些内核包

Fedora 上和内核相关的包很多,运行下面的命令看一下:


~% repoquery -q ‘kernel*’
kernel-0:2.6.35.11-83.fc14.x86_64
kernel-debug-0:2.6.35.11-83.fc14.x86_64
kernel-debug-debuginfo-0:2.6.35.6-45.fc14.x86_64
kernel-debug-devel-0:2.6.35.11-83.fc14.x86_64
kernel-debuginfo-0:2.6.35.6-45.fc14.x86_64
kernel-debuginfo-common-x86_64-0:2.6.35.6-45.fc14.x86_64
kernel-devel-0:2.6.35.11-83.fc14.x86_64
kernel-doc-0:2.6.35.11-83.fc14.noarch
kernel-headers-0:2.6.35.11-83.fc14.x86_64



我们一一看一下这些包的内容和用途。

kernel 这个包不言而喻了,必备的,里面包含了vmlinuz,initramfs,以及所有内核模块,也就是/lib/modules/uname -r下面的东东。

kernel-devel 这个包是给开发内核驱动,写内核模块的人用的,里面包含了内核源代码中的头文件,Kconfig文件,Makefile等等。

kernel-headers 这个包是给glibc 等用户空间的库、程序使用的,它提供内核导出到用户空间的所有头文件,主要在/usr/include/linux/中,这样以来用户空间就可以和内核使用相同的常量,结构体定义等等。

kernel-doc 这个包提供内核文档,即源代码 Documentation/目录下的文档,不过里面包含了make htmldocs 和 make mandocs 之后的文档。

kernel-debug 和 kernel 包类似,但编译时使用的是带debug选项的config文件。

kernel-debug-devel 同理,和 kernel-devel 包类似。

kernel-debuginfo,给SystemTap在 kernel 上使用的。 kernel-debug-debuginfo 同理,供 SystemTap在 kernel-debug 上使用。 而 kernel-debuginfo-common 包为它们提供一些共同的源文件。注意,kernel-debuginfo 包提供vmlinux! 像 crash 这样的工具也需要它。

这里似乎少了一个 kernel-firmware,原来在 Fedora 上它已经改名为 linux-firmware 了,但是在RHEL上面没改,里面提供内核源代码目录 firmware/ 里面的固件。

当然了,因为 perf 也在内核源代码树中,所以 perf 这个包也是从同一个spec文件生成的。