键盘上一些符号的英文读法真的让人头疼,很多根本就没有统一的念法。上葡语课时我问老师dash在葡语里怎么用,结果她不知道什么是dash,最后经过探讨我们达成共识,我问的是hyphen…… 因为我整天和程序打交道,“-”更多被读作dash,而非程序员更多读作hyphen。比较烦~~

这里简单整理一下键盘上所有特殊符号的英文读法,最后还有葡语中特殊符号的英文读法。参考资料见本文最后。

! 叹号 exclamation mark/bang
? 问号 question mark
, 逗号 comma
. 点号 dot/period/point
: 冒号 colon
; 分号 semicolon
” 双引号 quotation marks/double quote
‘ 单引号/撇号 apostrophe/single quote
` 重音号 backquote/grave accent
* 星号 asterisk/star
+ 加号 plus sign
- 减号/横线 hyphen/dash/minus sign/
= 等号 equal sign
/ 斜线 slash
\ 反斜线 backslash/escape
| 竖线 bar/pipe/vertical bar
_ 下划线 underline/underscore
$ 美元符号 dollar sign
@ at at sign
# 井号 crosshatch/sharp/hash
% 百分号 percent sign/mod
& and/和/兼 and/ampersand
^ 折音号 circumflex/caret
~ 波浪号 tilde
{} (左右)花括号/大括号 (left/right|open/close) braces
[] (左右)方括号/中括号 (left/right|open/close) brackets
() (左右)圆括号/小括号 (left/right|open/close) parentheses
<> 尖括号 angle brackets
< 大于号 less than
> 小于号 greater than

葡语中的变音符号(diacritic mark)在英文中的读法:

^ circumflex/caret
~ tilde/squiggle
´ acute
` grave
ç cedilla

参考资料:

1. http://www.codinghorror.com/blog/archives/001133.html
2. http://ascii-table.com/pronunciation-guide.php
3. http://www.learningportuguese.co.uk/language/diacritics.html

一年过了又一年,只是每年这个节日还是没变。:-)

希望明年有所改观,不过貌似我每年都这么说……

consoleterminal是很容易让人迷惑的两个概念。根据wikipedia上的定义,小型计算机的console应该就是键盘加显示器;而terminal则是输入数据进去,和显示数据来源的设备,通常是一个计算机系统。

Linux下的console除了真实的硬件设备外,还有virtual console,也就是你按alt+Fn或者alt+ctrl+Fn切换到的东西。所谓虚拟就是这些console共享同一个真实的设备,只有一个活动的console才显示在前面。这些console对应的设备是:/dev/ttyN,其中1 ≤ N ≤ 63。而/dev/tty0则是指向当前的terminal;/dev/console是指向当前console,但它现在并_不是_对/dev/tty0的符号链接。更多可参考console(4)。

/dev/tty是另一个特殊设备,它指向控制终端(controlling terminal)。如果某个进程的控制终端是/dev/tty3,那么/dev/tty就指向/dev/tty3了。控制终端是什么概念?它是一个进程的某个属性,是依附带该进程上的终端。比如我们在某个终端下输入ctrl+C,那么它控制的前台进程就会收到SIGINT,而后台进程会收到SIGTTIN或SIGTTOU ,如果它们读写该终端的话。被同一个终端控制的所有进程被称为一个会话(session),会话的领导就是创建改会话的进程,其子进程也会被该终端控制。所以,1) 需要交互的命令行程序通常会从/dev/tty这个设备进行读写;2) Unix后台进程都需要在fork之后调用setsid(2),3) 需要加O_NOCTTY,当你open一个可能是终端的文件时。

另外,想要确定/dev/tty究竟是指向哪个设备,可以调用TIOCCONS ioctl。参考tty(4)。

下面是另外一个概念——伪终端(pseudo-terminal),根据pty(7)的介绍,伪终端一对虚拟设备,提供端到端双向通信的通路,一端称为master,另一端称为slave。在slave那端看到的和在真实终端看到的效果一样。所以伪终端一般被ssh等网络登录程序使用。历史上,有两套伪终端接口,一个是Unix 98伪终端,另一个是BSD伪终端。

BSD提供的接口很简单:/dev/pty[p-za-e][0-9a-f] 是master; /dev/tty[p-za-e][0-9a-f] 是slave,它们都是配好对的。这样看起来很简单,但对程序员来说不容易,要找到一个合适的终端需要一个个从头尝试。所以这种方式已经被遗弃。而Unix 98伪终端则完全不同,它始终使用/dev/ptmx作为master复制设备,然后在每次打开它的时候才得到一个master设备的fd,同时在/dev/pts/目录下得到一个slave设备。这样编程就相对容易了,根据pts(4)介绍,需要三个新的API: ptsname(3),grantpt(3)和unlockpt(3)。我们可以通过一个实例看一下如何使用:

