Re: Thread safety issue in C++ extension module

From: Date: Wed, 26 Feb 2014 17:24:30 +0000
Subject: Re: Thread safety issue in C++ extension module
References: 1 2  Groups: php.internals 
Request: Send a blank email to internals+get-72831@lists.php.net to get a copy of this message
On 26/02/14 16:49, Johannes Schlüter wrote:
Yes, TSRM is our thread-safe resource manager providing a thread local storage for PHP request isolation. The information in your message is sparse though. Without any code, examples of crashes etc it is hard to see what you are actually doing, where you are stuck and how to help.
Thanks for your quick response. Please find code below: I have commented out my attempt to do some thread safety. I have cut out some PHP_METHODS to ease the readability. The line of code of interest is indicated by //**** in two places. Specifically, where we create the SaxonProcessor object and also destroy the JVM needs to be in a single os process (i.e.: "saxonProc = new SaxonProcessor(false); " and "obj->saxonProc->close();" ) =============================== #ifndef PHP_SAXON_H #define PHP_SAXON_H #define PHP_SAXON_EXTNAME "Saxon/C" #define PHP_SAXON_EXTVER "0.2" #ifdef HAVE_CONFIG_H #include "config.h" #endif /*#ifdef ZTS #include "TSRM.h" #define COUNTER_G(v) TSRMG(counter_globals_id, zend_counter_globals *, v) #else #define COUNTER_G(v) (counter_globals.v) #endif*/ extern "C" { #ifdef __linux__
    #include "php.h"
    #include "ext/standard/info.h"
#endif #include "zend_exceptions.h" } /*ZEND_BEGIN_MODULE_GLOBALS(saxon)
    long counter;
