随笔 - 55  文章 - 0  trackbacks - 0
<2018年6月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿

随笔分类

随笔档案

收藏夹

调试技巧

搜索

  •  

最新评论

阅读排行榜

评论排行榜

60天内阅读排行

ASANAddress-Sanitizier早先是LLVM中的特性,后被加入GCC 4.8,在GCC 4.9后加入对ARM平台的支持。因此GCC 4.8以上版本使用ASAN时不需要安装第三方库,通过在编译时指定编译CFLAGS即可打开开关。

1、编译选项

1.1 Gcc编译选项

# -fsanitize=address:开启内存越界检测

# -fsanitize-recover=address:一般后台程序为保证稳定性,不能遇到错误就简单退出,而是继续运行,采用该选项支持内存出错之后程序继续运行,需要叠加设置ASAN_OPTIONS=halt_on_error=0才会生效;若未设置此选项,则内存出错即报错退出

ASAN_CFLAGS += -fsanitize=address -fsanitize-recover=address

 

# -fno-stack-protector:去使能栈溢出保护

# -fno-omit-frame-pointer:去使能栈溢出保护

# -fno-var-tracking:默认选项为-fvar-tracking,会导致运行非常慢

# -g1:表示最小调试信息,通常debug版本用-g-g2

ASAN_CFLAGS += -fno-stack-protector -fno-omit-frame-pointer -fno-var-tracking -g1

1.2 Ld链接选项

ASAN_LDFLAGS += -fsanitize=address -g1

如果使用gcc链接,此处可忽略。

2ASAN运行选项

2.1 ASAN_OPTIONS设置

ASAN_OPTIONSAddress-Sanitizier的运行选项环境变量。

# halt_on_error=0:检测内存错误后继续运行

# detect_leaks=1:使能内存泄露检测

# malloc_context_size=15:内存错误发生时,显示的调用栈层数为15

# log_path=/home/xos/asan.log:内存检查问题日志存放文件路径

# suppressions=$SUPP_FILE:屏蔽打印某些内存错误

export ASAN_OPTIONS=halt_on_error=0:use_sigaltstack=0:detect_leaks=1:malloc_context_size=15:log_path=/home/xos/asan.log:suppressions=$SUPP_FILE

 

除了上述常用选项,以下还有一些选项可根据实际需要添加:

# detect_stack_use_after_return=1:检查访问指向已被释放的栈空间

# handle_segv=1:处理段错误;也可以添加handle_sigill=1处理SIGILL信号

# quarantine_size=4194304:内存cache可缓存free内存大小4M

ASAN_OPTIONS=${ASAN_OPTIONS}:verbosity=0:handle_segv=1:allow_user_segv_handler=1:detect_stack_use_after_return=1:fast_unwind_on_fatal=1:fast_unwind_on_check=1:fast_unwind_on_malloc=1:quarantine_size=4194304

2.2 LSAN_OPTIONS设置

LSAN_OPTIONSLeakSanitizier运行选项的环境变量,而LeakSanitizierASAN的内存泄漏检测模块,常用运行选项有:

# exitcode=0:设置内存泄露退出码为0,默认情况内存泄露退出码0x16

# use_unaligned=44字节对齐

export LSAN_OPTIONS=exitcode=0:use_unaligned=4

3、总结

实际开发环境中,可能存在gcc版本低,使用asan做内存检查时,需要链接libasan.so库的情况。其次,平台软件通常都会内部实现一套内存操作接口,为使用asan工具,需要替换成glibc提供的接口。此时,可以通过LD_PRELOAD环境变量解决这类问题。

export LD_PRELOAD= libasan.so.2:libprelib.so   #vos_malloc --> malloc



ps:
1、安装LLVM 3.1以上版本

2、编译参数附加

-fsanitize=address

3、设置环境变量参数

export ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer

export ASAN_OPTIONS=symbolize=1

4、运行程序,如果出错,addressSanitizer会给出详细的报告。

posted @ 2018-06-14 15:46 长戟十三千 阅读(7) | 评论 (0)编辑 收藏
#include<stdio.h>
#include<pthread.h>
#include<signal.h>
#include<setjmp.h>
#include<errno.h>

static sigjmp_buf env;
pthread_t thread;

void alarm_handler(int sig){
        siglongjmp(env, -1);
        printf("alarm_handler\n");
        return;
}