(以下代码摘自netvirt)

C:
  1. char    *mptname = "/dev/ptmx"; /* master pseudo-tty device */
  2. //...
  3. void
  4. getmaster()
  5. {
  6.     struct stat stb;
  7.  
  8.     if ((master = open(mptname, O_RDWR))>= 0) { /* a pseudo-tty is free */
  9.         (void) ioctl(0, TCGETS, (char *)&b);
  10.         (void) ioctl(0, TIOCGWINSZ, (char *)&size);
  11.         return;
  12.     } else {                /* out of pseudo-tty's */
  13.         perror(mptname);
  14.         fprintf(stderr, gettext("Out of pseudo-tty's\n"));
  15.         fail();
  16.     }
  17. }
  18.  
  19. void
  20. getslave()
  21. {
  22.     char *slavename;    /* name of slave pseudo-tty */
  23.  
  24.     grantpt(master);        /* change permissions of slave */
  25.     unlockpt(master);           /* unlock slave */
  26.     slavename = ptsname(master);        /* get name of slave */
  27.     slave = open(slavename, O_RDWR);    /* open slave */
  28.     if (slave <0) {         /* error on opening slave */
  29.         perror(slavename);
  30.         fail();
  31.     }
  32.     ioctl(slave, I_PUSH, "ptem");   /* push pt hw emulation module */
  33.     ioctl(slave, I_PUSH, "ldterm");     /* push line discipline */
  34.  
  35.     (void) ioctl(slave, TCSETSF, (char *)&b);
  36.     (void) ioctl(slave, TIOCSWINSZ, (char *)&size);
  37. }

然后我们再来看一下glibc中对ptsname(3)的实现:

(源文件sysdeps/unix/sysv/linux/ptsname.c)

C:
  1. #define _PATH_DEVPTS "/dev/pts/"
  2.  
  3. char *
  4. ptsname (int fd)
  5. {
  6.   return __ptsname_r (fd, buffer, sizeof (buffer)) != 0 ? NULL : buffer;
  7. }
  8.  
  9. int
  10. __ptsname_r (int fd, char *buf, size_t buflen)
  11. {
  12.  
  13. ...
  14.  
  15.   if (__ioctl (fd, TIOCGPTN, &ptyno) == 0)
  16. ...
  17.      numbuf[sizeof (numbuf) - 1] = '\0';
  18.       p = _itoa_word (ptyno, &numbuf[sizeof (numbuf) - 1], 10, 0);
  19. ...
  20.       memcpy (__stpcpy (buf, devpts), p, &numbuf[sizeof (numbuf)] - p);

我们可以看出,实际上是调用ioctl TIOCGPTN,通过内核,而Linux内核又是通过devpts这种文件系统实现了这一切:

$ mount | grep devpts
devpts on /dev/pts type devpts (rw,gid=5,mode=620)

这样我们终于把一切搞清楚了。:-)

pthread的API一直让我感到头疼,种类多而且名字又长,今天下决心把它们理清楚。

仅从名字上来看,pthread的API可以分为这么几类:

pthread_XXX:
此类API一般是对thread本身进行管理的。共包括如下API:

pthread_atfork()
pthread_create()
pthread_exit()
pthread_cancel()
pthread_join()
pthread_once()
pthread_self()
pthread_equal()
pthread_kill()
pthread_detach()
pthread_yeild()
pthread_sigmask()
pthread_key_create()
pthread_key_delete()
pthread_cleanup_push()
pthread_cleanup_pop()
pthread_testcancel()

它还可以分出两个子类,包括pthread_setWWW和pthread_getWWW,其中有:

pthread_getconcurrency()
pthread_getcpuclockid()
pthread_getschedparam()
pthread_getspecific()

pthread_setcancelstate()
pthread_setconcurrency()
pthread_setschedparam()
pthread_setschedprio()
pthread_setspecific()

pthread_attr_YYY:
YYY一般包括:init, destory, setZZZ, getZZZ。此类API是对thread本身的属性进行管理的。共包括如下API:

