source: trunk/mod_coverager/xc_coverager.c

Last change on this file was 1538, checked in by moo, 3 weeks ago

kill warning

  • Property svn:eol-style set to native
File size: 18.0 KB
Line 
1#include "xc_coverager.h"
2
3#include <stdio.h>
4#include "xcache.h"
5#include "ext/standard/flock_compat.h"
6#ifdef HAVE_SYS_FILE_H
7#   include <sys/file.h>
8#endif
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <fcntl.h>
12
13#include "xcache/xc_extension.h"
14#include "xcache/xc_ini.h"
15#include "xcache/xc_utils.h"
16#include "util/xc_stack.h"
17#include "util/xc_trace.h"
18#include "xcache_globals.h"
19
20#include "ext/standard/info.h"
21#include "zend_compile.h"
22
23typedef HashTable *coverager_t;
24#define PCOV_HEADER_MAGIC 0x564f4350
25
26static char *xc_coveragedump_dir = NULL;
27static zend_compile_file_t *old_compile_file = NULL;
28
29/* dumper */
30static void xc_destroy_coverage(void *pDest) /* {{{ */
31{
32    coverager_t cov = *(coverager_t*) pDest;
33    TRACE("destroy %p", (void *) cov);
34    zend_hash_destroy(cov);
35    efree(cov);
36}
37/* }}} */
38static void xcache_mkdirs_ex(char *root, long rootlen, char *path, long pathlen TSRMLS_DC) /* {{{ */
39{
40    char *fullpath;
41    struct stat st;
42    ALLOCA_FLAG(use_heap)
43
44    TRACE("mkdirs %s %ld %s %ld", root, rootlen, path, pathlen);
45    fullpath = xc_do_alloca(rootlen + pathlen + 1, use_heap);
46    memcpy(fullpath, root, rootlen);
47    memcpy(fullpath + rootlen, path, pathlen);
48    fullpath[rootlen + pathlen] = '\0';
49
50    if (stat(fullpath, &st) != 0) {
51        char *chr;
52
53        chr = strrchr(path, PHP_DIR_SEPARATOR);
54        if (chr && chr != path) {
55            *chr = '\0';
56            xcache_mkdirs_ex(root, rootlen, path, chr - path TSRMLS_CC);
57            *chr = PHP_DIR_SEPARATOR;
58        }
59        TRACE("mkdir %s", fullpath);
60#if PHP_MAJOR_VERSION > 5
61        php_stream_mkdir(fullpath, 0700, REPORT_ERRORS, NULL);
62#else
63        mkdir(fullpath, 0700);
64#endif
65    }
66    xc_free_alloca(fullpath, use_heap);
67}
68/* }}} */
69static void xc_coverager_save_cov(char *srcfile, char *outfilename, coverager_t cov TSRMLS_DC) /* {{{ */
70{
71    long *buf = NULL, *p;
72    long covlines, *phits;
73    int fd = -1;
74    size_t size;
75    int newfile;
76    struct stat srcstat, outstat;
77    HashPosition pos;
78    char *contents = NULL;
79    long len;
80
81    if (stat(srcfile, &srcstat) != 0) {
82        return;
83    }
84
85    newfile = 0;
86    if (stat(outfilename, &outstat) != 0) {
87        newfile = 1;
88    }
89    else {
90        if (srcstat.st_mtime > outstat.st_mtime) {
91            newfile = 1;
92        }
93    }
94
95    fd = open(outfilename, O_RDWR | O_CREAT, 0600);
96    if (fd < 0) {
97        char *chr;
98        chr = strrchr(srcfile, PHP_DIR_SEPARATOR);
99        if (chr) {
100            *chr = '\0';
101            xcache_mkdirs_ex(xc_coveragedump_dir, strlen(xc_coveragedump_dir), srcfile, chr - srcfile TSRMLS_CC);
102            *chr = PHP_DIR_SEPARATOR;
103        }
104        fd = open(outfilename, O_RDWR | O_CREAT, 0600);
105        if (fd < 0) {
106            goto bailout;
107        }
108    }
109    if (flock(fd, LOCK_EX) != SUCCESS) {
110        goto bailout;
111    }
112
113    if (newfile) {
114        TRACE("%s", "new file");
115    }
116    else if (outstat.st_size) {
117        len = outstat.st_size;
118        contents = emalloc(len);
119        if (read(fd, (void *) contents, len) != len) {
120            goto bailout;
121        }
122        TRACE("oldsize %d", (int) len);
123        do {
124            p = (long *) contents;
125            len -= sizeof(long);
126            if (len < 0) {
127                break;
128            }
129            if (*p++ != PCOV_HEADER_MAGIC) {
130                TRACE("wrong magic in file %s", outfilename);
131                break;
132            }
133
134            p += 2; /* skip covliens */
135            len -= sizeof(long) * 2;
136            if (len < 0) {
137                break;
138            }
139
140            for (; len >= (int) sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
141                if (zend_hash_index_find(cov, p[0], (void**)&phits) == SUCCESS) {
142                    if (p[1] == -1) {
143                        /* OPTIMIZE: already marked */
144                        continue;
145                    }
146                    if (*phits != -1) {
147                        p[1] += *phits;
148                    }
149                }
150                zend_hash_index_update(cov, p[0], &p[1], sizeof(p[1]), NULL);
151            }
152        } while (0);
153        efree(contents);
154        contents = NULL;
155    }
156
157
158    /* serialize */
159    size = (zend_hash_num_elements(cov) + 1) * sizeof(long) * 2 + sizeof(long);
160    p = buf = emalloc(size);
161    *p++ = PCOV_HEADER_MAGIC;
162    p += 2; /* for covlines */
163    covlines = 0;
164
165    zend_hash_internal_pointer_reset_ex(cov, &pos);
166    while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos) == SUCCESS) {
167        *p++ = pos->h;
168        *p++ = *phits;
169        if (*phits > 0) {
170            covlines ++;
171        }
172        zend_hash_move_forward_ex(cov, &pos);
173    }
174    p = buf + 1;
175    p[0] = 0;
176    p[1] = covlines;
177
178    if (ftruncate(fd, 0) != 0) {
179        goto bailout;
180    }
181    lseek(fd, 0, SEEK_SET);
182    if (write(fd, (char *) buf, size) != (ssize_t) size) {
183        goto bailout;
184    }
185
186bailout:
187    if (contents) efree(contents);
188    if (fd >= 0) close(fd);
189    if (buf) efree(buf);
190}
191/* }}} */
192
193static void xc_coverager_initenv(TSRMLS_D) /* {{{ */
194{
195    if (!XG(coverages)) {
196        XG(coverages) = emalloc(sizeof(HashTable));
197        zend_hash_init(XG(coverages), 0, NULL, xc_destroy_coverage, 0);
198    }
199}
200/* }}} */
201static void xc_coverager_clean(TSRMLS_D) /* {{{ */
202{
203    if (XG(coverages)) {
204        HashPosition pos;
205        coverager_t *pcov;
206
207        zend_hash_internal_pointer_reset_ex(XG(coverages), &pos);
208        while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) {
209            long *phits;
210            coverager_t cov;
211            HashPosition pos2;
212
213            cov = *pcov;
214
215            zend_hash_internal_pointer_reset_ex(cov, &pos2);
216            while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos2) == SUCCESS) {
217                long hits = *phits;
218
219                if (hits != -1) {
220                    hits = -1;
221                    zend_hash_index_update(cov, pos2->h, &hits, sizeof(hits), NULL);
222                }
223                zend_hash_move_forward_ex(cov, &pos2);
224            }
225
226            zend_hash_move_forward_ex(XG(coverages), &pos);
227        }
228    }
229}
230/* }}} */
231static void xc_coverager_cleanup(TSRMLS_D) /* {{{ */
232{
233    if (XG(coverages)) {
234        zend_hash_destroy(XG(coverages));
235        efree(XG(coverages));
236        XG(coverages) = NULL;
237    }
238}
239/* }}} */
240
241static void xc_coverager_start(TSRMLS_D) /* {{{ */
242{
243    XG(coverager_started) = 1;
244}
245/* }}} */
246static void xc_coverager_stop(TSRMLS_D) /* {{{ */
247{
248    XG(coverager_started) = 0;
249}
250/* }}} */
251
252static PHP_RINIT_FUNCTION(xcache_coverager) /* {{{ */
253{
254    if (XG(coverager)) {
255        if (XG(coverager_autostart)) {
256            xc_coverager_start(TSRMLS_C);
257        }
258#ifdef ZEND_COMPILE_EXTENDED_INFO
259        CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
260#else
261        CG(extended_info) = 1;
262#endif
263    }
264    else {
265        XG(coverager_started) = 0;
266    }
267    return SUCCESS;
268}
269/* }}} */
270static void xc_coverager_autodump(TSRMLS_D) /* {{{ */
271{
272    coverager_t *pcov;
273    zstr s;
274    char *outfilename;
275    size_t dumpdir_len, outfilelen, alloc_len = 0;
276    uint size;
277    HashPosition pos;
278
279    if (XG(coverages) && xc_coveragedump_dir) { 
280        dumpdir_len = strlen(xc_coveragedump_dir);
281        alloc_len = dumpdir_len + 1 + 128;
282        outfilename = emalloc(alloc_len);
283        strcpy(outfilename, xc_coveragedump_dir);
284
285        zend_hash_internal_pointer_reset_ex(XG(coverages), &pos);
286        while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) {
287            zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, &pos);
288            outfilelen = dumpdir_len + size + 5;
289            if (alloc_len < outfilelen) {
290                alloc_len = outfilelen + 128;
291                outfilename = erealloc(outfilename, alloc_len);
292            }
293            strcpy(outfilename + dumpdir_len, ZSTR_S(s));
294            strcpy(outfilename + dumpdir_len + size - 1, ".pcov");
295
296            TRACE("outfilename %s", outfilename);
297            xc_coverager_save_cov(ZSTR_S(s), outfilename, *pcov TSRMLS_CC);
298            zend_hash_move_forward_ex(XG(coverages), &pos);
299        }
300        efree(outfilename);
301    }
302}
303/* }}} */
304static void xc_coverager_dump(zval *return_value TSRMLS_DC) /* {{{ */
305{
306    coverager_t *pcov;
307    HashPosition pos;
308
309    if (XG(coverages)) {
310        array_init(return_value);
311
312        zend_hash_internal_pointer_reset_ex(XG(coverages), &pos);
313        while (zend_hash_get_current_data_ex(XG(coverages), (void **) &pcov, &pos) == SUCCESS) {
314            zval *lines;
315            long *phits;
316            coverager_t cov;
317            HashPosition pos2;
318            zstr filename;
319            uint size;
320
321            cov = *pcov;
322            zend_hash_get_current_key_ex(XG(coverages), &filename, &size, NULL, 0, &pos);
323
324            MAKE_STD_ZVAL(lines);
325            array_init(lines);
326            zend_hash_internal_pointer_reset_ex(cov, &pos2);
327            while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos2) == SUCCESS) {
328                long hits = *phits;
329                add_index_long(lines, pos2->h, hits >= 0 ? hits : 0);
330                zend_hash_move_forward_ex(cov, &pos2);
331            }
332            add_assoc_zval_ex(return_value, ZSTR_S(filename), (uint) strlen(ZSTR_S(filename)) + 1, lines);
333
334            zend_hash_move_forward_ex(XG(coverages), &pos);
335        }
336    }
337    else {
338        RETVAL_NULL();
339    }
340}
341/* }}} */
342static PHP_RSHUTDOWN_FUNCTION(xcache_coverager) /* {{{ */
343{
344    if (XG(coverager)) {
345        xc_coverager_autodump(TSRMLS_C);
346        xc_coverager_cleanup(TSRMLS_C);
347    }
348    return SUCCESS;
349}
350/* }}} */
351
352/* helper func to store hits into coverages */
353static coverager_t xc_coverager_get(const char *filename TSRMLS_DC) /* {{{ */
354{
355    uint len = (uint) strlen(filename) + 1;
356    coverager_t cov, *pcov;
357
358    if (zend_u_hash_find(XG(coverages), IS_STRING, filename, len, (void **) &pcov) == SUCCESS) {
359        TRACE("got coverage %s %p", filename, (void *) *pcov);
360        return *pcov;
361    }
362    else {
363        cov = emalloc(sizeof(HashTable));
364        zend_hash_init(cov, 0, NULL, NULL, 0);
365        zend_u_hash_add(XG(coverages), IS_STRING, filename, len, (void **) &cov, sizeof(cov), NULL);
366        TRACE("new coverage %s %p", filename, (void *) cov);
367        return cov;
368    }
369}
370/* }}} */
371static void xc_coverager_add_hits(HashTable *cov, long line, long hits TSRMLS_DC) /* {{{ */
372{
373    long *poldhits;
374
375    if (line == 0) {
376        return;
377    }
378    if (zend_hash_index_find(cov, line, (void**)&poldhits) == SUCCESS) {
379        if (hits == -1) {
380            /* OPTIMIZE: -1 == init-ing, but it's already initized */
381            return;
382        }
383        if (*poldhits != -1) {
384            hits += *poldhits;
385        }
386    }
387    zend_hash_index_update(cov, line, &hits, sizeof(hits), NULL);
388}
389/* }}} */
390
391static int xc_coverager_get_op_array_size_no_tail(zend_op_array *op_array) /* {{{ */
392{
393    zend_uint last = op_array->last;
394    do {
395next_op:
396        if (last == 0) {
397            break;
398        }
399        switch (op_array->opcodes[last - 1].opcode) {
400#ifdef ZEND_HANDLE_EXCEPTION
401            case ZEND_HANDLE_EXCEPTION:
402#endif
403            case ZEND_RETURN:
404            case ZEND_EXT_STMT:
405                --last;
406                goto next_op;
407        }
408    } while (0);
409    return last;
410}
411/* }}} */
412
413/* prefill */
414static int xc_coverager_init_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
415{
416    zend_uint size;
417    coverager_t cov;
418    zend_uint i;
419
420    if (op_array->type != ZEND_USER_FUNCTION) {
421        return 0;
422    }
423
424    size = xc_coverager_get_op_array_size_no_tail(op_array);
425    cov = xc_coverager_get(op_array->filename TSRMLS_CC);
426    for (i = 0; i < size; i ++) {
427        switch (op_array->opcodes[i].opcode) {
428            case ZEND_EXT_STMT:
429#if 0
430            case ZEND_EXT_FCALL_BEGIN:
431            case ZEND_EXT_FCALL_END:
432#endif
433                xc_coverager_add_hits(cov, op_array->opcodes[i].lineno, -1 TSRMLS_CC);
434                break;
435        }
436    }
437    return 0;
438}
439/* }}} */
440static void xc_coverager_init_compile_result(zend_op_array *op_array TSRMLS_DC) /* {{{ */
441{
442    xc_compile_result_t cr;
443
444    xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
445    xc_apply_op_array(&cr, (apply_func_t) xc_coverager_init_op_array TSRMLS_CC);
446    xc_compile_result_free(&cr);
447}
448/* }}} */
449static zend_op_array *xc_compile_file_for_coverage(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
450{
451    zend_op_array *op_array;
452
453    op_array = old_compile_file(h, type TSRMLS_CC);
454    if (op_array) {
455        if (XG(coverager)) {
456            xc_coverager_initenv(TSRMLS_C);
457            xc_coverager_init_compile_result(op_array TSRMLS_CC);
458        }
459    }
460    return op_array;
461}
462/* }}} */
463
464/* hits */
465static void xc_coverager_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ */
466{
467    TSRMLS_FETCH();
468
469    if (XG(coverages) && XG(coverager_started)) {
470        int size = xc_coverager_get_op_array_size_no_tail(op_array);
471        int oplineno = (int) ((*EG(opline_ptr)) - op_array->opcodes);
472        if (oplineno < size) {
473            xc_coverager_add_hits(xc_coverager_get(op_array->filename TSRMLS_CC), (*EG(opline_ptr))->lineno, 1 TSRMLS_CC);
474        }
475    }
476}
477/* }}} */
478
479/* user api */
480/* {{{ proto array xcache_coverager_decode(string data)
481 * decode specified data which is saved by auto dumper to array
482 */
483#ifdef ZEND_BEGIN_ARG_INFO_EX
484ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_coverager_decode, 0, 0, 1)
485    ZEND_ARG_INFO(0, data)
486ZEND_END_ARG_INFO()
487#else
488static unsigned char arginfo_xcache_coverager_decode[] = { 1, BYREF_NONE };
489#endif
490
491PHP_FUNCTION(xcache_coverager_decode)
492{
493    char *str;
494    int len;
495    long *p;
496
497    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) {
498        return;
499    }
500
501    array_init(return_value);
502
503    p = (long*) str;
504    len -= (int) sizeof(long);
505    if (len < 0) {
506        return;
507    }
508    if (*p++ != PCOV_HEADER_MAGIC) {
509        TRACE("%s", "wrong magic in xcache_coverager_decode");
510        return;
511    }
512
513    for (; len >= (int) sizeof(long) * 2; len -= (int) sizeof(long) * 2, p += 2) {
514        add_index_long(return_value, p[0], p[1] < 0 ? 0 : p[1]);
515    }
516}
517/* }}} */
518/* {{{ proto void xcache_coverager_start([bool clean = true])
519 * starts coverager data collecting
520 */
521#ifdef ZEND_BEGIN_ARG_INFO_EX
522ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_coverager_start, 0, 0, 0)
523    ZEND_ARG_INFO(0, clean)
524ZEND_END_ARG_INFO()
525#else
526static unsigned char arginfo_xcache_coverager_start[] = { 1, BYREF_NONE };
527#endif
528
529PHP_FUNCTION(xcache_coverager_start)
530{
531    zend_bool clean = 1;
532
533    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) {
534        return;
535    }
536
537    if (clean) {
538        xc_coverager_clean(TSRMLS_C);
539    }
540
541    if (XG(coverager)) {
542        xc_coverager_start(TSRMLS_C);
543    }
544    else {
545        php_error(E_WARNING, "You can only start coverager after you set 'xcache.coverager' to 'On' in ini");
546    }
547}
548/* }}} */
549/* {{{ proto void xcache_coverager_stop([bool clean = false])
550 * stop coverager data collecting
551 */
552#ifdef ZEND_BEGIN_ARG_INFO_EX
553ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_coverager_stop, 0, 0, 0)
554    ZEND_ARG_INFO(0, clean)
555ZEND_END_ARG_INFO()
556#else
557static unsigned char arginfo_xcache_coverager_stop[] = { 1, BYREF_NONE };
558#endif
559
560PHP_FUNCTION(xcache_coverager_stop)
561{
562    zend_bool clean = 0;
563
564    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) {
565        return;
566    }
567
568    xc_coverager_stop(TSRMLS_C);
569    if (clean) {
570        xc_coverager_clean(TSRMLS_C);
571    }
572}
573/* }}} */
574/* {{{ proto array xcache_coverager_get([bool clean = false])
575 * get coverager data collected
576 */
577#ifdef ZEND_BEGIN_ARG_INFO_EX
578ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_coverager_get, 0, 0, 0)
579    ZEND_ARG_INFO(0, clean)
580ZEND_END_ARG_INFO()
581#else
582static unsigned char arginfo_xcache_coverager_get[] = { 1, BYREF_NONE };
583#endif
584PHP_FUNCTION(xcache_coverager_get)
585{
586    zend_bool clean = 0;
587    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean) == FAILURE) {
588        return;
589    }
590
591    xc_coverager_dump(return_value TSRMLS_CC);
592    if (clean) {
593        xc_coverager_clean(TSRMLS_C);
594    }
595}
596/* }}} */
597static zend_function_entry xcache_coverager_functions[] = /* {{{ */
598{
599    PHP_FE(xcache_coverager_decode,  arginfo_xcache_coverager_decode)
600    PHP_FE(xcache_coverager_start,   arginfo_xcache_coverager_start)
601    PHP_FE(xcache_coverager_stop,    arginfo_xcache_coverager_stop)
602    PHP_FE(xcache_coverager_get,     arginfo_xcache_coverager_get)
603    PHP_FE_END
604};
605/* }}} */
606
607static int xc_coverager_zend_startup(zend_extension *extension) /* {{{ */
608{
609    old_compile_file = zend_compile_file;
610    zend_compile_file = xc_compile_file_for_coverage;
611
612    return SUCCESS;
613}
614/* }}} */
615static void xc_coverager_zend_shutdown(zend_extension *extension) /* {{{ */
616{
617    /* empty */
618}
619/* }}} */
620static void xc_statement_handler(zend_op_array *op_array) /* {{{ */
621{
622    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_STMT);
623}
624/* }}} */
625static void xc_fcall_begin_handler(zend_op_array *op_array) /* {{{ */
626{
627#if 0
628    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_BEGIN);
629#endif
630}
631/* }}} */
632static void xc_fcall_end_handler(zend_op_array *op_array) /* {{{ */
633{
634#if 0
635    xc_coverager_handle_ext_stmt(op_array, ZEND_EXT_FCALL_END);
636#endif
637}
638/* }}} */
639/* {{{ zend extension definition structure */
640static zend_extension xc_coverager_zend_extension_entry = {
641    XCACHE_NAME " Coverager",
642    XCACHE_VERSION,
643    XCACHE_AUTHOR,
644    XCACHE_URL,
645    XCACHE_COPYRIGHT,
646    xc_coverager_zend_startup,
647    xc_coverager_zend_shutdown,
648    NULL,           /* activate_func_t */
649    NULL,           /* deactivate_func_t */
650    NULL,           /* message_handler_func_t */
651    NULL,           /* statement_handler_func_t */
652    xc_statement_handler,
653    xc_fcall_begin_handler,
654    xc_fcall_end_handler,
655    NULL,           /* op_array_ctor_func_t */
656    NULL,           /* op_array_dtor_func_t */
657    STANDARD_ZEND_EXTENSION_PROPERTIES
658};
659/* }}} */
660/* {{{ PHP_INI */
661PHP_INI_BEGIN()
662    STD_PHP_INI_BOOLEAN("xcache.coverager",              "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, coverager,           zend_xcache_globals, xcache_globals)
663    STD_PHP_INI_BOOLEAN("xcache.coverager_autostart",    "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, coverager_autostart, zend_xcache_globals, xcache_globals)
664    PHP_INI_ENTRY1     ("xcache.coveragedump_directory",  "", PHP_INI_SYSTEM, xcache_OnUpdateDummy, NULL)
665PHP_INI_END()
666/* }}} */
667static PHP_MINFO_FUNCTION(xcache_coverager) /* {{{ */
668{
669    char *covdumpdir;
670
671    php_info_print_table_start();
672    php_info_print_table_row(2, "XCache Coverager Module", "enabled");
673    if (cfg_get_string("xcache.coveragedump_directory", &covdumpdir) != SUCCESS || !covdumpdir[0]) {
674        covdumpdir = NULL;
675    }
676    php_info_print_table_row(2, "Coverage Started", XG(coverager_started) && covdumpdir ? "On" : "Off");
677    php_info_print_table_end();
678
679    DISPLAY_INI_ENTRIES();
680}
681/* }}} */
682static PHP_MINIT_FUNCTION(xcache_coverager) /* {{{ */
683{
684    REGISTER_INI_ENTRIES();
685
686    if (cfg_get_string("xcache.coveragedump_directory", &xc_coveragedump_dir) == SUCCESS && xc_coveragedump_dir) {
687        size_t len;
688        xc_coveragedump_dir = pestrdup(xc_coveragedump_dir, 1);
689        len = strlen(xc_coveragedump_dir);
690        if (len) {
691            if (xc_coveragedump_dir[len - 1] == '/') {
692                xc_coveragedump_dir[len - 1] = '\0';
693            }
694        }
695        if (!strlen(xc_coveragedump_dir)) {
696            pefree(xc_coveragedump_dir, 1);
697            xc_coveragedump_dir = NULL;
698        }
699    }
700
701    return xcache_zend_extension_add(&xc_coverager_zend_extension_entry, 0);
702}
703/* }}} */
704static PHP_MSHUTDOWN_FUNCTION(xcache_coverager) /* {{{ */
705{
706    if (old_compile_file && zend_compile_file == xc_compile_file_for_coverage) {
707        zend_compile_file = old_compile_file;
708        old_compile_file = NULL;
709    }
710    if (xc_coveragedump_dir) {
711        pefree(xc_coveragedump_dir, 1);
712        xc_coveragedump_dir = NULL;
713    }
714    UNREGISTER_INI_ENTRIES();
715    return xcache_zend_extension_remove(&xc_coverager_zend_extension_entry);
716}
717/* }}} */
718
719static zend_module_entry xcache_coverager_module_entry = { /* {{{ */
720    STANDARD_MODULE_HEADER,
721    XCACHE_NAME " Coverager",
722    xcache_coverager_functions,
723    PHP_MINIT(xcache_coverager),
724    PHP_MSHUTDOWN(xcache_coverager),
725    PHP_RINIT(xcache_coverager),
726    PHP_RSHUTDOWN(xcache_coverager),
727    PHP_MINFO(xcache_coverager),
728    XCACHE_VERSION,
729#ifdef PHP_GINIT
730    NO_MODULE_GLOBALS,
731#endif
732#ifdef ZEND_ENGINE_2
733    NULL,
734#else
735    NULL,
736    NULL,
737#endif
738    STANDARD_MODULE_PROPERTIES_EX
739};
740/* }}} */
741int xc_coverager_startup_module() /* {{{ */
742{
743    return zend_startup_module(&xcache_coverager_module_entry);
744}
745/* }}} */
Note: See TracBrowser for help on using the repository browser.