source: branches/3.1/xcache.c @ 1436

Last change on this file since 1436 was 1436, checked in by moo, 5 months ago

branch 3.1

  • Property svn:eol-style set to native
File size: 25.4 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        if ((Z_TYPE_P(value) & ~IS_CONSTANT_TYPE_MASK)) {
354            *return_value = *value;
355            zval_copy_ctor(return_value);
356            return_value->type &= IS_CONSTANT_TYPE_MASK;
357        }
358        else {
359            RETURN_NULL();
360        }
361    }
362}
363/* }}} */
364/* {{{ proto int xcache_get_type(zval value)
365   XCache internal use only for disassembler to get variable type in engine level */
366PHP_FUNCTION(xcache_get_type)
367{
368    zval *value;
369
370    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
371        return;
372    }
373
374    RETURN_LONG(Z_TYPE_P(value));
375}
376/* }}} */
377/* {{{ proto string xcache_coredump(int op_type) */
378PHP_FUNCTION(xcache_coredump)
379{
380    if (xc_test) {
381        char *null_ptr = NULL;
382        *null_ptr = 0;
383        raise(SIGSEGV);
384    }
385    else {
386        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
387    }
388}
389/* }}} */
390/* {{{ proto string xcache_is_autoglobal(string name) */
391PHP_FUNCTION(xcache_is_autoglobal)
392{
393    zval *name;
394
395    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
396        return;
397    }
398
399#ifdef IS_UNICODE
400    convert_to_unicode(name);
401#else
402    convert_to_string(name);
403#endif
404
405    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
406}
407/* }}} */
408static zend_function_entry xcache_functions[] = /* {{{ */
409{
410    PHP_FE(xcache_coredump,          NULL)
411#ifdef HAVE_XCACHE_ASSEMBLER
412    PHP_FE(xcache_asm,               NULL)
413#endif
414#ifdef HAVE_XCACHE_ENCODER
415    PHP_FE(xcache_encode,            NULL)
416#endif
417#ifdef HAVE_XCACHE_DECODER
418    PHP_FE(xcache_decode_file,       NULL)
419    PHP_FE(xcache_decode_string,     NULL)
420#endif
421    PHP_FE(xcache_get_special_value, NULL)
422    PHP_FE(xcache_get_type,          NULL)
423    PHP_FE(xcache_get_op_type,       NULL)
424    PHP_FE(xcache_get_data_type,     NULL)
425    PHP_FE(xcache_get_opcode,        NULL)
426    PHP_FE(xcache_get_opcode_spec,   NULL)
427    PHP_FE(xcache_is_autoglobal,     NULL)
428    PHP_FE(xcache_get_refcount,      NULL)
429    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
430#ifdef HAVE_XCACHE_DPRINT
431    PHP_FE(xcache_dprint,            NULL)
432#endif
433    PHP_FE_END
434};
435/* }}} */
436
437#ifdef ZEND_WIN32
438#include "dbghelp.h"
439typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
440        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
441        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
442        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
443        );
444
445static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
446static HMODULE dbghelpModule = NULL;
447static char crash_dumpPath[_MAX_PATH] = { 0 };
448static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
449
450static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
451{
452    HANDLE fileHandle;
453    LONG ret = EXCEPTION_CONTINUE_SEARCH;
454
455    SetUnhandledExceptionFilter(oldFilter);
456
457    /* create the file */
458    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
459
460    if (fileHandle != INVALID_HANDLE_VALUE) {
461        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
462        MINIDUMP_TYPE type = xc_coredump_type ? xc_coredump_type : (MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory);
463        BOOL ok;
464
465        exceptionInformation.ThreadId = GetCurrentThreadId();
466        exceptionInformation.ExceptionPointers = pExceptionInfo;
467        exceptionInformation.ClientPointers = FALSE;
468
469        /* write the dump */
470        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, type, &exceptionInformation, NULL, NULL);
471        CloseHandle(fileHandle);
472        if (ok) {
473            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
474            ret = EXCEPTION_EXECUTE_HANDLER;
475        }
476        else {
477            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
478        }
479    }
480    else {
481        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
482    }
483
484    if (xc_disable_on_crash) {
485        xc_disable_on_crash = 0;
486        xc_cacher_disable();
487    }
488
489    return ret;
490}
491/* }}} */
492
493static void xcache_restore_crash_handler() /* {{{ */
494{
495    if (oldFilter) {
496        SetUnhandledExceptionFilter(oldFilter);
497        oldFilter = NULL;
498    }
499}
500/* }}} */
501static void xcache_init_crash_handler() /* {{{ */
502{
503    /* firstly see if dbghelp.dll is around and has the function we need
504       look next to the EXE first, as the one in System32 might be old
505       (e.g. Windows 2000) */
506    char dbghelpPath[_MAX_PATH];
507
508    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
509        char *slash = strchr(dbghelpPath, '\\');
510        if (slash) {
511            strcpy(slash + 1, "DBGHELP.DLL");
512            dbghelpModule = LoadLibrary(dbghelpPath);
513        }
514    }
515
516    if (!dbghelpModule) {
517        /* load any version we can */
518        dbghelpModule = LoadLibrary("DBGHELP.DLL");
519        if (!dbghelpModule) {
520            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
521            return;
522        }
523    }
524
525    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
526    if (!dbghelp_MiniDumpWriteDump) {
527        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");
528        return;
529    }
530
531#ifdef XCACHE_VERSION_REVISION
532#define REVISION "r" XCACHE_VERSION_REVISION
533#else
534#define REVISION ""
535#endif
536    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());
537#undef REVISION
538
539    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
540}
541/* }}} */
542#else
543/* old signal handlers {{{ */
544typedef void (*xc_sighandler_t)(int);
545#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
546#include "util/xc_foreachcoresig.h"
547#undef FOREACH_SIG
548/* }}} */
549static void xcache_signal_handler(int sig);
550static void xcache_restore_crash_handler() /* {{{ */
551{
552#define FOREACH_SIG(sig) do { \
553    if (old_##sig##_handler != xcache_signal_handler) { \
554        signal(sig, old_##sig##_handler); \
555    } \
556    else { \
557        signal(sig, SIG_DFL); \
558    } \
559} while (0)
560#include "util/xc_foreachcoresig.h"
561#undef FOREACH_SIG
562}
563/* }}} */
564static void xcache_init_crash_handler() /* {{{ */
565{
566#define FOREACH_SIG(sig) \
567    old_##sig##_handler = signal(sig, xcache_signal_handler)
568#include "util/xc_foreachcoresig.h"
569#undef FOREACH_SIG
570}
571/* }}} */
572static void xcache_signal_handler(int sig) /* {{{ */
573{
574    xcache_restore_crash_handler();
575    if (xc_coredump_dir && xc_coredump_dir[0]) {
576        if (chdir(xc_coredump_dir) != 0) {
577            /* error, but nothing can do about it
578             * and should'nt print anything which might SEGV again */
579        }
580    }
581    if (xc_disable_on_crash) {
582        xc_disable_on_crash = 0;
583        xc_cacher_disable();
584    }
585    raise(sig);
586}
587/* }}} */
588#endif
589
590/* {{{ incompatible zend extensions handling */
591typedef struct {
592    const char *name;
593    startup_func_t old_startup;
594} xc_incompatible_zend_extension_info_t;
595static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
596    { "Zend Extension Manager", NULL },
597    { "Zend Optimizer", NULL },
598    { "the ionCube PHP Loader", NULL }
599};
600
601static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
602{
603    size_t i;
604
605    for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
606        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
607        if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
608            return incompatible_zend_extension_info;
609        }
610    }
611
612    return NULL;
613}
614/* }}} */
615static void xc_zend_llist_add_element(zend_llist *list, zend_llist_element *element) /* {{{ */
616{
617    if (!zend_extensions.head) {
618        zend_extensions.head = zend_extensions.tail = element;
619    }
620    else {
621        zend_extensions.tail->next = element;
622        element->prev = zend_extensions.tail;
623        zend_extensions.tail = element;
624    }
625}
626/* }}} */
627static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
628{
629    xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
630    int status;
631    zend_bool catched = 0;
632    zend_llist saved_zend_extensions_container; /* without elements */
633    zend_llist_element **saved_zend_extensions_elments;
634    size_t new_zend_extensions_elments_count;
635    zend_llist_element **new_zend_extensions_elments;
636    zend_extension *ext;
637    size_t i;
638    zend_llist_element *element;
639    TSRMLS_FETCH();
640
641    /* restore startup hack */
642    extension->startup = incompatible_zend_extension_info->old_startup;
643    incompatible_zend_extension_info->old_startup = NULL;
644    assert(extension->startup);
645
646    /* save extensions list */
647    saved_zend_extensions_container = zend_extensions;
648    saved_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * saved_zend_extensions_container.count);
649    for (i = 0, element = saved_zend_extensions_container.head; element; ++i, element = element->next) {
650        saved_zend_extensions_elments[i] = element;
651    }
652
653    /* hide all XCache extensions from it */
654    zend_extensions.head = NULL;
655    zend_extensions.tail = NULL;
656    zend_extensions.count = 0;
657
658    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
659        element = saved_zend_extensions_elments[i];
660        element->next = element->prev = NULL;
661
662        ext = (zend_extension *) element->data;
663
664        if (!(strcmp(ext->name, XCACHE_NAME) == 0 || strncmp(ext->name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0)) {
665            xc_zend_llist_add_element(&zend_extensions, element);
666            ++zend_extensions.count;
667        }
668    }
669
670    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
671    zend_try {
672        status = extension->startup(extension);
673    } zend_catch {
674        catched = 1;
675    } zend_end_try();
676
677    /* save newly added extensions added by this extension*/
678    new_zend_extensions_elments_count = zend_extensions.count - 1;
679    new_zend_extensions_elments = NULL;
680    if (new_zend_extensions_elments_count) {
681        new_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * new_zend_extensions_elments_count);
682        element = zend_extensions.head;
683        for (i = 0, element = element->next; element; ++i, element = element->next) {
684            new_zend_extensions_elments[i] = element;
685        }
686    }
687
688    /* restore original extension list*/
689    zend_extensions = saved_zend_extensions_container;
690    zend_extensions.head = NULL;
691    zend_extensions.tail = NULL;
692    zend_extensions.count = 0;
693    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
694        element = saved_zend_extensions_elments[i];
695        element->next = element->prev = NULL;
696
697        xc_zend_llist_add_element(&zend_extensions, element);
698        ++zend_extensions.count;
699
700        ext = (zend_extension *) element->data;
701        if (ext == extension && new_zend_extensions_elments_count) {
702            /* add new created extension */
703            size_t j;
704            for (j = 0; j < new_zend_extensions_elments_count; ++j) {
705                element = new_zend_extensions_elments[j];
706                element->next = element->prev = NULL;
707
708                xc_zend_llist_add_element(&zend_extensions, element);
709                ++zend_extensions.count;
710            }
711        }
712    }
713    free(saved_zend_extensions_elments);
714    if (new_zend_extensions_elments) {
715        free(new_zend_extensions_elments);
716    }
717
718    if (catched) {
719        zend_bailout();
720    }
721    return status;
722}
723/* }}} */
724static int xc_zend_startup(zend_extension *extension) /* {{{ */
725{
726    zend_llist_position lpos;
727    zend_extension *ext;
728
729    ext = (zend_extension *) zend_extensions.head->data;
730    if (strcmp(ext->name, XCACHE_NAME) != 0) {
731        zend_error(E_WARNING, "XCache failed to load itself to before zend_extension=\"%s\". compatibility downgraded", ext->name);
732    }
733
734    for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
735            ext;
736            ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
737        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
738        if (incompatible_zend_extension_info) {
739            assert(!incompatible_zend_extension_info->old_startup);
740            incompatible_zend_extension_info->old_startup = ext->startup;
741            ext->startup = xc_incompatible_zend_extension_startup_hook;
742        }
743    }
744    return SUCCESS;
745}
746/* }}} */
747static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
748{
749}
750/* }}} */
751/* {{{ zend extension definition structure */
752static zend_extension xc_zend_extension_entry = {
753    XCACHE_NAME,
754    XCACHE_VERSION,
755    XCACHE_AUTHOR,
756    XCACHE_URL,
757    XCACHE_COPYRIGHT,
758    xc_zend_startup,
759    xc_zend_shutdown,
760    NULL,           /* activate_func_t */
761    NULL,           /* deactivate_func_t */
762    NULL,           /* message_handler_func_t */
763    NULL,           /* op_array_handler_func_t */
764    NULL,           /* statement_handler_func_t */
765    NULL,           /* fcall_begin_handler_func_t */
766    NULL,           /* fcall_end_handler_func_t */
767    NULL,           /* op_array_ctor_func_t */
768    NULL,           /* op_array_dtor_func_t */
769    STANDARD_ZEND_EXTENSION_PROPERTIES
770};
771/* }}} */
772
773/* {{{ PHP_INI */
774PHP_INI_BEGIN()
775    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
776#ifdef ZEND_WIN32
777    PHP_INI_ENTRY1     ("xcache.coredump_type",          "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_coredump_type)
778#endif
779    PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
780    PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
781    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
782PHP_INI_END()
783/* }}} */
784static PHP_MINFO_FUNCTION(xcache) /* {{{ */
785{
786    php_info_print_table_start();
787    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
788#ifdef XCACHE_VERSION_REVISION
789    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
790#endif
791    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
792    php_info_print_table_end();
793
794    DISPLAY_INI_ENTRIES();
795}
796/* }}} */
797static PHP_MINIT_FUNCTION(xcache) /* {{{ */
798{
799#ifndef PHP_GINIT
800    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
801#endif
802    REGISTER_INI_ENTRIES();
803
804    if (xc_coredump_dir && xc_coredump_dir[0]) {
805        xcache_init_crash_handler();
806    }
807
808    if (strcmp(sapi_module.name, "cli") == 0) {
809        char *env;
810        if ((env = getenv("XCACHE_TEST")) != NULL) {
811            xc_test = (zend_bool) atoi(env);
812        }
813    }
814
815    xc_init_constant(module_number TSRMLS_CC);
816    xc_shm_init_modules();
817
818    /* must be the first */
819    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
820    old_compile_file = zend_compile_file;
821    zend_compile_file = xc_check_initial_compile_file;
822
823#ifdef HAVE_XCACHE_OPTIMIZER
824    xc_optimizer_startup_module();
825#endif
826#ifdef HAVE_XCACHE_CACHER
827    xc_cacher_startup_module();
828#endif
829#ifdef HAVE_XCACHE_COVERAGER
830    xc_coverager_startup_module();
831#endif
832#ifdef HAVE_XCACHE_DISASSEMBLER
833    xc_disassembler_startup_module();
834#endif
835
836    return SUCCESS;
837}
838/* }}} */
839static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
840{
841    if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
842        zend_compile_file = old_compile_file;
843        old_compile_file = NULL;
844    }
845
846    if (xc_coredump_dir && xc_coredump_dir[0]) {
847        xcache_restore_crash_handler();
848    }
849    if (xc_coredump_dir) {
850        pefree(xc_coredump_dir, 1);
851        xc_coredump_dir = NULL;
852    }
853#ifndef PHP_GINIT
854#   ifdef ZTS
855    ts_free_id(xcache_globals_id);
856#   else
857    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
858#   endif
859#endif
860
861    UNREGISTER_INI_ENTRIES();
862    xcache_zend_extension_remove(&xc_zend_extension_entry);
863    return SUCCESS;
864}
865/* }}} */
866/* {{{ module dependencies */
867#ifdef STANDARD_MODULE_HEADER_EX
868static zend_module_dep xcache_module_deps[] = {
869    ZEND_MOD_REQUIRED("standard")
870    ZEND_MOD_CONFLICTS("apc")
871    ZEND_MOD_CONFLICTS("eAccelerator")
872    ZEND_MOD_CONFLICTS("Turck MMCache")
873    ZEND_MOD_END
874};
875#endif
876/* }}} */ 
877/* {{{ module definition structure */
878zend_module_entry xcache_module_entry = {
879#ifdef STANDARD_MODULE_HEADER_EX
880    STANDARD_MODULE_HEADER_EX,
881    NULL,
882    xcache_module_deps,
883#else
884    STANDARD_MODULE_HEADER,
885#endif
886    XCACHE_NAME,
887    xcache_functions,
888    PHP_MINIT(xcache),
889    PHP_MSHUTDOWN(xcache),
890    NULL, /* RINIT */
891    NULL, /* RSHUTDOWN */
892    PHP_MINFO(xcache),
893    XCACHE_VERSION,
894#ifdef PHP_GINIT
895    PHP_MODULE_GLOBALS(xcache),
896    PHP_GINIT(xcache),
897    PHP_GSHUTDOWN(xcache),
898#endif
899#ifdef ZEND_ENGINE_2
900    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
901#else
902    NULL,
903    NULL,
904#endif
905    STANDARD_MODULE_PROPERTIES_EX
906};
907
908#ifdef COMPILE_DL_XCACHE
909ZEND_GET_MODULE(xcache)
910#endif
911/* }}} */
Note: See TracBrowser for help on using the repository browser.