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