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-2007, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
16 #include "php_http_api.h"
18 #include "php_http_persistent_handle_api.h"
20 #ifndef HTTP_DEBUG_PHANDLES
21 # define HTTP_DEBUG_PHANDLES 0
23 #if HTTP_DEBUG_PHANDLES
28 static HashTable http_persistent_handles_hash
;
30 # define LOCK() tsrm_mutex_lock(http_persistent_handles_lock)
31 # define UNLOCK() tsrm_mutex_unlock(http_persistent_handles_lock)
32 static MUTEX_T http_persistent_handles_lock
;
38 typedef struct _http_persistent_handle_list_t
{
41 } http_persistent_handle_list
;
43 typedef struct _http_persistent_handle_provider_t
{
44 http_persistent_handle_list list
; /* "ident" => array(handles) entries */
45 http_persistent_handle_ctor ctor
;
46 http_persistent_handle_dtor dtor
;
47 http_persistent_handle_copy copy
;
48 } http_persistent_handle_provider
;
50 static inline http_persistent_handle_list
*http_persistent_handle_list_init(http_persistent_handle_list
*list
)
54 if ((free_list
= !list
)) {
55 list
= pemalloc(sizeof(http_persistent_handle_list
), 1);
60 if (SUCCESS
!= zend_hash_init(&list
->free
, 0, NULL
, NULL
, 1)) {
70 static inline void http_persistent_handle_list_dtor(http_persistent_handle_list
*list
, http_persistent_handle_dtor dtor
)
75 #if HTTP_DEBUG_PHANDLES
76 fprintf(stderr
, "LSTDTOR: %p\n", list
);
78 FOREACH_HASH_VAL(pos
, &list
->free
, handle
) {
79 #if HTTP_DEBUG_PHANDLES
80 fprintf(stderr
, "DESTROY: %p\n", *handle
);
85 zend_hash_destroy(&list
->free
);
88 static inline void http_persistent_handle_list_free(http_persistent_handle_list
**list
, http_persistent_handle_dtor dtor
)
90 http_persistent_handle_list_dtor(*list
, dtor
);
91 #if HTTP_DEBUG_PHANDLES
92 fprintf(stderr
, "LSTFREE: %p\n", *list
);
98 static inline http_persistent_handle_list
*http_persistent_handle_list_find(http_persistent_handle_provider
*provider TSRMLS_DC
)
100 http_persistent_handle_list
**list
, *new_list
;
102 if (SUCCESS
== zend_hash_quick_find(&provider
->list
.free
, HTTP_G
->persistent
.handles
.ident
.s
, HTTP_G
->persistent
.handles
.ident
.l
, HTTP_G
->persistent
.handles
.ident
.h
, (void *) &list
)) {
103 #if HTTP_DEBUG_PHANDLES
104 fprintf(stderr
, "LSTFIND: %p\n", *list
);
109 if ((new_list
= http_persistent_handle_list_init(NULL
))) {
110 if (SUCCESS
== zend_hash_quick_add(&provider
->list
.free
, HTTP_G
->persistent
.handles
.ident
.s
, HTTP_G
->persistent
.handles
.ident
.l
, HTTP_G
->persistent
.handles
.ident
.h
, (void *) &new_list
, sizeof(http_persistent_handle_list
*), (void *) &list
)) {
111 #if HTTP_DEBUG_PHANDLES
112 fprintf(stderr
, "LSTFIND: %p (new)\n", *list
);
116 http_persistent_handle_list_free(&new_list
, provider
->dtor
);
122 static inline STATUS
http_persistent_handle_do_acquire(http_persistent_handle_provider
*provider
, void **handle TSRMLS_DC
)
126 http_persistent_handle_list
*list
;
128 if ((list
= http_persistent_handle_list_find(provider TSRMLS_CC
))) {
129 zend_hash_internal_pointer_end(&list
->free
);
130 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
)) {
131 *handle
= *handle_ptr
;
132 zend_hash_index_del(&list
->free
, index
);
134 *handle
= provider
->ctor();
138 ++provider
->list
.used
;
149 static inline STATUS
http_persistent_handle_do_release(http_persistent_handle_provider
*provider
, void **handle TSRMLS_DC
)
151 http_persistent_handle_list
*list
;
153 if ((list
= http_persistent_handle_list_find(provider TSRMLS_CC
))) {
154 if (provider
->list
.used
>= HTTP_G
->persistent
.handles
.limit
) {
155 provider
->dtor(*handle
);
157 if (SUCCESS
!= zend_hash_next_index_insert(&list
->free
, (void *) handle
, sizeof(void *), NULL
)) {
163 --provider
->list
.used
;
171 static inline STATUS
http_persistent_handle_do_accrete(http_persistent_handle_provider
*provider
, void *old_handle
, void **new_handle TSRMLS_DC
)
173 http_persistent_handle_list
*list
;
175 if (provider
->copy
&& (*new_handle
= provider
->copy(old_handle
))) {
176 if ((list
= http_persistent_handle_list_find(provider TSRMLS_CC
))) {
179 ++provider
->list
.used
;
185 static void http_persistent_handles_hash_dtor(void *p
)
187 http_persistent_handle_provider
*provider
= (http_persistent_handle_provider
*) p
;
188 http_persistent_handle_list
**list
, *list_tmp
;
191 FOREACH_HASH_VAL(pos
, &provider
->list
.free
, list
) {
192 /* fix shutdown crash in PHP4 */
194 http_persistent_handle_list_free(&list_tmp
, provider
->dtor
);
197 zend_hash_destroy(&provider
->list
.free
);
200 PHP_MINIT_FUNCTION(http_persistent_handle
)
202 zend_hash_init(&http_persistent_handles_hash
, 0, NULL
, http_persistent_handles_hash_dtor
, 1);
204 http_persistent_handles_lock
= tsrm_mutex_alloc();
209 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle
)
211 zend_hash_destroy(&http_persistent_handles_hash
);
213 tsrm_mutex_free(http_persistent_handles_lock
);
218 PHP_HTTP_API STATUS
_http_persistent_handle_provide_ex(const char *name_str
, size_t name_len
, http_persistent_handle_ctor ctor
, http_persistent_handle_dtor dtor
, http_persistent_handle_copy copy
)
220 STATUS status
= FAILURE
;
221 http_persistent_handle_provider provider
;
224 if (http_persistent_handle_list_init(&provider
.list
)) {
225 provider
.ctor
= ctor
;
226 provider
.dtor
= dtor
;
227 provider
.copy
= copy
;
229 #if HTTP_DEBUG_PHANDLES
230 fprintf(stderr
, "PROVIDE: %s\n", name_str
);
233 if (SUCCESS
== zend_hash_add(&http_persistent_handles_hash
, HTTP_ZAPI_CONST_CAST(char *) name_str
, name_len
+1, (void *) &provider
, sizeof(http_persistent_handle_provider
), NULL
)) {
242 PHP_HTTP_API STATUS
_http_persistent_handle_acquire_ex(const char *name_str
, size_t name_len
, void **handle TSRMLS_DC
)
244 STATUS status
= FAILURE
;
245 http_persistent_handle_provider
*provider
;
249 if (SUCCESS
== zend_hash_find(&http_persistent_handles_hash
, HTTP_ZAPI_CONST_CAST(char *) name_str
, name_len
+1, (void *) &provider
)) {
250 status
= http_persistent_handle_do_acquire(provider
, handle TSRMLS_CC
);
254 #if HTTP_DEBUG_PHANDLES
255 fprintf(stderr
, "ACQUIRE: %p (%s)\n", *handle
, name_str
);
261 PHP_HTTP_API STATUS
_http_persistent_handle_release_ex(const char *name_str
, size_t name_len
, void **handle TSRMLS_DC
)
263 STATUS status
= FAILURE
;
264 http_persistent_handle_provider
*provider
;
265 #if HTTP_DEBUG_PHANDLES
266 void *handle_tmp
= *handle
;
270 if (SUCCESS
== zend_hash_find(&http_persistent_handles_hash
, HTTP_ZAPI_CONST_CAST(char *) name_str
, name_len
+1, (void *) &provider
)) {
271 status
= http_persistent_handle_do_release(provider
, handle TSRMLS_CC
);
275 #if HTTP_DEBUG_PHANDLES
276 fprintf(stderr
, "RELEASE: %p (%s)\n", handle_tmp
, name_str
);
282 PHP_HTTP_API STATUS
_http_persistent_handle_accrete_ex(const char *name_str
, size_t name_len
, void *old_handle
, void **new_handle TSRMLS_DC
)
284 STATUS status
= FAILURE
;
285 http_persistent_handle_provider
*provider
;
289 if (SUCCESS
== zend_hash_find(&http_persistent_handles_hash
, HTTP_ZAPI_CONST_CAST(char *) name_str
, name_len
+1, (void *) &provider
)) {
290 status
= http_persistent_handle_do_accrete(provider
, old_handle
, new_handle TSRMLS_CC
);
294 #if HTTP_DEBUG_PHANDLES
295 fprintf(stderr
, "ACCRETE: %p > %p (%s)\n", old_handle
, *new_handle
, name_str
);
301 PHP_HTTP_API
void _http_persistent_handle_cleanup_ex(const char *name_str
, size_t name_len
, int current_ident_only TSRMLS_DC
)
303 http_persistent_handle_provider
*provider
;
304 http_persistent_handle_list
*list
, **listp
;
305 HashPosition pos1
, pos2
;
308 if (name_str
&& name_len
) {
309 if (SUCCESS
== zend_hash_find(&http_persistent_handles_hash
, HTTP_ZAPI_CONST_CAST(char *) name_str
, name_len
+1, (void *) &provider
)) {
310 if (current_ident_only
) {
311 if ((list
= http_persistent_handle_list_find(provider TSRMLS_CC
))) {
312 http_persistent_handle_list_dtor(list
, provider
->dtor
);
313 http_persistent_handle_list_init(list
);
316 FOREACH_HASH_VAL(pos1
, &provider
->list
.free
, listp
) {
317 http_persistent_handle_list_dtor(*listp
, provider
->dtor
);
318 http_persistent_handle_list_init(*listp
);
323 FOREACH_HASH_VAL(pos1
, &http_persistent_handles_hash
, provider
) {
324 if (current_ident_only
) {
325 if ((list
= http_persistent_handle_list_find(provider TSRMLS_CC
))) {
326 http_persistent_handle_list_dtor(list
, provider
->dtor
);
327 http_persistent_handle_list_init(list
);
330 FOREACH_HASH_VAL(pos2
, &provider
->list
.free
, listp
) {
331 http_persistent_handle_list_dtor(*listp
, provider
->dtor
);
332 http_persistent_handle_list_init(*listp
);
340 PHP_HTTP_API HashTable
*_http_persistent_handle_statall_ex(HashTable
*ht TSRMLS_DC
)
343 HashPosition pos1
, pos2
;
344 HashKey key1
= initHashKey(0), key2
= initHashKey(0);
345 http_persistent_handle_provider
*provider
;
346 http_persistent_handle_list
**list
;
349 if (zend_hash_num_elements(&http_persistent_handles_hash
)) {
352 zend_hash_init(ht
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
355 FOREACH_HASH_KEYVAL(pos1
, &http_persistent_handles_hash
, key1
, provider
) {
356 MAKE_STD_ZVAL(zentry
[0]);
357 array_init(zentry
[0]);
359 FOREACH_HASH_KEYVAL(pos2
, &provider
->list
.free
, key2
, list
) {
360 MAKE_STD_ZVAL(zentry
[1]);
361 array_init(zentry
[1]);
362 add_assoc_long_ex(zentry
[1], ZEND_STRS("used"), (*list
)->used
);
363 add_assoc_long_ex(zentry
[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list
)->free
));
365 /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */
366 zend_hash_add(Z_ARRVAL_P(zentry
[0]), key2
.str
, key2
.len
, &zentry
[1], sizeof(zval
*), NULL
);
369 zend_hash_add(ht
, key1
.str
, key1
.len
, &zentry
[0], sizeof(zval
*), NULL
);
385 * vim600: noet sw=4 ts=4 fdm=marker
386 * vim<600: noet sw=4 ts=4