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
);
81 return (*listp
)->used
? ZEND_HASH_APPLY_KEEP
: ZEND_HASH_APPLY_REMOVE
;
84 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
)
86 #if PHP_HTTP_DEBUG_PHANDLES
87 fprintf(stderr
, "LSTDTOR: %p\n", list
);
89 zend_hash_apply_with_argument(&list
->free
, php_http_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
90 zend_hash_destroy(&list
->free
);
93 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
)
95 php_http_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
96 #if PHP_HTTP_DEBUG_PHANDLES
97 fprintf(stderr
, "LSTFREE: %p\n", *list
);
103 static int php_http_persistent_handle_list_apply_dtor(void *listp
, void *provider TSRMLS_DC
)
105 php_http_persistent_handle_list_free(listp
, provider TSRMLS_CC
);
106 return ZEND_HASH_APPLY_REMOVE
;
109 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
)
111 php_http_persistent_handle_list_t
**list
, *new_list
;
113 if (SUCCESS
== zend_symtable_find(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &list
)) {
114 #if PHP_HTTP_DEBUG_PHANDLES
115 fprintf(stderr
, "LSTFIND: %p\n", *list
);
120 if ((new_list
= php_http_persistent_handle_list_init(NULL
))) {
121 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
)) {
122 #if PHP_HTTP_DEBUG_PHANDLES
123 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
127 php_http_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
133 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
)
137 php_http_persistent_handle_list_t
*list
;
139 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
140 zend_hash_internal_pointer_end(&list
->free
);
141 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
)) {
142 *handle
= *handle_ptr
;
143 zend_hash_index_del(&list
->free
, index
);
145 *handle
= php_http_resource_factory_handle_ctor(&provider
->rf TSRMLS_CC
);
149 ++provider
->list
.used
;
160 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
)
162 php_http_persistent_handle_list_t
*list
;
164 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
165 if (provider
->list
.used
>= PHP_HTTP_G
->persistent_handle
.limit
) {
166 php_http_resource_factory_handle_dtor(&provider
->rf
, *handle TSRMLS_CC
);
168 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
174 --provider
->list
.used
;
182 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
)
184 php_http_persistent_handle_list_t
*list
;
186 if ((*new_handle
= php_http_resource_factory_handle_copy(&provider
->rf
, old_handle TSRMLS_CC
))) {
187 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
190 ++provider
->list
.used
;
196 static void php_http_persistent_handles_hash_dtor(void *p
)
198 php_http_persistent_handle_provider_t
*provider
= (php_http_persistent_handle_provider_t
*) p
;
201 zend_hash_apply_with_argument(&provider
->list
.free
, php_http_persistent_handle_list_apply_dtor
, provider TSRMLS_CC
);
202 zend_hash_destroy(&provider
->list
.free
);
203 php_http_resource_factory_dtor(&provider
->rf
);
206 PHP_MINIT_FUNCTION(http_persistent_handle
)
208 zend_hash_init(&php_http_persistent_handles_hash
, 0, NULL
, php_http_persistent_handles_hash_dtor
, 1);
210 php_http_persistent_handles_lock
= tsrm_mutex_alloc();
215 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle
)
217 zend_hash_destroy(&php_http_persistent_handles_hash
);
219 tsrm_mutex_free(php_http_persistent_handles_lock
);
224 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 *))
226 STATUS status
= FAILURE
;
227 php_http_persistent_handle_provider_t provider
;
230 if (php_http_persistent_handle_list_init(&provider
.list
)) {
231 if (php_http_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
232 #if PHP_HTTP_DEBUG_PHANDLES
233 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
236 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
)) {
239 php_http_resource_factory_dtor(&provider
.rf
);
248 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
)
250 STATUS status
= FAILURE
;
251 php_http_persistent_handle_factory_t
*free_a
= NULL
;
254 free_a
= a
= emalloc(sizeof(*a
));
256 memset(a
, 0, sizeof(*a
));
259 status
= zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &a
->provider
);
262 if (SUCCESS
== status
) {
263 a
->ident
.str
= estrndup(ident_str
, a
->ident
.len
= ident_len
);
265 a
->free_on_abandon
= 1;
274 #if PHP_HTTP_DEBUG_PHANDLES
275 fprintf(stderr
, "CONCEDE: %p (%s) (%s)\n", a
? a
->provider
: NULL
, name_str
, ident_str
);
281 PHP_HTTP_API
void php_http_persistent_handle_abandon(php_http_persistent_handle_factory_t
*a
)
283 zend_bool f
= a
->free_on_abandon
;
285 STR_FREE(a
->ident
.str
);
286 memset(a
, 0, sizeof(*a
));
292 PHP_HTTP_API
void *php_http_persistent_handle_acquire(php_http_persistent_handle_factory_t
*a TSRMLS_DC
)
297 php_http_persistent_handle_do_acquire(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
303 PHP_HTTP_API
void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
305 void *new_handle
= NULL
;
308 php_http_persistent_handle_do_accrete(a
->provider
, a
->ident
.str
, a
->ident
.len
, handle
, &new_handle TSRMLS_CC
);
314 PHP_HTTP_API
void php_http_persistent_handle_release(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
317 php_http_persistent_handle_do_release(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
321 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
)
323 php_http_persistent_handle_provider_t
*provider
;
324 php_http_persistent_handle_list_t
*list
;
327 if (name_str
&& name_len
) {
328 if (SUCCESS
== zend_symtable_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
329 if (ident_str
&& ident_len
) {
330 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
331 zend_hash_apply_with_argument(&list
->free
, php_http_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
334 zend_hash_apply_with_argument(&provider
->list
.free
, php_http_persistent_handle_apply_cleanup
, &provider
->list
.free TSRMLS_CC
);
340 FOREACH_HASH_VAL(pos
, &php_http_persistent_handles_hash
, provider
) {
341 if (ident_str
&& ident_len
) {
342 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
343 zend_hash_apply_with_argument(&list
->free
, php_http_persistent_handle_apply_cleanup_ex
, &provider
->rf TSRMLS_CC
);
346 zend_hash_apply_with_argument(&provider
->list
.free
, php_http_persistent_handle_apply_cleanup
, &provider
->list
.free TSRMLS_CC
);
353 PHP_HTTP_API HashTable
*php_http_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
356 HashPosition pos1
, pos2
;
357 php_http_array_hashkey_t key1
= php_http_array_hashkey_init(0), key2
= php_http_array_hashkey_init(0);
358 php_http_persistent_handle_provider_t
*provider
;
359 php_http_persistent_handle_list_t
**list
;
362 if (zend_hash_num_elements(&php_http_persistent_handles_hash
)) {
365 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
368 FOREACH_HASH_KEYVAL(pos1
, &php_http_persistent_handles_hash
, key1
, provider
) {
369 MAKE_STD_ZVAL(zentry
[0]);
370 array_init(zentry
[0]);
372 FOREACH_HASH_KEYVAL(pos2
, &provider
->list
.free
, key2
, list
) {
373 MAKE_STD_ZVAL(zentry
[1]);
374 array_init(zentry
[1]);
375 add_assoc_long_ex(zentry
[1], ZEND_STRS("used"), (*list
)->used
);
376 add_assoc_long_ex(zentry
[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list
)->free
));
377 add_assoc_zval_ex(zentry
[0], key2
.str
, key2
.len
, zentry
[1]);
380 zend_symtable_update(ht
, key1
.str
, key1
.len
, &zentry
[0], sizeof(zval
*), NULL
);
390 static php_http_resource_factory_ops_t php_http_persistent_handle_rf_ops
= {
391 (php_http_resource_factory_handle_ctor_t
) php_http_persistent_handle_acquire
,
392 (php_http_resource_factory_handle_copy_t
) php_http_persistent_handle_accrete
,
393 (php_http_resource_factory_handle_dtor_t
) php_http_persistent_handle_release
396 PHP_HTTP_API php_http_resource_factory_ops_t
*php_http_persistent_handle_resource_factory_ops(void)
398 return &php_http_persistent_handle_rf_ops
;
406 * vim600: noet sw=4 ts=4 fdm=marker
407 * vim<600: noet sw=4 ts=4