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_resource_factory_t rf
;
43 } php_http_persistent_handle_provider_t
;
45 static inline php_http_persistent_handle_list_t
*php_http_persistent_handle_list_init(php_http_persistent_handle_list_t
*list
)
49 if ((free_list
= !list
)) {
50 list
= pemalloc(sizeof(php_http_persistent_handle_list_t
), 1);
55 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
65 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
)
70 #if PHP_HTTP_DEBUG_PHANDLES
71 fprintf(stderr
, "LSTDTOR: %p\n", list
);
73 FOREACH_HASH_VAL(pos
, &list
->free
, handle
) {
74 #if PHP_HTTP_DEBUG_PHANDLES
75 fprintf(stderr
, "DESTROY: %p\n", *handle
);
78 provider
->rf
.fops
.dtor(provider
->rf
.data
, *handle TSRMLS_CC
);
80 zend_hash_destroy(&list
->free
);
83 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
)
85 php_http_persistent_handle_list_dtor(*list
, provider TSRMLS_CC
);
86 #if PHP_HTTP_DEBUG_PHANDLES
87 fprintf(stderr
, "LSTFREE: %p\n", *list
);
93 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
)
95 php_http_persistent_handle_list_t
**list
, *new_list
;
97 if (SUCCESS
== zend_hash_find(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &list
)) {
98 #if PHP_HTTP_DEBUG_PHANDLES
99 fprintf(stderr
, "LSTFIND: %p\n", *list
);
104 if ((new_list
= php_http_persistent_handle_list_init(NULL
))) {
105 if (SUCCESS
== zend_hash_add(&provider
->list
.free
, ident_str
, ident_len
+ 1, (void *) &new_list
, sizeof(php_http_persistent_handle_list_t
*), (void *) &list
)) {
106 #if PHP_HTTP_DEBUG_PHANDLES
107 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
111 php_http_persistent_handle_list_free(&new_list
, provider TSRMLS_CC
);
117 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
)
121 php_http_persistent_handle_list_t
*list
;
123 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
124 zend_hash_internal_pointer_end(&list
->free
);
125 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
)) {
126 *handle
= *handle_ptr
;
127 zend_hash_index_del(&list
->free
, index
);
129 *handle
= provider
->rf
.fops
.ctor(provider
->rf
.data TSRMLS_CC
);
133 ++provider
->list
.used
;
144 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
)
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 if (provider
->list
.used
>= PHP_HTTP_G
->persistent_handle
.limit
) {
150 provider
->rf
.fops
.dtor(provider
->rf
.data
, *handle TSRMLS_CC
);
152 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
158 --provider
->list
.used
;
166 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
)
168 php_http_persistent_handle_list_t
*list
;
170 if (provider
->rf
.fops
.copy
&& (*new_handle
= provider
->rf
.fops
.copy(provider
->rf
.data
, old_handle TSRMLS_CC
))) {
171 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
174 ++provider
->list
.used
;
180 static void php_http_persistent_handles_hash_dtor(void *p
)
182 php_http_persistent_handle_provider_t
*provider
= (php_http_persistent_handle_provider_t
*) p
;
183 php_http_persistent_handle_list_t
**list
, *list_tmp
;
186 FOREACH_HASH_VAL(pos
, &provider
->list
.free
, list
) {
187 /* fix shutdown crash in PHP4 */
189 php_http_persistent_handle_list_free(&list_tmp
, provider TSRMLS_CC
);
192 zend_hash_destroy(&provider
->list
.free
);
193 php_http_resource_factory_dtor(&provider
->rf
);
196 PHP_MINIT_FUNCTION(http_persistent_handle
)
198 zend_hash_init(&php_http_persistent_handles_hash
, 0, NULL
, php_http_persistent_handles_hash_dtor
, 1);
200 php_http_persistent_handles_lock
= tsrm_mutex_alloc();
205 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle
)
207 zend_hash_destroy(&php_http_persistent_handles_hash
);
209 tsrm_mutex_free(php_http_persistent_handles_lock
);
214 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 *))
216 STATUS status
= FAILURE
;
217 php_http_persistent_handle_provider_t provider
;
220 if (php_http_persistent_handle_list_init(&provider
.list
)) {
221 if (php_http_resource_factory_init(&provider
.rf
, fops
, data
, dtor
)) {
222 #if PHP_HTTP_DEBUG_PHANDLES
223 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
226 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
)) {
229 php_http_resource_factory_dtor(&provider
.rf
);
238 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
)
240 STATUS status
= FAILURE
;
241 php_http_persistent_handle_factory_t
*free_a
= NULL
;
244 free_a
= a
= emalloc(sizeof(*a
));
246 memset(a
, 0, sizeof(*a
));
249 status
= zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &a
->provider
);
252 if (SUCCESS
== status
) {
253 a
->ident
.str
= estrndup(ident_str
, a
->ident
.len
= ident_len
);
255 a
->free_on_abandon
= 1;
264 #if PHP_HTTP_DEBUG_PHANDLES
265 fprintf(stderr
, "CONCETE: %p (%s) (%s)\n", a
? a
->provider
: NULL
, name_str
, ident_str
);
271 PHP_HTTP_API
void php_http_persistent_handle_abandon(php_http_persistent_handle_factory_t
*a
)
273 zend_bool f
= a
->free_on_abandon
;
275 STR_FREE(a
->ident
.str
);
276 memset(a
, 0, sizeof(*a
));
282 PHP_HTTP_API
void *php_http_persistent_handle_acquire(php_http_persistent_handle_factory_t
*a TSRMLS_DC
)
287 php_http_persistent_handle_do_acquire(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle TSRMLS_CC
);
293 PHP_HTTP_API
void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
298 php_http_persistent_handle_do_accrete(a
->provider
, a
->ident
.str
, a
->ident
.len
, handle
, &new_handle TSRMLS_CC
);
304 PHP_HTTP_API
void php_http_persistent_handle_release(php_http_persistent_handle_factory_t
*a
, void *handle TSRMLS_DC
)
307 php_http_persistent_handle_do_release(a
->provider
, a
->ident
.str
, a
->ident
.len
, &handle
);
311 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
)
313 STATUS status
= FAILURE
;
314 php_http_persistent_handle_provider_t
*provider
;
318 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
319 status
= php_http_persistent_handle_do_acquire(provider
, ident_str
, ident_len
, handle TSRMLS_CC
);
323 #if PHP_HTTP_DEBUG_PHANDLES
324 fprintf(stderr
, "ACQUIRE: %p (%s)\n", *handle
, name_str
);
330 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
)
332 STATUS status
= FAILURE
;
333 php_http_persistent_handle_provider_t
*provider
;
334 #if PHP_HTTP_DEBUG_PHANDLES
335 void *handle_tmp
= *handle
;
339 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
340 status
= php_http_persistent_handle_do_release(provider
, ident_str
, ident_len
, handle TSRMLS_CC
);
344 #if PHP_HTTP_DEBUG_PHANDLES
345 fprintf(stderr
, "RELEASE: %p (%s)\n", handle_tmp
, name_str
);
351 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
)
353 STATUS status
= FAILURE
;
354 php_http_persistent_handle_provider_t
*provider
;
358 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
359 status
= php_http_persistent_handle_do_accrete(provider
, ident_str
, ident_len
, old_handle
, new_handle TSRMLS_CC
);
363 #if PHP_HTTP_DEBUG_PHANDLES
364 fprintf(stderr
, "ACCRETE: %p > %p (%s)\n", old_handle
, *new_handle
, name_str
);
370 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
)
372 php_http_persistent_handle_provider_t
*provider
;
373 php_http_persistent_handle_list_t
*list
, **listp
;
374 HashPosition pos1
, pos2
;
377 if (name_str
&& name_len
) {
378 if (SUCCESS
== zend_hash_find(&php_http_persistent_handles_hash
, name_str
, name_len
+1, (void *) &provider
)) {
379 if (ident_str
&& ident_len
) {
380 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
381 php_http_persistent_handle_list_dtor(list
, provider TSRMLS_CC
);
382 php_http_persistent_handle_list_init(list
);
385 FOREACH_HASH_VAL(pos1
, &provider
->list
.free
, listp
) {
386 php_http_persistent_handle_list_dtor(*listp
, provider TSRMLS_CC
);
387 php_http_persistent_handle_list_init(*listp
);
392 FOREACH_HASH_VAL(pos1
, &php_http_persistent_handles_hash
, provider
) {
393 if (ident_str
&& ident_len
) {
394 if ((list
= php_http_persistent_handle_list_find(provider
, ident_str
, ident_len TSRMLS_CC
))) {
395 php_http_persistent_handle_list_dtor(list
, provider TSRMLS_CC
);
396 php_http_persistent_handle_list_init(list
);
399 FOREACH_HASH_VAL(pos2
, &provider
->list
.free
, listp
) {
400 php_http_persistent_handle_list_dtor(*listp
, provider TSRMLS_CC
);
401 php_http_persistent_handle_list_init(*listp
);
409 PHP_HTTP_API HashTable
*php_http_persistent_handle_statall(HashTable
*ht TSRMLS_DC
)
412 HashPosition pos1
, pos2
;
413 php_http_array_hashkey_t key1
= php_http_array_hashkey_init(0), key2
= php_http_array_hashkey_init(0);
414 php_http_persistent_handle_provider_t
*provider
;
415 php_http_persistent_handle_list_t
**list
;
418 if (zend_hash_num_elements(&php_http_persistent_handles_hash
)) {
421 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
424 FOREACH_HASH_KEYVAL(pos1
, &php_http_persistent_handles_hash
, key1
, provider
) {
425 MAKE_STD_ZVAL(zentry
[0]);
426 array_init(zentry
[0]);
428 FOREACH_HASH_KEYVAL(pos2
, &provider
->list
.free
, key2
, list
) {
429 MAKE_STD_ZVAL(zentry
[1]);
430 array_init(zentry
[1]);
431 add_assoc_long_ex(zentry
[1], ZEND_STRS("used"), (*list
)->used
);
432 add_assoc_long_ex(zentry
[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list
)->free
));
434 /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */
435 zend_hash_add(Z_ARRVAL_P(zentry
[0]), key2
.str
, key2
.len
, &zentry
[1], sizeof(zval
*), NULL
);
438 zend_hash_add(ht
, key1
.str
, key1
.len
, &zentry
[0], sizeof(zval
*), NULL
);
454 * vim600: noet sw=4 ts=4 fdm=marker
455 * vim<600: noet sw=4 ts=4