2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
19 #include "ext/standard/info.h"
20 #include "php_raphf.h"
22 struct php_persistent_handle_globals
{
27 ZEND_BEGIN_MODULE_GLOBALS(raphf
)
28 struct php_persistent_handle_globals persistent_handle
;
29 ZEND_END_MODULE_GLOBALS(raphf
)
32 # define PHP_RAPHF_G ((zend_raphf_globals *) \
33 (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(raphf_globals_id)])
35 # define PHP_RAPHF_G (&raphf_globals)
38 ZEND_DECLARE_MODULE_GLOBALS(raphf
)
40 #ifndef PHP_RAPHF_DEBUG_PHANDLES
41 # define PHP_RAPHF_DEBUG_PHANDLES 0
43 #if PHP_RAPHF_DEBUG_PHANDLES
48 php_resource_factory_t
*php_resource_factory_init(php_resource_factory_t
*f
,
49 php_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *data
))
52 f
= emalloc(sizeof(*f
));
54 memset(f
, 0, sizeof(*f
));
56 memcpy(&f
->fops
, fops
, sizeof(*fops
));
66 unsigned php_resource_factory_addref(php_resource_factory_t
*rf
)
68 return ++rf
->refcount
;
71 void php_resource_factory_dtor(php_resource_factory_t
*f
)
80 void php_resource_factory_free(php_resource_factory_t
**f
)
83 php_resource_factory_dtor(*f
);
84 if (!(*f
)->refcount
) {
91 void *php_resource_factory_handle_ctor(php_resource_factory_t
*f
,
92 void *init_arg TSRMLS_DC
)
95 return f
->fops
.ctor(f
->data
, init_arg TSRMLS_CC
);
100 void *php_resource_factory_handle_copy(php_resource_factory_t
*f
,
101 void *handle TSRMLS_DC
)
104 return f
->fops
.copy(f
->data
, handle TSRMLS_CC
);
109 void php_resource_factory_handle_dtor(php_resource_factory_t
*f
,
110 void *handle TSRMLS_DC
)
113 f
->fops
.dtor(f
->data
, handle TSRMLS_CC
);
117 static inline php_persistent_handle_list_t
*php_persistent_handle_list_init(
118 php_persistent_handle_list_t
*list
)
120 list
= pemalloc(sizeof(*list
), 1);
122 zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1);
127 static int php_persistent_handle_apply_stat(zval
*p TSRMLS_DC
, int argc
,
128 va_list argv
, zend_hash_key
*key
)
130 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
131 zval zsubentry
, *zentry
= va_arg(argv
, zval
*);
133 array_init(&zsubentry
);
134 add_assoc_long_ex(&zsubentry
, ZEND_STRS("used"), list
->used
);
135 add_assoc_long_ex(&zsubentry
, ZEND_STRS("free"),
136 zend_hash_num_elements(&list
->free
));
137 add_assoc_zval_ex(zentry
, key
->key
->val
, key
->key
->len
, &zsubentry
);
139 return ZEND_HASH_APPLY_KEEP
;
142 static int php_persistent_handle_apply_statall(zval
*p TSRMLS_DC
, int argc
,
143 va_list argv
, zend_hash_key
*key
)
145 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
146 HashTable
*ht
= va_arg(argv
, HashTable
*);
151 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
152 php_persistent_handle_apply_stat
, 1, &zentry
);
153 zend_symtable_update(ht
, key
->key
, &zentry
);
155 return ZEND_HASH_APPLY_KEEP
;
158 static int php_persistent_handle_apply_cleanup_ex(zval
*p
, void *arg TSRMLS_DC
)
160 php_resource_factory_t
*rf
= arg
;
161 void *handle
= Z_PTR_P(p
);
163 #if PHP_RAPHF_DEBUG_PHANDLES
164 fprintf(stderr
, "DESTROY: %p\n", handle
);
166 php_resource_factory_handle_dtor(rf
, handle TSRMLS_CC
);
167 return ZEND_HASH_APPLY_REMOVE
;
170 static int php_persistent_handle_apply_cleanup(zval
*p
, void *arg TSRMLS_DC
)
172 php_resource_factory_t
*rf
= arg
;
173 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
175 zend_hash_apply_with_argument(&list
->free
,
176 php_persistent_handle_apply_cleanup_ex
, rf TSRMLS_CC
);
178 return ZEND_HASH_APPLY_KEEP
;
180 zend_hash_destroy(&list
->free
);
181 #if PHP_RAPHF_DEBUG_PHANDLES
182 fprintf(stderr
, "LSTFREE: %p\n", list
);
185 return ZEND_HASH_APPLY_REMOVE
;
188 static inline void php_persistent_handle_list_dtor(
189 php_persistent_handle_list_t
*list
,
190 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
192 #if PHP_RAPHF_DEBUG_PHANDLES
193 fprintf(stderr
, "LSTDTOR: %p\n", list
);
195 zend_hash_apply_with_argument(&list
->free
,
196 php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
197 zend_hash_destroy(&list
->free
);
200 static inline void php_persistent_handle_list_free(
201 php_persistent_handle_list_t
**list
,
202 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
204 php_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
205 #if PHP_RAPHF_DEBUG_PHANDLES
206 fprintf(stderr
, "LSTFREE: %p\n", *list
);
212 static int php_persistent_handle_list_apply_dtor(zval
*p
,
213 void *provider TSRMLS_DC
)
215 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
216 php_persistent_handle_list_free(&list
, provider TSRMLS_CC
);
217 return ZEND_HASH_APPLY_REMOVE
;
220 static inline php_persistent_handle_list_t
*php_persistent_handle_list_find(
221 php_persistent_handle_provider_t
*provider
, const char *ident_str
,
222 size_t ident_len TSRMLS_DC
)
224 php_persistent_handle_list_t
*list
;
226 list
= zend_symtable_str_find_ptr(&provider
->list
.free
, ident_str
,
230 #if PHP_RAPHF_DEBUG_PHANDLES
231 fprintf(stderr
, "LSTFIND: %p\n", list
);
236 if ((list
= php_persistent_handle_list_init(NULL
))) {
240 if (zend_symtable_str_update(&provider
->list
.free
, ident_str
, ident_len
+1,
242 #if PHP_RAPHF_DEBUG_PHANDLES
243 fprintf(stderr
, "LSTFIND: %p (new)\n", list
);
247 php_persistent_handle_list_free(&list
, provider TSRMLS_CC
);
253 static int php_persistent_handle_apply_cleanup_all(zval
*p TSRMLS_DC
, int argc
,
254 va_list argv
, zend_hash_key
*key
)
256 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
257 const char *ident_str
= va_arg(argv
, const char *);
258 size_t ident_len
= va_arg(argv
, size_t);
259 php_persistent_handle_list_t
*list
;
261 if (ident_str
&& ident_len
) {
262 if ((list
= php_persistent_handle_list_find(provider
, ident_str
,
263 ident_len TSRMLS_CC
))) {
264 zend_hash_apply_with_argument(&list
->free
,
265 php_persistent_handle_apply_cleanup_ex
,
266 &provider
->rf TSRMLS_CC
);
269 zend_hash_apply_with_argument(&provider
->list
.free
,
270 php_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
273 return ZEND_HASH_APPLY_KEEP
;
276 static void php_persistent_handle_hash_dtor(zval
*p
)
278 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
281 zend_hash_apply_with_argument(&provider
->list
.free
,
282 php_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
283 zend_hash_destroy(&provider
->list
.free
);
284 php_resource_factory_dtor(&provider
->rf
);
288 ZEND_RESULT_CODE
php_persistent_handle_provide(const char *name_str
,
289 size_t name_len
, php_resource_factory_ops_t
*fops
, void *data
,
290 void (*dtor
)(void *) TSRMLS_DC
)
292 php_persistent_handle_provider_t
*provider
= pemalloc(sizeof(*provider
), 1);
294 if (php_persistent_handle_list_init(&provider
->list
)) {
295 if (php_resource_factory_init(&provider
->rf
, fops
, data
, dtor
)) {
298 #if PHP_RAPHF_DEBUG_PHANDLES
299 fprintf(stderr
, "PROVIDE: %p %s\n", PHP_RAPHF_G
, name_str
);
302 ZVAL_PTR(&p
, provider
);
303 if (zend_symtable_str_update(&PHP_RAPHF_G
->persistent_handle
.hash
,
304 name_str
, name_len
+1, &p
)) {
307 php_resource_factory_dtor(&provider
->rf
);
314 php_persistent_handle_factory_t
*php_persistent_handle_concede(
315 php_persistent_handle_factory_t
*a
, const char *name_str
,
316 size_t name_len
, const char *ident_str
, size_t ident_len
,
317 php_persistent_handle_wakeup_t wakeup
,
318 php_persistent_handle_retire_t retire TSRMLS_DC
)
320 php_persistent_handle_factory_t
*free_a
= NULL
;
323 free_a
= a
= emalloc(sizeof(*a
));
325 memset(a
, 0, sizeof(*a
));
327 a
->provider
= zend_symtable_str_find_ptr(&PHP_RAPHF_G
->persistent_handle
.hash
,
328 name_str
, name_len
+1);
331 a
->ident
.str
= estrndup(ident_str
, ident_len
);
332 a
->ident
.len
= ident_len
;
338 a
->free_on_abandon
= 1;
347 #if PHP_RAPHF_DEBUG_PHANDLES
348 fprintf(stderr
, "CONCEDE: %p %p (%s) (%s)\n", PHP_RAPHF_G
,
349 a
? a
->provider
: NULL
, name_str
, ident_str
);
355 void php_persistent_handle_abandon(php_persistent_handle_factory_t
*a
)
357 zend_bool f
= a
->free_on_abandon
;
359 #if PHP_RAPHF_DEBUG_PHANDLES
360 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
366 memset(a
, 0, sizeof(*a
));
372 void *php_persistent_handle_acquire(php_persistent_handle_factory_t
*a
,
373 void *init_arg TSRMLS_DC
)
379 php_persistent_handle_list_t
*list
;
381 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
382 a
->ident
.len TSRMLS_CC
);
384 zend_hash_internal_pointer_end(&list
->free
);
385 key
= zend_hash_get_current_key(&list
->free
, NULL
, &index
, 0);
386 p
= zend_hash_get_current_data(&list
->free
);
387 if (p
&& HASH_KEY_NON_EXISTENT
!= key
) {
390 a
->wakeup(a
, &handle TSRMLS_CC
);
392 zend_hash_index_del(&list
->free
, index
);
394 handle
= php_resource_factory_handle_ctor(&a
->provider
->rf
,
397 #if PHP_RAPHF_DEBUG_PHANDLES
398 fprintf(stderr
, "CREATED: %p\n", *handle
);
401 ++a
->provider
->list
.used
;
409 void *php_persistent_handle_accrete(php_persistent_handle_factory_t
*a
,
410 void *handle TSRMLS_DC
)
412 void *new_handle
= NULL
;
413 php_persistent_handle_list_t
*list
;
415 new_handle
= php_resource_factory_handle_copy(&a
->provider
->rf
,
418 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
419 a
->ident
.len TSRMLS_CC
);
423 ++a
->provider
->list
.used
;
429 void php_persistent_handle_release(php_persistent_handle_factory_t
*a
,
430 void *handle TSRMLS_DC
)
432 php_persistent_handle_list_t
*list
;
434 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
435 a
->ident
.len TSRMLS_CC
);
437 if (a
->provider
->list
.used
>= PHP_RAPHF_G
->persistent_handle
.limit
) {
438 #if PHP_RAPHF_DEBUG_PHANDLES
439 fprintf(stderr
, "DESTROY: %p\n", *handle
);
441 php_resource_factory_handle_dtor(&a
->provider
->rf
, handle TSRMLS_CC
);
444 a
->retire(a
, &handle TSRMLS_CC
);
446 zend_hash_next_index_insert_ptr(&list
->free
, handle
);
449 --a
->provider
->list
.used
;
454 void php_persistent_handle_cleanup(const char *name_str
, size_t name_len
,
455 const char *ident_str
, size_t ident_len TSRMLS_DC
)
457 php_persistent_handle_provider_t
*provider
;
458 php_persistent_handle_list_t
*list
;
460 if (name_str
&& name_len
) {
461 provider
= zend_symtable_str_find_ptr(&PHP_RAPHF_G
->persistent_handle
.hash
,
462 name_str
, name_len
+1);
465 if (ident_str
&& ident_len
) {
466 list
= php_persistent_handle_list_find(provider
, ident_str
,
467 ident_len TSRMLS_CC
);
469 zend_hash_apply_with_argument(&list
->free
,
470 php_persistent_handle_apply_cleanup_ex
,
471 &provider
->rf TSRMLS_CC
);
474 zend_hash_apply_with_argument(&provider
->list
.free
,
475 php_persistent_handle_apply_cleanup
,
476 &provider
->rf TSRMLS_CC
);
480 zend_hash_apply_with_arguments(
481 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
482 php_persistent_handle_apply_cleanup_all
, 2, ident_str
,
487 HashTable
*php_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
489 if (zend_hash_num_elements(&PHP_RAPHF_G
->persistent_handle
.hash
)) {
492 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
494 zend_hash_apply_with_arguments(
495 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
496 php_persistent_handle_apply_statall
, 1, ht
);
504 static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops
= {
505 (php_resource_factory_handle_ctor_t
) php_persistent_handle_acquire
,
506 (php_resource_factory_handle_copy_t
) php_persistent_handle_accrete
,
507 (php_resource_factory_handle_dtor_t
) php_persistent_handle_release
510 php_resource_factory_ops_t
*php_persistent_handle_get_resource_factory_ops(void)
512 return &php_persistent_handle_resource_factory_ops
;
515 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles
, 0, 0, 0)
517 static PHP_FUNCTION(raphf_stat_persistent_handles
)
519 if (SUCCESS
== zend_parse_parameters_none()) {
520 object_init(return_value
);
521 if (php_persistent_handle_statall(HASH_OF(return_value
) TSRMLS_CC
)) {
524 zval_dtor(return_value
);
529 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles
, 0, 0, 0)
530 ZEND_ARG_INFO(0, name
)
531 ZEND_ARG_INFO(0, ident
)
533 static PHP_FUNCTION(raphf_clean_persistent_handles
)
535 char *name_str
= NULL
, *ident_str
= NULL
;
536 int name_len
= 0, ident_len
= 0;
538 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!s!",
539 &name_str
, &name_len
, &ident_str
, &ident_len
)) {
540 php_persistent_handle_cleanup(name_str
, name_len
, ident_str
,
541 ident_len TSRMLS_CC
);
545 static const zend_function_entry raphf_functions
[] = {
546 ZEND_NS_FENTRY("raphf", stat_persistent_handles
,
547 ZEND_FN(raphf_stat_persistent_handles
),
548 ai_raphf_stat_persistent_handles
, 0)
549 ZEND_NS_FENTRY("raphf", clean_persistent_handles
,
550 ZEND_FN(raphf_clean_persistent_handles
),
551 ai_raphf_clean_persistent_handles
, 0)
556 STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM
,
557 OnUpdateLong
, persistent_handle
.limit
, zend_raphf_globals
,
561 static HashTable
*php_persistent_handles_global_hash
;
563 static PHP_GINIT_FUNCTION(raphf
)
565 raphf_globals
->persistent_handle
.limit
= -1;
567 zend_hash_init(&raphf_globals
->persistent_handle
.hash
, 0, NULL
,
568 php_persistent_handle_hash_dtor
, 1);
569 if (php_persistent_handles_global_hash
) {
570 zend_hash_copy(&raphf_globals
->persistent_handle
.hash
,
571 php_persistent_handles_global_hash
, NULL
);
575 static PHP_GSHUTDOWN_FUNCTION(raphf
)
577 zend_hash_destroy(&raphf_globals
->persistent_handle
.hash
);
580 PHP_MINIT_FUNCTION(raphf
)
582 php_persistent_handles_global_hash
= &PHP_RAPHF_G
->persistent_handle
.hash
;
583 REGISTER_INI_ENTRIES();
587 PHP_MSHUTDOWN_FUNCTION(raphf
)
589 UNREGISTER_INI_ENTRIES();
590 php_persistent_handles_global_hash
= NULL
;
594 static int php_persistent_handle_apply_info_ex(zval
*p TSRMLS_DC
, int argc
,
595 va_list argv
, zend_hash_key
*key
)
597 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
598 zend_hash_key
*super_key
= va_arg(argv
, zend_hash_key
*);
599 char used
[21], free
[21];
601 slprintf(used
, sizeof(used
), "%u", list
->used
);
602 slprintf(free
, sizeof(free
), "%d", zend_hash_num_elements(&list
->free
));
604 php_info_print_table_row(4, super_key
->key
->val
, key
->key
->val
, used
, free
);
606 return ZEND_HASH_APPLY_KEEP
;
609 static int php_persistent_handle_apply_info(zval
*p TSRMLS_DC
, int argc
,
610 va_list argv
, zend_hash_key
*key
)
612 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
614 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
615 php_persistent_handle_apply_info_ex
, 1, key
);
617 return ZEND_HASH_APPLY_KEEP
;
620 PHP_MINFO_FUNCTION(raphf
)
622 php_info_print_table_start();
623 php_info_print_table_header(2,
624 "Resource and persistent handle factory support", "enabled");
625 php_info_print_table_row(2, "Extension version", PHP_RAPHF_VERSION
);
626 php_info_print_table_end();
628 php_info_print_table_start();
629 php_info_print_table_colspan_header(4, "Persistent handles in this "
636 php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
637 zend_hash_apply_with_arguments(
638 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
639 php_persistent_handle_apply_info
, 0);
640 php_info_print_table_end();
642 DISPLAY_INI_ENTRIES();
645 zend_module_entry raphf_module_entry
= {
646 STANDARD_MODULE_HEADER
,
650 PHP_MSHUTDOWN(raphf
),
655 ZEND_MODULE_GLOBALS(raphf
),
657 PHP_GSHUTDOWN(raphf
),
659 STANDARD_MODULE_PROPERTIES_EX
663 #ifdef COMPILE_DL_RAPHF
664 ZEND_GET_MODULE(raphf
)
673 * vim600: noet sw=4 ts=4 fdm=marker
674 * vim<600: noet sw=4 ts=4