Abstract: The php version read here is PHP-7.1.0 RC3, and the platform for reading the code is linuxZTS. We will see that there are many places in the article: #ifdef ZTS # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v ) #else # define CG(v) (compi...
The php version read here is PHP-7.1.0 RC3, and the platform for reading the code is linux
ZTS
We will see that there are many places in the article that are :
1 #ifdef ZTS 2 # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) 3 #else 4 # define CG(v) (compiler_globals.v) 5 extern ZEND_API struct _zend_compiler_globals compiler_globals; 6 #endif
What is the concept of ZTS here? The PHP we often use runs in a single-process, single-threaded environment, such as cgi. When a request comes in, one process serves it. When the request ends, the process That's it. So for example, like global variables, the PHP kernel does not consider thread safety issues when multiple threads modify and obtain them at the same time. Later, PHP is gradually developing towards a single-process multi-thread server. At this time, it will be necessary. A layer to specifically deal with thread safety issues. This is TSRM (Thread Safe Resource Management).
But when compiling, you can specify parameters to enable compiling a thread-safe version of php. -enable-maintainer-zts option, Windows platform is --enable-zts) This is the origin of ZTS here.
For example, in the above example, CG(V) obtains the v of the global structure compiler_globals structure under non-thread safety. Attributes are obtained through the ZEND_TSREMG method under thread safety.
zend_try
We will see the zend_try_catch related code as follows:
1 zend_try { 2 ...exec_try 3 } zend_catch { 4 ...exec_catch 5 } zend_end_try();
Expand the macro, we can see the approximate code as follows:
01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }
What does this mean? You need to understand setjmp and longjmp first. These two functions are methods provided by Linux. They are used in combination to achieve the function of the coroutine.
#include ade979de5fc0e1ca0540f360a64c230b
# include 141642a285ad26cf7e55efeead7f8373
jmp_buf env;
void foo() {
printf("before jmpn");
int ret = setjmp(env);
if(ret == 0) {
return;
} else {
printf("return %dn", ret);
}
printf("after jmpn");
}
int main(int argc, char* argv[]) {
foo();
longjmp(env, 999);
return 0;
}// Output:
/* before jmp
return 999
after jmp */
In the above example, setjmp is equivalent to program fragment 1 handing over the initiative, and then executing the program below if (ret == 0) until longjmp is encountered, and the execution right is returned to fragment 1. And set jmp_buf to 999, fragment 1 continues to execute, and when ret!=0 is found, return 999 is output.
Okay, back to this program:
01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }
The exec_try code segment in this program contains a call to the longjmp function when an error is encountered and needs to be returned. In this way, our usual function of calling try...catch...finnal is formed:
1 First save the bailout in the global variable
2 Use setjmp to jump to execute the following program
3 Execute exec_try
4 If exec_try this There is longjmp in the code segment, and longjmp returns non-0 (generally it is indeed non-0), execute exec_catch
5 Finally, restore the bailout in the global variable
There may be two doubts here. What should I do if there is no longjmp in exec_try? , then just execute exec_try directly and skip exec_catch. This is also the standard way to use setjmp and longjmp to implement try catch.
The implementation of these two makes up for the limitation that the goto keyword can only jump inside the function. This is called a "long jump".
So in PHP code, if the function you execute may throw an exception. You might as well use this method to put the program you want to execute inside.
The above is the content of PHP kernel analysis (2). For more related content, please pay attention to the PHP Chinese website (www.php.cn)!