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-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 /* $Id: http_persistent_handle_api.c 292841 2009-12-31 08:48:57Z mike $ */
17 #ifndef PHP_HTTP_DEBUG_PHANDLES
18 # define PHP_HTTP_DEBUG_PHANDLES 0
20 #if PHP_HTTP_DEBUG_PHANDLES
25 static HashTable php_http_persistent_handles_hash
;
27 # define LOCK() tsrm_mutex_lock(php_http_persistent_handles_lock)
28 # define UNLOCK() tsrm_mutex_unlock(php_http_persistent_handles_lock)
29 static MUTEX_T php_http_persistent_handles_lock
;
35 typedef struct php_http_persistent_handle_list
{
38 } php_http_persistent_handle_list_t
;
40 typedef struct php_http_persistent_handle_provider
{
41 php_http_persistent_handle_list_t list
; /* "ident" => array(handles) entries */
42 php_http_persistent_handle_ctor_t ctor
;
43 php_http_persistent_handle_dtor_t dtor
;
44 php_http_persistent_handle_copy_t copy
;
45 } php_http_persistent_handle_provider_t
;
47 static inline php_http_persistent_handle_list_t
*php_http_persistent_handle_list_init(php_http_persistent_handle_list_t
*list
)
51 if ((free_list
= !list
)) {
52 list
= pemalloc(sizeof(php_http_persistent_handle_list_t
), 1);
57 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
67 static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t
*list
, php_http_persistent_handle_dtor_t dtor
)
72 #if PHP_HTTP_DEBUG_PHANDLES
73 fprintf(stderr
, "LSTDTOR: %p\n", list
);
75 FOREACH_HASH_VAL(pos
, &list
->free
, handle
) {
76 #if PHP_HTTP_DEBUG_PHANDLES
77 fprintf(stderr
, "DESTROY: %p\n", *handle
);
82 zend_hash_destroy(&list
->free
);
85 static inline void php_http_persistent_handle_list_free(php_http_persistent_handle_list_t
**list
, php_http_persistent_handle_dtor_t dtor
)
87 php_http_persistent_handle_list_dtor(*list
, dtor
);
88 #if PHP_HTTP_DEBUG_PHANDLES
89 fprintf(stderr
, "LSTFREE: %p\n", *list
);
95 static inline php_http_persistent_handle_list_t
*php_http_persistent_handle_list_find(php_http_persistent_handle_provider_t
*provider TSRMLS_DC
)
97 php_http_persistent_handle_list_t
**list
, *new_list
;
99 if (SUCCESS
== zend_hash_quick_find(&provider
->list
.free
, PHP_HTTP_G
->persistent_handle
.ident
.s
, PHP_HTTP_G
->persistent_handle
.ident
.l
, PHP_HTTP_G
->persistent_handle
.ident
.h
, (void *) &list
)) {
100 #if PHP_HTTP_DEBUG_PHANDLES
101 fprintf(stderr
, "LSTFIND: %p\n", *list
);
106 if ((new_list
= php_http_persistent_handle_list_init(NULL
))) {
107 if (SUCCESS
== zend_hash_quick_add(&provider
->list
.free
, PHP_HTTP_G
->persistent_handle
.ident
.s
, PHP_HTTP_G
->persistent_handle
.ident
.l
, PHP_HTTP_G
->persistent_handle
.ident
.h
, (void *) &new_list
, sizeof(php_http_persistent_handle_list_t
*), (void *) &list
)) {
108 #if PHP_HTTP_DEBUG_PHANDLES
109 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
113 php_http_persistent_handle_list_free(&new_list
, provider
->dtor
);
119 static inline STATUS
php_http_persistent_handle_do_acquire(php_http_persistent_handle_provider_t
*provider
, void **handle TSRMLS_DC
)
123 php_http_persistent_handle_list_t
*list
;
125 if ((list
= php_http_persistent_handle_list_find(provider TSRMLS_CC
))) {
126 zend_hash_internal_pointer_end(&list
->free
);
127 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
)) {
128 *handle
= *handle_ptr
;
129 zend_hash_index_del(&list
->free
, index
);
131 *handle
= provider
->ctor();
135 ++provider
->list
.used
;
146 static inline STATUS
php_http_persistent_handle_do_release(php_http_persistent_handle_provider_t
*provider
, void **handle TSRMLS_DC
)
148 php_http_persistent_handle_list_t
*list
;
150 if ((list
= php_http_persistent_handle_list_find(provider TSRMLS_CC
))) {
151 if (provider
->list
.used
>= PHP_HTTP_G
->persistent_handle
.limit
) {
152 provider
->dtor(*handle
);
154 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
160 --provider
->list
.used
;
168 static inline STATUS
php_http_persistent_handle_do_accrete(php_http_persistent_handle_provider_t
*provider
, void *old_handle
, void **new_handle TSRMLS_DC
)
170 php_http_persistent_handle_list_t
*list
;
172 if (provider
->copy
&& (*new_handle
= provider
->copy(old_handle
))) {
173 if ((list
= php_http_persistent_handle_list_find(provider TSRMLS_CC
))) {
176 ++provider
->list
.used
;
182 static void php_http_persistent_handles_hash_dtor(void *p
)
184 php_http_persistent_handle_provider_t
*provider
= (php_http_persistent_handle_provider_t
*) p
;
185 php_http_persistent_handle_list_t
**list
, *list_tmp
;
188 FOREACH_HASH_VAL(pos
, &provider
->list
.free
, list
) {
189 /* fix shutdown crash in PHP4 */
191 php_http_persistent_handle_list_free(&list_tmp
, provider
->dtor
);
194 zend_hash_destroy(&provider
->list
.free
);
197 PHP_MINIT_FUNCTION(http_persistent_handle
)
199 zend_hash_init(&php_http_persistent_handles_hash
, 0, NULL
, php_http_persistent_handles_hash_dtor
, 1);
201 php_http_persistent_handles_lock
= tsrm_mutex_alloc();
206 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle
)
208 zend_hash_destroy(&php_http_persistent_handles_hash
);
210 tsrm_mutex_free(php_http_persistent_handles_lock
);
215 PHP_HTTP_API STATUS
php_http_persistent_handle_provide(const char *name_str
, size_t name_len
, php_http_persistent_handle_ctor_t ctor
, php_http_persistent_handle_dtor_t dtor
, php_http_persistent_handle_copy_t copy
)
217 STATUS status
= FAILURE
;
218 php_http_persistent_handle_provider_t provider
;
221 if (php_http_persistent_handle_list_init(&provider
.list
)) {
222 provider
.ctor
= ctor
;
223 provider
.dtor
= dtor
;
224 provider
.copy
= copy
;
226 #if PHP_HTTP_DEBUG_PHANDLES
227 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
230 if (SUCCESS
== zend_hash_add(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
, sizeof(php_http_persistent_handle_provider_t
), NULL
)) {
239 PHP_HTTP_API STATUS
php_http_persistent_handle_acquire(const char *name_str
, size_t name_len
, void **handle TSRMLS_DC
)
241 STATUS status
= FAILURE
;
242 php_http_persistent_handle_provider_t
*provider
;
246 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
247 status
= php_http_persistent_handle_do_acquire(provider
, handle TSRMLS_CC
);
251 #if PHP_HTTP_DEBUG_PHANDLES
252 fprintf(stderr
, "ACQUIRE: %p (%s)\n", *handle
, name_str
);
258 PHP_HTTP_API STATUS
php_http_persistent_handle_release(const char *name_str
, size_t name_len
, void **handle TSRMLS_DC
)
260 STATUS status
= FAILURE
;
261 php_http_persistent_handle_provider_t
*provider
;
262 #if PHP_HTTP_DEBUG_PHANDLES
263 void *handle_tmp
= *handle
;
267 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
268 status
= php_http_persistent_handle_do_release(provider
, handle TSRMLS_CC
);
272 #if PHP_HTTP_DEBUG_PHANDLES
273 fprintf(stderr
, "RELEASE: %p (%s)\n", handle_tmp
, name_str
);
279 PHP_HTTP_API STATUS
php_http_persistent_handle_accrete(const char *name_str
, size_t name_len
, void *old_handle
, void **new_handle TSRMLS_DC
)
281 STATUS status
= FAILURE
;
282 php_http_persistent_handle_provider_t
*provider
;
286 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
287 status
= php_http_persistent_handle_do_accrete(provider
, old_handle
, new_handle TSRMLS_CC
);
291 #if PHP_HTTP_DEBUG_PHANDLES
292 fprintf(stderr
, "ACCRETE: %p > %p (%s)\n", old_handle
, *new_handle
, name_str
);
298 PHP_HTTP_API
void php_http_persistent_handle_cleanup(const char *name_str
, size_t name_len
, int current_ident_only TSRMLS_DC
)
300 php_http_persistent_handle_provider_t
*provider
;
301 php_http_persistent_handle_list_t
*list
, **listp
;
302 HashPosition pos1
, pos2
;
305 if (name_str
&& name_len
) {
306 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
307 if (current_ident_only
) {
308 if ((list
= php_http_persistent_handle_list_find(provider TSRMLS_CC
))) {
309 php_http_persistent_handle_list_dtor(list
, provider
->dtor
);
310 php_http_persistent_handle_list_init(list
);
313 FOREACH_HASH_VAL(pos1
, &provider
->list
.free
, listp
) {
314 php_http_persistent_handle_list_dtor(*listp
, provider
->dtor
);
315 php_http_persistent_handle_list_init(*listp
);
320 FOREACH_HASH_VAL(pos1
, &php_http_persistent_handles_hash
, provider
) {
321 if (current_ident_only
) {
322 if ((list
= php_http_persistent_handle_list_find(provider TSRMLS_CC
))) {
323 php_http_persistent_handle_list_dtor(list
, provider
->dtor
);
324 php_http_persistent_handle_list_init(list
);
327 FOREACH_HASH_VAL(pos2
, &provider
->list
.free
, listp
) {
328 php_http_persistent_handle_list_dtor(*listp
, provider
->dtor
);
329 php_http_persistent_handle_list_init(*listp
);
337 PHP_HTTP_API HashTable
*php_http_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
340 HashPosition pos1
, pos2
;
341 php_http_array_hashkey_t key1
= php_http_array_hashkey_init(0), key2
= php_http_array_hashkey_init(0);
342 php_http_persistent_handle_provider_t
*provider
;
343 php_http_persistent_handle_list_t
**list
;
346 if (zend_hash_num_elements(&php_http_persistent_handles_hash
)) {
349 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
352 FOREACH_HASH_KEYVAL(pos1
, &php_http_persistent_handles_hash
, key1
, provider
) {
353 MAKE_STD_ZVAL(zentry
[0]);
354 array_init(zentry
[0]);
356 FOREACH_HASH_KEYVAL(pos2
, &provider
->list
.free
, key2
, list
) {
357 MAKE_STD_ZVAL(zentry
[1]);
358 array_init(zentry
[1]);
359 add_assoc_long_ex(zentry
[1], ZEND_STRS("used"), (*list
)->used
);
360 add_assoc_long_ex(zentry
[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list
)->free
));
362 /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */
363 zend_hash_add(Z_ARRVAL_P(zentry
[0]), key2
.str
, key2
.len
, &zentry
[1], sizeof(zval
*), NULL
);
366 zend_hash_add(ht
, key1
.str
, key1
.len
, &zentry
[0], sizeof(zval
*), NULL
);
382 * vim600: noet sw=4 ts=4 fdm=marker
383 * vim<600: noet sw=4 ts=4