void threadtest(){
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGALRM);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    struct sigaction act,oldact;
    act.sa_handler = alarm_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags |= SA_INTERRUPT;
    sigaction(SIGALRM, &act, &oldact);
    if(sigsetjmp(env, 1) != 0){
        printf("sigsetjmp\n");
        alarm(0);
        sigaction(SIGALRM, &oldact, NULL);
        sigprocmask(SIG_BLOCK, &set, NULL);  //还不行就使用pthread_sigmask(SIG_UNBLOCK, &set, NULL);
        return;
    }
    alarm(2);
    printf("sleep before\n");
    int i = 1;
    while(i<= 10) {
        printf("i = %d\n",i++);
        sleep(1);
    }
    printf("sleep end\n");
    alarm(0);
    sigaction(SIGALRM, &oldact, NULL);
    sigprocmask(SIG_BLOCK, &set, NULL);  //还不行就使用pthread_sigmask(SIG_UNBLOCK, &set, NULL);
    return;
}

int main(){
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGALRM);
    sigprocmask(SIG_BLOCK, &set, NULL);
    int err = 1;
    threadtest();  //函数调用
   while(err <= 3) {
         printf("err = %d\n",err++);
         sleep(1);
    }
    putchar('\n');
        
    pthread_create(&thread,NULL,(void *)threadtest,NULL);   //用线程的方式
   err = 1;
    while(err <= 5) {
        printf("err = %d\n",err++);
        sleep(1);
    }
    pthread_join(thread,NULL);
}
posted @ 2018-06-14 15:27 长戟十三千 阅读(5) | 评论 (0)编辑 收藏
     摘要: 《守望先锋》架构设计与网络同步Overwatch Gameplay Architecture and NetcodeTimothy FordLead Gameplay EngineerBlizzard Entertainment翻译:kevinan 在GDC2017【Overwatch Gameplay Architecture andNetcode 】的分享会上,来自暴雪的T...  阅读全文
posted @ 2018-06-12 16:52 长戟十三千 阅读(7) | 评论 (0)编辑 收藏

环境:centos6.3 

1. 要使用distcc当然需要先去安装。这里使用官方源码编译安装。 下载地址:https://code.google.com/p/distcc/downloads/list 

   这里选择需要下载的内容,我选择的是distcc-3.2rc1.tar.bz2 

2. 编译distcc源码需要先安装python支持, 在centos中使用 sudo yum install python-devel  其他linux可以参照

3. 安装好了python后,解压distcc源码: 

             进入distcc-3.2rc1.tar.bz2  : cd distcc-3.2rc1

      执行:./autogen.sh ---->./configure ---> make -----> make install

4. 至此distcc就算安装完成,安装结束后还需要开启distccd这个守护进程。为方便每次自启动该守护进程,可以将其添加到开机自启动项

在centos中 可以到 /etc/rc.local 中添加

其中 --user 表明使用nobody这个用户身份 --allow 表明那一些ip允许访问,这里 192.168.168.0/8 表明192.168.168.1—192.168.168.254这个区间的IP可以使用该机器的distcc

5. distcc相关的环境变量:

distcc需要指明他可以使用的编译阵列。这些环境变量可以存放在~/.bashrc. 使用vim打开该文件:vim ~/.bashrc

DISTCC_HOSTS 指明那些机器安装了distcc 且开启了distccd。编译过程中可以使用这些机器进行编译

DISTCC_LOG 表明distcc相关日志

6. 重启centos

PS:在其他DISTCC_HOSTS列表中的机器上重复1-6步骤。 注意DISTCC_HOSTS 中的列表项用空格隔开。

7. 进入你要进行编译的文件目录:

-j16 可以同时编译多个, CXX=distcc 表明c++文件使用distcc来进行编译 对饮C文件 可以使用 CC=distcc

然后就开始编译了,在编译过程中可以使用命令 distccmon-text 2 来查看编译过程中使用了那一些机器

可以看到有很多文件在其他机器上编译。

就我们项目而言,之前单个机器上编译gameserver差不多需要20分钟,在部署之后,使用distcc编译缩短在6分钟左右。 效果不错。

posted @ 2018-06-08 10:06 长戟十三千 阅读(8) | 评论 (0)编辑 收藏

CentOS7系统自带的Python版本是Python2.7,如需使用Python3.6,需要自行安装Python3.6。

CentOS7安装Python3.6有两种方式:

  • 使用Yum源安装Python3.6
  • 使用Python3.6源文件安装

推荐使用CentOS7 Yum源安装Python3.6。

CentOS7使用Yum源安装Python3.6

