之前感觉自己的Emacs启动很慢。查看启动日志会发现,启动正常的时候会有比较长的一段时间。之前没注意。今天花了点时间摸索,发现罪魁祸首其实是exec-path-from-shell这个包。现将探索过程记录如下:由于使用了spacemacs的配置,配置比较复杂,不想通过实验降低配置来找出问题所在。最近刚学会使用strace这个工具,所以决定用strace看看Emacs卡在什么地方了。straceemacs--fg-daemon输出了很多内容,这里只截取冻结前的部分内容readlinkat(AT_FDCWD,"/home",0x7ffd1d3abb50,1024)=-1EINVAL(invalidparameter)readlinkat(AT_FDCWD,"/home/lujun9972",0x7ffd1d3abf00,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d",0x7ffd1d3ac2b0,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d/elpa",0x7ffd1d3ac660,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d/elpa/exec-path-from-shell-20180323.1904",0x7ffd1d3aca10,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d/elpa/exec-path-from-shell-20180323.1904/exec-path-from-shell.elc",0x7ffd1d3acdc0,1024)=-1EINVAL(无效参数)lseek(7,-2655,SEEK_CUR)=1441read(7,"\n(defvarexec-path-from-shell-de"..,4096)=4096lseek(7,5537,SEEK_SET)=5537lseek(7,5537,SEEK_SET)=5537lseek(7,5537,SEEK_SET)=5537lseek(7,5537,SEEK_SET)=5537lseek(7,5537,SEEK_SET)=5537lseek(7,5537,SEEK_SET)=5537brk(0x7507000)=0x7507000lseek(7,5537,SEEK_SET)=5537lseek(7,5537,SEEK_SET)=57,5=57,5SEEK_SET)=5537read(7,"230\\205\26\0\t\22\\307\\310\t!\vC\\\"\\211\24\\2"...,4096)=2430lseek(7,7967,SEEK_SET)=7967lseek(7,7967,SEEK_SET)=7967lseek(7,7967,SEEK_SET)=7967lseek(7,7967,SEEK_SET)=7967read(7,"",4096)=0close(7)=0getpid()=10818faccessat(AT_FDCWD,"/home/lujun9972/bin/printf",X_OK)=-1ENOENT(没有那个文件或目录)faccessat(AT_FDCWD,"/usr/local/sbin/printf",X_OK)=-1ENOENT(没有这样的文件或目录)faccessat(AT_FDCWD,"/usr/local/bin/printf",X_OK)=-1ENOENT(没有这样的文件或目录)faccessat(AT_FDCWD,"/usr/bin/printf",X_OK)=0stat("/usr/bin/printf",{st_mode=S_IFREG|0755,st_size=51176,...})=0openat(AT_FDCWD,"/dev/null",O_RDONLY|O_CLOEXEC)=7faccessat(AT_FDCWD,"/proc/5070/fd/.",F_OK)=0faccessat(AT_FDCWD,"/proc/5070/fd/.",F_OK)=0faccessat(AT_FDCWD,"/bin/bash",X_OK)=0stat("/bin/bash",{st_mode=S_IFREG|0755,st_size=903440,...})=0pipe2([8,9],O_CLOEXEC)=0rt_sigprocmask(SIG_BLOCK,[INTCHLD],[],8)=0vfork()=10949rt_sigprocmask(SIG_SETMASK,[],NULL,8)=0close(9)=0close(7)=0read(8,"庆典:\346\227\240\346\263\225\350\256\276\345\256\232\347\273\210\347\253\257\350\277\233\347\250\213\347\273"...,16384)=74read(8,"bash:\346\255\244s地狱\344\270\255\346\227\240\344\273\273\345\212\241\346\216\247\345"...,16310)=35read(8,"setterm:\347\273\210\347\253\257xterm-256color\344"...,16275)=51read(8,"无法获取文件描述符r"...,16224)=56read(8,"bash:[:\357\274\232\351\234\200\350\246\201\346\225\264\346\225\260\350\241\250\350\276\276\345\274"...,16168)=34read(8,"你的显示号是0\n",16134)=25read(8,"测试fcitx是否正在运行"...,16109)=53read(8,"Fcitx是正确运行。\n\n==="...,16056)=87read(8,"Launchfbterm...\n",15969)=17read(8,"stdinisn'tatty!\n",15952)=19read(8,"__RESULT\0/home/lujun9972/bin:/ho"...,15933)=298read(8,0x7ffd1d39ce9d,15635)=?ERESTARTSYS(如果设置了SA_RESTART则重新启动)---SIGCHLD{si_signo=SIGCHLD,si_code=CLD_EXITED,si_pid=10949,si_uid=1000,si_status=0,si_utime=10,si_stime=7}---rt_sigreturn({mask=[]})=-1EINTR(中断的系统调用)read(8,"",15635)=0wait4(10949,[{WIFEXITED(s)&&WEXITSTATUS(s)==0}],0,NULL)=10949close(8)=0getpid()=10818faccessat(AT_FDCWD,"/home/lujun9972/bin/printf",X_OK)=-1ENOENT(没有这样的文件或目录)faccessat(AT_FDCWD,"/usr/local/sbin/printf",X_OK)=-1ENOENT(没有那个文件或目录)faccessat(AT_FDCWD,"/usr/local/bin/printf",X_OK)=-1ENOENT(没有那个文件或目录)faccessat(AT_FDCWD,"/usr/bin/printf",X_OK)=0stat("/usr/bin/printf",{st_mode=S_IFREG|0755,st_size=51176,...})=0openat(AT_FDCWD,"/dev/null",O_RDONLY|O_CLOEXEC)=7faccessat(AT_FDCWD,"/proc/5070/fd/.",F_OK)=0faccessat(AT_FDCWD,"/proc/5070/fd/.",F_OK)=0faccessat(AT_FDCWD,"/bin/bash",X_OK)=0stat("/bin/bash",{st_mode=S_IFREG|0755,st_size=903440,...})=0pipe2([8,9],O_CLOEXEC)=0rt_sigprocmask(SIG_BLOCK,[INTCHLD],[],8)=0vfork()=11679rt_sigprocmask(SIG_SETMASK,[],NULL,8)=0close(9)=0close(7)=0read(8,"setterm:\347\273\210\347\253\257xterm-256color\344"...,16384)=51read(8,"Couldn'tgetafiledescriptorr"...,16333)=56read(8,"/home/lujun9972/.bash_profile:\347"...,16277)=72read(8,"你的显示器numberis0\nTestwh"...,16205)=78read(8,"Fcitx运行正常。\n\n==="...,16127)=104read(8,"stdin不是tty!\n",16023)=19read(8,"__RESULT\0b269cd09e7ec4e8a115188c"...,16004)=298read(8,0x7ffd1d39cba6,15706)=?ERESTARTSYS(如果设置了SA_RESTART则重新启动)---SIGCHLD{si_signo=SIGCHLD,si_code=CLD_EXITED,si_pid=11679,si_uid=1000,si_status=0,si_utime=1,si_stime=1}---rt_sigreturn({mask=[]})=-1EINTR(interruptedsystemcall)read(8,很容易看出,当Emacs卡住了,它正在尝试从8号文件句柄读取。8号文件句柄在哪里定义的?向前看,可以看到:pipe2([8,9],O_CLOEXEC)=0rt_sigprocmask(SIG_BLOCK,[INTCHLD],[],8)=0vfork()=11679rt_sigprocmask(SIG_SETMASK,[],NULL,8)=0close(9)=0可以推断Emacs主进程fork了一个子进程(进程号为11679),并通过管道读取子进程的内容。但是,来自---SIGCHLD{si_signo=SIGCHLD,si_code=CLD_EXITED,si_pid=11679,si_uid=1000,si_status=0,si_utime=1,si_stime=1}----rt_sigreturn({mask=[]})=-1EINTR(中断系统调用)read(8,可以看出子进程实际上已经退出了(父进程收到SIGCHLD信号),父进程是仍在尝试从管道中读取,导致阻塞。从read(8,"setterm:\347\273\210\347\253\257xterm-256color\344"...,16384)=51read(8,"无法获取文件描述符r"...,16333)=56read(8,"/home/lujun9972/.bash_profile:\347"...,16277)=72read(8,"你的显示号是0\n测试wh"...,16205)=78read(8,"Fcitx运行正常。\n\n==="...,16127)=104read(8,"stdin不是tty!\n",16023)=19read(8,"__RESULT\0b269cd09e7ec4e8a115188c"...,16004)=298read(8,0x7ffd1d39cba6,15706)=?ERESTARTSYS(ToberestartedifSA_RESTARTisset)看,子进程的输出好像是我交互式登录bash启动时的输出(loading.bash_profile)往前看,发现了这么一条信息:readlinkat(AT_FDCWD,"/home",0x7ffd1d3abb50,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972",0x7ffd1d3abf00,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d",0x7ffd1d3ac2b0,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d/elpa",0x7ffd1d3ac660,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d/elpa/exec-path-from-shell-20180323.1904",0x7ffd1d3aca10,1024)=-1EINVAL(无效参数)readlinkat(AT_FDCWD,"/home/lujun9972/.emacs.d/elpa/exec-path-from-shell-20180323.1904/exec-path-from-shell.elc",0x7ffd1d3acdc0,1024)=-1EINVAL(无效参数)lseek(7,-2655,SEEK_CUR)=1441read(7,"\n(defvarexec-path-from-shell-de"...,4096)=4096这个很明显和exec-path-from-shell有关,通过查看exec-path-from-shell的实现,发现exec-path-from-shell的实现原理其实是启动一个shell,然后输出PATH和MANPATH的值。而对于bash,默认的启动参数是-i-l(可以通过exec-path-from-shell-arguments设置)。也就是说,bash将作为交互式登录shell启动是的,所以会加载.bash_profile和.bashrc。既然发现和exec-pa有关th-from-shell包,据说这个包对linux意义不大,直接禁用比较好。dotspacemacs-excluded-packages'(exec-path-from-shell)再次重启Emacs,发现这次启动速度明显加快了。
