source: branches/3.0/xcache.c @ 1209

Last change on this file since 1209 was 1201, checked in by moo, 20 months ago

fix some 64bit warnings

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