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 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
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 int php_http_persistent_handle_apply_cleanup_ex(void *pp
, void *arg TSRMLS_DC
)
65 php_http_resource_factory_t
*rf
= arg
;
68 #if PHP_HTTP_DEBUG_PHANDLES
69 fprintf(stderr
, "DESTROY: %p\n", *handle
);
71 php_http_resource_factory_handle_dtor(rf
, *handle TSRMLS_CC
);
72 return ZEND_HASH_APPLY_REMOVE
;
75 static int php_http_persistent_handle_apply_cleanup(void *pp
, void *arg TSRMLS_DC
)
77 php_http_resource_factory_t
*rf
= arg
;
78 php_http_persistent_handle_list_t
**listp
= pp
;
80 zend_hash_apply_with_argument(&(*listp
)->free
, php_http_persistent_handle_apply_cleanup_ex
, rf TSRMLS_CC
);
82 return ZEND_HASH_APPLY_KEEP
;
84 zend_hash_destroy(&(*listp
)->free
);
85 #if PHP_HTTP_DEBUG_PHANDLES
86 fprintf(stderr
, "LSTFREE: %p\n", *listp
);
90 return ZEND_HASH_APPLY_REMOVE
;
93 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
)
95 #if PHP_HTTP_DEBUG_PHANDLES
96 fprintf(stderr
, "LSTDTOR: %p\n", list
);
98 zend_hash_apply_with_argument(&list
->free
, php_http_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
99 zend_hash_destroy(&list
->free
);
102 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
)
104 php_http_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
105 #if PHP_HTTP_DEBUG_PHANDLES
106 fprintf(stderr
, "LSTFREE: %p\n", *list
);
112 static int php_http_persistent_handle_list_apply_dtor(void *listp
, void *provider TSRMLS_DC
)
114 php_http_persistent_handle_list_free(listp
, provider TSRMLS_CC
);
115 return ZEND_HASH_APPLY_REMOVE
;
118 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
)
120 php_http_persistent_handle_list_t
**list
, *new_list
;
122 if (SUCCESS
== zend_symtable_find(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &list
)) {
123 #if PHP_HTTP_DEBUG_PHANDLES
124 fprintf(stderr
, "LSTFIND: %p\n", *list
);
129 if ((new_list
= php_http_persistent_handle_list_init(NULL
))) {
130 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
)) {
131 #if PHP_HTTP_DEBUG_PHANDLES
132 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
136 php_http_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
142 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
)
146 php_http_persistent_handle_list_t
*list
;
148 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
149 zend_hash_internal_pointer_end(&list
->free
);
150 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
)) {
151 *handle
= *handle_ptr
;
152 zend_hash_index_del(&list
->free
, index
);
154 *handle
= php_http_resource_factory_handle_ctor(&provider
->rf TSRMLS_CC
);
156 #if PHP_HTTP_DEBUG_PHANDLES
157 fprintf(stderr
, "CREATED: %p\n", *handle
);
160 ++provider
->list
.used
;
171 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
)
173 php_http_persistent_handle_list_t
*list
;
175 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
176 if (provider
->list
.used
>= PHP_HTTP_G
->persistent_handle
.limit
) {
177 #if PHP_HTTP_DEBUG_PHANDLES
178 fprintf(stderr
, "DESTROY: %p\n", *handle
);
180 php_http_resource_factory_handle_dtor(&provider
->rf
, *handle TSRMLS_CC
);
182 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
188 --provider
->list
.used
;
196 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
)
198 php_http_persistent_handle_list_t
*list
;
200 if ((*new_handle
= php_http_resource_factory_handle_copy(&provider
->rf
, old_handle TSRMLS_CC
))) {
201 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
204 ++provider
->list
.used
;
210 static void php_http_persistent_handles_hash_dtor(void *p
)
212 php_http_persistent_handle_provider_t
*provider
= (php_http_persistent_handle_provider_t
*) p
;
215 zend_hash_apply_with_argument(&provider
->list
.free
, php_http_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
216 zend_hash_destroy(&provider
->list
.free
);
217 php_http_resource_factory_dtor(&provider
->rf
);
220 PHP_MINIT_FUNCTION(http_persistent_handle
)
222 zend_hash_init(&php_http_persistent_handles_hash
, 0, NULL
, php_http_persistent_handles_hash_dtor
, 1);
224 php_http_persistent_handles_lock
= tsrm_mutex_alloc();
229 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle
)
231 zend_hash_destroy(&php_http_persistent_handles_hash
);
233 tsrm_mutex_free(php_http_persistent_handles_lock
);
238 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 *))
240 STATUS status
= FAILURE
;
241 php_http_persistent_handle_provider_t provider
;
244 if (php_http_persistent_handle_list_init(&provider
.list
)) {
245 if (php_http_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
246 #if PHP_HTTP_DEBUG_PHANDLES
247 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
250 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
)) {
253 php_http_resource_factory_dtor(&provider
.rf
);
262 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
)
264 STATUS status
= FAILURE
;
265 php_http_persistent_handle_factory_t
*free_a
= NULL
;
268 free_a
= a
= emalloc(sizeof(*a
));
270 memset(a
, 0, sizeof(*a
));
273 status
= zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &a
->provider
);
276 if (SUCCESS
== status
) {
277 a
->ident
.str
= estrndup(ident_str
, a
->ident
.len
= ident_len
);
279 a
->free_on_abandon
= 1;
288 #if PHP_HTTP_DEBUG_PHANDLES
289 fprintf(stderr
, "CONCEDE: %p (%s) (%s)\n", a
? a
->provider
: NULL
, name_str
, ident_str
);
295 PHP_HTTP_API
void php_http_persistent_handle_abandon(php_http_persistent_handle_factory_t
*a
)
297 zend_bool f
= a
->free_on_abandon
;
299 #if PHP_HTTP_DEBUG_PHANDLES
300 fprintf(stderr
, "ABANDON: %p\n", a
->provider
);
303 STR_FREE(a
->ident
.str
);
304 memset(a
, 0, sizeof(*a
));
310 PHP_HTTP_API
void *php_http_persistent_handle_acquire(php_http_persistent_handle_factory_t
*a TSRMLS_DC
)
315 php_http_persistent_handle_do_acquire(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
321 PHP_HTTP_API
void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
323 void *new_handle
= NULL
;
326 php_http_persistent_handle_do_accrete(a
->provider
, a
->ident
.str
, a
->ident
.len
, handle
, &new_handle TSRMLS_CC
);
332 PHP_HTTP_API
void php_http_persistent_handle_release(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
335 php_http_persistent_handle_do_release(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
339 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
)
341 php_http_persistent_handle_provider_t
*provider
;
342 php_http_persistent_handle_list_t
*list
;
345 if (name_str
&& name_len
) {
346 if (SUCCESS
== zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
347 if (ident_str
&& ident_len
) {
348 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
349 zend_hash_apply_with_argument(&list
->free
, php_http_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
352 zend_hash_apply_with_argument(&provider
->list
.free
, php_http_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
358 FOREACH_HASH_VAL(pos
, &php_http_persistent_handles_hash
, provider
) {
359 if (ident_str
&& ident_len
) {
360 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
361 zend_hash_apply_with_argument(&list
->free
, php_http_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
364 zend_hash_apply_with_argument(&provider
->list
.free
, php_http_persistent_handle_apply_cleanup
, &provider
->rf TSRMLS_CC
);
371 PHP_HTTP_API HashTable
*php_http_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
374 HashPosition pos1
, pos2
;
375 php_http_array_hashkey_t key1
= php_http_array_hashkey_init(0), key2
= php_http_array_hashkey_init(0);
376 php_http_persistent_handle_provider_t
*provider
;
377 php_http_persistent_handle_list_t
**list
;
380 if (zend_hash_num_elements(&php_http_persistent_handles_hash
)) {
383 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
386 FOREACH_HASH_KEYVAL(pos1
, &php_http_persistent_handles_hash
, key1
, provider
) {
387 MAKE_STD_ZVAL(zentry
[0]);
388 array_init(zentry
[0]);
390 FOREACH_HASH_KEYVAL(pos2
, &provider
->list
.free
, key2
, list
) {
391 MAKE_STD_ZVAL(zentry
[1]);
392 array_init(zentry
[1]);
393 add_assoc_long_ex(zentry
[1], ZEND_STRS("used"), (*list
)->used
);
394 add_assoc_long_ex(zentry
[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list
)->free
));
395 add_assoc_zval_ex(zentry
[0], key2
.str
, key2
.len
, zentry
[1]);
398 zend_symtable_update(ht
, key1
.str
, key1
.len
, &zentry
[0], sizeof(zval
*), NULL
);
408 static php_http_resource_factory_ops_t php_http_persistent_handle_rf_ops
= {
409 (php_http_resource_factory_handle_ctor_t
) php_http_persistent_handle_acquire
,
410 (php_http_resource_factory_handle_copy_t
) php_http_persistent_handle_accrete
,
411 (php_http_resource_factory_handle_dtor_t
) php_http_persistent_handle_release
414 PHP_HTTP_API php_http_resource_factory_ops_t
*php_http_persistent_handle_resource_factory_ops(void)
416 return &php_http_persistent_handle_rf_ops
;
424 * vim600: noet sw=4 ts=4 fdm=marker
425 * vim<600: noet sw=4 ts=4