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) 2004-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #ifndef PHP_HTTP_DEBUG_PHANDLES
16 # define PHP_HTTP_DEBUG_PHANDLES 0
18 #if PHP_HTTP_DEBUG_PHANDLES
23 static HashTable php_http_persistent_handles_hash
;
25 # define LOCK() tsrm_mutex_lock(php_http_persistent_handles_lock)
26 # define UNLOCK() tsrm_mutex_unlock(php_http_persistent_handles_lock)
27 static MUTEX_T php_http_persistent_handles_lock
;
33 typedef struct php_http_persistent_handle_list
{
36 } php_http_persistent_handle_list_t
;
38 typedef struct php_http_persistent_handle_provider
{
39 php_http_persistent_handle_list_t list
; /* "ident" => array(handles) entries */
40 php_http_resource_factory_t rf
;
41 } php_http_persistent_handle_provider_t
;
43 static inline php_http_persistent_handle_list_t
*php_http_persistent_handle_list_init(php_http_persistent_handle_list_t
*list
)
47 if ((free_list
= !list
)) {
48 list
= pemalloc(sizeof(php_http_persistent_handle_list_t
), 1);
53 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
63 static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t
*list
, php_http_persistent_handle_provider_t
*provider TSRMLS_DC
)
68 #if PHP_HTTP_DEBUG_PHANDLES
69 fprintf(stderr
, "LSTDTOR: %p\n", list
);
71 FOREACH_HASH_VAL(pos
, &list
->free
, handle
) {
72 #if PHP_HTTP_DEBUG_PHANDLES
73 fprintf(stderr
, "DESTROY: %p\n", *handle
);
76 provider
->rf
.fops
.dtor(provider
->rf
.data
, *handle TSRMLS_CC
);
78 zend_hash_destroy(&list
->free
);
81 static inline void php_http_persistent_handle_list_free(php_http_persistent_handle_list_t
**list
, php_http_persistent_handle_provider_t
*provider TSRMLS_DC
)
83 php_http_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
84 #if PHP_HTTP_DEBUG_PHANDLES
85 fprintf(stderr
, "LSTFREE: %p\n", *list
);
91 static inline php_http_persistent_handle_list_t
*php_http_persistent_handle_list_find(php_http_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len TSRMLS_DC
)
93 php_http_persistent_handle_list_t
**list
, *new_list
;
95 if (SUCCESS
== zend_symtable_find(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &list
)) {
96 #if PHP_HTTP_DEBUG_PHANDLES
97 fprintf(stderr
, "LSTFIND: %p\n", *list
);
102 if ((new_list
= php_http_persistent_handle_list_init(NULL
))) {
103 if (SUCCESS
== zend_symtable_update(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &new_list
, sizeof(php_http_persistent_handle_list_t
*), (void *) &list
)) {
104 #if PHP_HTTP_DEBUG_PHANDLES
105 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
109 php_http_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
115 static inline STATUS
php_http_persistent_handle_do_acquire(php_http_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len
, void **handle TSRMLS_DC
)
119 php_http_persistent_handle_list_t
*list
;
121 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
122 zend_hash_internal_pointer_end(&list
->free
);
123 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
)) {
124 *handle
= *handle_ptr
;
125 zend_hash_index_del(&list
->free
, index
);
127 *handle
= provider
->rf
.fops
.ctor(provider
->rf
.data TSRMLS_CC
);
131 ++provider
->list
.used
;
142 static inline STATUS
php_http_persistent_handle_do_release(php_http_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len
, void **handle TSRMLS_DC
)
144 php_http_persistent_handle_list_t
*list
;
146 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
147 if (provider
->list
.used
>= PHP_HTTP_G
->persistent_handle
.limit
) {
148 provider
->rf
.fops
.dtor(provider
->rf
.data
, *handle TSRMLS_CC
);
150 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
156 --provider
->list
.used
;
164 static inline STATUS
php_http_persistent_handle_do_accrete(php_http_persistent_handle_provider_t
*provider
, const char *ident_str
, size_t ident_len
, void *old_handle
, void **new_handle TSRMLS_DC
)
166 php_http_persistent_handle_list_t
*list
;
168 if (provider
->rf
.fops
.copy
&& (*new_handle
= provider
->rf
.fops
.copy(provider
->rf
.data
, old_handle TSRMLS_CC
))) {
169 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
172 ++provider
->list
.used
;
178 static void php_http_persistent_handles_hash_dtor(void *p
)
180 php_http_persistent_handle_provider_t
*provider
= (php_http_persistent_handle_provider_t
*) p
;
181 php_http_persistent_handle_list_t
**list
, *list_tmp
;
185 FOREACH_HASH_VAL(pos
, &provider
->list
.free
, list
) {
186 /* fix shutdown crash in PHP4 */
188 php_http_persistent_handle_list_free(&list_tmp
, provider TSRMLS_CC
);
191 zend_hash_destroy(&provider
->list
.free
);
192 php_http_resource_factory_dtor(&provider
->rf
);
195 PHP_MINIT_FUNCTION(http_persistent_handle
)
197 zend_hash_init(&php_http_persistent_handles_hash
, 0, NULL
, php_http_persistent_handles_hash_dtor
, 1);
199 php_http_persistent_handles_lock
= tsrm_mutex_alloc();
204 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle
)
206 zend_hash_destroy(&php_http_persistent_handles_hash
);
208 tsrm_mutex_free(php_http_persistent_handles_lock
);
213 PHP_HTTP_API STATUS
php_http_persistent_handle_provide(const char *name_str
, size_t name_len
, php_http_resource_factory_ops_t
*fops
, void *data
, void (*dtor
)(void *))
215 STATUS status
= FAILURE
;
216 php_http_persistent_handle_provider_t provider
;
219 if (php_http_persistent_handle_list_init(&provider
.list
)) {
220 if (php_http_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
221 #if PHP_HTTP_DEBUG_PHANDLES
222 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
225 if (SUCCESS
== zend_symtable_update(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
, sizeof(php_http_persistent_handle_provider_t
), NULL
)) {
228 php_http_resource_factory_dtor(&provider
.rf
);
237 PHP_HTTP_API php_http_persistent_handle_factory_t
*php_http_persistent_handle_concede(php_http_persistent_handle_factory_t
*a
, const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len TSRMLS_DC
)
239 STATUS status
= FAILURE
;
240 php_http_persistent_handle_factory_t
*free_a
= NULL
;
243 free_a
= a
= emalloc(sizeof(*a
));
245 memset(a
, 0, sizeof(*a
));
248 status
= zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &a
->provider
);
251 if (SUCCESS
== status
) {
252 a
->ident
.str
= estrndup(ident_str
, a
->ident
.len
= ident_len
);
254 a
->free_on_abandon
= 1;
263 #if PHP_HTTP_DEBUG_PHANDLES
264 fprintf(stderr
, "CONCETE: %p (%s) (%s)\n", a
? a
->provider
: NULL
, name_str
, ident_str
);
270 PHP_HTTP_API
void php_http_persistent_handle_abandon(php_http_persistent_handle_factory_t
*a
)
272 zend_bool f
= a
->free_on_abandon
;
274 STR_FREE(a
->ident
.str
);
275 memset(a
, 0, sizeof(*a
));
281 PHP_HTTP_API
void *php_http_persistent_handle_acquire(php_http_persistent_handle_factory_t
*a TSRMLS_DC
)
286 php_http_persistent_handle_do_acquire(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
292 PHP_HTTP_API
void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
297 php_http_persistent_handle_do_accrete(a
->provider
, a
->ident
.str
, a
->ident
.len
, handle
, &new_handle TSRMLS_CC
);
303 PHP_HTTP_API
void php_http_persistent_handle_release(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
306 php_http_persistent_handle_do_release(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
310 PHP_HTTP_API STATUS
php_http_persistent_handle_acquire2(const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len
, void **handle TSRMLS_DC
)
312 STATUS status
= FAILURE
;
313 php_http_persistent_handle_provider_t
*provider
;
317 if (SUCCESS
== zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
318 status
= php_http_persistent_handle_do_acquire(provider
, ident_str
, ident_len
, handle TSRMLS_CC
);
322 #if PHP_HTTP_DEBUG_PHANDLES
323 fprintf(stderr
, "ACQUIRE: %p (%s)\n", *handle
, name_str
);
329 PHP_HTTP_API STATUS
php_http_persistent_handle_release2(const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len
, void **handle TSRMLS_DC
)
331 STATUS status
= FAILURE
;
332 php_http_persistent_handle_provider_t
*provider
;
333 #if PHP_HTTP_DEBUG_PHANDLES
334 void *handle_tmp
= *handle
;
338 if (SUCCESS
== zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
339 status
= php_http_persistent_handle_do_release(provider
, ident_str
, ident_len
, handle TSRMLS_CC
);
343 #if PHP_HTTP_DEBUG_PHANDLES
344 fprintf(stderr
, "RELEASE: %p (%s)\n", handle_tmp
, name_str
);
350 PHP_HTTP_API STATUS
php_http_persistent_handle_accrete2(const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len
, void *old_handle
, void **new_handle TSRMLS_DC
)
352 STATUS status
= FAILURE
;
353 php_http_persistent_handle_provider_t
*provider
;
357 if (SUCCESS
== zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
358 status
= php_http_persistent_handle_do_accrete(provider
, ident_str
, ident_len
, old_handle
, new_handle TSRMLS_CC
);
362 #if PHP_HTTP_DEBUG_PHANDLES
363 fprintf(stderr
, "ACCRETE: %p > %p (%s)\n", old_handle
, *new_handle
, name_str
);
369 PHP_HTTP_API
void php_http_persistent_handle_cleanup(const char *name_str
, size_t name_len
, const char *ident_str
, size_t ident_len TSRMLS_DC
)
371 php_http_persistent_handle_provider_t
*provider
;
372 php_http_persistent_handle_list_t
*list
, **listp
;
373 HashPosition pos1
, pos2
;
376 if (name_str
&& name_len
) {
377 if (SUCCESS
== zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
378 if (ident_str
&& ident_len
) {
379 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
380 php_http_persistent_handle_list_dtor(list
, provider TSRMLS_CC
);
381 php_http_persistent_handle_list_init(list
);
384 FOREACH_HASH_VAL(pos1
, &provider
->list
.free
, listp
) {
385 php_http_persistent_handle_list_dtor(*listp
, provider TSRMLS_CC
);
386 php_http_persistent_handle_list_init(*listp
);
391 FOREACH_HASH_VAL(pos1
, &php_http_persistent_handles_hash
, provider
) {
392 if (ident_str
&& ident_len
) {
393 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
394 php_http_persistent_handle_list_dtor(list
, provider TSRMLS_CC
);
395 php_http_persistent_handle_list_init(list
);
398 FOREACH_HASH_VAL(pos2
, &provider
->list
.free
, listp
) {
399 php_http_persistent_handle_list_dtor(*listp
, provider TSRMLS_CC
);
400 php_http_persistent_handle_list_init(*listp
);
408 PHP_HTTP_API HashTable
*php_http_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
411 HashPosition pos1
, pos2
;
412 php_http_array_hashkey_t key1
= php_http_array_hashkey_init(0), key2
= php_http_array_hashkey_init(0);
413 php_http_persistent_handle_provider_t
*provider
;
414 php_http_persistent_handle_list_t
**list
;
417 if (zend_hash_num_elements(&php_http_persistent_handles_hash
)) {
420 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
423 FOREACH_HASH_KEYVAL(pos1
, &php_http_persistent_handles_hash
, key1
, provider
) {
424 MAKE_STD_ZVAL(zentry
[0]);
425 array_init(zentry
[0]);
427 FOREACH_HASH_KEYVAL(pos2
, &provider
->list
.free
, key2
, list
) {
428 MAKE_STD_ZVAL(zentry
[1]);
429 array_init(zentry
[1]);
430 add_assoc_long_ex(zentry
[1], ZEND_STRS("used"), (*list
)->used
);
431 add_assoc_long_ex(zentry
[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list
)->free
));
432 add_assoc_zval_ex(zentry
[0], key2
.str
, key2
.len
, zentry
[1]);
435 zend_symtable_update(ht
, key1
.str
, key1
.len
, &zentry
[0], sizeof(zval
*), NULL
);
451 * vim600: noet sw=4 ts=4 fdm=marker
452 * vim<600: noet sw=4 ts=4