tmux支持gbk编码

其实背景是这样的,我用Mac,字符编码是UTF-8,我们的开发环境是Linux,字符编码是GBK,当然我可以把终端的编码改成GBK,就能轻松使用了。但是谁叫咱总觉得把本地终端的编码改得跟Host环境不一致别扭的呢,于是只能想其他办法。我在screen里是找到了完美的解决方案的。但是tmux之前实在是玩不转。后来Google到一个工具,luit,给你举个例子,聪明的你可能就明白这东西怎么用了:

luit -encoding gbk freaky_gbk_app

是的,就是这么简单,就可以把任何命令的输出按照你指定的格式转换为UTF-8,于是在我的.zshrc里加上一条

alias ssh-gbk='/usr/local/luit/bin/luit -encoding gbk ssh'

当我用ssh-gbk登录开发机的时候,luit会自动将输出从gbk转换到utf-8。

当然,也可以在开发机上装上luit后,加个如下的命令:

alias tmux-gbk='/usr/local/luit/bin/luit -encoding gbk tmux'

世界变得美好了,就是这样。

话说我已经从bash+screen的拥趸渐渐转移到zsh+tmux了,这个世界有多种选择,也是件美好的事情。

389 次查看 | 没有评论
2014年7月22日 | 归档于 Linux
标签: , ,

如何hook一个系统调用

背景 是这样的:某高人写的library里判断了新sock出来的socket的文件句柄要>0,且不谈这个assertion是否,我们的系统在运行到某个时间后,会不满足这个断言,说明有人把stdin给关了。

仔细想了一下,没有什么地方是需要把stdin关闭掉的,只能说明程序里有bug,比如某个fd被错误的赋予了0这个初始值,在没有初始化的情况下被关闭了。这是个bug。首先想到的办法是在所有调用close的地方都加上日志,这个工作量巨大,而且很容易出现遗露。其实在Linux里可以通过插入so的方式,hook某些动态连接库里的函数。只要用户没有选择静态编译,就会调用我们替换的版本。经过一翻Google,主要参考了 这篇 文章。最后成品的代码如下:

my_close.c

#define _GNU_SOURCE
#include <dlfcn.h>
#include <assert.h>

typedef int (*orig_close_f_type)(int fd);

int close(int fd)
{
    /* Some evil injected code goes here. */
    assert(fd > 0);
    orig_close_f_type orig_close;
    orig_close = (orig_close_f_type)dlsym(RTLD_NEXT, "close");
    return orig_close(fd);
}

使用这个方法编译:

gcc -g -shared -fPIC my_close.c -o my_close.so -ldl

然后在运行程序前定义LD_PRELOAD,方法为

export LD_PRELOAD=$PWD/my_close.so
./run_your_app

或者

LD_PRELOAD=$PWD/my_close.so ./run_your_app

如上代码在调用close时,如果fd等于0,会coredump。

332 次查看 | 3 条评论
2014年7月21日 | 归档于 Linux, 工作
标签: , , , ,

把git repository导入到svn