IUS软件源中包含了Python3.6,可以使用IUS软件源安装Python3.6,查看如何安装使用IUS软件源

1)安装IUS软件源

#安装EPEL依赖 sudo yum install epel-release  #安装IUS软件源 sudo yum install https://centos7.iuscommunity.org/ius-release.rpm

2)安装Python3.6

sudo yum install python36u

安装Python3完成后的shell命令为python3.6,为了使用方便,创建一个到python3的符号链接

sudo ln -s /bin/python3.6 /bin/python3

3)安装pip3

安装完成python36u并没有安装pip,安装pip

sudo yum install python36u-pip

安装pip完成后的shell命令为pip3.6,为了使用方便,创建一个到pip3的符号链接

sudo ln -s /bin/pip3.6 /bin/pip3

CentOS7使用源文件安装Python3.6

1)在安装Python3.6之前,先安装Python3.6需要的依赖:

sudo yum -y groupinstall development sudo yum -y install zlib-devel

2)运行如下命令安装Python3.6

wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz tar xJf Python-3.6.0.tar.xz cd Python-3.6.0 sudo ./configure sudo make sudo make install

安装完成后,Python安装在了/usr/local文件夹中,可运行文件/usr/local/bin,库文件/usr/local/lib

posted @ 2018-06-06 13:49 长戟十三千 阅读(10) | 评论 (0)编辑 收藏

由于安装与配置一个适合开发的vim环境比较复杂,本文将自己安装配置vim及其插件的过程进行记录,以便以后查看。希望也能对喜欢vim的同学提供一些帮助。

目的:在CentOS7上安装配置vim8.1,打造一个适合开发的编辑环境。


说明:相关配置文件可以在我的github中获取:

https://github.com/stevenzscn/vim_install


一、准备工作

1. 安装dircolors:

git clone https://github.com/seebi/dircolors-solarized.git

cd dircolors-solarized/

mv dircolors.ansi-dark ~/.dircolors


在bash_profile中添加:

export TERM=xterm-256color
if [ -x /usr/bin/dircolors ]; then
alias ls='ls --color=auto'
alias dir='dir --color=auto'
alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
alias tree='tree -C'
fi


重新登录后,生效。



2. 安装依赖:

yum install libXt-devel gtk2-devel

yum -y install python-devel ruby ruby-devel perl perl-devel perl-ExtUtils-Embed

yum install ncurses-devel

yum install ctags

需要依赖python3:

下载Python-3.6.5.tgz

tar -zxv -f Python-3.6.5.tgz

cd Python-3.6.5

./configure --prefix=/usr/local/python3

make

sudo make install


3. 关闭SELinux

修改/etc/selinux/config 文件

将SELINUX=enforcing改为SELINUX=disabled

重启机器。


二、安装vim8.1

git clone https://github.com/vim/vim.git

cd vim

./configure --disable-selinux --enable-perlinterp=yes --enable-python3interp=yes --enable-rubyinterp=yes --enable-cscope --enable-gui=auto --with-features=huge --enable-multibyte --enable-xim --with-x --with-gnome --with-compiledby="Steven Zhang" --prefix=/usr/local/vim8

make

make install

到此vim8.1安装完成,查看version信息:


三、安装vim插件

下面将安装vim插件,使用vundle管理插件:

Plugin 'VundleVim/Vundle.vim'
Plugin 'altercation/vim-colors-solarized'
Plugin 'tomasr/molokai'
Plugin 'vim-scripts/phd'
Plugin 'vim-airline/vim-airline'
Plugin 'vim-airline/vim-airline-themes'
Plugin 'octol/vim-cpp-enhanced-highlight'
Plugin 'derekwyatt/vim-fswitch'
Plugin 'vim-scripts/a.vim'
Plugin 'kshenoy/vim-signature'
Plugin 'vim-scripts/BOOKMARKS--Mark-and-Highlight-Full-Lines'
Plugin 'majutsushi/tagbar'
Plugin 'vim-scripts/indexer.tar.gz'
Plugin 'vim-scripts/DfrankUtil'
Plugin 'vim-scripts/vimprj'
Plugin 'dyng/ctrlsf.vim'
Plugin 'scrooloose/nerdcommenter'
Plugin 'vim-scripts/DrawIt'
Plugin 'SirVer/ultisnips'
Plugin 'Valloric/YouCompleteMe'
Plugin 'rdnetto/YCM-Generator'
Plugin 'derekwyatt/vim-protodef'
Plugin 'scrooloose/nerdtree'
Plugin 'gcmt/wildfire.vim'
Plugin 'sjl/gundo.vim'
Plugin 'Lokaltog/vim-easymotion'
Plugin 'suan/vim-instant-markdown'
Plugin 'qpkorr/vim-bufkill'
Plugin 'skywind3000/asyncrun.vim'

