source: trunk/xcache.c @ 1346

Last change on this file since 1346 was 1346, checked in by moo, 12 months ago

fixed #320: void warning for gcc only pragma

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