我这个需求确实比较奇葩。一般人都是先有了svn了,然后用git svn在本地管理一下,或者与某个git remote绑定一下。但是我的需求是先有了gitlab上的某个git repository,然后第一版写完之后,才申请了svn repository,我想把git中的内容全部导入到svn里,并且以后还是基于git svn来管理。( 因为狼厂现在统一的SCM还是SVN

然后大体思路是这样的

git svn clone https://svn.baidu.com/xxx/trunk/yyy
git remote add -f -tags -m master gitlab g@gitlab.baidu.com:xxx/yyy.git
git merge gitlab/master
git svn dcommit

之后再怎么搞就比较灵活了,比如直接绑定到gitlab/master上,或者在本地开发,再merge到gitlab/master上,或者在gitlab上再建一个svn的分支。

哎,git这种先进的生产工具怎么就被一帮人调研过之后给否定了呢。

309 次查看 | 没有评论
2014年7月21日 | 归档于 Linux, 技术

gdb中dump一段内存

我们会有这种需求,在 gdb 中将某段内存 dump 保存到文件中,比如一段无法在 gdb 中直接访问的二进制数据(一段私有格式的网络包什么的)。其实在 gdb 里这个命令就叫dump,这里仅给出一种简单的用法,其他的可以在gdbhelp

dump binary memory file start_addr end_addr

前面就写dump binary memory,后面接文件名,接着是起始地址,然后是尾地址。dump出来的数据怎么用就随君了。

话说都一年没写博客了,再过两天入职就三年了。

345 次查看 | 没有评论
2014年7月3日 | 归档于 C++, Linux, Unix, 工作
标签: , ,

入职两年了

上个月7月13日是我入职百度满两周年的日子。一直以为我曾经在入职一周年的时候写过一篇日志,可以翻来翻去,只找到一篇入职半月小记。本还想比较一下现在与一年前的心态,此已无从考据。唯有一篇27岁了的日志,还能回想起当时所说的那些烦心事情。好在也像当时所写,现在能嘴角一扬,没有想像中的那么坏,咬咬牙,没有过不去的坎。

前段时间,跟一位老程序员聊天,说到工作,我问他你觉得怎么衡量一个工作的好坏。他告诉我,看两点,一是成长;二是收获。回想自己在百度这两年,成长,学到了、巩固了许多知识;收获,职称和薪水都有不错的涨幅。我曾经在找工作回顾(7+1):微软中写过:

去百度是做基础相关的东西,我更偏向于这个方向,而且可以继续接触Linux相关的技术,对于一个对开源有着极大热情的我来说,更偏向于选择去这里,而且百度整个就是一个互联网企业,也是符合我的初衷。

这段话大体是没有错的,但其中有一点不正确,如果对于开源有着狂热的热情的话,还是不要来百度。在百度,很多东西都是自己做的。开源的东西也用,但绝对不是主流;核心的技术一般也不会开源出去。不过好在,不用开源一般也是因为开源产品在性能、稳定性、功能等方面满足不了我们的需求,而不是非得搞个新的出来。你如果非得问我,为啥不去修改开源的实现,我只能说,有些系统在提需求的时候,业界还没有相应的开源实现。

两年了,人越来越老,老了就不想过生日;老了就更加知道有些话,只能憋肚子里,不能说出来。我想每个事物都有他好的一面与坏的一面。曾经觉得应该在五年后评价自己当初找工作的选择,那就等再过段时间,等到自己离开了这家公司,亦或是干满了五年再说。

1,715 次查看 | 1 条评论
2013年8月12日 | 归档于 未分类
标签:

换到rMBP了

我为什么要换Mac?

其实我挺喜欢Linux的,上学的时候用来作实验、编程环境;工作以后作为日常的桌面。各种软件使用起来得心应手,多桌面切换随心所欲,各种开源软件自己编译、使用的各种开心。工作效率绝对不输Windows。

但是,很多『为什么』的问题总会有一个『但是』做转折,我这里也不例外。Ubuntu是我用了两年的发行版,Unity是我很喜欢的桌面环境,说到这里很多人可能就会因为世界观、人生观、价值观跟我不同关掉这个页面了。我们应该允许人们有着不同的追求。我为啥喜欢Ubuntu/Unity,因为用这俩不用折腾,一点都不折腾,开箱即用,配合各种快捷键,其实很爽啊。我基本上没怎么遇到过很多人说的经常崩溃、系统不稳定的问题。嗯,又瞎扯了半天,还没但出来。但是,很多软件没有Linux的版本,却有Mac的版本,而且很漂亮。即使有Linux上的版本的,也没有Mac上的漂亮。比如Chrome这货。在Linux上丑的我基本上不愿意使用。还有QQ,官方有Mac的版本,而且做得还挺好。Linux上呢,以前发行过32位的版本,后来好像也不维护了。

是的,因为Linux虽然好用,但是不够漂亮,一些锦上添花的软件在Linux下的使用体验不如Mac。有人说Mac是 命令行与桌面环境的完美结合 。我很认同。再加之MBP那帅气的外型,去香港玩的时候就顺了一台。

所以,简单的总结一下,就是Mac比Linux更漂亮,哈哈

为什么选Retina屏幕

我觉得,任何使用过视网膜屏幕的人,都不会再会喜欢用传统屏幕的笔记本,简直是渣,颗粒感太强。视网膜屏真的很舒服。如果你有购买MBP的冲动,强烈推荐。

Mac目前改变了我的什么习惯?

  1. 不再使用Firefox,转向Chrome
  2. 不再使用Thunderbird,转向Mail.app(我也试过其他一些好用的App,但是都不支持Exchange Server)
  3. 买了一套iWorks,不再使用LibreOffice
  4. 常用的Terminal换成了iTerm2
  5. 又开始用QQ、QQ五笔、迅雷
  6. 学会了用brew安装一些常用的软件包,这东西不错,适合有洁癖的人

我现在使用不习惯的地方

  1. 外接显示器时,某个应用全屏后,另一显示器则不能显示。这个要有多傻逼就有多傻逼,等着10.9升级可以解决这个,工作效率又能上一个台阶了
  2. 目录结构不是标准的Unix/Linux,所以能看到Applications/System啥的目录,有洁癖的人略觉不爽
1,489 次查看 | 2 条评论
2013年8月2日 | 归档于 未分类
标签:

一处死锁分析

最近在进行回归测试的时候,QA同学反映有一处死锁,导致大量线程Hang死。通过pstack查看后,发现如下可疑的两个线程:

Thread 1: 1. Hold A.ReadLock, 2. Request B.ReadLock
Thread 2: 1. Hold B.ReadLock, 2. Request A.WriteLock

看到此处就觉得比较奇怪,Thread2被Hang住很正常,因为A的读锁被Thread1占有了,此时无法加上A的写锁,但是为什么Thread 1会被锁死呢?因为此时B的读锁最少被Thread 2加上了,说明没有写线程占有写锁。且其他大量线程都被锁死在请求B的读锁的时候。

排除掉所有那些请求B的读锁被Hang死的线程后,发现了一个可疑的线程,这个线程Hang在如下位置

Thread 3: Request B.WriteLock

即存在一个线程在请求B的写锁,且处于等待的过程中。疑点比较明显,于是gdb之后,打印了一下这个pthread_rwlock_t的属性,发现其__rw_kind的属性值是1,顺藤摸瓜,发现这个读写锁在初始化的时候使用了如下过程:

pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr)
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
pthread_rwlock_init(&_rwlock, &attr);

