source: trunk/xcache.c @ 1278

Last change on this file since 1278 was 1278, checked in by moo, 13 months ago

disable optimizer for PHP 5.5 for now. TODO: support for finally_op/finally_end

  • Property svn:eol-style set to native
File size: 25.1 KB
Line 
1/* {{{ macros */
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5
6#include <signal.h>
7
8#include "xcache.h"
9
10#ifdef HAVE_XCACHE_OPTIMIZER
11#   include "mod_optimizer/xc_optimizer.h"
12#endif
13#ifdef HAVE_XCACHE_CACHER
14#   include "mod_cacher/xc_cacher.h"
15#endif
16#ifdef HAVE_XCACHE_COVERAGER
17#   include "mod_coverager/xc_coverager.h"
18#endif
19#ifdef HAVE_XCACHE_DISASSEMBLER
20#   include "mod_disassembler/xc_disassembler.h"
21#endif
22
23#include "xcache_globals.h"
24#include "xcache/xc_extension.h"
25#include "xcache/xc_ini.h"
26#include "xcache/xc_const_string.h"
27#include "xcache/xc_opcode_spec.h"
28#include "xcache/xc_utils.h"
29#include "util/xc_stack.h"
30
31#include "php.h"
32#include "ext/standard/info.h"
33#include "ext/standard/php_string.h"
34#include "SAPI.h"
35/* }}} */
36
37/* {{{ globals */
38static char *xc_coredump_dir = NULL;
39#ifdef ZEND_WIN32
40static zend_ulong xc_coredump_type = 0;
41#endif
42static zend_bool xc_disable_on_crash = 0;
43
44static zend_compile_file_t *old_compile_file = NULL;
45
46zend_bool xc_test = 0;
47
48ZEND_DECLARE_MODULE_GLOBALS(xcache)
49
50/* }}} */
51
52static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
53{
54    XG(initial_compile_file_called) = 1;
55    return old_compile_file(h, type TSRMLS_CC);
56}
57/* }}} */
58
59/* devel helper function */
60#if 0
61static void xc_list_extensions() /* {{{ */
62{
63    zend_llist_element *element;
64    zend_extension *ext;
65    fprintf(stderr, "extensions:\n");
66    for (element = zend_extensions.head; element; element = element->next) {
67        ext = (zend_extension *) element->data;
68        fprintf(stderr, " - %s\n", ext->name);
69    }
70}
71/* }}} */
72#endif
73
74/* module helper function */
75static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
76{
77    typedef struct {
78        const char *prefix;
79        zend_uchar (*getsize)();
80        const char *(*get)(zend_uchar i);
81    } xc_nameinfo_t;
82    xc_nameinfo_t nameinfos[] = {
83        { "",        xc_get_op_type_count,   xc_get_op_type   },
84        { "",        xc_get_data_type_count, xc_get_data_type },
85        { "",        xc_get_opcode_count,    xc_get_opcode    },
86        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
87        { NULL, NULL, NULL }
88    };
89    int undefdone = 0;
90    xc_nameinfo_t *p;
91
92    for (p = nameinfos; p->getsize; p ++) {
93        zend_uchar i, count;
94        char const_name[96];
95        int const_name_len;
96
97        count = p->getsize();
98        for (i = 0; i < count; i ++) {
99            const char *name = p->get(i);
100            if (!name) continue;
101            if (strcmp(name, "UNDEF") == 0) {
102                if (undefdone) continue;
103                undefdone = 1;
104            }
105            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
106            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
107        }
108    }
109
110    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
111    zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
112    zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
113    return 0;
114}
115/* }}} */
116/* {{{ PHP_GINIT_FUNCTION(xcache) */
117#pragma GCC push_options
118#pragma GCC diagnostic ignored "-Wshadow"
119
120#ifdef PHP_GINIT_FUNCTION
121static PHP_GINIT_FUNCTION(xcache)
122#else
123static void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
124#endif
125{
126#pragma GCC pop_options
127
128    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
129
130#ifdef HAVE_XCACHE_CONSTANT
131    zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
132#endif
133    zend_hash_init_ex(&xcache_globals->internal_function_table, 1, NULL, NULL, 1, 0);
134    zend_hash_init_ex(&xcache_globals->internal_class_table,    1, NULL, NULL, 1, 0);
135}
136/* }}} */
137/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
138static
139#ifdef PHP_GSHUTDOWN_FUNCTION
140PHP_GSHUTDOWN_FUNCTION(xcache)
141#else
142void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
143#endif
144{
145    size_t i;
146
147    if (xcache_globals->php_holds != NULL) {
148        for (i = 0; i < xcache_globals->php_holds_size; i ++) {
149            xc_stack_destroy(&xcache_globals->php_holds[i]);
150        }
151        free(xcache_globals->php_holds);
152        xcache_globals->php_holds = NULL;
153        xcache_globals->php_holds_size = 0;
154    }
155
156    if (xcache_globals->var_holds != NULL) {
157        for (i = 0; i < xcache_globals->var_holds_size; i ++) {
158            xc_stack_destroy(&xcache_globals->var_holds[i]);
159        }
160        free(xcache_globals->var_holds);
161        xcache_globals->var_holds = NULL;
162        xcache_globals->var_holds_size = 0;
163    }
164
165    if (xcache_globals->internal_table_copied) {
166#ifdef HAVE_XCACHE_CONSTANT
167        zend_hash_destroy(&xcache_globals->internal_constant_table);
168#endif
169        zend_hash_destroy(&xcache_globals->internal_function_table);
170        zend_hash_destroy(&xcache_globals->internal_class_table);
171    }
172}
173/* }}} */
174
175/* {{{ proto int xcache_get_refcount(mixed variable)
176   XCache internal uses only: Get reference count of variable */
177PHP_FUNCTION(xcache_get_refcount)
178{
179    zval *variable;
180    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
181        RETURN_NULL();
182    }
183
184    RETURN_LONG(Z_REFCOUNT(*variable));
185}
186/* }}} */
187/* {{{ proto bool xcache_get_isref(mixed variable)
188   XCache internal uses only: Check if variable data is marked referenced */
189#ifdef ZEND_BEGIN_ARG_INFO_EX
190ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
191    ZEND_ARG_INFO(1, variable)
192ZEND_END_ARG_INFO()
193#else
194static unsigned char arginfo_xcache_get_isref[] = { 1, BYREF_FORCE };
195#endif
196
197PHP_FUNCTION(xcache_get_isref)
198{
199    zval *variable;
200    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
201        RETURN_NULL();
202    }
203
204    RETURN_BOOL(Z_ISREF(*variable) && Z_REFCOUNT(*variable) >= 3);
205}
206/* }}} */
207#ifdef HAVE_XCACHE_DPRINT
208/* {{{ proto bool  xcache_dprint(mixed value)
209   Prints variable (or value) internal struct (debug only) */
210PHP_FUNCTION(xcache_dprint)
211{
212    zval *value;
213
214    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
215        return;
216    }
217    xc_dprint_zval(value, 0 TSRMLS_CC);
218}
219/* }}} */
220#endif
221/* {{{ proto string xcache_asm(string filename)
222 */
223#ifdef HAVE_XCACHE_ASSEMBLER
224PHP_FUNCTION(xcache_asm)
225{
226}
227#endif
228/* }}} */
229/* {{{ proto string xcache_encode(string filename)
230   Encode php file into XCache opcode encoded format */
231#ifdef HAVE_XCACHE_ENCODER
232PHP_FUNCTION(xcache_encode)
233{
234}
235#endif
236/* }}} */
237/* {{{ proto bool xcache_decode_file(string filename)
238   Decode(load) opcode from XCache encoded format file */
239#ifdef HAVE_XCACHE_DECODER
240PHP_FUNCTION(xcache_decode_file)
241{
242}
243#endif
244/* }}} */
245/* {{{ proto bool xcache_decode_string(string data)
246   Decode(load) opcode from XCache encoded format data */
247#ifdef HAVE_XCACHE_DECODER
248PHP_FUNCTION(xcache_decode_string)
249{
250}
251#endif
252/* }}} */
253/* {{{ xc_call_getter */
254typedef const char *(xc_name_getter_t)(zend_uchar type);
255static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
256{
257    long spec;
258    const char *name;
259
260    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
261        return;
262    }
263    if (spec >= 0 && spec < count) {
264        name = getter((zend_uchar) spec);
265        if (name) {
266            /* RETURN_STRING */
267            int len = (int) strlen(name);
268            return_value->value.str.len = len;
269            return_value->value.str.val = estrndup(name, len);
270            return_value->type = IS_STRING; 
271            return;
272        }
273    }
274    RETURN_NULL();
275}
276/* }}} */
277/* {{{ proto string xcache_get_op_type(int op_type) */
278PHP_FUNCTION(xcache_get_op_type)
279{
280    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
281}
282/* }}} */
283/* {{{ proto string xcache_get_data_type(int type) */
284PHP_FUNCTION(xcache_get_data_type)
285{
286    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
287}
288/* }}} */
289/* {{{ proto string xcache_get_opcode(int opcode) */
290PHP_FUNCTION(xcache_get_opcode)
291{
292    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
293}
294/* }}} */
295/* {{{ proto string xcache_get_op_spec(int op_type) */
296PHP_FUNCTION(xcache_get_op_spec)
297{
298    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
299}
300/* }}} */
301/* {{{ proto string xcache_get_opcode_spec(int opcode) */
302PHP_FUNCTION(xcache_get_opcode_spec)
303{
304    long spec;
305    const xc_opcode_spec_t *opspec;
306
307    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
308        return;
309    }
310    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
311        opspec = xc_get_opcode_spec((zend_uchar) spec);
312        if (opspec) {
313            array_init(return_value);
314            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
315            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
316            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
317            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
318            return;
319        }
320    }
321    RETURN_NULL();
322}
323/* }}} */
324/* {{{ proto mixed xcache_get_special_value(zval value)
325   XCache internal use only: For decompiler to get static value with type fixed */
326PHP_FUNCTION(xcache_get_special_value)
327{
328    zval *value;
329
330    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
331        return;
332    }
333
334    switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
335    case IS_CONSTANT:
336        *return_value = *value;
337        zval_copy_ctor(return_value);
338        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
339        break;
340
341    case IS_CONSTANT_ARRAY:
342        *return_value = *value;
343        zval_copy_ctor(return_value);
344        return_value->type = IS_ARRAY;
345        break;
346
347    default:
348        RETURN_NULL();
349    }
350}
351/* }}} */
352/* {{{ proto int xcache_get_type(zval value)
353   XCache internal use only for disassembler to get variable type in engine level */
354PHP_FUNCTION(xcache_get_type)
355{
356    zval *value;
357
358    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
359        return;
360    }
361
362    RETURN_LONG(Z_TYPE_P(value));
363}
364/* }}} */
365/* {{{ proto string xcache_coredump(int op_type) */
366PHP_FUNCTION(xcache_coredump)
367{
368    if (xc_test) {
369        char *null_ptr = NULL;
370        *null_ptr = 0;
371        raise(SIGSEGV);
372    }
373    else {
374        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
375    }
376}
377/* }}} */
378/* {{{ proto string xcache_is_autoglobal(string name) */
379PHP_FUNCTION(xcache_is_autoglobal)
380{
381    zval *name;
382
383    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
384        return;
385    }
386
387#ifdef IS_UNICODE
388    convert_to_unicode(name);
389#else
390    convert_to_string(name);
391#endif
392
393    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
394}
395/* }}} */
396static zend_function_entry xcache_functions[] = /* {{{ */
397{
398    PHP_FE(xcache_coredump,          NULL)
399#ifdef HAVE_XCACHE_ASSEMBLER
400    PHP_FE(xcache_asm,               NULL)
401#endif
402#ifdef HAVE_XCACHE_ENCODER
403    PHP_FE(xcache_encode,            NULL)
404#endif
405#ifdef HAVE_XCACHE_DECODER
406    PHP_FE(xcache_decode_file,       NULL)
407    PHP_FE(xcache_decode_string,     NULL)
408#endif
409    PHP_FE(xcache_get_special_value, NULL)
410    PHP_FE(xcache_get_type,          NULL)
411    PHP_FE(xcache_get_op_type,       NULL)
412    PHP_FE(xcache_get_data_type,     NULL)
413    PHP_FE(xcache_get_opcode,        NULL)
414    PHP_FE(xcache_get_opcode_spec,   NULL)
415    PHP_FE(xcache_is_autoglobal,     NULL)
416    PHP_FE(xcache_get_refcount,      NULL)
417    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
418#ifdef HAVE_XCACHE_DPRINT
419    PHP_FE(xcache_dprint,            NULL)
420#endif
421    PHP_FE_END
422};
423/* }}} */
424
425#ifdef ZEND_WIN32
426#include "dbghelp.h"
427typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
428        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
429        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
430        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
431        );
432
433static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
434static HMODULE dbghelpModule = NULL;
435static char crash_dumpPath[_MAX_PATH] = { 0 };
436static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
437
438static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
439{
440    HANDLE fileHandle;
441    LONG ret = EXCEPTION_CONTINUE_SEARCH;
442
443    SetUnhandledExceptionFilter(oldFilter);
444
445    /* create the file */
446    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
447
448    if (fileHandle != INVALID_HANDLE_VALUE) {
449        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
450        MINIDUMP_TYPE type = xc_coredump_type ? xc_coredump_type : (MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory);
451        BOOL ok;
452
453        exceptionInformation.ThreadId = GetCurrentThreadId();
454        exceptionInformation.ExceptionPointers = pExceptionInfo;
455        exceptionInformation.ClientPointers = FALSE;
456
457        /* write the dump */
458        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, type, &exceptionInformation, NULL, NULL);
459        CloseHandle(fileHandle);
460        if (ok) {
461            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
462            ret = EXCEPTION_EXECUTE_HANDLER;
463        }
464        else {
465            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
466        }
467    }
468    else {
469        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
470    }
471
472    if (xc_disable_on_crash) {
473        xc_disable_on_crash = 0;
474        xc_cacher_disable();
475    }
476
477    return ret;
478}
479/* }}} */
480
481static void xcache_restore_crash_handler() /* {{{ */
482{
483    if (oldFilter) {
484        SetUnhandledExceptionFilter(oldFilter);
485        oldFilter = NULL;
486    }
487}
488/* }}} */
489static void xcache_init_crash_handler() /* {{{ */
490{
491    /* firstly see if dbghelp.dll is around and has the function we need
492       look next to the EXE first, as the one in System32 might be old
493       (e.g. Windows 2000) */
494    char dbghelpPath[_MAX_PATH];
495
496    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
497        char *slash = strchr(dbghelpPath, '\\');
498        if (slash) {
499            strcpy(slash + 1, "DBGHELP.DLL");
500            dbghelpModule = LoadLibrary(dbghelpPath);
501        }
502    }
503
504    if (!dbghelpModule) {
505        /* load any version we can */
506        dbghelpModule = LoadLibrary("DBGHELP.DLL");
507        if (!dbghelpModule) {
508            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
509            return;
510        }
511    }
512
513    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
514    if (!dbghelp_MiniDumpWriteDump) {
515        zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL too old. Get updated dll and put it aside of php_xcache.dll");
516        return;
517    }
518
519#ifdef XCACHE_VERSION_REVISION
520#define REVISION "r" XCACHE_VERSION_REVISION
521#else
522#define REVISION ""
523#endif
524    sprintf(crash_dumpPath, "%s\\php-%s-xcache-%s%s-%lu-%lu.dmp", xc_coredump_dir, zend_get_module_version("standard"), XCACHE_VERSION, REVISION, (unsigned long) time(NULL), (unsigned long) GetCurrentProcessId());
525#undef REVISION
526
527    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
528}
529/* }}} */
530#else
531/* old signal handlers {{{ */
532typedef void (*xc_sighandler_t)(int);
533#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
534#include "util/xc_foreachcoresig.h"
535#undef FOREACH_SIG
536/* }}} */
537static void xcache_signal_handler(int sig);
538static void xcache_restore_crash_handler() /* {{{ */
539{
540#define FOREACH_SIG(sig) do { \
541    if (old_##sig##_handler != xcache_signal_handler) { \
542        signal(sig, old_##sig##_handler); \
543    } \
544    else { \
545        signal(sig, SIG_DFL); \
546    } \
547} while (0)
548#include "util/xc_foreachcoresig.h"
549#undef FOREACH_SIG
550}
551/* }}} */
552static void xcache_init_crash_handler() /* {{{ */
553{
554#define FOREACH_SIG(sig) \
555    old_##sig##_handler = signal(sig, xcache_signal_handler)
556#include "util/xc_foreachcoresig.h"
557#undef FOREACH_SIG
558}
559/* }}} */
560static void xcache_signal_handler(int sig) /* {{{ */
561{
562    xcache_restore_crash_handler();
563    if (xc_coredump_dir && xc_coredump_dir[0]) {
564        if (chdir(xc_coredump_dir) != 0) {
565            /* error, but nothing can do about it
566             * and should'nt print anything which might SEGV again */
567        }
568    }
569    if (xc_disable_on_crash) {
570        xc_disable_on_crash = 0;
571        xc_cacher_disable();
572    }
573    raise(sig);
574}
575/* }}} */
576#endif
577
578/* {{{ incompatible zend extensions handling */
579typedef struct {
580    const char *name;
581    startup_func_t old_startup;
582} xc_incompatible_zend_extension_info_t;
583static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
584    { "Zend Extension Manager", NULL },
585    { "Zend Optimizer", NULL },
586    { "the ionCube PHP Loader", NULL }
587};
588
589static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
590{
591    size_t i;
592
593    for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
594        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
595        if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
596            return incompatible_zend_extension_info;
597        }
598    }
599
600    return NULL;
601}
602/* }}} */
603static void xc_zend_llist_add_element(zend_llist *list, zend_llist_element *element) /* {{{ */
604{
605    if (!zend_extensions.head) {
606        zend_extensions.head = zend_extensions.tail = element;
607    }
608    else {
609        zend_extensions.tail->next = element;
610        element->prev = zend_extensions.tail;
611        zend_extensions.tail = element;
612    }
613}
614/* }}} */
615static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
616{
617    xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
618    int status;
619    zend_bool catched = 0;
620    zend_llist saved_zend_extensions_container; /* without elements */
621    zend_llist_element **saved_zend_extensions_elments;
622    size_t new_zend_extensions_elments_count;
623    zend_llist_element **new_zend_extensions_elments;
624    zend_extension *ext;
625    size_t i;
626    zend_llist_element *element;
627    TSRMLS_FETCH();
628
629    /* restore startup hack */
630    extension->startup = incompatible_zend_extension_info->old_startup;
631    incompatible_zend_extension_info->old_startup = NULL;
632    assert(extension->startup);
633
634    /* save extensions list */
635    saved_zend_extensions_container = zend_extensions;
636    saved_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * saved_zend_extensions_container.count);
637    for (i = 0, element = saved_zend_extensions_container.head; element; ++i, element = element->next) {
638        saved_zend_extensions_elments[i] = element;
639    }
640
641    /* hide all XCache extensions from it */
642    zend_extensions.head = NULL;
643    zend_extensions.tail = NULL;
644    zend_extensions.count = 0;
645
646    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
647        element = saved_zend_extensions_elments[i];
648        element->next = element->prev = NULL;
649
650        ext = (zend_extension *) element->data;
651
652        if (!(strcmp(ext->name, XCACHE_NAME) == 0 || strncmp(ext->name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0)) {
653            xc_zend_llist_add_element(&zend_extensions, element);
654            ++zend_extensions.count;
655        }
656    }
657
658    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
659    zend_try {
660        status = extension->startup(extension);
661    } zend_catch {
662        catched = 1;
663    } zend_end_try();
664
665    /* save newly added extensions added by this extension*/
666    new_zend_extensions_elments_count = zend_extensions.count - 1;
667    new_zend_extensions_elments = NULL;
668    if (new_zend_extensions_elments_count) {
669        new_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * new_zend_extensions_elments_count);
670        element = zend_extensions.head;
671        for (i = 0, element = element->next; element; ++i, element = element->next) {
672            new_zend_extensions_elments[i] = element;
673        }
674    }
675
676    /* restore original extension list*/
677    zend_extensions = saved_zend_extensions_container;
678    zend_extensions.head = NULL;
679    zend_extensions.tail = NULL;
680    zend_extensions.count = 0;
681    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
682        element = saved_zend_extensions_elments[i];
683        element->next = element->prev = NULL;
684
685        xc_zend_llist_add_element(&zend_extensions, element);
686        ++zend_extensions.count;
687
688        ext = (zend_extension *) element->data;
689        if (ext == extension && new_zend_extensions_elments_count) {
690            /* add new created extension */
691            size_t j;
692            for (j = 0; j < new_zend_extensions_elments_count; ++j) {
693                element = new_zend_extensions_elments[j];
694                element->next = element->prev = NULL;
695
696                xc_zend_llist_add_element(&zend_extensions, element);
697                ++zend_extensions.count;
698            }
699        }
700    }
701    free(saved_zend_extensions_elments);
702    if (new_zend_extensions_elments) {
703        free(new_zend_extensions_elments);
704    }
705
706    if (catched) {
707        zend_bailout();
708    }
709    return status;
710}
711/* }}} */
712static int xc_zend_startup(zend_extension *extension) /* {{{ */
713{
714    zend_llist_position lpos;
715    zend_extension *ext;
716
717    ext = (zend_extension *) zend_extensions.head->data;
718    if (strcmp(ext->name, XCACHE_NAME) != 0) {
719        zend_error(E_WARNING, "XCache failed to load itself as the before \"%s\". compatibility downgraded", ext->name);
720    }
721
722    old_compile_file = zend_compile_file;
723    zend_compile_file = xc_check_initial_compile_file;
724
725    for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
726            ext;
727            ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
728        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
729        if (incompatible_zend_extension_info) {
730            assert(!incompatible_zend_extension_info->old_startup);
731            incompatible_zend_extension_info->old_startup = ext->startup;
732            ext->startup = xc_incompatible_zend_extension_startup_hook;
733        }
734    }
735    return SUCCESS;
736}
737/* }}} */
738static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
739{
740}
741/* }}} */
742/* {{{ zend extension definition structure */
743static zend_extension xc_zend_extension_entry = {
744    XCACHE_NAME,
745    XCACHE_VERSION,
746    XCACHE_AUTHOR,
747    XCACHE_URL,
748    XCACHE_COPYRIGHT,
749    xc_zend_startup,
750    xc_zend_shutdown,
751    NULL,           /* activate_func_t */
752    NULL,           /* deactivate_func_t */
753    NULL,           /* message_handler_func_t */
754    NULL,           /* op_array_handler_func_t */
755    NULL,           /* statement_handler_func_t */
756    NULL,           /* fcall_begin_handler_func_t */
757    NULL,           /* fcall_end_handler_func_t */
758    NULL,           /* op_array_ctor_func_t */
759    NULL,           /* op_array_dtor_func_t */
760    STANDARD_ZEND_EXTENSION_PROPERTIES
761};
762/* }}} */
763
764/* {{{ PHP_INI */
765PHP_INI_BEGIN()
766    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
767#ifdef ZEND_WIN32
768    PHP_INI_ENTRY1     ("xcache.coredump_type",          "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_coredump_type)
769#endif
770    PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
771    PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
772    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
773PHP_INI_END()
774/* }}} */
775static PHP_MINFO_FUNCTION(xcache) /* {{{ */
776{
777    php_info_print_table_start();
778    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
779#ifdef XCACHE_VERSION_REVISION
780    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
781#endif
782    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
783    php_info_print_table_end();
784
785    DISPLAY_INI_ENTRIES();
786}
787/* }}} */
788static PHP_MINIT_FUNCTION(xcache) /* {{{ */
789{
790#ifndef PHP_GINIT
791    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
792#endif
793    REGISTER_INI_ENTRIES();
794
795    if (xc_coredump_dir && xc_coredump_dir[0]) {
796        xcache_init_crash_handler();
797    }
798
799    if (strcmp(sapi_module.name, "cli") == 0) {
800        char *env;
801        if ((env = getenv("XCACHE_TEST")) != NULL) {
802            xc_test = (zend_bool) atoi(env);
803        }
804    }
805
806    xc_init_constant(module_number TSRMLS_CC);
807    xc_shm_init_modules();
808
809    /* must be the first */
810    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
811#ifdef HAVE_XCACHE_OPTIMIZER
812#   ifndef ZEND_ENGINE_2_5
813    xc_optimizer_startup_module();
814#   endif
815#endif
816#ifdef HAVE_XCACHE_CACHER
817    xc_cacher_startup_module();
818#endif
819#ifdef HAVE_XCACHE_COVERAGER
820    xc_coverager_startup_module();
821#endif
822#ifdef HAVE_XCACHE_DISASSEMBLER
823    xc_disassembler_startup_module();
824#endif
825
826    return SUCCESS;
827}
828/* }}} */
829static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
830{
831    if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
832        zend_compile_file = old_compile_file;
833        old_compile_file = NULL;
834    }
835
836    if (xc_coredump_dir && xc_coredump_dir[0]) {
837        xcache_restore_crash_handler();
838    }
839    if (xc_coredump_dir) {
840        pefree(xc_coredump_dir, 1);
841        xc_coredump_dir = NULL;
842    }
843#ifndef PHP_GINIT
844#   ifdef ZTS
845    ts_free_id(xcache_globals_id);
846#   else
847    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
848#   endif
849#endif
850
851    UNREGISTER_INI_ENTRIES();
852    xcache_zend_extension_remove(&xc_zend_extension_entry);
853    return SUCCESS;
854}
855/* }}} */
856/* {{{ module dependencies */
857#ifdef STANDARD_MODULE_HEADER_EX
858static zend_module_dep xcache_module_deps[] = {
859    ZEND_MOD_REQUIRED("standard")
860    ZEND_MOD_CONFLICTS("apc")
861    ZEND_MOD_CONFLICTS("eAccelerator")
862    ZEND_MOD_CONFLICTS("Turck MMCache")
863    ZEND_MOD_END
864};
865#endif
866/* }}} */ 
867/* {{{ module definition structure */
868zend_module_entry xcache_module_entry = {
869#ifdef STANDARD_MODULE_HEADER_EX
870    STANDARD_MODULE_HEADER_EX,
871    NULL,
872    xcache_module_deps,
873#else
874    STANDARD_MODULE_HEADER,
875#endif
876    XCACHE_NAME,
877    xcache_functions,
878    PHP_MINIT(xcache),
879    PHP_MSHUTDOWN(xcache),
880    NULL, /* RINIT */
881    NULL, /* RSHUTDOWN */
882    PHP_MINFO(xcache),
883    XCACHE_VERSION,
884#ifdef PHP_GINIT
885    PHP_MODULE_GLOBALS(xcache),
886    PHP_GINIT(xcache),
887    PHP_GSHUTDOWN(xcache),
888#endif
889#ifdef ZEND_ENGINE_2
890    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
891#else
892    NULL,
893    NULL,
894#endif
895    STANDARD_MODULE_PROPERTIES_EX
896};
897
898#ifdef COMPILE_DL_XCACHE
899ZEND_GET_MODULE(xcache)
900#endif
901/* }}} */
Note: See TracBrowser for help on using the repository browser.