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_get_ls_cache()))[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
, void *init_arg
)
98 return f
->fops
.ctor(f
->data
, init_arg
);
103 void *php_resource_factory_handle_copy(php_resource_factory_t
*f
, void *handle
)
106 return f
->fops
.copy(f
->data
, handle
);
111 void php_resource_factory_handle_dtor(php_resource_factory_t
*f
, void *handle
)
114 f
->fops
.dtor(f
->data
, handle
);
118 php_resource_factory_t
*php_persistent_handle_resource_factory_init(
119 php_resource_factory_t
*a
, php_persistent_handle_factory_t
*pf
)
121 return php_resource_factory_init(a
,
122 php_persistent_handle_get_resource_factory_ops(), pf
,
123 (void(*)(void*)) php_persistent_handle_abandon
);
126 zend_bool
php_resource_factory_is_persistent(php_resource_factory_t
*a
)
128 return a
->dtor
== (void(*)(void *)) php_persistent_handle_abandon
;
131 static inline php_persistent_handle_list_t
*php_persistent_handle_list_init(
132 php_persistent_handle_list_t
*list
)
135 list
= pemalloc(sizeof(*list
), 1);
138 zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1);
143 static int php_persistent_handle_apply_stat(zval
*p
, int argc
, va_list argv
,
146 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
147 zval zsubentry
, *zentry
= va_arg(argv
, zval
*);
149 array_init(&zsubentry
);
150 add_assoc_long_ex(&zsubentry
, ZEND_STRL("used"), list
->used
);
151 add_assoc_long_ex(&zsubentry
, ZEND_STRL("free"),
152 zend_hash_num_elements(&list
->free
));
154 add_assoc_zval_ex(zentry
, key
->key
->val
, key
->key
->len
, &zsubentry
);
156 add_index_zval(zentry
, key
->h
, &zsubentry
);
158 return ZEND_HASH_APPLY_KEEP
;
161 static int php_persistent_handle_apply_statall(zval
*p
, int argc
, va_list argv
,
164 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
165 HashTable
*ht
= va_arg(argv
, HashTable
*);
170 zend_hash_apply_with_arguments(&provider
->list
.free
,
171 php_persistent_handle_apply_stat
, 1, &zentry
);
174 zend_hash_update(ht
, key
->key
, &zentry
);
176 zend_hash_index_update(ht
, key
->h
, &zentry
);
179 return ZEND_HASH_APPLY_KEEP
;
182 static int php_persistent_handle_apply_cleanup_ex(zval
*p
, void *arg
)
184 php_resource_factory_t
*rf
= arg
;
185 void *handle
= Z_PTR_P(p
);
187 #if PHP_RAPHF_DEBUG_PHANDLES
188 fprintf(stderr
, "DESTROY: %p\n", handle
);
190 php_resource_factory_handle_dtor(rf
, handle
);
191 return ZEND_HASH_APPLY_REMOVE
;
194 static int php_persistent_handle_apply_cleanup(zval
*p
, void *arg
)
196 php_resource_factory_t
*rf
= arg
;
197 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
199 zend_hash_apply_with_argument(&list
->free
,
200 php_persistent_handle_apply_cleanup_ex
, rf
);
202 return ZEND_HASH_APPLY_KEEP
;
204 zend_hash_destroy(&list
->free
);
205 #if PHP_RAPHF_DEBUG_PHANDLES
206 fprintf(stderr
, "LSTFREE: %p\n", list
);
209 return ZEND_HASH_APPLY_REMOVE
;
212 static inline void php_persistent_handle_list_dtor(
213 php_persistent_handle_list_t
*list
,
214 php_persistent_handle_provider_t
*provider
)
216 #if PHP_RAPHF_DEBUG_PHANDLES
217 fprintf(stderr
, "LSTDTOR: %p\n", list
);
219 zend_hash_apply_with_argument(&list
->free
,
220 php_persistent_handle_apply_cleanup_ex
, &provider
->rf
);
221 zend_hash_destroy(&list
->free
);
224 static inline void php_persistent_handle_list_free(
225 php_persistent_handle_list_t
**list
,
226 php_persistent_handle_provider_t
*provider
)
228 php_persistent_handle_list_dtor(*list
, provider
);
229 #if PHP_RAPHF_DEBUG_PHANDLES
230 fprintf(stderr
, "LSTFREE: %p\n", *list
);
236 static int php_persistent_handle_list_apply_dtor(zval
*p
, void *provider
)
238 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
240 php_persistent_handle_list_free(&list
, provider
);
242 return ZEND_HASH_APPLY_REMOVE
;
245 static inline php_persistent_handle_list_t
*php_persistent_handle_list_find(
246 php_persistent_handle_provider_t
*provider
, zend_string
*ident
,
249 php_persistent_handle_list_t
*list
;
250 zval
*zlist
= zend_symtable_find(&provider
->list
.free
, ident
);
252 if (zlist
&& (list
= Z_PTR_P(zlist
))) {
253 #if PHP_RAPHF_DEBUG_PHANDLES
254 fprintf(stderr
, "LSTFIND: %p\n", list
);
259 if (create
&& (list
= php_persistent_handle_list_init(NULL
))) {
264 id
= zend_string_init(ident
->val
, ident
->len
, 1);
265 rv
= zend_symtable_update(&provider
->list
.free
, id
, &p
);
266 zend_string_release(id
);
269 #if PHP_RAPHF_DEBUG_PHANDLES
270 fprintf(stderr
, "LSTFIND: %p (new)\n", list
);
274 php_persistent_handle_list_free(&list
, provider
);
280 static int php_persistent_handle_apply_cleanup_all(zval
*p
, int argc
,
281 va_list argv
, zend_hash_key
*key
)
283 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
284 zend_string
*ident
= va_arg(argv
, zend_string
*);
285 php_persistent_handle_list_t
*list
;
287 if (ident
&& ident
->len
) {
288 if ((list
= php_persistent_handle_list_find(provider
, ident
, 0))) {
289 zend_hash_apply_with_argument(&list
->free
,
290 php_persistent_handle_apply_cleanup_ex
,
294 zend_hash_apply_with_argument(&provider
->list
.free
,
295 php_persistent_handle_apply_cleanup
, &provider
->rf
);
298 return ZEND_HASH_APPLY_KEEP
;
301 static void php_persistent_handle_hash_dtor(zval
*p
)
303 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
305 zend_hash_apply_with_argument(&provider
->list
.free
,
306 php_persistent_handle_list_apply_dtor
, provider
);
307 zend_hash_destroy(&provider
->list
.free
);
308 php_resource_factory_dtor(&provider
->rf
);
312 ZEND_RESULT_CODE
php_persistent_handle_provide(zend_string
*name
,
313 php_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *))
315 php_persistent_handle_provider_t
*provider
= pemalloc(sizeof(*provider
), 1);
317 if (php_persistent_handle_list_init(&provider
->list
)) {
318 if (php_resource_factory_init(&provider
->rf
, fops
, data
, dtor
)) {
322 #if PHP_RAPHF_DEBUG_PHANDLES
323 fprintf(stderr
, "PROVIDE: %p %s\n", PHP_RAPHF_G
, name_str
);
326 ZVAL_PTR(&p
, provider
);
327 ns
= zend_string_init(name
->val
, name
->len
, 1);
328 rv
= zend_symtable_update(&PHP_RAPHF_G
->persistent_handle
.hash
, ns
, &p
);
329 zend_string_release(ns
);
334 php_resource_factory_dtor(&provider
->rf
);
342 php_persistent_handle_factory_t
*php_persistent_handle_concede(
343 php_persistent_handle_factory_t
*a
,
344 zend_string
*name
, zend_string
*ident
,
345 php_persistent_handle_wakeup_t wakeup
,
346 php_persistent_handle_retire_t retire
)
348 zval
*zprovider
= zend_symtable_find(&PHP_RAPHF_G
->persistent_handle
.hash
, name
);
351 zend_bool free_a
= 0;
354 a
= emalloc(sizeof(*a
));
356 memset(a
, 0, sizeof(*a
));
358 a
->provider
= Z_PTR_P(zprovider
);
359 a
->ident
= zend_string_copy(ident
);
362 a
->free_on_abandon
= free_a
;
367 #if PHP_RAPHF_DEBUG_PHANDLES
368 fprintf(stderr
, "CONCEDE: %p %p (%s) (%s)\n", PHP_RAPHF_G
,
369 a
? a
->provider
: NULL
, name
->val
, ident
->val
);
375 void php_persistent_handle_abandon(php_persistent_handle_factory_t
*a
)
377 zend_bool f
= a
->free_on_abandon
;
379 #if PHP_RAPHF_DEBUG_PHANDLES
380 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
383 zend_string_release(a
->ident
);
384 memset(a
, 0, sizeof(*a
));
390 void *php_persistent_handle_acquire(php_persistent_handle_factory_t
*a
, void *init_arg
)
396 php_persistent_handle_list_t
*list
;
398 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
, 1);
400 zend_hash_internal_pointer_end(&list
->free
);
401 key
= zend_hash_get_current_key(&list
->free
, NULL
, &index
);
402 p
= zend_hash_get_current_data(&list
->free
);
403 if (p
&& HASH_KEY_NON_EXISTENT
!= key
) {
406 a
->wakeup(a
, &handle
);
408 zend_hash_index_del(&list
->free
, index
);
410 handle
= php_resource_factory_handle_ctor(&a
->provider
->rf
, init_arg
);
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
, void *handle
)
426 void *new_handle
= NULL
;
427 php_persistent_handle_list_t
*list
;
429 new_handle
= php_resource_factory_handle_copy(&a
->provider
->rf
, handle
);
431 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
, 1);
435 ++a
->provider
->list
.used
;
441 void php_persistent_handle_release(php_persistent_handle_factory_t
*a
, void *handle
)
443 php_persistent_handle_list_t
*list
;
445 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
, 1);
447 if (a
->provider
->list
.used
>= PHP_RAPHF_G
->persistent_handle
.limit
) {
448 #if PHP_RAPHF_DEBUG_PHANDLES
449 fprintf(stderr
, "DESTROY: %p\n", handle
);
451 php_resource_factory_handle_dtor(&a
->provider
->rf
, handle
);
454 a
->retire(a
, &handle
);
456 zend_hash_next_index_insert_ptr(&list
->free
, handle
);
459 --a
->provider
->list
.used
;
464 void php_persistent_handle_cleanup(zend_string
*name
, zend_string
*ident
)
466 php_persistent_handle_provider_t
*provider
;
467 php_persistent_handle_list_t
*list
;
470 zval
*zprovider
= zend_symtable_find(&PHP_RAPHF_G
->persistent_handle
.hash
,
473 if (zprovider
&& (provider
= Z_PTR_P(zprovider
))) {
475 list
= php_persistent_handle_list_find(provider
, ident
, 0);
477 zend_hash_apply_with_argument(&list
->free
,
478 php_persistent_handle_apply_cleanup_ex
,
482 zend_hash_apply_with_argument(&provider
->list
.free
,
483 php_persistent_handle_apply_cleanup
,
488 zend_hash_apply_with_arguments(
489 &PHP_RAPHF_G
->persistent_handle
.hash
,
490 php_persistent_handle_apply_cleanup_all
, 1, ident
);
494 HashTable
*php_persistent_handle_statall(HashTable
*ht
)
496 if (zend_hash_num_elements(&PHP_RAPHF_G
->persistent_handle
.hash
)) {
499 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
501 zend_hash_apply_with_arguments(
502 &PHP_RAPHF_G
->persistent_handle
.hash
,
503 php_persistent_handle_apply_statall
, 1, ht
);
511 static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops
= {
512 (php_resource_factory_handle_ctor_t
) php_persistent_handle_acquire
,
513 (php_resource_factory_handle_copy_t
) php_persistent_handle_accrete
,
514 (php_resource_factory_handle_dtor_t
) php_persistent_handle_release
517 php_resource_factory_ops_t
*php_persistent_handle_get_resource_factory_ops(void)
519 return &php_persistent_handle_resource_factory_ops
;
522 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles
, 0, 0, 0)
524 static PHP_FUNCTION(raphf_stat_persistent_handles
)
526 if (SUCCESS
== zend_parse_parameters_none()) {
527 object_init(return_value
);
528 if (php_persistent_handle_statall(HASH_OF(return_value
))) {
531 zval_dtor(return_value
);
536 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles
, 0, 0, 0)
537 ZEND_ARG_INFO(0, name
)
538 ZEND_ARG_INFO(0, ident
)
540 static PHP_FUNCTION(raphf_clean_persistent_handles
)
542 zend_string
*name
= NULL
, *ident
= NULL
;
544 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &name
, &ident
)) {
545 php_persistent_handle_cleanup(name
, ident
);
550 # include "php_raphf_test.c"
553 static const zend_function_entry raphf_functions
[] = {
554 ZEND_NS_FENTRY("raphf", stat_persistent_handles
,
555 ZEND_FN(raphf_stat_persistent_handles
),
556 ai_raphf_stat_persistent_handles
, 0)
557 ZEND_NS_FENTRY("raphf", clean_persistent_handles
,
558 ZEND_FN(raphf_clean_persistent_handles
),
559 ai_raphf_clean_persistent_handles
, 0)
561 ZEND_NS_FENTRY("raphf", provide
, ZEND_FN(raphf_provide
), NULL
, 0)
562 ZEND_NS_FENTRY("raphf", conceal
, ZEND_FN(raphf_conceal
), NULL
, 0)
563 ZEND_NS_FENTRY("raphf", concede
, ZEND_FN(raphf_concede
), NULL
, 0)
564 ZEND_NS_FENTRY("raphf", dispute
, ZEND_FN(raphf_dispute
), NULL
, 0)
565 ZEND_NS_FENTRY("raphf", handle_ctor
, ZEND_FN(raphf_handle_ctor
), NULL
, 0)
566 ZEND_NS_FENTRY("raphf", handle_copy
, ZEND_FN(raphf_handle_copy
), NULL
, 0)
567 ZEND_NS_FENTRY("raphf", handle_dtor
, ZEND_FN(raphf_handle_dtor
), NULL
, 0)
573 STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM
,
574 OnUpdateLong
, persistent_handle
.limit
, zend_raphf_globals
,
578 static HashTable
*php_persistent_handles_global_hash
;
580 static PHP_GINIT_FUNCTION(raphf
)
582 raphf_globals
->persistent_handle
.limit
= -1;
584 zend_hash_init(&raphf_globals
->persistent_handle
.hash
, 0, NULL
,
585 php_persistent_handle_hash_dtor
, 1);
586 if (php_persistent_handles_global_hash
) {
587 zend_hash_copy(&raphf_globals
->persistent_handle
.hash
,
588 php_persistent_handles_global_hash
, NULL
);
592 static PHP_GSHUTDOWN_FUNCTION(raphf
)
594 zend_hash_destroy(&raphf_globals
->persistent_handle
.hash
);
597 PHP_MINIT_FUNCTION(raphf
)
599 php_persistent_handles_global_hash
= &PHP_RAPHF_G
->persistent_handle
.hash
;
602 PHP_MINIT(raphf_test
)(INIT_FUNC_ARGS_PASSTHRU
);
605 REGISTER_INI_ENTRIES();
609 PHP_MSHUTDOWN_FUNCTION(raphf
)
612 PHP_MSHUTDOWN(raphf_test
)(SHUTDOWN_FUNC_ARGS_PASSTHRU
);
615 UNREGISTER_INI_ENTRIES();
616 php_persistent_handles_global_hash
= NULL
;
620 static int php_persistent_handle_apply_info_ex(zval
*p
, int argc
,
621 va_list argv
, zend_hash_key
*key
)
623 php_persistent_handle_list_t
*list
= Z_PTR_P(p
);
624 zend_hash_key
*super_key
= va_arg(argv
, zend_hash_key
*);
625 char used
[21], free
[21];
627 slprintf(used
, sizeof(used
), "%u", list
->used
);
628 slprintf(free
, sizeof(free
), "%d", zend_hash_num_elements(&list
->free
));
630 php_info_print_table_row(4, super_key
->key
->val
, key
->key
->val
, used
, free
);
632 return ZEND_HASH_APPLY_KEEP
;
635 static int php_persistent_handle_apply_info(zval
*p
, int argc
,
636 va_list argv
, zend_hash_key
*key
)
638 php_persistent_handle_provider_t
*provider
= Z_PTR_P(p
);
640 zend_hash_apply_with_arguments(&provider
->list
.free
,
641 php_persistent_handle_apply_info_ex
, 1, key
);
643 return ZEND_HASH_APPLY_KEEP
;
646 PHP_MINFO_FUNCTION(raphf
)
648 php_info_print_table_start();
649 php_info_print_table_header(2,
650 "Resource and persistent handle factory support", "enabled");
651 php_info_print_table_row(2, "Extension version", PHP_RAPHF_VERSION
);
652 php_info_print_table_end();
654 php_info_print_table_start();
655 php_info_print_table_colspan_header(4, "Persistent handles in this "
662 php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
663 zend_hash_apply_with_arguments(
664 &PHP_RAPHF_G
->persistent_handle
.hash
,
665 php_persistent_handle_apply_info
, 0);
666 php_info_print_table_end();
668 DISPLAY_INI_ENTRIES();
671 zend_module_entry raphf_module_entry
= {
672 STANDARD_MODULE_HEADER
,
676 PHP_MSHUTDOWN(raphf
),
681 ZEND_MODULE_GLOBALS(raphf
),
683 PHP_GSHUTDOWN(raphf
),
685 STANDARD_MODULE_PROPERTIES_EX
689 #ifdef COMPILE_DL_RAPHF
690 ZEND_GET_MODULE(raphf
)
698 * vim600: noet sw=4 ts=4 fdm=marker
699 * vim<600: noet sw=4 ts=4