其中PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP表明写锁优先的模式,即有写者等待时,所有读者被阻塞,所以因为Thread 3在获取B的写锁,则Thread 1无法获取B的读锁,从而导致A的读锁不会被释放,此种情况Thread 2无法获取A的写锁,也不会释放B的读锁,导致死锁。

解完Bug后,大呼原来多线程情况下,两个以前线程也有可能在某些情况下造成死锁。即只要有加锁顺序不一致的情况,且有读写锁混合的情况下,如果有写锁优先的情况,也有可能导致死锁。

1,789 次查看 | 1 条评论
2013年5月14日 | 归档于 C++, Linux, 工作, 技术

修改pantheon-terminal字体

前两天看了elementary OS的介绍,感觉挺漂亮的,而且基于Ubuntu,用起来也会比较习惯。在虚拟机上安装试用了一下以后,很想在本本上尝试一下。于是想了想办法,从home分区上拆了20G的空间下来安装。折腾了一个中午,终于装上了,此后曲折,以后再表。

装完以后,没找到地方改pantheon-terminal,这可是我天天要用的东西,默认的字体虽然也挺漂亮,但是我还是习惯了用Yahei Mono,虽说可以通过修改gconf的全局变量来达到目的,可是作为一个有些强迫症的人,还是Google了一把,最后找到了这个网页,最终解决了问题。其实pantheon-terminal是有相关配置项的,就是没有个可视化工具配置,只需要执行以下命令,就可以修改字体:

$ gsettings set org.pantheon.terminal.settings font <name of font>

改完了之后我发现一个问题,由于默认字体的大小有些小,配合我的字体看起来不太舒服,于是加忆了一下gconf里的配置方法,使用如下命令

$ gsettings set org.pantheon.terminal.settings font 'Yahei Mono 11'

即在字体后面加上字号即可。有兴趣的还可以看一下org.pantheon.terminal.settings的其它配置项。

1,847 次查看 | 没有评论
2013年5月13日 | 归档于 未分类
标签:

27岁了

终于还是更老了一岁。年纪越大,越是不想过生日。这一年经历了很多事情,最近才觉得自己其实没有想像中的那么成熟,很多事情处理得还是很幼稚。不过还好,起码自己意识到了这一点,希望自己明年过生日的时候,看到这段话,还能想得起自己说的是什么事情,能够嘴角微微一扬,告诉自己,有些事情,没有想像中的那样坏,有些事情,自己有能力去改变。

工作上都还好,工作一年了,学到了很多,无论是技术上还是为人处事上。

过去的一年,还是有很多事情要记在心里不用记在博客上的,能忘掉的就忘掉,忘记不了的就改掉。更多的还是希望下面的一年能过得好,下一次写生日日志的时候,可以更开心一些。

 

2,305 次查看 | 没有评论
2012年8月8日 | 归档于 总结, 感悟, 生日
标签:

pthread_cond_timedwait时间设置

最近在使用pthread_cond_timedwait的时候,发现当超时时间设置成1秒以下的值时,无法得到想要的效果,具体表现为,没有wait足够的时间就被唤醒,且返回值正确。首先来看一下pthread_cond_timedwait的原型:

#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);

abstime是一个绝对时间,struct timespce的原型为:

struct timespec
{
__time_t tv_sec;        /* Seconds. */
long int tv_nsec;       /* Nanoseconds. */
};

其中tv_sec是秒,tv_nsec是纳秒(即1000,000,000分之一秒)

那么,看一下我之前出错的代码:

struct timespec abstime;
abstime.tv_nsec = (timeout_ms % 1000) * 1000000;
abstime.tv_sec = time(NULL) + timeout_ms / 1000;
pthread_cond_timedwait(&_read_cond, &_read_mutex, &abstime);

以上代码有问题,主要是因为time(NULL)的返回结果的精度是秒级的,那么如果当前时间是m秒+n毫秒,那么实际等待的时间只是timeout_ms – n,且还有可能发生n > timeout_ms的情况,这种情形下,如果这段代码处在一处while循环内,则会造成大量的pthread_cond_timedwait系统调用,并造成大量的context switch,系统CPU会占用很高。

正确的代码应该改为如下:

struct timespec abstime;
struct timeval now;
gettimeofday(&now, NULL);
int nsec = now.tv_usec * 1000 + (timeout_ms % 1000) * 1000000;
abstime.tv_nsec = nsec % 1000000000;
abstime.tv_sec = now.tv_sec + nsec / 1000000000 + timeout_ms / 1000;

pthread_cond_timedwait(&_read_cond, &_read_mutex, &abstime);

通过gettimeofday获得精确到微秒(1000,000分之一秒)的时间数据,并处理不足一秒加上超时时间超过一秒的情况(即tv_sec上需要加上nsec/1000000000)。

3,657 次查看 | 没有评论
2012年7月19日 | 归档于 C++, Linux, 技术

无觅相关文章插件,快速提升流量