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 static inline php_persistent_handle_list_t
*php_persistent_handle_list_init(
129 php_persistent_handle_list_t
*list
)
133 if ((free_list
= !list
)) {
134 list
= pemalloc(sizeof(php_persistent_handle_list_t
), 1);
139 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
149 static int php_persistent_handle_apply_stat(void *p TSRMLS_DC
, int argc
,
150 va_list argv
, zend_hash_key
*key
)
152 php_persistent_handle_list_t
**list
= p
;
153 zval
*zsubentry
, *zentry
= va_arg(argv
, zval
*);
155 MAKE_STD_ZVAL(zsubentry
);
156 array_init(zsubentry
);
157 add_assoc_long_ex(zsubentry
, ZEND_STRS("used"), (*list
)->used
);
158 add_assoc_long_ex(zsubentry
, ZEND_STRS("free"),
159 zend_hash_num_elements(&(*list
)->free
));
160 add_assoc_zval_ex(zentry
, key
->arKey
, key
->nKeyLength
, zsubentry
);
162 return ZEND_HASH_APPLY_KEEP
;
165 static int php_persistent_handle_apply_statall(void *p TSRMLS_DC
, int argc
,
166 va_list argv
, zend_hash_key
*key
)
168 php_persistent_handle_provider_t
*provider
= p
;
169 HashTable
*ht
= va_arg(argv
, HashTable
*);
172 MAKE_STD_ZVAL(zentry
);
175 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
176 php_persistent_handle_apply_stat
, 1, zentry
);
177 zend_symtable_update(ht
, key
->arKey
, key
->nKeyLength
, &zentry
,
178 sizeof(zval
*), NULL
);
180 return ZEND_HASH_APPLY_KEEP
;
183 static int php_persistent_handle_apply_cleanup_ex(void *pp
, void *arg TSRMLS_DC
)
185 php_resource_factory_t
*rf
= arg
;
188 #if PHP_RAPHF_DEBUG_PHANDLES
189 fprintf(stderr
, "DESTROY: %p\n", *handle
);
191 php_resource_factory_handle_dtor(rf
, *handle TSRMLS_CC
);
192 return ZEND_HASH_APPLY_REMOVE
;
195 static int php_persistent_handle_apply_cleanup(void *pp
, void *arg TSRMLS_DC
)
197 php_resource_factory_t
*rf
= arg
;
198 php_persistent_handle_list_t
**listp
= pp
;
200 zend_hash_apply_with_argument(&(*listp
)->free
,
201 php_persistent_handle_apply_cleanup_ex
, rf TSRMLS_CC
);
202 if ((*listp
)->used
) {
203 return ZEND_HASH_APPLY_KEEP
;
205 zend_hash_destroy(&(*listp
)->free
);
206 #if PHP_RAPHF_DEBUG_PHANDLES
207 fprintf(stderr
, "LSTFREE: %p\n", *listp
);
211 return ZEND_HASH_APPLY_REMOVE
;
214 static inline void php_persistent_handle_list_dtor(
215 php_persistent_handle_list_t
*list
,
216 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
218 #if PHP_RAPHF_DEBUG_PHANDLES
219 fprintf(stderr
, "LSTDTOR: %p\n", list
);
221 zend_hash_apply_with_argument(&list
->free
,
222 php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
223 zend_hash_destroy(&list
->free
);
226 static inline void php_persistent_handle_list_free(
227 php_persistent_handle_list_t
**list
,
228 php_persistent_handle_provider_t
*provider TSRMLS_DC
)
230 php_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
231 #if PHP_RAPHF_DEBUG_PHANDLES
232 fprintf(stderr
, "LSTFREE: %p\n", *list
);
238 static int php_persistent_handle_list_apply_dtor(void *listp
,
239 void *provider TSRMLS_DC
)
241 php_persistent_handle_list_free(listp
, provider TSRMLS_CC
);
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
, const char *ident_str
,
247 size_t ident_len TSRMLS_DC
)
249 php_persistent_handle_list_t
**list
, *new_list
;
250 ZEND_RESULT_CODE rv
= zend_symtable_find(&provider
->list
.free
, ident_str
,
251 ident_len
+ 1, (void *) &list
);
254 #if PHP_RAPHF_DEBUG_PHANDLES
255 fprintf(stderr
, "LSTFIND: %p\n", *list
);
260 if ((new_list
= php_persistent_handle_list_init(NULL
))) {
261 rv
= zend_symtable_update(&provider
->list
.free
, ident_str
, ident_len
+1,
262 (void *) &new_list
, sizeof(php_persistent_handle_list_t
*),
265 #if PHP_RAPHF_DEBUG_PHANDLES
266 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
270 php_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
276 static int php_persistent_handle_apply_cleanup_all(void *p TSRMLS_DC
, int argc
,
277 va_list argv
, zend_hash_key
*key
)
279 php_persistent_handle_provider_t
*provider
= p
;
280 const char *ident_str
= va_arg(argv
, const char *);
281 size_t ident_len
= va_arg(argv
, size_t);
282 php_persistent_handle_list_t
*list
;
284 if (ident_str
&& ident_len
) {
285 if ((list
= php_persistent_handle_list_find(provider
, ident_str
,
286 ident_len TSRMLS_CC
))) {
287 zend_hash_apply_with_argument(&list
->free
,
288 php_persistent_handle_apply_cleanup_ex
,
289 &provider
->rf TSRMLS_CC
);
292 zend_hash_apply_with_argument(&provider
->list
.free
,
293 php_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
296 return ZEND_HASH_APPLY_KEEP
;
299 static void php_persistent_handle_hash_dtor(void *p
)
301 php_persistent_handle_provider_t
*provider
;
304 provider
= (php_persistent_handle_provider_t
*) p
;
305 zend_hash_apply_with_argument(&provider
->list
.free
,
306 php_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
307 zend_hash_destroy(&provider
->list
.free
);
308 php_resource_factory_dtor(&provider
->rf
);
311 PHP_RAPHF_API ZEND_RESULT_CODE
php_persistent_handle_provide(const char *name_str
,
312 size_t name_len
, php_resource_factory_ops_t
*fops
, void *data
,
313 void (*dtor
)(void *) TSRMLS_DC
)
315 ZEND_RESULT_CODE status
= FAILURE
;
316 php_persistent_handle_provider_t provider
;
318 if (php_persistent_handle_list_init(&provider
.list
)) {
319 if (php_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
320 #if PHP_RAPHF_DEBUG_PHANDLES
321 fprintf(stderr
, "PROVIDE: %p %s\n", PHP_RAPHF_G
, name_str
);
324 status
= zend_symtable_update(&PHP_RAPHF_G
->persistent_handle
.hash
,
325 name_str
, name_len
+1, (void *) &provider
,
326 sizeof(php_persistent_handle_provider_t
), NULL
);
327 if (SUCCESS
!= status
) {
328 php_resource_factory_dtor(&provider
.rf
);
336 php_persistent_handle_factory_t
*php_persistent_handle_concede(
337 php_persistent_handle_factory_t
*a
, const char *name_str
,
338 size_t name_len
, const char *ident_str
, size_t ident_len
,
339 php_persistent_handle_wakeup_t wakeup
,
340 php_persistent_handle_retire_t retire TSRMLS_DC
)
342 ZEND_RESULT_CODE status
= FAILURE
;
343 php_persistent_handle_factory_t
*free_a
= NULL
;
346 free_a
= a
= emalloc(sizeof(*a
));
348 memset(a
, 0, sizeof(*a
));
350 status
= zend_symtable_find(&PHP_RAPHF_G
->persistent_handle
.hash
, name_str
,
351 name_len
+1, (void *) &a
->provider
);
353 if (SUCCESS
== status
) {
354 a
->ident
.str
= estrndup(ident_str
, ident_len
);
355 a
->ident
.len
= ident_len
;
361 a
->free_on_abandon
= 1;
370 #if PHP_RAPHF_DEBUG_PHANDLES
371 fprintf(stderr
, "CONCEDE: %p %p (%s) (%s)\n", PHP_RAPHF_G
,
372 a
? a
->provider
: NULL
, name_str
, ident_str
);
378 PHP_RAPHF_API
void php_persistent_handle_abandon(
379 php_persistent_handle_factory_t
*a
)
381 zend_bool f
= a
->free_on_abandon
;
383 #if PHP_RAPHF_DEBUG_PHANDLES
384 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
387 STR_FREE(a
->ident
.str
);
388 memset(a
, 0, sizeof(*a
));
394 void *php_persistent_handle_acquire(
395 php_persistent_handle_factory_t
*a
, void *init_arg TSRMLS_DC
)
400 void **handle_ptr
, *handle
= NULL
;
401 php_persistent_handle_list_t
*list
;
403 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
404 a
->ident
.len TSRMLS_CC
);
406 zend_hash_internal_pointer_end(&list
->free
);
407 key
= zend_hash_get_current_key(&list
->free
, NULL
, &index
, 0);
408 rv
= zend_hash_get_current_data(&list
->free
, (void *) &handle_ptr
);
409 if (HASH_KEY_NON_EXISTANT
!= key
&& SUCCESS
== rv
) {
410 handle
= *handle_ptr
;
412 a
->wakeup(a
, &handle TSRMLS_CC
);
414 zend_hash_index_del(&list
->free
, index
);
416 handle
= php_resource_factory_handle_ctor(&a
->provider
->rf
,
419 #if PHP_RAPHF_DEBUG_PHANDLES
420 fprintf(stderr
, "CREATED: %p\n", *handle
);
423 ++a
->provider
->list
.used
;
431 void *php_persistent_handle_accrete(
432 php_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
434 void *new_handle
= NULL
;
435 php_persistent_handle_list_t
*list
;
437 new_handle
= php_resource_factory_handle_copy(&a
->provider
->rf
,
440 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
441 a
->ident
.len TSRMLS_CC
);
445 ++a
->provider
->list
.used
;
451 void php_persistent_handle_release(
452 php_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
454 php_persistent_handle_list_t
*list
;
456 list
= php_persistent_handle_list_find(a
->provider
, a
->ident
.str
,
457 a
->ident
.len TSRMLS_CC
);
459 if (a
->provider
->list
.used
>= PHP_RAPHF_G
->persistent_handle
.limit
) {
460 #if PHP_RAPHF_DEBUG_PHANDLES
461 fprintf(stderr
, "DESTROY: %p\n", *handle
);
463 php_resource_factory_handle_dtor(&a
->provider
->rf
,
467 a
->retire(a
, &handle TSRMLS_CC
);
469 zend_hash_next_index_insert(&list
->free
, (void *) &handle
,
470 sizeof(void *), NULL
);
473 --a
->provider
->list
.used
;
478 void php_persistent_handle_cleanup(const char *name_str
, size_t name_len
,
479 const char *ident_str
, size_t ident_len TSRMLS_DC
)
481 php_persistent_handle_provider_t
*provider
;
482 php_persistent_handle_list_t
*list
;
485 if (name_str
&& name_len
) {
486 rv
= zend_symtable_find(&PHP_RAPHF_G
->persistent_handle
.hash
, name_str
,
487 name_len
+1, (void *) &provider
);
490 if (ident_str
&& ident_len
) {
491 list
= php_persistent_handle_list_find(provider
, ident_str
,
492 ident_len TSRMLS_CC
);
494 zend_hash_apply_with_argument(&list
->free
,
495 php_persistent_handle_apply_cleanup_ex
,
496 &provider
->rf TSRMLS_CC
);
499 zend_hash_apply_with_argument(&provider
->list
.free
,
500 php_persistent_handle_apply_cleanup
,
501 &provider
->rf TSRMLS_CC
);
505 zend_hash_apply_with_arguments(
506 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
507 php_persistent_handle_apply_cleanup_all
, 2, ident_str
,
512 HashTable
*php_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
514 if (zend_hash_num_elements(&PHP_RAPHF_G
->persistent_handle
.hash
)) {
517 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
519 zend_hash_apply_with_arguments(
520 &PHP_RAPHF_G
->persistent_handle
.hash TSRMLS_CC
,
521 php_persistent_handle_apply_statall
, 1, ht
);
529 static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops
= {
530 (php_resource_factory_handle_ctor_t
) php_persistent_handle_acquire
,
531 (php_resource_factory_handle_copy_t
) php_persistent_handle_accrete
,
532 (php_resource_factory_handle_dtor_t
) php_persistent_handle_release
535 php_resource_factory_ops_t
*php_persistent_handle_get_resource_factory_ops(void)
537 return &php_persistent_handle_resource_factory_ops
;
540 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles
, 0, 0, 0)
542 static PHP_FUNCTION(raphf_stat_persistent_handles
)
544 if (SUCCESS
== zend_parse_parameters_none()) {
545 object_init(return_value
);
546 if (php_persistent_handle_statall(HASH_OF(return_value
) TSRMLS_CC
)) {
549 zval_dtor(return_value
);
554 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles
, 0, 0, 0)
555 ZEND_ARG_INFO(0, name
)
556 ZEND_ARG_INFO(0, ident
)
558 static PHP_FUNCTION(raphf_clean_persistent_handles
)
560 char *name_str
= NULL
, *ident_str
= NULL
;
561 int name_len
= 0, ident_len
= 0;
563 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!s!",
564 &name_str
, &name_len
, &ident_str
, &ident_len
)) {
565 php_persistent_handle_cleanup(name_str
, name_len
, ident_str
,
566 ident_len TSRMLS_CC
);
570 static const zend_function_entry raphf_functions
[] = {
571 ZEND_NS_FENTRY("raphf", stat_persistent_handles
,
572 ZEND_FN(raphf_stat_persistent_handles
),
573 ai_raphf_stat_persistent_handles
, 0)
574 ZEND_NS_FENTRY("raphf", clean_persistent_handles
,
575 ZEND_FN(raphf_clean_persistent_handles
),
576 ai_raphf_clean_persistent_handles
, 0)
581 STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM
,
582 OnUpdateLong
, persistent_handle
.limit
, zend_raphf_globals
,
586 static HashTable
*php_persistent_handles_global_hash
;
588 static PHP_GINIT_FUNCTION(raphf
)
590 raphf_globals
->persistent_handle
.limit
= -1;
592 zend_hash_init(&raphf_globals
->persistent_handle
.hash
, 0, NULL
,
593 php_persistent_handle_hash_dtor
, 1);
594 if (php_persistent_handles_global_hash
) {
595 zend_hash_copy(&raphf_globals
->persistent_handle
.hash
,
596 php_persistent_handles_global_hash
, NULL
, NULL
,
597 sizeof(php_persistent_handle_provider_t
));
601 static PHP_GSHUTDOWN_FUNCTION(raphf
)
603 zend_hash_destroy(&raphf_globals
->persistent_handle
.hash
);
606 PHP_MINIT_FUNCTION(raphf
)
608 php_persistent_handles_global_hash
= &PHP_RAPHF_G
->persistent_handle
.hash
;
609 REGISTER_INI_ENTRIES();
613 PHP_MSHUTDOWN_FUNCTION(raphf
)
615 UNREGISTER_INI_ENTRIES();
616 php_persistent_handles_global_hash
= NULL
;
620 static int php_persistent_handle_apply_info_ex(void *p TSRMLS_DC
, int argc
,
621 va_list argv
, zend_hash_key
*key
)
623 php_persistent_handle_list_t
**list
= 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
->arKey
, key
->arKey
, used
, free
);
632 return ZEND_HASH_APPLY_KEEP
;
635 static int php_persistent_handle_apply_info(void *p TSRMLS_DC
, int argc
,
636 va_list argv
, zend_hash_key
*key
)
638 php_persistent_handle_provider_t
*provider
= p
;
640 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
,
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 TSRMLS_CC
,
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
)
699 * vim600: noet sw=4 ts=4 fdm=marker
700 * vim<600: noet sw=4 ts=4