One failed PHP extension development

Source: Internet
Author: User
One failed PHP extension development One failedPHP Extended development journey

By warezhou 2014.11.19


Origin

After continuous iteration, our department's coroutine network framework (CoSvrFrame) was finally released! This was originally a great thing, but as new businesses continue to access, many inherent defects gradually emerge:

  • "TCP connection pool" is not supported"
  • "Dispatcher-Workers model" is not supported"
  • "Overload protection" is not supported"
  • "Hot restart" is not supported"
  • "64Bit" is not supported"
  • ......
  • For senior background development, most of the problems listed above are difficult to understand. the reason for this problem is a bit like "warm boiled frog": the iteration process lacks a macro perspective and introduces too many business features, the overall architecture is unreasonable. Recently, the "coroutine version" was originally my personal work in my spare time. I only used the original SvrFrame at the underlying layer to write business code happily and make it easy to get out of work, the earth is shaking! Take the most extreme 64Bit as an example. I believe everyone understands it in seconds.

    After many surveys and discussions, we finally gave the following forward directions:

  • Introducing the company's open-source SPP3.0 framework, absorbing its infrastructure and surrounding facilities for secondary business development
  • Extensions of SPP support embedded programming using PHP as a scripting language, and provide PHP with coroutine capabilities in the form of C extensions (from now on, PHPer can also happily write asynchronous code, mom no longer needs to worry about my callback !)
  • What do you mean? After so long, we can start with the topic: how to implement C ++/PHP hybrid programming?

    Disclaimer:As I am a programmer and have not been familiar with PHP extension development for weeks, I can't go deep into WHY, just stay at HOW, just for record purposes, please forgive me!

    Opening EmbeddedPHP

    The combination of C ++/PHP in the industry is generally due to "performance" considerations. C/C ++ extensions are called in PHP code, to solve specific performance bottlenecks (such as PB serialization ).

    As a C/C ++ developer, "development efficiency" is obviously more attractive than "performance". Therefore, our idea is to use PHP as a script language to quickly develop business logic, insert to SPP framework for running.

    1. open the php dynamic library in RTLD_GLOBAL mode

    void *php_handler = dlopen("libphp5.so", RTLD_LAZY | RTLD_GLOBAL);if (!php_handler) {    base->log_.LOG_P_PID(LOG_FATAL, "%s\n", dlerror());    return -1; }   dlclose(php_handler);

    2. initialize with php_embed_init

    php_embed_module.php_ini_path_override = "../php/php.ini";php_embed_init(0, NULL);

    3. introduce the PHP script through zend_eval_string

    zend_first_try {    char exec_str[256];    snprintf(exec_str, sizeof(exec_str), "include '%s';", "../php/demo_handler.php");    if (int ret = zend_eval_string(exec_str, NULL, exec_str TSRMLS_CC)) {        base->log_.LOG_P_PID(LOG_FATAL, "zend_eval_string fail. ret=%d\n", ret);        return -1;     }    base->log_.LOG_P_PID(LOG_DEBUG, "zend_eval_string succ.\n");} zend_catch {    base->log_.LOG_P_PID(LOG_FATAL, "zend_eval_string catch.\n");} zend_end_try ();

    4. call back the PHP function through call_user_function

    zval z_funcname;ZVAL_STRING(&z_funcname, "EchoDemo::init", 1);zval *zp_svr;MAKE_STD_ZVAL(zp_svr);ZVAL_LONG(zp_svr, (long)base);zval *zp_etc;MAKE_STD_ZVAL(zp_etc);ZVAL_STRING(zp_etc, etc, 1);zval z_retval;zval *z_params[] = {zp_svr, zp_etc};int call_ret = call_user_function(CG(function_table), NULL, &z_funcname, &z_retval, sizeof(z_params) / sizeof(z_params[0]), z_params TSRM convert_to_long(&z_retval);int func_ret = Z_LVAL_P(&z_retval);zval_ptr_dtor(&zp_etc);zval_dtor(&z_funcname);zval_dtor(&z_retval);if (call_ret < 0 || func_ret < 0) {    base->log_.LOG_P_PID(LOG_FATAL, "call_user_function fail. call_ret=%d func_ret=%d\n", call_ret, func_ret);    return -1;}

    5. clean up through php_embed_shutdown

    php_embed_shutdown(TSRMLS_C);

    PHPExtension

    Php c extension development articles on the Internet can be said to have reached the flood level. interested readers can read the appendix at the end of the article.

    1. download the php source code package and manually compile it. in order to work with the above embedded application, do you need to open it? Enable-embed option

    ./Configure -- enable-embedmakemake install (optional)

    2. go to the ext Directory of the php source code package and use the ext_skel tool to generate the plug-in shelf code

    cd ext./ext_skel --extname=demo

    3. edit config. m4, open the PHP_ARG_WITH or PHP_ARG_ENABLE option (tell the truth the difference is still unclear, ask someone to give advice), add C ++ support, dependency path, etc.

    PHP_ARG_ENABLE(demo, whether to enable demo support,    [  --enable-demo           Enable demo support])if test "$PHP_DEMO" != "no"; then  PHP_REQUIRE_CXX()  PHP_ADD_LIBRARY(stdc++, 1, EXTRA_LDFLAGS)  PHP_ADD_INCLUDE(/root/spp/module/include/)  PHP_ADD_INCLUDE(/root/spp/module/include/spp_incl/)  PHP_NEW_EXTENSION(demo, demo.cpp, $ext_shared)fi

    4. edit demo. cpp, add extension definitions and implementations (functions, classes, variables ...), the function definition example is provided here. readers who are interested in the class will explore the function according to the appendix. The sendrecv function is typically defined here. among them, the 3rd rsp parameter is a reference parameter and is responsible for returning the received data to the PHP caller.

    ZEND_BEGIN_ARG_INFO_EX(arginfo_sendrecv, 0, 0, 7)    ZEND_ARG_INFO(0, req)    ZEND_ARG_INFO(0, req_len)    ZEND_ARG_INFO(1, rsp)    ZEND_ARG_INFO(0, rsp_len)    ZEND_ARG_INFO(0, ip)    ZEND_ARG_INFO(0, port)    ZEND_ARG_INFO(0, timeout)ZEND_END_ARG_INFO()PHP_FUNCTION(sendrecv){    char *req = NULL;    int req_str_len = 0;    long req_len = 0;    zval *rsp = NULL;    long rsp_len = 0;    char *ip = NULL;    int ip_str_len = 0;    long port = 0;    long timeout = 0;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slzlsll", &req, &req_str_len,&req_len, &rsp, &rsp_len, &ip, &ip_str_len, &port, &timeout) == FAILURE) {        return;}       struct sockaddr_in addr;    memset(&addr, 0, sizeof(addr));    addr.sin_family = AF_INET;    addr.sin_addr.s_addr = inet_addr(std::string(ip, ip_str_len).c_str());    addr.sin_port = htons(port);    char *rsp_buf = (char *)emalloc(rsp_len);    int rsp_buf_len = rsp_len;    if (int ret = mt_udpsendrcv(&addr, req, req_len > req_str_len ? req_str_len : req_len, rsp_buf, rsp_buf_len, timeout)) {        efree(rsp_buf);        RETURN_LONG(ret);    }    zval_dtor(rsp);    ZVAL_STRINGL(rsp, rsp_buf, rsp_buf_len, 0);    RETURN_LONG(0);}
    const zend_function_entry demo_functions[] = {    PHP_FE(sendrecv, arginfo_sendrecv)    PHP_FE_END  /* Must be the last line in demo_functions[] */};

    5. everything is ready and can be compiled and extended. I personally prefer dynamic compilation (static compilation requires re-compilation of php source code, which is too time-consuming and laborious) to generate. so is located in the current extended modules Directory

    /usr/local/bin/phpize./configure --with-php-config=/usr/local/bin/php-configmake

    6. edit the php. ini file, add new extensions, and then you can happily call the new extensions in the PHP code.

    extension_dir="/somewhere/modules"extension="demo.so"extension="xxxx.so"

    Climax

    Finally, it was time to assemble and form. I played several echodemos via telnet, and I was in a good mood when I saw a line of Echo.

     

    The most amazing thing here is the extended call of the process function for sendrecv. here, the coroutine has actually implemented an asynchronous network interaction: it can write logic code like synchronizing CGI, it is also easy to enjoy asynchronous high concurrency.

    The desire is beautiful, and the reality is cruel!

    I was suddenly excited: Let's test the performance to see how much performance degrades compared to the native C ++ code. 1 KB for a single request, apply the pressure of 1 w/s, and press coredump for a while.

    Memory leakage? Coroutine stack overflow ?...

    Various tossing during the period: GDB, modify the coroutine stack size, Google, consult PHPer...

    Soon after the evening, I checked all the items I checked and asked all the questions. I did not know. I stopped to have a cup of tea: "Can call_user_function be reloaded "? Think of this layer, I believe that the brother who understands the essence of coroutine understands it in seconds: Your sister's, how do people know that the calling thread will also play with coroutine for user-State scheduling when implementing Zend, everything in this black box is possible! Global variables, static variables...

    All right, remove the coroutine-based extension such as sendrecv and re-stress test. a single worker is easy and stress-free for 3 w/s echo.

    Conclusion

    Although the most attractive Feature was not implemented in the end, I was very happy because it once again confirmed a point of view:Thinking is often a hundred times more efficient than doing it.Especially when dealing with difficult problems, it is often hard and thankless to break into the chaos without a head fly. at this time, if you can calm down and try your best to collect existing knowledge reserves, you may be inspired to patronize you.

    Possible future direction: PHP introduced yield from version 5.5. I feel that Zend may be well integrated with our C framework if it finds out the details of yield support, but I always think it is a big pitfall. If you leave aside other factors, maybe I still want to use Golang to enjoy goroutine's advantages. haha!

    Appendix

    PHP extension development and kernel applications

    Http://www.walu.cc/phpbook/preface.md

    Two methods for compiling PHP extensions

    Http://521-wf.com/archives/227.html

    How to use C ++ to develop PHP extensions (I)

    Http://521-wf.com/archives/241.html

    How to use C ++ to develop PHP extensions (below)

    Http://521-wf.com/archives/245.html

    Wrapping C ++ Classes in a PHP Extension

    Http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.