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 #if PHP_VERSION_ID < 50500
49 #ifndef PHP_RAPHF_DEBUG_PHANDLES
50 # define PHP_RAPHF_DEBUG_PHANDLES 0
52 #if PHP_RAPHF_DEBUG_PHANDLES
57 php_resource_factory_t
*php_resource_factory_init(php_resource_factory_t
*f
,
58 php_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *data
))
61 f
= emalloc(sizeof(*f
));
63 memset(f
, 0, sizeof(*f
));
65 memcpy(&f
->fops
, fops
, sizeof(*fops
));
75 unsigned php_resource_factory_addref(php_resource_factory_t
*rf
)
77 return ++rf
->refcount
;
80 void php_resource_factory_dtor(php_resource_factory_t
*f
)
91 void php_resource_factory_free(php_resource_factory_t
**f
)
94 php_resource_factory_dtor(*f
);
95 if (!(*f
)->refcount
) {
102 void *php_resource_factory_handle_ctor(php_resource_factory_t
*f
,
103 void *init_arg TSRMLS_DC
)
106 return f
->fops
.ctor(f
->data
, init_arg TSRMLS_CC
);
111 void *php_resource_factory_handle_copy(php_resource_factory_t
*f
,
112 void *handle TSRMLS_DC
)
115 return f
->fops
.copy(f
->data
, handle TSRMLS_CC
);
120 void php_resource_factory_handle_dtor(php_resource_factory_t
*f
,
121 void *handle TSRMLS_DC
)
124 f
->fops
.dtor(f
->data
, handle TSRMLS_CC
);
128 php_resource_factory_t
*php_persistent_handle_resource_factory_init(
129 php_resource_factory_t
*a
, php_persistent_handle_factory_t
*pf
)
131 return php_resource_factory_init(a
,
132 php_persistent_handle_get_resource_factory_ops(), pf
,
133 (void(*)(void*)) php_persistent_handle_abandon
);
136 zend_bool
php_resource_factory_is_persistent(php_resource_factory_t
*a
)
138 return a
->dtor
== (void(*)(void *)) php_persistent_handle_abandon
;
142 static inline php_persistent_handle_list_t
*php_persistent_handle_list_init(
143 php_persistent_handle_list_t
*list
)
147 if ((free_list
= !list
)) {
148 list
= pemalloc(sizeof(php_persistent_handle_list_t
), 1);
153 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
163 static int php_persistent_handle_apply_stat(void *p TSRMLS_DC
, int argc
,
164 va_list argv
, zend_hash_key
*key
)
166 php_persistent_handle_list_t
**list
= p
;
167 zval
*zsubentry
, *zentry
= va_arg(argv
, zval
*);
169 MAKE_STD_ZVAL(zsubentry
);
170 array_init(zsubentry
);
171 add_assoc_long_ex(zsubentry
, ZEND_STRS("used"), (*list
)->used
);
172 add_assoc_long_ex(zsubentry
, ZEND_STRS("free"),
173 zend_hash_num_elements(&(*list
)->free
));
174 add_assoc_zval_ex(zentry
, key
->arKey
, key
->nKeyLength
, zsubentry
);
176 return ZEND_HASH_APPLY_KEEP
;
179 static int php_persistent_handle_apply_statall(void *p TSRMLS_DC
, int argc
,
180 va_list argv
, zend_hash_key
*key
)
182 php_persistent_handle_provider_t
*provider
= p
;
183 HashTable
*ht
= va_arg(argv
, HashTable
*);
186 MAKE_STD_ZVAL(zentry
);
189 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
190 php_persistent_handle_apply_stat
, 1, zentry
);
191 zend_symtable_update(ht
, key
->arKey
, key
->nKeyLength
, &zentry
,
192 sizeof(zval
*), NULL
);
194 return ZEND_HASH_APPLY_KEEP
;
197 static int php_persistent_handle_apply_cleanup_ex(void *pp
, void *arg TSRMLS_DC
)
199 php_resource_factory_t
*rf
= arg
;
202 #if PHP_RAPHF_DEBUG_PHANDLES
203 fprintf(stderr
, "DESTROY: %p\n", *handle
);
205 php_resource_factory_handle_dtor(rf
, *handle TSRMLS_CC
);
206 return ZEND_HASH_APPLY_REMOVE
;
209 static int php_persistent_handle_apply_cleanup(void *pp
, void *arg TSRMLS_DC
)
211 php_resource_factory_t
*rf
= arg
;
212 php_persistent_handle_list_t
**listp
= pp
;
214 zend_hash_apply_with_argument(&(*listp
)->free
,
215 php_persistent_handle_apply_cleanup_ex
, rf TSRMLS_CC
);
216 if ((*listp
)->used
) {
217 return ZEND_HASH_APPLY_KEEP
;
219 zend_hash_destroy(&(*listp
)->free
);
220 #if PHP_RAPHF_DEBUG_PHANDLES
221 fprintf(stderr
, "LSTFREE: %p\n", *listp
);
225 return ZEND_HASH_APPLY_REMOVE
;
228 static inline void php_persistent_handle_list_dtor(
229 php_persistent_handle_list_t
*list
,
230 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
232 #if PHP_RAPHF_DEBUG_PHANDLES
233 fprintf(stderr
, "LSTDTOR: %p\n", list
);
235 zend_hash_apply_with_argument(&list
->free
,
236 php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
237 zend_hash_destroy(&list
->free
);
240 static inline void php_persistent_handle_list_free(
241 php_persistent_handle_list_t
**list
,
242 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
244 php_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
245 #if PHP_RAPHF_DEBUG_PHANDLES
246 fprintf(stderr
, "LSTFREE: %p\n", *list
);
252 static int php_persistent_handle_list_apply_dtor(void *listp
,
253 void *provider TSRMLS_DC
)
255 php_persistent_handle_list_free(listp
, provider TSRMLS_CC
);
256 return ZEND_HASH_APPLY_REMOVE
;
259 static inline php_persistent_handle_list_t
*php_persistent_handle_list_find(
260 php_persistent_handle_provider_t
*provider
, const char *ident_str
,
261 size_t ident_len TSRMLS_DC
)
263 php_persistent_handle_list_t
**list
, *new_list
;
264 ZEND_RESULT_CODE rv
= zend_symtable_find(&provider
->list
.free
, ident_str
,
265 ident_len
+ 1, (void *) &list
);
268 #if PHP_RAPHF_DEBUG_PHANDLES
269 fprintf(stderr
, "LSTFIND: %p\n", *list
);
274 if ((new_list
= php_persistent_handle_list_init(NULL
))) {
275 rv
= zend_symtable_update(&provider
->list
.free
, ident_str
, ident_len
+1,
276 (void *) &new_list
, sizeof(php_persistent_handle_list_t
*),
279 #if PHP_RAPHF_DEBUG_PHANDLES
280 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
284 php_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
290 static int php_persistent_handle_apply_cleanup_all(void *p TSRMLS_DC
, int argc
,
291 va_list argv
, zend_hash_key
*key
)
293 php_persistent_handle_provider_t
*provider
= p
;
294 const char *ident_str
= va_arg(argv
, const char *);
295 size_t ident_len
= va_arg(argv
, size_t);
296 php_persistent_handle_list_t
*list
;
298 if (ident_str
&& ident_len
) {
299 if ((list
= php_persistent_handle_list_find(provider
, ident_str
,
300 ident_len TSRMLS_CC
))) {
301 zend_hash_apply_with_argument(&list
->free
,
302 php_persistent_handle_apply_cleanup_ex
,
303 &provider
->rf TSRMLS_CC
);
306 zend_hash_apply_with_argument(&provider
->list
.free
,
307 php_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
310 return ZEND_HASH_APPLY_KEEP
;
313 static void php_persistent_handle_hash_dtor(void *p
)
315 php_persistent_handle_provider_t
*provider
;
318 provider
= (php_persistent_handle_provider_t
*) p
;
319 zend_hash_apply_with_argument(&provider
->list
.free
,
320 php_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
321 zend_hash_destroy(&provider
->list
.free
);
322 php_resource_factory_dtor(&provider
->rf
);
325 PHP_RAPHF_API ZEND_RESULT_CODE
php_persistent_handle_provide(const char *name_str
,
326 size_t name_len
, php_resource_factory_ops_t
*fops
, void *data
,
327 void (*dtor
)(void *) TSRMLS_DC
)
329 ZEND_RESULT_CODE status
= FAILURE
;
330 php_persistent_handle_provider_t provider
;
332 if (php_persistent_handle_list_init(&provider
.list
)) {
333 if (php_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
334 #if PHP_RAPHF_DEBUG_PHANDLES
335 fprintf(stderr
, "PROVIDE: %p %s\n", PHP_RAPHF_G
, name_str
);
338 status
= zend_symtable_update(&PHP_RAPHF_G
->persistent_handle
.hash
,
339 name_str
, name_len
+1, (void *) &provider
,
340 sizeof(php_persistent_handle_provider_t
), NULL
);
341 if (SUCCESS
!= status
) {
342 php_resource_factory_dtor(&provider
.rf
);
350 php_persistent_handle_factory_t
*php_persistent_handle_concede(
351 php_persistent_handle_factory_t
*a
, const char *name_str
,
352 size_t name_len
, const char *ident_str
, size_t ident_len
,
353 php_persistent_handle_wakeup_t wakeup
,
354 php_persistent_handle_retire_t retire TSRMLS_DC
)
356 ZEND_RESULT_CODE status
= FAILURE
;
357 php_persistent_handle_factory_t
*free_a
= NULL
;
360 free_a
= a
= emalloc(sizeof(*a
));
362 memset(a
, 0, sizeof(*a
));
364 status
= zend_symtable_find(&PHP_RAPHF_G
->persistent_handle
.hash
, name_str
,
365 name_len
+1, (void *) &a
->provider
);
367 if (SUCCESS
== status
) {
368 a
->ident
.str
= estrndup(ident_str
, ident_len
);
369 a
->ident
.len
= ident_len
;
375 a
->free_on_abandon
= 1;
384 #if PHP_RAPHF_DEBUG_PHANDLES
385 fprintf(stderr
, "CONCEDE: %p %p (%s) (%s)\n", PHP_RAPHF_G
,
386 a
? a
->provider
: NULL
, name_str
, ident_str
);
392 PHP_RAPHF_API
void php_persistent_handle_abandon(
393 php_persistent_handle_factory_t
*a
)
395 zend_bool f
= a
->free_on_abandon
;
397 #if PHP_RAPHF_DEBUG_PHANDLES
398 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
401 STR_FREE(a
->ident
.str
);
402 memset(a
, 0, sizeof(*a
));
408 void *php_persistent_handle_acquire(
409 php_persistent_handle_factory_t
*a
, void *init_arg TSRMLS_DC
)
414 void **handle_ptr
, *handle
= NULL
;
415 php_persistent_handle_list_t
*list
;
417 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
418 a
->ident
.len TSRMLS_CC
);
420 zend_hash_internal_pointer_end(&list
->free
);
421 key
= zend_hash_get_current_key(&list
->free
, NULL
, &index
, 0);
422 rv
= zend_hash_get_current_data(&list
->free
, (void *) &handle_ptr
);
423 if (HASH_KEY_NON_EXISTANT
!= key
&& SUCCESS
== rv
) {
424 handle
= *handle_ptr
;
426 a
->wakeup(a
, &handle TSRMLS_CC
);
428 zend_hash_index_del(&list
->free
, index
);
430 handle
= php_resource_factory_handle_ctor(&a
->provider
->rf
,
433 #if PHP_RAPHF_DEBUG_PHANDLES
434 fprintf(stderr
, "CREATED: %p\n", *handle
);
437 ++a
->provider
->list
.used
;
445 void *php_persistent_handle_accrete(
446 php_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
448 void *new_handle
= NULL
;
449 php_persistent_handle_list_t
*list
;
451 new_handle
= php_resource_factory_handle_copy(&a
->provider
->rf
,
454 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
455 a
->ident
.len TSRMLS_CC
);
459 ++a
->provider
->list
.used
;
465 void php_persistent_handle_release(
466 php_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
468 php_persistent_handle_list_t
*list
;
470 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
471 a
->ident
.len TSRMLS_CC
);
473 if (a
->provider
->list
.used
>= PHP_RAPHF_G
->persistent_handle
.limit
) {
474 #if PHP_RAPHF_DEBUG_PHANDLES
475 fprintf(stderr
, "DESTROY: %p\n", *handle
);
477 php_resource_factory_handle_dtor(&a
->provider
->rf
,
481 a
->retire(a
, &handle TSRMLS_CC
);
483 zend_hash_next_index_insert(&list
->free
, (void *) &handle
,
484 sizeof(void *), NULL
);
487 --a
->provider
->list
.used
;
492 void php_persistent_handle_cleanup(const char *name_str
, size_t name_len
,
493 const char *ident_str
, size_t ident_len TSRMLS_DC
)
495 php_persistent_handle_provider_t
*provider
;
496 php_persistent_handle_list_t
*list
;
499 if (name_str
&& name_len
) {
500 rv
= zend_symtable_find(&PHP_RAPHF_G
->persistent_handle
.hash
, name_str
,
501 name_len
+1, (void *) &provider
);
504 if (ident_str
&& ident_len
) {
505 list
= php_persistent_handle_list_find(provider
, ident_str
,
506 ident_len TSRMLS_CC
);
508 zend_hash_apply_with_argument(&list
->free
,
509 php_persistent_handle_apply_cleanup_ex
,
510 &provider
->rf TSRMLS_CC
);
513 zend_hash_apply_with_argument(&provider
->list
.free
,
514 php_persistent_handle_apply_cleanup
,
515 &provider
->rf TSRMLS_CC
);
519 zend_hash_apply_with_arguments(
520 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
521 php_persistent_handle_apply_cleanup_all
, 2, ident_str
,
526 HashTable
*php_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
528 if (zend_hash_num_elements(&PHP_RAPHF_G
->persistent_handle
.hash
)) {
531 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
533 zend_hash_apply_with_arguments(
534 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
535 php_persistent_handle_apply_statall
, 1, ht
);
543 static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops
= {
544 (php_resource_factory_handle_ctor_t
) php_persistent_handle_acquire
,
545 (php_resource_factory_handle_copy_t
) php_persistent_handle_accrete
,
546 (php_resource_factory_handle_dtor_t
) php_persistent_handle_release
549 php_resource_factory_ops_t
*php_persistent_handle_get_resource_factory_ops(void)
551 return &php_persistent_handle_resource_factory_ops
;
554 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles
, 0, 0, 0)
556 static PHP_FUNCTION(raphf_stat_persistent_handles
)
558 if (SUCCESS
== zend_parse_parameters_none()) {
559 object_init(return_value
);
560 if (php_persistent_handle_statall(HASH_OF(return_value
) TSRMLS_CC
)) {
563 zval_dtor(return_value
);
568 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles
, 0, 0, 0)
569 ZEND_ARG_INFO(0, name
)
570 ZEND_ARG_INFO(0, ident
)
572 static PHP_FUNCTION(raphf_clean_persistent_handles
)
574 char *name_str
= NULL
, *ident_str
= NULL
;
575 int name_len
= 0, ident_len
= 0;
577 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!s!",
578 &name_str
, &name_len
, &ident_str
, &ident_len
)) {
579 php_persistent_handle_cleanup(name_str
, name_len
, ident_str
,
580 ident_len TSRMLS_CC
);
584 static const zend_function_entry raphf_functions
[] = {
585 ZEND_NS_FENTRY("raphf", stat_persistent_handles
,
586 ZEND_FN(raphf_stat_persistent_handles
),
587 ai_raphf_stat_persistent_handles
, 0)
588 ZEND_NS_FENTRY("raphf", clean_persistent_handles
,
589 ZEND_FN(raphf_clean_persistent_handles
),
590 ai_raphf_clean_persistent_handles
, 0)
595 STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM
,
596 OnUpdateLong
, persistent_handle
.limit
, zend_raphf_globals
,
600 static HashTable
*php_persistent_handles_global_hash
;
602 static PHP_GINIT_FUNCTION(raphf
)
604 raphf_globals
->persistent_handle
.limit
= -1;
606 zend_hash_init(&raphf_globals
->persistent_handle
.hash
, 0, NULL
,
607 php_persistent_handle_hash_dtor
, 1);
608 if (php_persistent_handles_global_hash
) {
609 zend_hash_copy(&raphf_globals
->persistent_handle
.hash
,
610 php_persistent_handles_global_hash
, NULL
, NULL
,
611 sizeof(php_persistent_handle_provider_t
));
615 static PHP_GSHUTDOWN_FUNCTION(raphf
)
617 zend_hash_destroy(&raphf_globals
->persistent_handle
.hash
);
620 PHP_MINIT_FUNCTION(raphf
)
622 php_persistent_handles_global_hash
= &PHP_RAPHF_G
->persistent_handle
.hash
;
623 REGISTER_INI_ENTRIES();
627 PHP_MSHUTDOWN_FUNCTION(raphf
)
629 UNREGISTER_INI_ENTRIES();
630 php_persistent_handles_global_hash
= NULL
;
634 static int php_persistent_handle_apply_info_ex(void *p TSRMLS_DC
, int argc
,
635 va_list argv
, zend_hash_key
*key
)
637 php_persistent_handle_list_t
**list
= p
;
638 zend_hash_key
*super_key
= va_arg(argv
, zend_hash_key
*);
639 char used
[21], free
[21];
641 slprintf(used
, sizeof(used
), "%u", (*list
)->used
);
642 slprintf(free
, sizeof(free
), "%d", zend_hash_num_elements(&(*list
)->free
));
644 php_info_print_table_row(4, super_key
->arKey
, key
->arKey
, used
, free
);
646 return ZEND_HASH_APPLY_KEEP
;
649 static int php_persistent_handle_apply_info(void *p TSRMLS_DC
, int argc
,
650 va_list argv
, zend_hash_key
*key
)
652 php_persistent_handle_provider_t
*provider
= p
;
654 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
655 php_persistent_handle_apply_info_ex
, 1, key
);
657 return ZEND_HASH_APPLY_KEEP
;
660 PHP_MINFO_FUNCTION(raphf
)
662 php_info_print_table_start();
663 php_info_print_table_header(2,
664 "Resource and persistent handle factory support", "enabled");
665 php_info_print_table_row(2, "Extension version", PHP_RAPHF_VERSION
);
666 php_info_print_table_end();
668 php_info_print_table_start();
669 php_info_print_table_colspan_header(4, "Persistent handles in this "
676 php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
677 zend_hash_apply_with_arguments(
678 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
679 php_persistent_handle_apply_info
, 0);
680 php_info_print_table_end();
682 DISPLAY_INI_ENTRIES();
685 zend_module_entry raphf_module_entry
= {
686 STANDARD_MODULE_HEADER
,
690 PHP_MSHUTDOWN(raphf
),
695 ZEND_MODULE_GLOBALS(raphf
),
697 PHP_GSHUTDOWN(raphf
),
699 STANDARD_MODULE_PROPERTIES_EX
703 #ifdef COMPILE_DL_RAPHF
704 ZEND_GET_MODULE(raphf
)
713 * vim600: noet sw=4 ts=4 fdm=marker
714 * vim<600: noet sw=4 ts=4