ZEND_END_MODULE_GLOBALS(saxon) ZEND_DECLARE_MODULE_GLOBALS(saxon) int saxon_globals_id; */ extern zend_module_entry saxon_module_entry; #define phpext_saxon_ptr &saxon_module_entry; zend_object_handlers XsltProcessor_object_handlers; zend_object_handlers XQueryProcessor_object_handlers; zend_object_handlers xdmValue_object_handlers; struct SaxonProcessor_object {
    zend_object std;
    SaxonProcessor * saxonProc;
}; struct XsltProcessor_object {
    zend_object std;
    XsltProcessor *xsltProcessor;
    SaxonProcessor * saxonProc;
}; struct xdmValue_object {
    zend_object std;
    XdmValue * xdmValue;
}; zend_class_entry *xsltProcessor_ce; zend_class_entry *xqueryProcessor_ce; zend_class_entry *xdmValue_ce; void XsltProcessor_free_storage(void *object TSRMLS_DC) { php_error(E_WARNING, "XXXXXXXXXXXXXXXX - free storage");
    XsltProcessor_object *obj = (XsltProcessor_object *)object;
     if (obj->saxonProc != NULL) {
    obj->saxonProc->close(); //**** - CONTAINS CODE THAT CAN ONLY BE RUN IN SINGLE OS PROCESS
    }
    delete obj->saxonProc;
    delete obj->xsltProcessor;
    zend_hash_destroy(obj->std.properties);
    FREE_HASHTABLE(obj->std.properties);
    efree(obj);
} zend_object_value XsltProcessor_create_handler(zend_class_entry *type TSRMLS_DC) {
    zval *tmp;
    zend_object_value retval;
    XsltProcessor_object *obj = (XsltProcessor_object *)emalloc(sizeof(XsltProcessor_object));
    memset(obj, 0, sizeof(XsltProcessor_object));
    obj->std.ce = type;
    ALLOC_HASHTABLE(obj->std.properties);
    zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
    retval.handle = zend_objects_store_put(obj, NULL,
        XsltProcessor_free_storage, NULL TSRMLS_CC);
    retval.handlers = &XsltProcessor_object_handlers;
    return retval;
} PHP_METHOD(Xslt2Processor, __construct) {
    char cwd[256];
    getcwd(cwd, sizeof(cwd));
    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        php_error(E_WARNING,"getcwd error");
    }
    XsltProcessor *xsltProcessor = NULL;
    zval *object = getThis();
    SaxonProcessor * saxonProc;
    SaxonProcessor_object *saxonProcObj = (SaxonProcessor_object *)zend_object_store_get_object(object TSRMLS_CC);
    SaxonProcessor * saxonProc =  saxonProcObj->saxonProc;
    if(saxonProc == NULL) {
    saxonProc = new SaxonProcessor(false);    //**** - CONTAINS CODE THAT CAN ONLY BE RUN IN SINGLE OS PROCESS
    saxonProcObj->saxonProc = saxonProc;
    }
    saxonProc->setcwd(cwd);
    XsltProcessor_object *obj = (XsltProcessor_object *)zend_object_store_get_object(object TSRMLS_CC);
    obj->saxonProc = saxonProc;
    /*saxonProc = obj->saxonProc;
    if(saxonProc == NULL) {
    php_error(E_WARNING, "Xslt2Processor Construct - call to SAxonProcessor");
        saxonProc = new SaxonProcessor(false);
        obj->saxonProc = saxonProc;
    }
    saxonProc->setcwd(cwd);*/
    xsltProcessor = saxonProc->newTransformer();
    obj->xsltProcessor = xsltProcessor;
} PHP_METHOD(Xslt2Processor, __destruct) { XsltProcessor_object *obj = (XsltProcessor_object *)zend_object_store_get_object(
        getThis() TSRMLS_CC);
    SaxonProcessor_object *obj2 = (SaxonProcessor_object *)zend_object_store_get_object(
        getThis() TSRMLS_CC);
    XsltProcessor *xsltProcessor =  obj->xsltProcessor;
    SaxonProcessor * saxonProc= obj2->saxonProc;
    delete xsltProcessor;
    delete saxonProc
} PHP_METHOD(Xslt2Processor, xsltSaveResultToFile) { XsltProcessor *xsltProcessor; char * sourcefile; char * stylesheet; char * outputfile; int len1, len2, len3;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &sourcefile, &len1, &stylesheet, &len2, &outputfile, &len3) == FAILURE) {
        RETURN_NULL();
    }
    XsltProcessor_object *obj = (XsltProcessor_object *)zend_object_store_get_object(
        getThis() TSRMLS_CC);
    xsltProcessor = obj->xsltProcessor;
    if (xsltProcessor != NULL) {
     xsltProcessor->xsltSaveResultToFile(sourcefile, stylesheet, outputfile);
     if(xsltProcessor->exceptionOccurred()) {
         //throw exception
     }
    }
} PHP_METHOD(Xslt2Processor, xsltApplyStylesheet) { XsltProcessor *xsltProcessor; char * sourcefile; char * stylesheet; int len1, len2, myint;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &sourcefile, &len1, &stylesheet, &len2) == FAILURE) {
        RETURN_NULL();
    }
    XsltProcessor_object *obj = (XsltProcessor_object *)zend_object_store_get_object(
        getThis() TSRMLS_CC);
    xsltProcessor = obj->xsltProcessor;
    if (xsltProcessor != NULL) {
    const char * result = xsltProcessor->xsltApplyStylesheet(sourcefile, stylesheet);
    xsltProcessor->checkException();
    if(result != NULL ) {
         char *str = estrdup(result);
          RETURN_STRING(str, 0);
       }
    }
