20b25ead45afe0d7b248dbc82c3aea537b1cee3f
[m6w6/ext-psi] / src / module.c
1
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #include "php.h"
7 #include "php_ini.h"
8 #include "ext/standard/info.h"
9
10 #include "php_psi.h"
11 #include "parser.h"
12
13 #if HAVE_LIBJIT
14 # include "libjit.h"
15 # ifndef HAVE_LIBFFI
16 # define PSI_ENGINE "jit"
17 # endif
18 #endif
19 #if HAVE_LIBFFI
20 # include "libffi.h"
21 # define PSI_ENGINE "ffi"
22 #endif
23
24 ZEND_DECLARE_MODULE_GLOBALS(psi);
25
26 PHP_INI_BEGIN()
27 STD_PHP_INI_ENTRY("psi.engine", PSI_ENGINE, PHP_INI_SYSTEM, OnUpdateString, engine, zend_psi_globals, psi_globals)
28 STD_PHP_INI_ENTRY("psi.directory", "psi.d", PHP_INI_SYSTEM, OnUpdateString, directory, zend_psi_globals, psi_globals)
29 PHP_INI_END();
30
31 void psi_error(int type, const char *msg, ...)
32 {
33 char buf[0x1000];
34 va_list argv;
35
36 va_start(argv, msg);
37 vslprintf(buf, 0x1000, msg, argv);
38 va_end(argv);
39
40 php_error(type, buf);
41 }
42
43 size_t psi_t_alignment(token_t t)
44 {
45 size_t align;
46 #define PSI_TAS_D(T) struct PSI_TAS_ ##T { \
47 char c; \
48 T x; \
49 }
50 #define PSI_TAS_P(T) struct PSI_TAS_ ## T ## _pointer { \
51 char c; \
52 T *x; \
53 }
54 #define PSI_TAS_C(T) align = offsetof(struct PSI_TAS_ ##T, x)
55 #define PSI_TAS_CASE(T) { \
56 PSI_TAS_D(T); \
57 PSI_TAS_C(T); \
58 }
59 switch (t) {
60 case PSI_T_INT8:
61 PSI_TAS_CASE(int8_t);
62 break;
63 case PSI_T_UINT8:
64 PSI_TAS_CASE(uint8_t);
65 break;
66 case PSI_T_INT16:
67 PSI_TAS_CASE(int16_t);
68 break;
69 case PSI_T_UINT16:
70 PSI_TAS_CASE(uint16_t);
71 break;
72 case PSI_T_INT32:
73 PSI_TAS_CASE(int32_t);
74 break;
75 case PSI_T_UINT32:
76 PSI_TAS_CASE(uint32_t);
77 break;
78 case PSI_T_INT64:
79 PSI_TAS_CASE(int64_t);
80 break;
81 case PSI_T_UINT64:
82 PSI_TAS_CASE(uint64_t);
83 break;
84 case PSI_T_FLOAT:
85 PSI_TAS_CASE(float);
86 break;
87 case PSI_T_DOUBLE:
88 PSI_TAS_CASE(double);
89 break;
90 case PSI_T_POINTER:
91 {
92 PSI_TAS_P(char);
93 PSI_TAS_C(char_pointer);
94 }
95 break;
96 EMPTY_SWITCH_DEFAULT_CASE();
97 }
98
99 return align;
100 }
101
102 size_t psi_t_size(token_t t)
103 {
104 size_t size;
105
106 switch (t) {
107 case PSI_T_INT8:
108 case PSI_T_UINT8:
109 size = 1;
110 break;
111 case PSI_T_INT16:
112 case PSI_T_UINT16:
113 size = 2;
114 break;
115 case PSI_T_INT:
116 size = sizeof(int);
117 break;
118 case PSI_T_INT32:
119 case PSI_T_UINT32:
120 size = 4;
121 break;
122 case PSI_T_INT64:
123 case PSI_T_UINT64:
124 size = 8;
125 break;
126 case PSI_T_FLOAT:
127 size = sizeof(float);
128 break;
129 case PSI_T_DOUBLE:
130 size = sizeof(double);
131 break;
132 case PSI_T_POINTER:
133 size = sizeof(char *);
134 break;
135 EMPTY_SWITCH_DEFAULT_CASE();
136 }
137 return size;
138 }
139
140 size_t psi_t_align(token_t t, size_t s)
141 {
142 size_t a = psi_t_alignment(t);
143 return ((s - 1) | (a - 1)) + 1;
144 }
145
146 int psi_internal_type(impl_type *type)
147 {
148 switch (type->type) {
149 case PSI_T_BOOL:
150 return _IS_BOOL;
151 case PSI_T_INT:
152 return IS_LONG;
153 case PSI_T_FLOAT:
154 case PSI_T_DOUBLE:
155 return IS_DOUBLE;
156 case PSI_T_STRING:
157 return IS_STRING;
158 case PSI_T_ARRAY:
159 return IS_ARRAY;
160 default:
161 return 0;
162 }
163 }
164
165 zend_internal_arg_info *psi_internal_arginfo(impl *impl)
166 {
167 size_t i;
168 zend_internal_arg_info *aip;
169 zend_internal_function_info *fi;
170
171 aip = calloc(impl->func->args->count + 1, sizeof(*aip));
172
173 fi = (zend_internal_function_info *) &aip[0];
174 fi->required_num_args = psi_num_min_args(impl);
175 fi->return_reference = impl->func->return_reference;
176 fi->type_hint = psi_internal_type(impl->func->return_type);
177
178 for (i = 0; i < impl->func->args->count; ++i) {
179 impl_arg *iarg = impl->func->args->args[i];
180 zend_internal_arg_info *ai = &aip[i+1];
181
182 ai->name = iarg->var->name;
183 ai->type_hint = psi_internal_type(iarg->type);
184 if (iarg->var->reference) {
185 ai->pass_by_reference = 1;
186 }
187 if (iarg->var->reference || (iarg->def && iarg->def->type == PSI_T_NULL)) {
188 ai->allow_null = 1;
189 }
190 }
191
192 return aip;
193 }
194
195 size_t psi_num_min_args(impl *impl)
196 {
197 size_t i, n = impl->func->args->count;
198
199 for (i = 0; i < impl->func->args->count; ++i) {
200 if (impl->func->args->args[i]->def) {
201 --n;
202 }
203 }
204 return n;
205 }
206
207 void psi_to_bool(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
208 {
209 impl_val *v = deref_impl_val(ret_val, var);
210
211 switch (t) {
212 case PSI_T_FLOAT:
213 RETVAL_DOUBLE((double) v->fval);
214 break;
215 case PSI_T_DOUBLE:
216 RETVAL_DOUBLE(v->dval);
217 break;
218 default:
219 RETVAL_LONG(v->lval);
220 break;
221 }
222 convert_to_boolean(return_value);
223 }
224
225 void psi_to_int(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
226 {
227 impl_val *v = deref_impl_val(ret_val, var);
228
229 switch (t) {
230 case PSI_T_FLOAT:
231 RETVAL_DOUBLE((double) v->fval);
232 break;
233 case PSI_T_DOUBLE:
234 RETVAL_DOUBLE(v->dval);
235 break;
236 default:
237 RETVAL_LONG(v->lval);
238 return;
239 }
240 convert_to_long(return_value);
241 }
242
243 void psi_to_double(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
244 {
245 impl_val *v = deref_impl_val(ret_val, var);
246
247 switch (t) {
248 case PSI_T_FLOAT:
249 RETVAL_DOUBLE((double) v->fval);
250 break;
251 case PSI_T_DOUBLE:
252 RETVAL_DOUBLE(v->dval);
253 break;
254 default:
255 RETVAL_DOUBLE((double) v->lval);
256 break;
257 }
258 }
259
260 void psi_to_string(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
261 {
262 switch (t) {
263 case PSI_T_INT8:
264 case PSI_T_UINT8:
265 if (!var->arg->var->pointer_level) {
266 RETVAL_STRINGL(&ret_val->cval, 1);
267 } else {
268 ret_val = deref_impl_val(ret_val, var);
269 if (ret_val && ret_val->ptr) {
270 RETVAL_STRING(ret_val->ptr);
271 } else {
272 RETVAL_EMPTY_STRING();
273 }
274 }
275 return;
276 case PSI_T_FLOAT:
277 RETVAL_DOUBLE((double) deref_impl_val(ret_val, var)->fval);
278 break;
279 case PSI_T_DOUBLE:
280 RETVAL_DOUBLE(deref_impl_val(ret_val, var)->dval);
281 break;
282 default:
283 RETVAL_LONG(deref_impl_val(ret_val, var)->lval);
284 break;
285 }
286 convert_to_string(return_value);
287 }
288
289
290 static impl_val *iterate(impl_val *val, token_t t, unsigned i, impl_val *tmp)
291 {
292 size_t size = psi_t_size(t);
293
294 memset(tmp, 0, sizeof(*tmp));
295 memcpy(tmp, val->ptr + size * i, size);
296 return tmp;
297 }
298
299 void psi_from_zval(impl_val *mem, decl_arg *spec, zval *zv, void **tmp)
300 {
301 decl_type *type = real_decl_type(spec->type);
302
303 switch (type->type) {
304 case PSI_T_FLOAT:
305 mem->fval = (float) zval_get_double(zv);
306 break;
307 case PSI_T_DOUBLE:
308 mem->dval = zval_get_double(zv);
309 break;
310 case PSI_T_INT8:
311 case PSI_T_UINT8:
312 if (spec->var->pointer_level) {
313 zend_string *zs = zval_get_string(zv);
314 *tmp = mem->ptr = estrndup(zs->val, zs->len);
315 zend_string_release(zs);
316 break;
317 }
318 /* no break */
319 default:
320 mem->zend.lval = zval_get_long(zv);
321 break;
322 }
323 }
324
325 void *psi_array_to_struct(decl_struct *s, HashTable *arr)
326 {
327 size_t i, j = 0;
328 char *mem = ecalloc(1, s->size + s->args->count * sizeof(void *));
329
330 if (arr) for (i = 0; i < s->args->count; ++i) {
331 decl_arg *darg = s->args->args[i];
332 zval *entry = zend_hash_str_find_ind(arr, darg->var->name, strlen(darg->var->name));
333
334 if (entry) {
335 impl_val val;
336 void *tmp = NULL;
337
338 memset(&tmp, 0, sizeof(tmp));
339 psi_from_zval(&val, darg, entry, &tmp);
340 memcpy(mem + darg->layout->pos, &val, darg->layout->len);
341 if (tmp) {
342 ((void **)(mem + s->size))[j++] = tmp;
343 }
344 }
345 }
346 return mem;
347 }
348
349 void psi_to_array(zval *return_value, token_t t, impl_val *ret_val, set_value *set, decl_var *var)
350 {
351 zval ele;
352 unsigned i;
353 impl_val tmp;
354
355 array_init(return_value);
356
357 if (t == PSI_T_STRUCT) {
358 decl_struct *s = real_decl_type(var->arg->type)->strct;
359 ret_val = deref_impl_val(ret_val, var);
360
361 ZEND_ASSERT(s);
362
363 if (set->count) {
364 /* explicit member casts */
365 for (i = 0; i < set->count; ++i) {
366 zval ztmp;
367 impl_val *tmp_ptr;
368 set_value *sub_set = set->inner[i];
369 decl_var *sub_var = sub_set->vars->vars[0];
370 decl_arg *sub_arg = sub_var->arg;
371
372 if (sub_arg) {
373 token_t t = real_decl_type(sub_arg->type)->type;
374 void *ptr = malloc(sub_arg->layout->len);
375
376 memcpy(ptr, (char *) ret_val->ptr + sub_arg->layout->pos,
377 sub_arg->layout->len);
378 tmp_ptr = enref_impl_val(ptr, sub_arg->var);
379 sub_set->func->handler(&ztmp, t, tmp_ptr, sub_set, sub_var);
380 add_assoc_zval(return_value, sub_var->name, &ztmp);
381 free(tmp_ptr);
382 if (tmp_ptr != ptr) {
383 free(ptr);
384 }
385 }
386 }
387 }
388 return;
389
390 // for (i = 0; i < s->args->count; ++i) {
391 // decl_arg *darg = s->args->args[i];
392 // impl_val tmp, tmp_ptr;
393 // zval ztmp;
394 // char *ptr = (char *) ret_val->ptr + darg->layout->pos;
395 //
396 // tmp_ptr.ptr = &tmp;
397 // memset(&tmp, 0, sizeof(tmp));
398 // memcpy(&tmp, ptr, darg->layout->len);
399 // switch (real_decl_type(darg->type)->type) {
400 // case PSI_T_FLOAT:
401 // case PSI_T_DOUBLE:
402 // psi_to_double(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
403 // break;
404 // case PSI_T_INT8:
405 // case PSI_T_UINT8:
406 // if (darg->var->pointer_level) {
407 // psi_to_string(&ztmp, real_decl_type(darg->type)->type, &tmp_ptr, darg->var);
408 // break;
409 // }
410 // /* no break */
411 // case PSI_T_INT16:
412 // case PSI_T_UINT16:
413 // case PSI_T_INT32:
414 // case PSI_T_UINT32:
415 // case PSI_T_INT64:
416 // case PSI_T_UINT64:
417 // psi_to_int(&ztmp, real_decl_type(darg->type)->type, &tmp, darg->var);
418 // break;
419 // case PSI_T_STRUCT:
420 // psi_to_array(&ztmp, real_decl_type(darg->type)->type, &tmp_ptr, darg->var);
421 // break;
422 // default:
423 // printf("t=%d\n", real_decl_type(darg->type)->type);
424 // abort();
425 // }
426 // add_assoc_zval(return_value, darg->var->name, &ztmp);
427 // }
428 return;
429 }
430 ret_val = deref_impl_val(ret_val, var);
431 for (i = 0; i < var->arg->var->array_size; ++i) {
432 impl_val *ptr = iterate(ret_val, t, i, &tmp);
433
434 switch (t) {
435 case PSI_T_FLOAT:
436 ZVAL_DOUBLE(&ele, (double) ptr->fval);
437 break;
438 case PSI_T_DOUBLE:
439 ZVAL_DOUBLE(&ele, ptr->dval);
440 break;
441 default:
442 ZVAL_LONG(&ele, ptr->lval);
443 break;
444 }
445
446 add_next_index_zval(return_value, &ele);
447 }
448 }
449
450 static inline ZEND_RESULT_CODE psi_parse_args(zend_execute_data *execute_data, impl *impl)
451 {
452 impl_arg *iarg;
453
454 if (!impl->func->args->count) {
455 return zend_parse_parameters_none();
456 }
457
458 ZEND_PARSE_PARAMETERS_START(psi_num_min_args(impl), impl->func->args->count)
459 nextarg:
460 iarg = impl->func->args->args[_i];
461 if (iarg->def) {
462 Z_PARAM_OPTIONAL;
463 }
464 if (PSI_T_BOOL == iarg->type->type) {
465 if (iarg->def) {
466 iarg->val.zend.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
467 }
468 Z_PARAM_BOOL(iarg->val.zend.bval);
469 } else if (PSI_T_INT == iarg->type->type) {
470 if (iarg->def) {
471 iarg->val.zend.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
472 }
473 Z_PARAM_LONG(iarg->val.zend.lval);
474 } else if (PSI_T_FLOAT == iarg->type->type || PSI_T_DOUBLE == iarg->type->type) {
475 if (iarg->def) {
476 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
477 }
478 Z_PARAM_DOUBLE(iarg->val.dval);
479 } else if (PSI_T_STRING == iarg->type->type) {
480 struct {char *val; size_t len;} str;
481 if (iarg->def) {
482 /* FIXME */
483 str.len = strlen(iarg->def->text) - 2;
484 str.val = &iarg->def->text[1];
485 }
486 Z_PARAM_STR_EX(iarg->val.zend.str, 1, 0);
487 if (iarg->val.zend.str) {
488 zend_string_addref(iarg->val.zend.str);
489 } else if (iarg->def) {
490 iarg->val.zend.str = zend_string_init(str.val, str.len, 0);
491 }
492 } else if (PSI_T_ARRAY == iarg->type->type) {
493 /* handled as _zv in let or set */
494 Z_PARAM_PROLOGUE(0);
495 } else {
496 error_code = ZPP_ERROR_FAILURE;
497 break;
498 }
499 iarg->_zv = _arg;
500 if (_i < _max_num_args) {
501 goto nextarg;
502 }
503 ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
504
505 return SUCCESS;
506 }
507
508 static inline void *psi_do_calloc(let_calloc *alloc)
509 {
510 decl_type *type = real_decl_type(alloc->type);
511 size_t size;
512
513 if (type->type == PSI_T_STRUCT) {
514 /* psi_do_clean expects at least one NULL pointer after the struct */
515 size = type->strct->size + sizeof(void *);
516 } else {
517 size = psi_t_size(type->type);
518 }
519
520 return ecalloc(alloc->n, size);
521 }
522
523 static inline void *psi_do_let(decl_arg *darg)
524 {
525 impl_arg *iarg = darg->let->arg;
526 impl_val *arg_val;
527
528 darg->let->ptr = &darg->let->out;
529 arg_val = darg->let->ptr;
530
531 if (!iarg) {
532 /* let foo = calloc(1, long);
533 * let foo = NULL;
534 * let foo;
535 */
536 if (darg->let->val->func && darg->let->val->func->type == PSI_T_CALLOC) {
537 arg_val->ptr = psi_do_calloc(darg->let->val->func->alloc);
538 darg->let->mem = arg_val->ptr;
539 } else if (darg->var->array_size) {
540 arg_val->ptr = ecalloc(darg->var->array_size, sizeof(*arg_val));
541 darg->let->mem = arg_val->ptr;
542 } else {
543 memset(arg_val, 0, sizeof(*arg_val));
544 }
545 } else {
546
547 switch (darg->let->val->func->type) {
548 case PSI_T_BOOLVAL:
549 if (iarg->type->type == PSI_T_BOOL) {
550 arg_val->cval = iarg->val.zend.bval;
551 } else {
552 arg_val->cval = zend_is_true(iarg->_zv);
553 }
554 break;
555 case PSI_T_INTVAL:
556 if (iarg->type->type == PSI_T_INT) {
557 arg_val->lval = iarg->val.zend.lval;
558 } else {
559 arg_val->lval = zval_get_long(iarg->_zv);
560 }
561 break;
562 case PSI_T_STRVAL:
563 if (iarg->type->type == PSI_T_STRING) {
564 arg_val->ptr = estrdup(iarg->val.zend.str->val);
565 darg->let->mem = arg_val->ptr;
566 zend_string_release(iarg->val.zend.str);
567 } else {
568 zend_string *zs = zval_get_string(iarg->_zv);
569 arg_val->ptr = estrdup(zs->val);
570 darg->let->mem = arg_val->ptr;
571 zend_string_release(zs);
572 }
573 break;
574 case PSI_T_STRLEN:
575 if (iarg->type->type == PSI_T_STRING) {
576 arg_val->lval = iarg->val.zend.str->len;
577 zend_string_release(iarg->val.zend.str);
578 } else {
579 zend_string *zs = zval_get_string(iarg->_zv);
580 arg_val->lval = zs->len;
581 zend_string_release(zs);
582 }
583 break;
584 case PSI_T_ARRVAL:
585 if (iarg->type->type == PSI_T_ARRAY) {
586 decl_type *type = real_decl_type(darg->type);
587
588 switch (type->type) {
589 case PSI_T_STRUCT:
590 arg_val->ptr = psi_array_to_struct(type->strct, HASH_OF(iarg->_zv));
591 darg->let->mem = arg_val->ptr;
592 break;
593 }
594 }
595 break;
596 EMPTY_SWITCH_DEFAULT_CASE();
597 }
598 }
599
600 if (darg->let->val && darg->let->val->is_reference) {
601 return &darg->let->ptr;
602 } else {
603 return darg->let->ptr;
604 }
605 }
606
607 static inline void psi_do_set(zval *return_value, set_value *set)
608 {
609 impl_val *val = (impl_val *) &set->vars->vars[0]->arg->let->ptr;
610 token_t t = real_decl_type(set->vars->vars[0]->arg->type)->type;
611
612 ZVAL_DEREF(return_value);
613 zval_dtor(return_value);
614
615 set->func->handler(return_value, t, val, set, set->vars->vars[0]);
616 }
617
618 static inline void psi_do_return(zval *return_value, return_stmt *ret, impl_val *ret_val)
619 {
620 token_t t = real_decl_type(ret->decl->type)->type;
621
622 ret->set->func->handler(return_value, t, ret_val, ret->set, ret->decl->var);
623 }
624
625 static inline void psi_do_free(free_stmt *fre)
626 {
627 size_t i, j;
628 impl_val dummy;
629
630 for (i = 0; i < fre->calls->count; ++i) {
631 free_call *f = fre->calls->list[i];
632
633 for (j = 0; j < f->vars->count; ++j) {
634 decl_var *dvar = f->vars->vars[j];
635 decl_arg *darg = dvar->arg;
636
637 f->decl->call.args[j] = &darg->let->out;
638 }
639
640 /* FIXME: check in validate_* that free functions return scalar */
641 PSI_ContextCall(&PSI_G(context), &dummy, f->decl);
642 }
643 }
644
645 static inline void psi_do_clean(impl *impl)
646 {
647 size_t i;
648
649 for (i = 0; i < impl->func->args->count; ++i ) {
650 impl_arg *iarg = impl->func->args->args[i];
651
652 switch (iarg->type->type) {
653 case PSI_T_STRING:
654 if (iarg->val.zend.str) {
655 zend_string_release(iarg->val.zend.str);
656 }
657 break;
658 }
659 }
660
661 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
662 decl_arg *darg = impl->decl->args->args[i];
663
664 if (darg->let && darg->let->mem) {
665 decl_type *type = real_decl_type(darg->type);
666
667 if (type->type == PSI_T_STRUCT) {
668 void **ptr = (void **) ((char *) darg->let->mem + type->strct->size);
669
670 while (*ptr) {
671 efree(*ptr++);
672 }
673 }
674 efree(darg->let->mem);
675 darg->let->mem = NULL;
676 }
677 }
678 }
679
680 void psi_call(zend_execute_data *execute_data, zval *return_value, impl *impl)
681 {
682 impl_val ret_val;
683 size_t i;
684
685 if (SUCCESS != psi_parse_args(execute_data, impl)) {
686 return;
687 }
688
689 if (impl->decl->args) {
690 for (i = 0; i < impl->decl->args->count; ++i) {
691 decl_arg *darg = impl->decl->args->args[i];
692
693 impl->decl->call.args[i] = psi_do_let(darg);
694 }
695 }
696
697 memset(&ret_val, 0, sizeof(ret_val));
698 PSI_ContextCall(&PSI_G(context), &ret_val, impl->decl);
699
700 psi_do_return(return_value, impl->stmts->ret.list[0], &ret_val);
701
702 for (i = 0; i < impl->stmts->set.count; ++i) {
703 set_stmt *set = impl->stmts->set.list[i];
704
705 if (set->arg->_zv) {
706 psi_do_set(set->arg->_zv, set->val);
707 }
708 }
709
710 for (i = 0; i < impl->stmts->fre.count; ++i) {
711 free_stmt *fre = impl->stmts->fre.list[i];
712
713 psi_do_free(fre);
714 }
715
716 psi_do_clean(impl);
717 }
718
719 PHP_MINIT_FUNCTION(psi)
720 {
721 PSI_ContextOps *ops = NULL;
722
723 REGISTER_INI_ENTRIES();
724
725 #ifdef HAVE_LIBJIT
726 if (!strcasecmp(PSI_G(engine), "jit")) {
727 ops = PSI_Libjit();
728 } else
729 #endif
730 #ifdef HAVE_LIBFFI
731 ops = PSI_Libffi();
732 #endif
733
734 if (!ops) {
735 php_error(E_WARNING, "No PSI engine found");
736 return FAILURE;
737 }
738
739 PSI_ContextInit(&PSI_G(context), ops, psi_error);
740 PSI_ContextBuild(&PSI_G(context), PSI_G(directory));
741
742 return SUCCESS;
743 }
744 PHP_MSHUTDOWN_FUNCTION(psi)
745 {
746 PSI_ContextDtor(&PSI_G(context));
747
748 UNREGISTER_INI_ENTRIES();
749
750 return SUCCESS;
751 }
752
753 /* Remove if there's nothing to do at request start */
754 /* {{{ PHP_RINIT_FUNCTION
755 */
756 PHP_RINIT_FUNCTION(psi)
757 {
758 #if defined(COMPILE_DL_PSI) && defined(ZTS)
759 ZEND_TSRMLS_CACHE_UPDATE();
760 #endif
761 return SUCCESS;
762 }
763 /* }}} */
764
765 /* Remove if there's nothing to do at request end */
766 /* {{{ PHP_RSHUTDOWN_FUNCTION
767 */
768 PHP_RSHUTDOWN_FUNCTION(psi)
769 {
770 return SUCCESS;
771 }
772 /* }}} */
773
774 PHP_MINFO_FUNCTION(psi)
775 {
776 php_info_print_table_start();
777 php_info_print_table_header(2, "psi support", "enabled");
778 php_info_print_table_end();
779
780 DISPLAY_INI_ENTRIES();
781 }
782 const zend_function_entry psi_functions[] = {
783 PHP_FE_END
784 };
785
786 zend_module_entry psi_module_entry = {
787 STANDARD_MODULE_HEADER,
788 "psi",
789 psi_functions,
790 PHP_MINIT(psi),
791 PHP_MSHUTDOWN(psi),
792 PHP_RINIT(psi), /* Replace with NULL if there's nothing to do at request start */
793 PHP_RSHUTDOWN(psi), /* Replace with NULL if there's nothing to do at request end */
794 PHP_MINFO(psi),
795 PHP_PSI_VERSION,
796 STANDARD_MODULE_PROPERTIES
797 };
798
799 #ifdef COMPILE_DL_PSI
800 #ifdef ZTS
801 ZEND_TSRMLS_CACHE_DEFINE();
802 #endif
803 ZEND_GET_MODULE(psi)
804 #endif
805
806 /*
807 * Local variables:
808 * tab-width: 4
809 * c-basic-offset: 4
810 * End:
811 * vim600: noet sw=4 ts=4 fdm=marker
812 * vim<600: noet sw=4 ts=4
813 */