2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2012 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 +----------------------------------------------------------------------+
27 #include "ext/standard/info.h"
28 #include "php_raphf.h"
30 ZEND_DECLARE_MODULE_GLOBALS(raphf
)
34 #ifndef PHP_RAPHF_DEBUG_PHANDLES
35 # define PHP_RAPHF_DEBUG_PHANDLES 0
37 #if PHP_RAPHF_DEBUG_PHANDLES
42 static HashTable php_persistent_handle_hash
;
45 # define LOCK() tsrm_mutex_lock(php_persistent_handle_lock)
46 # define UNLOCK() tsrm_mutex_unlock(php_persistent_handle_lock)
47 static MUTEX_T php_persistent_handle_lock
;
53 typedef struct php_persistent_handle_list
{
56 } php_persistent_handle_list_t
;
58 typedef struct php_persistent_handle_provider
{
59 php_persistent_handle_list_t list
; /* "ident" => array(handles) entries */
60 php_resource_factory_t rf
;
61 } php_persistent_handle_provider_t
;
64 PHP_RAPHF_API php_resource_factory_t
*php_resource_factory_init(php_resource_factory_t
*f
, php_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *data
))
67 f
= emalloc(sizeof(*f
));
69 memset(f
, 0, sizeof(*f
));
71 memcpy(&f
->fops
, fops
, sizeof(*fops
));
81 PHP_RAPHF_API
unsigned php_resource_factory_addref(php_resource_factory_t
*rf
)
83 return ++rf
->refcount
;
86 PHP_RAPHF_API
void php_resource_factory_dtor(php_resource_factory_t
*f
)
97 PHP_RAPHF_API
void php_resource_factory_free(php_resource_factory_t
**f
)
100 php_resource_factory_dtor(*f
);
101 if (!(*f
)->refcount
) {
108 PHP_RAPHF_API
void *php_resource_factory_handle_ctor(php_resource_factory_t
*f
, void *init_arg TSRMLS_DC
)
111 return f
->fops
.ctor(f
->data
, init_arg TSRMLS_CC
);
116 PHP_RAPHF_API
void *php_resource_factory_handle_copy(php_resource_factory_t
*f
, void *handle TSRMLS_DC
)
119 return f
->fops
.copy(f
->data
, handle TSRMLS_CC
);
124 PHP_RAPHF_API
void php_resource_factory_handle_dtor(php_resource_factory_t
*f
, void *handle TSRMLS_DC
)
127 f
->fops
.dtor(f
->data
, handle TSRMLS_CC
);
131 static inline php_persistent_handle_list_t
*php_persistent_handle_list_init(php_persistent_handle_list_t
*list
)
135 if ((free_list
= !list
)) {
136 list
= pemalloc(sizeof(php_persistent_handle_list_t
), 1);
141 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
151 static int php_persistent_handle_apply_stat(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
153 php_persistent_handle_list_t
**list
= p
;
154 zval
*zsubentry
, *zentry
= va_arg(argv
, zval
*);
156 MAKE_STD_ZVAL(zsubentry
);
157 array_init(zsubentry
);
158 add_assoc_long_ex(zsubentry
, ZEND_STRS("used"), (*list
)->used
);
159 add_assoc_long_ex(zsubentry
, ZEND_STRS("free"), 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
, va_list argv
, zend_hash_key
*key
)
167 php_persistent_handle_provider_t
*provider
= p
;
168 HashTable
*ht
= va_arg(argv
, HashTable
*);
171 MAKE_STD_ZVAL(zentry
);
174 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
, php_persistent_handle_apply_stat
, 1, zentry
);
175 zend_symtable_update(ht
, key
->arKey
, key
->nKeyLength
, &zentry
, sizeof(zval
*), NULL
);
177 return ZEND_HASH_APPLY_KEEP
;
180 static int php_persistent_handle_apply_cleanup_ex(void *pp
, void *arg TSRMLS_DC
)
182 php_resource_factory_t
*rf
= arg
;
185 #if PHP_RAPHF_DEBUG_PHANDLES
186 fprintf(stderr
, "DESTROY: %p\n", *handle
);
188 php_resource_factory_handle_dtor(rf
, *handle TSRMLS_CC
);
189 return ZEND_HASH_APPLY_REMOVE
;
192 static int php_persistent_handle_apply_cleanup(void *pp
, void *arg TSRMLS_DC
)
194 php_resource_factory_t
*rf
= arg
;
195 php_persistent_handle_list_t
**listp
= pp
;
197 zend_hash_apply_with_argument(&(*listp
)->free
, php_persistent_handle_apply_cleanup_ex
, rf TSRMLS_CC
);
198 if ((*listp
)->used
) {
199 return ZEND_HASH_APPLY_KEEP
;
201 zend_hash_destroy(&(*listp
)->free
);
202 #if PHP_RAPHF_DEBUG_PHANDLES
203 fprintf(stderr
, "LSTFREE: %p\n", *listp
);
207 return ZEND_HASH_APPLY_REMOVE
;
210 static inline void php_persistent_handle_list_dtor(php_persistent_handle_list_t
*list
, php_persistent_handle_provider_t
*provider TSRMLS_DC
)
212 #if PHP_RAPHF_DEBUG_PHANDLES
213 fprintf(stderr
, "LSTDTOR: %p\n", list
);
215 zend_hash_apply_with_argument(&list
->free
, php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
216 zend_hash_destroy(&list
->free
);
219 static inline void php_persistent_handle_list_free(php_persistent_handle_list_t
**list
, php_persistent_handle_provider_t
*provider TSRMLS_DC
)
221 php_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
222 #if PHP_RAPHF_DEBUG_PHANDLES
223 fprintf(stderr
, "LSTFREE: %p\n", *list
);
229 static int php_persistent_handle_list_apply_dtor(void *listp
, void *provider TSRMLS_DC
)
231 php_persistent_handle_list_free(listp
, provider TSRMLS_CC
);
232 return ZEND_HASH_APPLY_REMOVE
;
235 static inline php_persistent_handle_list_t
*php_persistent_handle_list_find(php_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len TSRMLS_DC
)
237 php_persistent_handle_list_t
**list
, *new_list
;
239 if (SUCCESS
== zend_symtable_find(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &list
)) {
240 #if PHP_RAPHF_DEBUG_PHANDLES
241 fprintf(stderr
, "LSTFIND: %p\n", *list
);
246 if ((new_list
= php_persistent_handle_list_init(NULL
))) {
247 if (SUCCESS
== zend_symtable_update(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &new_list
, sizeof(php_persistent_handle_list_t
*), (void *) &list
)) {
248 #if PHP_RAPHF_DEBUG_PHANDLES
249 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
253 php_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
259 static int php_persistent_handle_apply_cleanup_all(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
261 php_persistent_handle_provider_t
*provider
= p
;
262 const char *ident_str
= va_arg(argv
, const char *);
263 size_t ident_len
= va_arg(argv
, size_t);
264 php_persistent_handle_list_t
*list
;
266 if (ident_str
&& ident_len
) {
267 if ((list
= php_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
268 zend_hash_apply_with_argument(&list
->free
, php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
271 zend_hash_apply_with_argument(&provider
->list
.free
, php_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
274 return ZEND_HASH_APPLY_KEEP
;
277 static inline STATUS
php_persistent_handle_do_acquire(php_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len
, void *init_arg
, void **handle TSRMLS_DC
)
281 php_persistent_handle_list_t
*list
;
283 if ((list
= php_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
284 zend_hash_internal_pointer_end(&list
->free
);
285 if (HASH_KEY_NON_EXISTANT
!= zend_hash_get_current_key(&list
->free
, NULL
, &index
, 0) && SUCCESS
== zend_hash_get_current_data(&list
->free
, (void *) &handle_ptr
)) {
286 *handle
= *handle_ptr
;
287 zend_hash_index_del(&list
->free
, index
);
289 *handle
= php_resource_factory_handle_ctor(&provider
->rf
, init_arg TSRMLS_CC
);
291 #if PHP_RAPHF_DEBUG_PHANDLES
292 fprintf(stderr
, "CREATED: %p\n", *handle
);
295 ++provider
->list
.used
;
306 static inline STATUS
php_persistent_handle_do_release(php_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len
, void **handle TSRMLS_DC
)
308 php_persistent_handle_list_t
*list
;
310 if ((list
= php_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
311 if (provider
->list
.used
>= PHP_RAPHF_G
->persistent_handle
.limit
) {
312 #if PHP_RAPHF_DEBUG_PHANDLES
313 fprintf(stderr
, "DESTROY: %p\n", *handle
);
315 php_resource_factory_handle_dtor(&provider
->rf
, *handle TSRMLS_CC
);
317 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
323 --provider
->list
.used
;
331 static inline STATUS
php_persistent_handle_do_accrete(php_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len
, void *old_handle
, void **new_handle TSRMLS_DC
)
333 php_persistent_handle_list_t
*list
;
335 if ((*new_handle
= php_resource_factory_handle_copy(&provider
->rf
, old_handle TSRMLS_CC
))) {
336 if ((list
= php_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
339 ++provider
->list
.used
;
345 static void php_persistent_handle_hash_dtor(void *p
)
347 php_persistent_handle_provider_t
*provider
= (php_persistent_handle_provider_t
*) p
;
350 zend_hash_apply_with_argument(&provider
->list
.free
, php_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
351 zend_hash_destroy(&provider
->list
.free
);
352 php_resource_factory_dtor(&provider
->rf
);
355 PHP_RAPHF_API STATUS
php_persistent_handle_provide(const char *name_str
, size_t name_len
, php_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *))
357 STATUS status
= FAILURE
;
358 php_persistent_handle_provider_t provider
;
361 if (php_persistent_handle_list_init(&provider
.list
)) {
362 if (php_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
363 #if PHP_RAPHF_DEBUG_PHANDLES
364 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
367 if (SUCCESS
== zend_symtable_update(&php_persistent_handle_hash
, name_str
, name_len
+1, (void *) &provider
, sizeof(php_persistent_handle_provider_t
), NULL
)) {
370 php_resource_factory_dtor(&provider
.rf
);
379 PHP_RAPHF_API php_persistent_handle_factory_t
*php_persistent_handle_concede(php_persistent_handle_factory_t
*a
, const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len TSRMLS_DC
)
381 STATUS status
= FAILURE
;
382 php_persistent_handle_factory_t
*free_a
= NULL
;
385 free_a
= a
= emalloc(sizeof(*a
));
387 memset(a
, 0, sizeof(*a
));
390 status
= zend_symtable_find(&php_persistent_handle_hash
, name_str
, name_len
+1, (void *) &a
->provider
);
393 if (SUCCESS
== status
) {
394 a
->ident
.str
= estrndup(ident_str
, a
->ident
.len
= ident_len
);
396 a
->free_on_abandon
= 1;
405 #if PHP_RAPHF_DEBUG_PHANDLES
406 fprintf(stderr
, "CONCEDE: %p (%s) (%s)\n", a
? a
->provider
: NULL
, name_str
, ident_str
);
412 PHP_RAPHF_API
void php_persistent_handle_abandon(php_persistent_handle_factory_t
*a
)
414 zend_bool f
= a
->free_on_abandon
;
416 #if PHP_RAPHF_DEBUG_PHANDLES
417 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
420 STR_FREE(a
->ident
.str
);
421 memset(a
, 0, sizeof(*a
));
427 PHP_RAPHF_API
void *php_persistent_handle_acquire(php_persistent_handle_factory_t
*a
, void *init_arg TSRMLS_DC
)
432 php_persistent_handle_do_acquire(a
->provider
, a
->ident
.str
, a
->ident
.len
, init_arg
, &handle TSRMLS_CC
);
438 PHP_RAPHF_API
void *php_persistent_handle_accrete(php_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
440 void *new_handle
= NULL
;
443 php_persistent_handle_do_accrete(a
->provider
, a
->ident
.str
, a
->ident
.len
, handle
, &new_handle TSRMLS_CC
);
449 PHP_RAPHF_API
void php_persistent_handle_release(php_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
452 php_persistent_handle_do_release(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
456 PHP_RAPHF_API
void php_persistent_handle_cleanup(const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len TSRMLS_DC
)
458 php_persistent_handle_provider_t
*provider
;
459 php_persistent_handle_list_t
*list
;
462 if (name_str
&& name_len
) {
463 if (SUCCESS
== zend_symtable_find(&php_persistent_handle_hash
, name_str
, name_len
+1, (void *) &provider
)) {
464 if (ident_str
&& ident_len
) {
465 if ((list
= php_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
466 zend_hash_apply_with_argument(&list
->free
, php_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
469 zend_hash_apply_with_argument(&provider
->list
.free
, php_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
473 zend_hash_apply_with_arguments(&php_persistent_handle_hash TSRMLS_CC
, php_persistent_handle_apply_cleanup_all
, 2, ident_str
, ident_len
);
478 PHP_RAPHF_API HashTable
*php_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
481 if (zend_hash_num_elements(&php_persistent_handle_hash
)) {
484 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
486 zend_hash_apply_with_arguments(&php_persistent_handle_hash TSRMLS_CC
, php_persistent_handle_apply_statall
, 1, ht
);
495 static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops
= {
496 (php_resource_factory_handle_ctor_t
) php_persistent_handle_acquire
,
497 (php_resource_factory_handle_copy_t
) php_persistent_handle_accrete
,
498 (php_resource_factory_handle_dtor_t
) php_persistent_handle_release
501 PHP_RAPHF_API php_resource_factory_ops_t
*php_persistent_handle_get_resource_factory_ops(void)
503 return &php_persistent_handle_resource_factory_ops
;
506 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles
, 0, 0, 0)
508 static PHP_FUNCTION(raphf_stat_persistent_handles
)
510 if (SUCCESS
== zend_parse_parameters_none()) {
511 object_init(return_value
);
512 if (php_persistent_handle_statall(HASH_OF(return_value
) TSRMLS_CC
)) {
515 zval_dtor(return_value
);
520 ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles
, 0, 0, 0)
521 ZEND_ARG_INFO(0, name
)
522 ZEND_ARG_INFO(0, ident
)
524 static PHP_FUNCTION(raphf_clean_persistent_handles
)
526 char *name_str
= NULL
, *ident_str
= NULL
;
527 int name_len
= 0, ident_len
= 0;
529 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s!s!", &name_str
, &name_len
, &ident_str
, &ident_len
)) {
530 php_persistent_handle_cleanup(name_str
, name_len
, ident_str
, ident_len TSRMLS_CC
);
534 static const zend_function_entry raphf_functions
[] = {
535 ZEND_NS_FENTRY("raphf", stat_persistent_handles
, ZEND_FN(raphf_stat_persistent_handles
), ai_raphf_stat_persistent_handles
, 0)
536 ZEND_NS_FENTRY("raphf", clean_persistent_handles
, ZEND_FN(raphf_clean_persistent_handles
), ai_raphf_clean_persistent_handles
, 0)
541 STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM
, OnUpdateLong
, persistent_handle
.limit
, zend_raphf_globals
, raphf_globals
)
544 static void php_raphf_init_globals(zend_raphf_globals
*raphf_globals
)
546 raphf_globals
->persistent_handle
.limit
= -1;
549 PHP_MINIT_FUNCTION(raphf
)
551 ZEND_INIT_MODULE_GLOBALS(raphf
, php_raphf_init_globals
, NULL
);
552 zend_hash_init(&php_persistent_handle_hash
, 0, NULL
, php_persistent_handle_hash_dtor
, 1);
554 php_persistent_handle_lock
= tsrm_mutex_alloc();
556 REGISTER_INI_ENTRIES();
560 PHP_MSHUTDOWN_FUNCTION(raphf
)
562 zend_hash_destroy(&php_persistent_handle_hash
);
564 tsrm_mutex_free(php_persistent_handle_lock
);
566 UNREGISTER_INI_ENTRIES();
570 static int php_persistent_handle_apply_info_ex(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
572 php_persistent_handle_list_t
**list
= p
;
573 zend_hash_key
*super_key
= va_arg(argv
, zend_hash_key
*);
574 char used
[21], free
[21];
576 slprintf(used
, sizeof(used
), "%u", (*list
)->used
);
577 slprintf(free
, sizeof(free
), "%d", zend_hash_num_elements(&(*list
)->free
));
579 php_info_print_table_row(4, super_key
->arKey
, key
->arKey
, used
, free
);
581 return ZEND_HASH_APPLY_KEEP
;
584 static int php_persistent_handle_apply_info(void *p TSRMLS_DC
, int argc
, va_list argv
, zend_hash_key
*key
)
586 php_persistent_handle_provider_t
*provider
= p
;
588 zend_hash_apply_with_arguments(&provider
->list
.free TSRMLS_CC
, php_persistent_handle_apply_info_ex
, 1, key
);
590 return ZEND_HASH_APPLY_KEEP
;
593 PHP_MINFO_FUNCTION(raphf
)
595 php_info_print_table_start();
596 php_info_print_table_header(2, "Resource and persistent handle factory support", "enabled");
597 php_info_print_table_row(2, "Extension version", PHP_RAPHF_VERSION
);
598 php_info_print_table_end();
600 php_info_print_table_start();
601 php_info_print_table_colspan_header(4, "Persistent handles");
602 php_info_print_table_header(4, "Provider", "Ident", "Used", "Free");
604 zend_hash_apply_with_arguments(&php_persistent_handle_hash TSRMLS_CC
, php_persistent_handle_apply_info
, 0);
606 php_info_print_table_end();
608 DISPLAY_INI_ENTRIES();
611 zend_module_entry raphf_module_entry
= {
612 STANDARD_MODULE_HEADER
,
616 PHP_MSHUTDOWN(raphf
),
621 STANDARD_MODULE_PROPERTIES
625 #ifdef COMPILE_DL_RAPHF
626 ZEND_GET_MODULE(raphf
)
635 * vim600: noet sw=4 ts=4 fdm=marker
636 * vim<600: noet sw=4 ts=4