下面是我的vim配置 .vimrc 可以在我的github获取。

1. 安装vundle

vundle会自动下载插件,除YouCompleteMe以外不需要额外的安装操作,YouCompleteMe的安装将在后面说明。
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
vundle会管理.vim下的插件。
打开vim,执行 :BundleInstall ,vundle将自动下载配置的插件。

有时会出现显示异常,比如NERDTree的分支箭头。一般在Linux GNome里是显示正常的,但是使用xshell等终端可能就显示异常,这时可以将分支显示修改成传统的“+ 、~” 符号。


查看.vim/bundle/nerdtree/plugin/NERD_tree.vim
看到 if !nerdtree#runningWindows() 判断后是出现显示异常的地方,可以去掉条件判断:


这样除了YouCompleteMe以外,都搞定了。

2. 安装YouCompleteMe

1) 安装cmake

cmake 2版本安装YCM会有问题,所以这里需要升级cmake。如果使用yum安装了2版本的,请先yum remove cmake  。
下载cmake-3.9.1.tar.gz,安装:
tar -zxv -f cmake-3.9.1.tar.gz
cd cmake-3.9.1/
./bootstrap && make && make install

2) 安装YouCompleteMe

cd .vim/bundle/YouCompleteMe

./install.sh --clang-completer


安装完成后,打开vim会显示python import ycm_core 找不到libclang.so.3.9


复制一份.ycm_extra_conf.py到用户目录下:

cp YouCompleteMe/third_party/ycmd/examples/.ycm_extra_conf.py ~/

.ycm_extra_conf.py是YCM的配置文件,可以根据自己的项目情况进行配置。


也可以使用YCM-Generator插件,根据项目去生成:

./config_gen.py PROJECT_DIRECTORY

或在vim中使用:YcmGenerateConfig

详细用法请查看YCM-Generator文档。


至此YCM安装完成,效果如下:


现在,vim8.1就安装配置完成了。上几张安装后的图:

posted @ 2018-06-06 13:23 长戟十三千 阅读(53) | 评论 (0)编辑 收藏
#define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("%s:%d error no: %d error msg %s\n", __FILE__, __LINE__, errno, strerror(errno)); exit(1);}
posted @ 2018-05-22 00:43 长戟十三千 阅读(6) | 评论 (0)编辑 收藏

linux 多线程信号总结(一)

1. 在多线程环境下,产生的信号是传递给整个进程的,一般而言,所有线程都有机会收到这个信号,进程在收到信号的的线程上下文执行信号处理函数,具体是哪个线程执行的难以获知。也就是说,信号会随机发个该进程的一个线程。

2 signal函数BSD/Linux的实现并不在信号处理函数调用时,恢复信号的处理为默认,而是在信号处理时阻塞此信号,直到信号处理函数返回。其他实现可能在调用信号处理函数时,恢复信号的处理为默认方式,因而需要在信号处理函数中重建信号处理函数为我们定义的处理函数,在这些系统中,较好的方法是使用sigaction来建立信号处理函数。

3 发送信号给进程,哪个线程会收到?APUE说,在多线程的程序中,如果不做特殊的信号阻塞处理,当发送信号给进程时,由系统选择一个线程来处理这个信号。

4 如果进程中,有的线程可以屏蔽了某个信号,而某些线程可以处理这个信号,则当我们发送这个信号给进程或者进程中不能处理这个信号的线程时,系统会将这个信号投递到进程号最小的那个可以处理这个信号的线程中去处理。

5 如果我们同时注册了信号处理函数,同时又用sigwait来等待这个信号,谁会取到信号?经过实验,Linux上sigwait的优先级高。 

6 在Linux中的posix线程模型中,线程拥有独立的进程号,可以通过getpid()得到线程的进程号,而线程号保存在pthread_t的值中。而主线程的进程号就是整个进程的进程号,因此向主进程发送信号只会将信号发送到主线程中去。如果主线程设置了信号屏蔽,则信号会投递到一个可以处理的线程中去。

7 当调用SYSTEM函数去执行SHELL命令时,可以放心的阻塞SIGCHLD,因为SYSTEM会自己处理子进程终止的问题。 