RETURN_NULL(); } zend_function_entry XsltProcessor_methods[] = {
    PHP_ME(Xslt2Processor,  __construct,     NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
    PHP_ME(Xslt2Processor,  __destruct,     NULL, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
    PHP_ME(Xslt2Processor,  xsltSaveResultToFile,           NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  xsltApplyStylesheet,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  xsltApplyStylesheet1,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  setSourceValue,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  parseString,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  setParameter,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  setProperty,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  clear,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  exceptionClear,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  close,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  getErrorCode,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  getErrorMessage,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  getExceptionCount,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Xslt2Processor,  version,      NULL, ZEND_ACC_PUBLIC)
    {NULL, NULL, NULL}
}; PHP_MINIT_FUNCTION(saxon) { // ts_allocate_id(&saxon_globals_id, sizeof(XsltProcessor_object), (ts_allocate_ctor)XsltProcessor_object,(ts_allocate_dtor)XsltProcessor_object);
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "Xslt2Processor", XsltProcessor_methods);
    xsltProcessor_ce = zend_register_internal_class(&ce TSRMLS_CC);
    xsltProcessor_ce->create_object = XsltProcessor_create_handler;
    memcpy(&XsltProcessor_object_handlers,
        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    XsltProcessor_object_handlers.clone_obj = NULL;
    INIT_CLASS_ENTRY(ce, "XQueryProcessor", XQueryProcessor_methods);
    xqueryProcessor_ce = zend_register_internal_class(&ce TSRMLS_CC);
    xqueryProcessor_ce->create_object = XQueryProcessor_create_handler;
    memcpy(&XQueryProcessor_object_handlers,
        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    XQueryProcessor_object_handlers.clone_obj = NULL;
    INIT_CLASS_ENTRY(ce, "XdmValue", xdmValue_methods);
    xdmValue_ce = zend_register_internal_class(&ce TSRMLS_CC);
    xdmValue_ce->create_object = xdmValue_create_handler;
    memcpy(&xdmValue_object_handlers,
        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    xdmValue_object_handlers.clone_obj = NULL;
// ZEND_INIT_MODULE_GLOBALS(saxon, php_saxon_init_globals,NULL); // REGISTER_INI_ENTRIES();
    return SUCCESS;
} // function implementation PHP_MINFO_FUNCTION(saxon) {
    php_info_print_table_start();
    php_info_print_table_header(2, "Saxon/C", "enabled");
    php_info_print_table_row(2, "Saxon/C EXT version", "0.2");
    php_info_print_table_row(2, "Saxon-HEJ", "9.5.1.3");
    php_info_print_table_row(2, "Excelsior JET (MP1)", "9.0");
    php_info_print_table_end();
    DISPLAY_INI_ENTRIES();
} PHP_MSHUTDOWN_FUNCTION(saxon){
     php_error(E_WARNING,"entered MSHUTDOWN");
    UNREGISTER_INI_ENTRIES();
    return SUCCESS;
} PHP_RSHUTDOWN_FUNCTION(saxon){
     php_error(E_WARNING,"entered RSHUTDOWN");
    efree(xsltProcessor_ce);
    return SUCCESS;
} PHP_RINIT_FUNCTION(saxon){
    php_error(E_WARNING,"entered RINT");
/*    string str = ""+((SAXON_G(counter)));
const char * result = str.c_str(); php_error(E_WARNING, result);
    SAXON_G(counter) = 0;*/
    return SUCCESS;
} zend_module_entry saxon_module_entry = { #if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_SAXON_EXTNAME,
    NULL/*saxon_static_functions*/,        /* Functions */
    PHP_MINIT(saxon),        /* MINIT */
    PHP_MSHUTDOWN(saxon),        /* MSHUTDOWN */
    /*PHP_RINIT(saxon)*/NULL,        /* RINIT */
    PHP_RSHUTDOWN(saxon),        /* RSHUTDOWN */
    PHP_MINFO(saxon),        /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
    PHP_SAXON_EXTVER,
#endif
    STANDARD_MODULE_PROPERTIES
}; //#ifdef COMPILE_DL_SAXON extern "C" { ZEND_GET_MODULE(saxon) } //#endif =================== kind regards, -- O'Neil Delpratt Software Developer, Saxonica Limited Email: oneil@saxonica.com <mailto:oneil@saxonica.com> Tel: +44 118 946 5894 Web: http://www.saxonica.com Saxonica Community Site: http://dev.saxonica.com Saxonica Bug tracking System: https://saxonica.plan.io/

« previous php.internals (#72831) next »