pthread_attr_destroy()
pthread_attr_getinheritsched()
pthread_attr_getschedparam()
pthread_attr_getschedpolicy()
pthread_attr_getscope()
pthread_attr_getstackaddr()
pthread_attr_getstack()
pthread_attr_init()
pthread_attr_setdetachstate()
pthread_attr_setguardsize()
pthread_attr_setinheritsched()
pthread_attr_setschedparam()
pthread_attr_setschedpolicy()
pthread_attr_setscope()
pthread_attr_setstackaddr()
pthread_attr_setstack()
pthread_attr_setstacksize()

pthread_MMM_XXX:
XXX一般是上面和那个XXX集合类似的操作,但MMM一般是thread的一个工具,比如:mutex,cond等。此类API是对thread的MMM工具进行操作。共包括如下API:

mutex类:
pthread_mutex_init()
pthread_mutex_destroy()
pthread_mutex_lock()
pthread_mutex_unlock()
pthread_mutex_trylock()
pthread_mutex_setprioceiling()
pthread_mutex_getprioceiling()

cond类:
pthread_cond_init()
pthread_cond_destroy()
pthread_cond_signal()
pthread_cond_broadcast()
pthread_cond_wait()
pthread_cond_timedwait()

rwlock类:
pthread_rwlock_destroy()
pthread_rwlock_init()
pthread_rwlock_rdlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
pthread_rwlock_tryrdlock()
pthread_rwlock_trywrlock()
pthread_rwlock_unlock()
pthread_rwlock_wrlock()

spin类:
pthread_spin_destroy()
pthread_spin_init()
pthread_spin_lock()
pthread_spin_trylock()
pthread_spin_unlock()

barrier类:
pthread_barrier_destroy()
pthread_barrier_init()
pthread_barrier_wait()

pthread_MMMattr_YYY:
MMM和YYY同上(spin除外),此类API是对MMM工具的属性进行操作。和上面有着密切的关系。共包括如下API:

mutex类:
pthread_mutexattr_destroy()
pthread_mutexattr_getprioceiling()
pthread_mutexattr_getprotocol()
pthread_mutexattr_getpshared()
pthread_mutexattr_gettype()
pthread_mutexattr_init()
pthread_mutexattr_setprioceiling()
pthread_mutexattr_setprotocol()
pthread_mutexattr_setpshared()
pthread_mutexattr_settype()

cond类:
pthread_condattr_destroy()
pthread_condattr_getclock()
pthread_condattr_getpshared()
pthread_condattr_init()
pthread_condattr_setclock()
pthread_condattr_setpshared()

rwlock类:
pthread_rwlockattr_destroy()
pthread_rwlockattr_getpshared()
pthread_rwlockattr_init()
pthread_rwlockattr_setpshared()

barrier类:
pthread_barrierattr_destroy()
pthread_barrierattr_getpshared()
pthread_barrierattr_init()
pthread_barrierattr_setpshared()

这还没完,还有N多的新类型,比如pthread_t,pthread_attr_t,pthread_once_t,以及随之而来的宏。。。我在这就不总结了。

最后,介绍pthread的书籍有:

"PThreads Primer". Lewis, Bill and Daniel J. Berg. California: Prentice Hall.
"Pthreads Programming". B. Nichols et al. O'Reilly and Associates.
"Programming With POSIX Threads". D. Butenhof. Addison Wesley
"Programming With Threads". S. Kleiman et al. Prentice Hall

网上有个查询的网站,可惜什么结果都查不出来!靠!我实在看不下去了,动手写一个python程序来搞定,不过仍有局限性,那就是只能查询.iso.org子树。。。啥也不说了,上代码!

PYTHON:
  1. #!/usr/bin/env python
  2.  
  3. import os,sys
  4. import string
  5. import re
  6. import urllib2
  7.  
  8.  
  9. if __name__ == '__main__':
  10.  
  11.     if len(sys.argv) != 2:
  12.         sys.stderr.write("Please provide one OID number or string to lookup.\n");
  13.         sys.exit(1)
  14.  
  15.     flag = 0
  16.     found = False
  17.  
  18.     r = re.compile('^[0-9\\.]+$')
  19.     if r.match(sys.argv[1]):
  20.         r = re.compile('^1\\.3')
  21.         if r.match(sys.argv[1]):
  22.             flag = 1
  23.         else:
  24.             sys.stderr.write("Please provide the full OID number under .iso.org!\n")
  25.             sys.exit(1)
  26.    
  27.     try:
  28.         req = urllib2.Request('http://www.kix.in/plan9/mirror/sources/contrib/gabidiaz/root/lib/ndb/snmp')
  29.         resp = urllib2.urlopen(req)
  30.         oid = resp.readline()
  31.         name = resp.readline()
  32.         while oid and name:
  33.             if flag == 1:
  34.                 if oid.find(sys.argv[1]) != -1:
  35.                     print name
  36.                     found = True
  37.                     break
  38.             else:
  39.                 n = name.lower().find(sys.argv[1].lower())
  40.                 if n != -1:
  41.                     print oid
  42.                     found = True
  43.                     if n+len(sys.argv[1]) <len(name)-1:
  44.                         print name
  45.             oid = resp.readline()
  46.             name = resp.readline()
  47.         if not found:
  48.             print "Not found!"
  49.         sys.exit(0)
  50.     except IOError:
  51.         sys.stderr.write("Probably you don't have Internet.\n")
  52.         sys.exit(1)