8 使用sleep()时,要以放心的去阻塞SIGALRM信号,目前sleep函数都不会依赖于ALRM函数的SIGALRM信号来工作。

 

 

linux 多线程信号总结(二)

1. 默认情况下,信号将由主进程接收处理,就算信号处理函数是由子线程注册的

2. 每个线程均有自己的信号屏蔽字,可以使用sigprocmask函数来屏蔽某个线程对该信号的响应处理,仅留下需要处理该信号的线程来处理指定的信号。

3. 对某个信号处理函数,以程序执行时最后一次注册的处理函数为准,即在所有的线程里,同一个信号在任何线程里对该信号的处理一定相同

4. 可以使用pthread_kill对指定的线程发送信号

APUE的说法:每个线程都有自己的信号屏蔽字,但是信号的处理是进程中所有的线程共享的,这意味着尽管单个线程可以阻止某些信号,但当线程修改了与某个信号相关的处理行为后,所有的线程都共享这个处理行为的改变。这样如果一个线程选择忽略某个信号,而其他线程可以恢复信号的默认处理行为,或者为信号设置一个新的处理程序,从而可以撤销上述线程的信号选择。

进程中的信号是送到单个线程的,如果信号与硬件故障或者计时器超时有关,该型号就被发送到引起该事件的线程中去,而其他的信号则被发送到任意一个线程。

sigprocmask的行为在多线程的进程中没有定义,线程必须使用pthread_sigmask

总结:一个信号可以被没屏蔽它的任何一个线程处理,但是在一个进程内只有一个多个线程共用的处理函数。......

 

linux 多线程信号总结(三)

1 Linux 多线程应用中,每个线程可以通过调用pthread_sigmask() 设置本线程的信号掩码。一般情况下,被阻塞的信号将不能中断此线程的执行,除非此信号的产生是因为程序运行出错如SIGSEGV;另外不能被忽略处理的信号SIGKILL 和SIGSTOP 也无法被阻塞。

2 当一个线程调用pthread_create() 创建新的线程时,此线程的信号掩码会被新创建的线程继承。

信号安装最好采用sigaction方式,sigaction,是为替代signal 来设计的较稳定的信号处理,signal的使用比较简单。signal(signalNO,signalproc);

不能完成的任务是:1.不知道信号产生的原因;

2.处理信号中不能阻塞其他的信号

而signaction,则可以设置比较多的消息。尤其是在信号处理函数过程中接受信号,进行何种处理。

sigaction函数用于改变进程接收到特定信号后的行为。

4 sigprocmask函数只能用于单线程,在多线程中使用pthread_sigmask函数。

5 信号是发给进程的特殊消息,其典型特性是具有异步性。

6 信号集代表多个信号的集合,其类型是sigset_t。

7 每个进程都有一个信号掩码(或称为信号屏蔽字),其中定义了当前进程要求阻塞的信号集。

所谓阻塞,指Linux内核不向进程交付在掩码中的所有信号。于是进程可以通过修改信号掩码来暂时阻塞特定信号的交付,被阻塞的信号不会影响进程的行为直到该信号被真正交付。 

忽略信号不同于阻塞信号,忽略信号是指Linux内核已经向应用程序交付了产生的信号,只是应用程序直接丢弃了该信号而已。

10 sleep和nanosleep,如果没有在它调用之前设置信号屏蔽字的话,都可能会被信号处理函数打断。参见sleep和nanosleep的mannual。

posted @ 2018-05-18 17:02 长戟十三千 阅读(6) | 评论 (0)编辑 收藏
     摘要: 1. 为什么用volatile?    C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明:A volatile specifier is a hint t...  阅读全文
posted @ 2018-05-17 17:16 长戟十三千 阅读(7) | 评论 (0)编辑 收藏
     摘要: Linux 多线程应用中编写安全的信号处理函数在开发多线程应用时,开发人员一般都会考虑线程安全,会使用 pthread_mutex 去保护全局变量。如果应用中使用了信号,而且信号的产生不是因为程序运行出错,而是程序逻辑需要,譬如 SIGUSR1、SIGRTMIN 等,信号在被处理后应用程序还将正常运行。在编写这类信号处理函数时,应用层面的开发人员却往往忽略了信号处理函数执行的上...  阅读全文
posted @ 2018-05-17 17:09 长戟十三千 阅读(9) | 评论 (0)编辑 收藏
仅列出标题  下一页