(点击上方公众号,可快速关注)
作者:叶剑峰
链接:www.cnblogs.com/yjf512/p/6092708.html
PHP内核分析(1):sapi_module_struct
这里阅读的php版本为PHP-7.1.0RC3,阅读代码的平台为linux
ZTS
我们会看到文章中有很多地方是:
#ifdefZTS
#defineCG(v)ZEND_TSRMG(compiler_globals_id,zend_compiler_globals*,v)
#else
#defineCG(v)(compiler_globals.v)
externZEND_APIstruct_zend_compiler_globalscompiler_globals;
#endif
这里的ZTS是个什么概念呢。我们常常利用的php都是运行在单进程,单线程环境,比如cgi,都是一个哀求进来,就一个进程为它服务,当哀求竣事了,进程也就竣事了。以是比如像全局变量,php内核就没有思量多线程同时修改获取的时间线程安全题目。厥后,php渐渐也在往单进程多线程服务器方向发展。那么这个时间,就会必要有一个层来专门处理惩罚线程安全题目。这个就是TSRM(ThreadSafeResourceManagement)。
但是php默认是关闭线程安全的。在编译的时间,你可以指定参数开启编译一个线程安全版本的php。(–enable-maintainer-zts选项,Windows平台为–enable-zts)这个就是这里的ZTS的由来。
比如上面的例子,CG(V)在非线程安全下获取的是全局布局compiler_globals布局的v属性,在线程安全下获取的是通过ZEND_TSREMG方法来获取。
zend_try
我们会看到zend_try_catch相干的代码如下:
zend_try{
...exec_try
}zend_catch{
...exec_catch
}zend_end_try();
把宏睁开,我们可以看到大概代码如下:
{
JMP_BUF*__orig_bailout=EG(bailout);
JMP_BUF__bailout;
EG(bailout)=__bailout;
if(SETJMP(__bailout)==0){
{
...exec_try
}
}else{
EG(bailout)=__orig_bailout;
{
...exec_catch
}
}
EG(bailout)=__orig_bailout;
}
这个是什么意思呢,必要先明白下setjmp和longjmp,这两个函数是linux提供的方法。他们是组合起来利用的,到达协同程序的功能
#include
#include
jmp_bufenv;
voidfoo(){
printf("beforejmpn");
intret=setjmp(env);
if(ret==0){
return;
}else{
printf("return%dn",ret);
}
printf("afterjmpn");
}
intmain(intargc,char*argv[]){
foo();
longjmp(env,999);
return0;
}
//输出:
/*
beforejmp
return999
afterjmp
*/
上面的这个例子,setjmp的时间相称于程序片断1把主动权交出来,然后实行if(ret==0)下面的程序,直到碰到longjmp,把实行权还给了片断1,而且设置jmp_buf为999,片断1继承实行,发现了ret!=0,就输出return999。
好了,回到这个程序:
{
JMP_BUF*__orig_bailout=EG(bailout);
JMP_BUF__bailout;
EG(bailout)=__bailout;
if(SETJMP(__bailout)==0){
{
...exec_try
}
}else{
EG(bailout)=__orig_bailout;
{
...exec_catch
}
}
EG(bailout)=__orig_bailout;
}
这个程序内里的exec_try代码段内里,在碰到错误的时间,必要返回的时间,就会包罗一个longjmp函数的调用。如许,就形成了我们平常调用try…catch…finnal的功能:
1老师存全局变量内里的bailout
2利用setjmp来做跳转实行下面的程序
3实行exec_try
4假如exec_try这个代码段内里有longjmp,而且longjmp返回非0(一样平常也确实非0),就实行exec_catch
5末了,把全局变量内里的bailout规复
这里大概会有两个迷惑,假如exec_try内里没有longjmp怎么办,那就直接只实行了exec_try,就跳过exec_catch了。这个也是标准的用setjmp和longjmp实现trycatch的写法。
这两个的实现补充了goto关键字只能在函数内部举行跳转的限定。这个叫做“长跳转”。
以是在PHP代码中,假如你实行的函数有大概抛出非常。不妨利用这个方式把你要实行的程序放在内里。
参考
https://blog.lucode.net/skills/talk-about-setjmp-and-longjmp.html
关注「PHP开辟者」
看更多精选PHP技能文章
↓↓↓
我要评论