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 #ifndef PHP_RAPHF_TEST
23 # define PHP_RAPHF_TEST 0
26 struct php_persistent_handle_globals
{
31 ZEND_BEGIN_MODULE_GLOBALS(raphf
)
32 struct php_persistent_handle_globals persistent_handle
;
33 ZEND_END_MODULE_GLOBALS(raphf
)
36 # define PHP_RAPHF_G ((zend_raphf_globals *) \
37 (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(raphf_globals_id)])
39 # define PHP_RAPHF_G (&raphf_globals)
42 ZEND_DECLARE_MODULE_GLOBALS(raphf
)
44 #ifndef PHP_RAPHF_DEBUG_PHANDLES
45 # define PHP_RAPHF_DEBUG_PHANDLES 0
47 #if PHP_RAPHF_DEBUG_PHANDLES
52 php_resource_factory_t
*php_resource_factory_init(php_resource_factory_t
*f
,
53 php_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *data
))
56 f
= emalloc(sizeof(*f
));
58 memset(f
, 0, sizeof(*f
));
60 memcpy(&f
->fops
, fops
, sizeof(*fops
));
70 unsigned php_resource_factory_addref(php_resource_factory_t
*rf
)
72 return ++rf
->refcount
;
75 void php_resource_factory_dtor(php_resource_factory_t
*f
)
84 void php_resource_factory_free(php_resource_factory_t
**f
)
87 php_resource_factory_dtor(*f
);
88 if (!(*f
)->refcount
) {
95 void *php_resource_factory_handle_ctor(php_resource_factory_t
*f
,
96 void *init_arg TSRMLS_DC
)
99 return f
->fops
.ctor(f
->data
, init_arg TSRMLS_CC
);
104 void *php_resource_factory_handle_copy(php_resource_factory_t
*f
,
105 void *handle TSRMLS_DC
)
108 return f
->fops
.copy(f
->data
, handle TSRMLS_CC
);
113 void php_resource_factory_handle_dtor(php_resource_factory_t
*f
,
114 void *handle TSRMLS_DC
)
117 f
->fops
.dtor(f
->data
, handle TSRMLS_CC
);
121 static inline php_persistent_handle_list_t
*php_persistent_handle_list_init(
122 php_persistent_handle_list_t
*list
)
125 list
= pemalloc(sizeof(*list
), 1);
128 zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1);
133 static int php_persistent_handle_apply_stat(zval
*p TSRMLS_DC
, int argc
,
134 va_list argv
, zend_hash_key
*key
)
136 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
137 zval zsubentry
, *zentry
= va_arg(argv
, zval
*);
139 array_init(&zsubentry
);
140 add_assoc_long_ex(&zsubentry
, ZEND_STRL("used"), list
->used
);
141 add_assoc_long_ex(&zsubentry
, ZEND_STRL("free"),
142 zend_hash_num_elements(&list
->free
));
144 add_assoc_zval_ex(zentry
, key
->key
->val
, key
->key
->len
, &zsubentry
);
146 add_index_zval(zentry
, key
->h
, &zsubentry
);
148 return ZEND_HASH_APPLY_KEEP
;
151 static int php_persistent_handle_apply_statall(zval
*p TSRMLS_DC
, int argc
,
152 va_list argv
, zend_hash_key
*key
)
154 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
155 HashTable
*ht
= va_arg(argv
, HashTable
*);
160 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
161 php_persistent_handle_apply_stat
, 1, &zentry
);
164 zend_hash_update(ht
, key
->key
, &zentry
);
166 zend_hash_index_update(ht
, key
->h
, &zentry
);
169 return ZEND_HASH_APPLY_KEEP
;
172 static int php_persistent_handle_apply_cleanup_ex(zval
*p
, void *arg TSRMLS_DC
)
174 php_resource_factory_t
*rf
= arg
;
175 void *handle
= Z_PTR_P(p
);
177 #if PHP_RAPHF_DEBUG_PHANDLES
178 fprintf(stderr
, "DESTROY: %p\n", handle
);
180 php_resource_factory_handle_dtor(rf
, handle TSRMLS_CC
);
181 return ZEND_HASH_APPLY_REMOVE
;
184 static int php_persistent_handle_apply_cleanup(zval
*p
, void *arg TSRMLS_DC
)
186 php_resource_factory_t
*rf
= arg
;
187 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
189 zend_hash_apply_with_argument(&list
->free
,
190 php_persistent_handle_apply_cleanup_ex
, rf TSRMLS_CC
);
192 return ZEND_HASH_APPLY_KEEP
;
194 zend_hash_destroy(&list
->free
);
195 #if PHP_RAPHF_DEBUG_PHANDLES
196 fprintf(stderr
, "LSTFREE: %p\n", list
);
199 return ZEND_HASH_APPLY_REMOVE
;
202 static inline void php_persistent_handle_list_dtor(
203 php_persistent_handle_list_t
*list
,
204 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
206 #if PHP_RAPHF_DEBUG_PHANDLES
207 fprintf(stderr
, "LSTDTOR: %p\n", list
);
209 zend_hash_apply_with_argument(&list
->free
,
210 php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
211 zend_hash_destroy(&list
->free
);
214 static inline void php_persistent_handle_list_free(
215 php_persistent_handle_list_t
**list
,
216 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
218 php_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
219 #if PHP_RAPHF_DEBUG_PHANDLES
220 fprintf(stderr
, "LSTFREE: %p\n", *list
);
226 static int php_persistent_handle_list_apply_dtor(zval
*p
,
227 void *provider TSRMLS_DC
)
229 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
230 php_persistent_handle_list_free(&list
, provider TSRMLS_CC
);
232 return ZEND_HASH_APPLY_REMOVE
;
235 static inline php_persistent_handle_list_t
*php_persistent_handle_list_find(
236 php_persistent_handle_provider_t
*provider
, const char *ident_str
,
237 size_t ident_len TSRMLS_DC
)
239 php_persistent_handle_list_t
*list
;
241 list
= zend_symtable_str_find_ptr(&provider
->list
.free
, ident_str
, ident_len
);
244 #if PHP_RAPHF_DEBUG_PHANDLES
245 fprintf(stderr
, "LSTFIND: %p\n", list
);
250 if ((list
= php_persistent_handle_list_init(NULL
))) {
254 if (zend_symtable_str_update(&provider
->list
.free
, ident_str
, ident_len
,
256 #if PHP_RAPHF_DEBUG_PHANDLES
257 fprintf(stderr
, "LSTFIND: %p (new)\n", list
);
261 php_persistent_handle_list_free(&list
, provider TSRMLS_CC
);
267 static int php_persistent_handle_apply_cleanup_all(zval
*p TSRMLS_DC
, int argc
,
268 va_list argv
, zend_hash_key
*key
)
270 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
271 const char *ident_str
= va_arg(argv
, const char *);
272 size_t ident_len
= va_arg(argv
, size_t);
273 php_persistent_handle_list_t
*list
;
275 if (ident_str
&& ident_len
) {
276 if ((list
= php_persistent_handle_list_find(provider
, ident_str
,
277 ident_len TSRMLS_CC
))) {
278 zend_hash_apply_with_argument(&list
->free
,
279 php_persistent_handle_apply_cleanup_ex
,
280 &provider
->rf TSRMLS_CC
);
283 zend_hash_apply_with_argument(&provider
->list
.free
,
284 php_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
287 return ZEND_HASH_APPLY_KEEP
;
290 static void php_persistent_handle_hash_dtor(zval
*p
)
292 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
295 zend_hash_apply_with_argument(&provider
->list
.free
,
296 php_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
297 zend_hash_destroy(&provider
->list
.free
);
298 php_resource_factory_dtor(&provider
->rf
);
302 ZEND_RESULT_CODE
php_persistent_handle_provide(const char *name_str
,
303 size_t name_len
, php_resource_factory_ops_t
*fops
, void *data
,
304 void (*dtor
)(void *) TSRMLS_DC
)
306 php_persistent_handle_provider_t
*provider
= pemalloc(sizeof(*provider
), 1);
308 if (php_persistent_handle_list_init(&provider
->list
)) {
309 if (php_resource_factory_init(&provider
->rf
, fops
, data
, dtor
)) {
312 #if PHP_RAPHF_DEBUG_PHANDLES
313 fprintf(stderr
, "PROVIDE: %p %s\n", PHP_RAPHF_G
, name_str
);
316 ZVAL_PTR(&p
, provider
);
317 if (zend_symtable_str_update(&PHP_RAPHF_G
->persistent_handle
.hash
,
318 name_str
, name_len
, &p
)) {
321 php_resource_factory_dtor(&provider
->rf
);
329 php_persistent_handle_factory_t
*php_persistent_handle_concede(
330 php_persistent_handle_factory_t
*a
, const char *name_str
,
331 size_t name_len
, const char *ident_str
, size_t ident_len
,
332 php_persistent_handle_wakeup_t wakeup
,
333 php_persistent_handle_retire_t retire TSRMLS_DC
)
335 php_persistent_handle_factory_t
*free_a
= NULL
;
338 free_a
= a
= emalloc(sizeof(*a
));
340 memset(a
, 0, sizeof(*a
));
342 a
->provider
= zend_symtable_str_find_ptr(&PHP_RAPHF_G
->persistent_handle
.hash
,
346 a
->ident
.str
= estrndup(ident_str
, ident_len
);
347 a
->ident
.len
= ident_len
;
353 a
->free_on_abandon
= 1;
362 #if PHP_RAPHF_DEBUG_PHANDLES
363 fprintf(stderr
, "CONCEDE: %p %p (%s) (%s)\n", PHP_RAPHF_G
,
364 a
? a
->provider
: NULL
, name_str
, ident_str
);
370 void php_persistent_handle_abandon(php_persistent_handle_factory_t
*a
)
372 zend_bool f
= a
->free_on_abandon
;
374 #if PHP_RAPHF_DEBUG_PHANDLES
375 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
381 memset(a
, 0, sizeof(*a
));
387 void *php_persistent_handle_acquire(php_persistent_handle_factory_t
*a
,
388 void *init_arg TSRMLS_DC
)
394 php_persistent_handle_list_t
*list
;
396 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
397 a
->ident
.len TSRMLS_CC
);
399 zend_hash_internal_pointer_end(&list
->free
);
400 key
= zend_hash_get_current_key(&list
->free
, NULL
, &index
, 0);
401 p
= zend_hash_get_current_data(&list
->free
);
402 if (p
&& HASH_KEY_NON_EXISTENT
!= key
) {
405 a
->wakeup(a
, &handle TSRMLS_CC
);
407 zend_hash_index_del(&list
->free
, index
);
409 handle
= php_resource_factory_handle_ctor(&a
->provider
->rf
,
412 #if PHP_RAPHF_DEBUG_PHANDLES
413 fprintf(stderr
, "CREATED: %p\n", handle
);
416 ++a
->provider
->list
.used
;
424 void *php_persistent_handle_accrete(php_persistent_handle_factory_t
*a
,
425 void *handle TSRMLS_DC
)
427 void *new_handle
= NULL
;
428 php_persistent_handle_list_t
*list
;
430 new_handle
= php_resource_factory_handle_copy(&a
->provider
->rf
,
433 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
434 a
->ident
.len TSRMLS_CC
);
438 ++a
->provider
->list
.used
;
444 void php_persistent_handle_release(php_persistent_handle_factory_t
*a
,
445 void *handle TSRMLS_DC
)
447 php_persistent_handle_list_t
*list
;
449 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
450 a
->ident
.len TSRMLS_CC
);
452 if (a
->provider
->list
.used
>= PHP_RAPHF_G
->persistent_handle
.limit
) {
453 #if PHP_RAPHF_DEBUG_PHANDLES
454 fprintf(stderr
, "DESTROY: %p\n", handle
);
456 php_resource_factory_handle_dtor(&a
->provider
->rf
, handle TSRMLS_CC
);
459 a
->retire(a
, &handle TSRMLS_CC
);
461 zend_hash_next_index_insert_ptr(&list
->free
, handle
);
464 --a
->provider
->list
.used
;
469 void php_persistent_handle_cleanup(const char *name_str
, size_t name_len
,
470 const char *ident_str
, size_t ident_len TSRMLS_DC
)
472 php_persistent_handle_provider_t
*provider
;
473 php_persistent_handle_list_t
*list
;
475 if (name_str
&& name_len
) {
476 provider
= zend_symtable_str_find_ptr(&PHP_RAPHF_G
->persistent_handle
.hash
,
480 if (ident_str
&& ident_len
) {
481 list
= php_persistent_handle_list_find(provider
, ident_str
,
482 ident_len TSRMLS_CC
);
484 zend_hash_apply_with_argument(&list
->free
,
485 php_persistent_handle_apply_cleanup_ex
,
486 &provider
->rf TSRMLS_CC
);
489 zend_hash_apply_with_argument(&provider
->list
.free
,
490 php_persistent_handle_apply_cleanup
,
491 &provider
->rf TSRMLS_CC
);
495 zend_hash_apply_with_arguments(
496 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
497 php_persistent_handle_apply_cleanup_all
, 2, ident_str
,
502 HashTable
*php_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
504 if (zend_hash_num_elements(&PHP_RAPHF_G
->persistent_handle
.hash
)) {
507 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
509 zend_hash_apply_with_arguments(
510 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
511 php_persistent_handle_apply_statall
, 1, ht
);
519 static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops
= {
520 (php_resource_factory_handle_ctor_t
) php_persistent_handle_acquire
,
521 (php_resource_factory_handle_copy_t
) php_persistent_handle_accrete
,
522 (php_resource_factory_handle_dtor_t
) php_persistent_handle_release
525 php_resource_factory_ops_t
*php_persistent_handle_get_resource_factory_ops(void)
527 return &php_persistent_handle_resource_factory_ops
;
530 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles
, 0, 0, 0)
532 static PHP_FUNCTION(raphf_stat_persistent_handles
)
534 if (SUCCESS
== zend_parse_parameters_none()) {
535 object_init(return_value
);
536 if (php_persistent_handle_statall(HASH_OF(return_value
) TSRMLS_CC
)) {
539 zval_dtor(return_value
);
544 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles
, 0, 0, 0)
545 ZEND_ARG_INFO(0, name
)
546 ZEND_ARG_INFO(0, ident
)
548 static PHP_FUNCTION(raphf_clean_persistent_handles
)
550 char *name_str
= NULL
, *ident_str
= NULL
;
551 int name_len
= 0, ident_len
= 0;
553 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!s!",
554 &name_str
, &name_len
, &ident_str
, &ident_len
)) {
555 php_persistent_handle_cleanup(name_str
, name_len
, ident_str
,
556 ident_len TSRMLS_CC
);
561 # include "php_raphf_test.c"
564 static const zend_function_entry raphf_functions
[] = {
565 ZEND_NS_FENTRY("raphf", stat_persistent_handles
,
566 ZEND_FN(raphf_stat_persistent_handles
),
567 ai_raphf_stat_persistent_handles
, 0)
568 ZEND_NS_FENTRY("raphf", clean_persistent_handles
,
569 ZEND_FN(raphf_clean_persistent_handles
),
570 ai_raphf_clean_persistent_handles
, 0)
572 ZEND_NS_FENTRY("raphf", provide
, ZEND_FN(raphf_provide
), NULL
, 0)
573 ZEND_NS_FENTRY("raphf", conceal
, ZEND_FN(raphf_conceal
), NULL
, 0)
574 ZEND_NS_FENTRY("raphf", concede
, ZEND_FN(raphf_concede
), NULL
, 0)
575 ZEND_NS_FENTRY("raphf", dispute
, ZEND_FN(raphf_dispute
), NULL
, 0)
576 ZEND_NS_FENTRY("raphf", handle_ctor
, ZEND_FN(raphf_handle_ctor
), NULL
, 0)
577 ZEND_NS_FENTRY("raphf", handle_copy
, ZEND_FN(raphf_handle_copy
), NULL
, 0)
578 ZEND_NS_FENTRY("raphf", handle_dtor
, ZEND_FN(raphf_handle_dtor
), NULL
, 0)
584 STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM
,
585 OnUpdateLong
, persistent_handle
.limit
, zend_raphf_globals
,
589 static HashTable
*php_persistent_handles_global_hash
;
591 static PHP_GINIT_FUNCTION(raphf
)
593 raphf_globals
->persistent_handle
.limit
= -1;
595 zend_hash_init(&raphf_globals
->persistent_handle
.hash
, 0, NULL
,
596 php_persistent_handle_hash_dtor
, 1);
597 if (php_persistent_handles_global_hash
) {
598 zend_hash_copy(&raphf_globals
->persistent_handle
.hash
,
599 php_persistent_handles_global_hash
, NULL
);
603 static PHP_GSHUTDOWN_FUNCTION(raphf
)
605 zend_hash_destroy(&raphf_globals
->persistent_handle
.hash
);
608 PHP_MINIT_FUNCTION(raphf
)
610 php_persistent_handles_global_hash
= &PHP_RAPHF_G
->persistent_handle
.hash
;
613 PHP_MINIT(raphf_test
)(INIT_FUNC_ARGS_PASSTHRU
);
616 REGISTER_INI_ENTRIES();
620 PHP_MSHUTDOWN_FUNCTION(raphf
)
623 PHP_MSHUTDOWN(raphf_test
)(SHUTDOWN_FUNC_ARGS_PASSTHRU
);
626 UNREGISTER_INI_ENTRIES();
627 php_persistent_handles_global_hash
= NULL
;
631 static int php_persistent_handle_apply_info_ex(zval
*p TSRMLS_DC
, int argc
,
632 va_list argv
, zend_hash_key
*key
)
634 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
635 zend_hash_key
*super_key
= va_arg(argv
, zend_hash_key
*);
636 char used
[21], free
[21];
638 slprintf(used
, sizeof(used
), "%u", list
->used
);
639 slprintf(free
, sizeof(free
), "%d", zend_hash_num_elements(&list
->free
));
641 php_info_print_table_row(4, super_key
->key
->val
, key
->key
->val
, used
, free
);
643 return ZEND_HASH_APPLY_KEEP
;
646 static int php_persistent_handle_apply_info(zval
*p TSRMLS_DC
, int argc
,
647 va_list argv
, zend_hash_key
*key
)
649 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
651 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
652 php_persistent_handle_apply_info_ex
, 1, key
);
654 return ZEND_HASH_APPLY_KEEP
;
657 PHP_MINFO_FUNCTION(raphf
)
659 php_info_print_table_start();
660 php_info_print_table_header(2,
661 "Resource and persistent handle factory support", "enabled");
662 php_info_print_table_row(2, "Extension version", PHP_RAPHF_VERSION
);
663 php_info_print_table_end();
665 php_info_print_table_start();
666 php_info_print_table_colspan_header(4, "Persistent handles in this "
673 php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
674 zend_hash_apply_with_arguments(
675 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
676 php_persistent_handle_apply_info
, 0);
677 php_info_print_table_end();
679 DISPLAY_INI_ENTRIES();
682 zend_module_entry raphf_module_entry
= {
683 STANDARD_MODULE_HEADER
,
687 PHP_MSHUTDOWN(raphf
),
692 ZEND_MODULE_GLOBALS(raphf
),
694 PHP_GSHUTDOWN(raphf
),
696 STANDARD_MODULE_PROPERTIES_EX
700 #ifdef COMPILE_DL_RAPHF
701 ZEND_GET_MODULE(raphf
)
709 * vim600: noet sw=4 ts=4 fdm=marker
710 * vim<600: noet sw=4 ts=4