可参考ASN.1关于octet string的介绍。

BASH:
  1. #!/bin/bash
  2.  
  3. i=1;
  4. while(($i<=${#1}))
  5. do
  6.         printf "%d" "'$(expr substr $1 $i 1)"
  7.         if (($i != ${#1}))
  8.         then
  9.                 echo -n '.'
  10.         fi
  11.         i=$((i+1))
  12. done
  13. echo
  14. exit 0

上面使用了一个鲜为人知的小技巧,而且不仔细看也不太容易察觉。

此脚本可以这么用(假设此脚本被存为to_string.sh):

$ snmpwalk -v2c -c test 192.168.90.72 .1.3.6.1.4.1.8072.1.3.2.4.1.2.${#STRING}.$(./to_string.sh $STRING).1

这是我见过的最牛的解答:

我昨天晚上做梦的时候好像把这个事情想清楚了。现在又不记得了。

你简直是太有才了!!!!!!!!!!!!!!!!

上个周末真的玩疯了。

因为bruno要去瑞士了,上个周五晚上就算是为他送行了。先是在一个餐馆一起吃饭,critcial links来了很多人。那个餐馆的菜并不是很好,不过谁有在乎呢,大家在一起聊得开心就好。最后,我被灌了四杯葡萄酒,加上我自己那瓶啤酒,结果下来真的有点醉了,不过还好能撑得住。吃完都十二点多了,本以为这就完了,没想到疯狂这才开始……

然后又跟着他们去了另一个酒吧去接着喝,这次我比较聪明,没跟着他们喝那种带酒精的饮料,我叫了两瓶红牛,没想到它效果那么好,喝了一瓶就已经完全清醒了。marco说我喝两瓶忒多了,整个晚上都会睡不着了,我不信。大约坐了一个多小时后我们就去另一个地方,我还在想怎么还非得换另一个地方继续喝,在这里不是一样么?没想到这次去的是舞厅……这时又来一些人,包括几个HR的美女。进了舞厅才发现那真是一个彻底疯狂的地方,里面响着疯狂的音乐,而且挤满了年轻人,闪烁的彩灯,DJ师,调酒师,各种各样的美女……管它呢,我们这些人围成一圈也跳了起来。说实话,跳舞其实并不难,简单地来说就是扭扭屁股,甩甩胳膊,不过想要跳好可真就不容易了。我跟着另一个bruno和marco慢慢地学着跳,感觉真的很疯,不过也感觉真的很轻松!!好久没能这么释放自己了,真的很开心。我们就这样一直玩到舞厅关门,都快凌晨五点了……

“送君千里终需一别”。最后我们不得不和bruno真的道别了,我以后再也听不到我对面这个bruno对着我另一边叫另一个bruno了,再也不能看着他那熟练卷烟的动作说他是cigarette machine了……希望他在瑞士过得更好,一路顺风!

有时候,唯一保持清醒的办法就是发点儿疯。:-)

Americans are NOT stupid

http://www.youtube.com/watch?v=fJuNgBkloFE

同事推荐给我的,里面那个KFC的都快把我们笑翻了……里面的美国人不是一般有才~~

祝大家周末愉快! :-)

在 arch/x86/include/asm/uaccess.h 中有这么一段代码:

#define __range_not_ok(addr, size)                                      \
({                                                                      \
unsigned long flag, roksum;                                     \
__chk_user_ptr(addr);                                           \
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0"             \
: "=&r" (flag), "=r" (roksum)                               \
: "1" (addr), "g" ((long)(size)),                           \
"rm" (current_thread_info()->addr_limit.seg));            \
flag;                                                           \
})

这段汇编写得很有技巧性,充分利用了sbb指令carry flag,值得你仔细体会一番。还有一个关于sbb的技巧:

sbb eax,eax
sbb eax,0FFFFFFFFh