X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_persistent_handle_api.c;h=84f1b48960fdcfbfe6cdacf55fcf26be372ce28d;hp=b07caffdda4220966b5dc4564d48292387fd6a20;hb=ad5f896b03adaa073134a00108a9cdf00720673a;hpb=18dc0cdcdaf502f2cf2ad9e824212cfab0df7808 diff --git a/http_persistent_handle_api.c b/http_persistent_handle_api.c index b07caff..84f1b48 100644 --- a/http_persistent_handle_api.c +++ b/http_persistent_handle_api.c @@ -6,7 +6,7 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2007, Michael Wallner | + | Copyright (c) 2004-2010, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -15,12 +15,15 @@ #include "php_http.h" #include "php_http_api.h" -#ifdef HTTP_HAVE_PERSISTENT_HANDLES #include "php_http_persistent_handle_api.h" #ifndef HTTP_DEBUG_PHANDLES # define HTTP_DEBUG_PHANDLES 0 #endif +#if HTTP_DEBUG_PHANDLES +# undef inline +# define inline +#endif static HashTable http_persistent_handles_hash; #ifdef ZTS @@ -32,70 +35,166 @@ static MUTEX_T http_persistent_handles_lock; # define UNLOCK() #endif -typedef struct _http_persistent_handle_t { - void *ptr; -} http_persistent_handle; - -typedef HashTable *http_persistent_handle_list; +typedef struct _http_persistent_handle_list_t { + HashTable free; + ulong used; +} http_persistent_handle_list; typedef struct _http_persistent_handle_provider_t { http_persistent_handle_list list; /* "ident" => array(handles) entries */ http_persistent_handle_ctor ctor; http_persistent_handle_dtor dtor; + http_persistent_handle_copy copy; } http_persistent_handle_provider; - -static inline STATUS http_persistent_handle_list_find(http_persistent_handle_list parent_list, http_persistent_handle_list **ident_list, int create TSRMLS_DC) +static inline http_persistent_handle_list *http_persistent_handle_list_init(http_persistent_handle_list *list) { - http_persistent_handle_list new_list; + int free_list; - if (SUCCESS == zend_hash_quick_find(parent_list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) ident_list)) { - return SUCCESS; + if ((free_list = !list)) { + list = pemalloc(sizeof(http_persistent_handle_list), 1); } - if (create) { - if ((new_list = pemalloc(sizeof(HashTable), 1))) { - if (SUCCESS == zend_hash_init(new_list, 0, NULL, NULL, 1)) { - if (SUCCESS == zend_hash_quick_add(parent_list, 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 *) ident_list)) { - return SUCCESS; - } - zend_hash_destroy(new_list); - } - pefree(new_list, 1); + list->used = 0; + + if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) { + if (free_list) { + pefree(list, 1); } + list = NULL; } - return FAILURE; + return list; } -static inline void http_persistent_handle_list_dtor(http_persistent_handle_list list, http_persistent_handle_dtor dtor) +static inline void http_persistent_handle_list_dtor(http_persistent_handle_list *list, http_persistent_handle_dtor dtor) { HashPosition pos; - http_persistent_handle *handle; + void **handle; + +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "LSTDTOR: %p\n", list); +#endif + FOREACH_HASH_VAL(pos, &list->free, handle) { +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "DESTROY: %p\n", *handle); +#endif + + dtor(*handle); + } + zend_hash_destroy(&list->free); +} + +static inline void http_persistent_handle_list_free(http_persistent_handle_list **list, http_persistent_handle_dtor dtor) +{ + http_persistent_handle_list_dtor(*list, dtor); +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "LSTFREE: %p\n", *list); +#endif + pefree(*list, 1); + *list = NULL; +} + +static inline http_persistent_handle_list *http_persistent_handle_list_find(http_persistent_handle_provider *provider TSRMLS_DC) +{ + http_persistent_handle_list **list, *new_list; - FOREACH_HASH_VAL(pos, list, handle) { + 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)) { #if HTTP_DEBUG_PHANDLES - fprintf(stderr, "DESTROY: %p\n", handle->ptr); + fprintf(stderr, "LSTFIND: %p\n", *list); #endif + return *list; + } + + if ((new_list = http_persistent_handle_list_init(NULL))) { + 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)) { +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "LSTFIND: %p (new)\n", *list); +#endif + return *list; + } + http_persistent_handle_list_free(&new_list, provider->dtor); + } + + return NULL; +} + +static inline STATUS http_persistent_handle_do_acquire(http_persistent_handle_provider *provider, void **handle TSRMLS_DC) +{ + ulong index; + void **handle_ptr; + http_persistent_handle_list *list; + + if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { + zend_hash_internal_pointer_end(&list->free); + 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)) { + *handle = *handle_ptr; + zend_hash_index_del(&list->free, index); + } else { + *handle = provider->ctor(); + } - dtor(handle->ptr); + if (*handle) { + ++provider->list.used; + ++list->used; + return SUCCESS; + } + } else { + *handle = NULL; } - zend_hash_clean(list); + + return FAILURE; +} + +static inline STATUS http_persistent_handle_do_release(http_persistent_handle_provider *provider, void **handle TSRMLS_DC) +{ + http_persistent_handle_list *list; + + if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { + if (provider->list.used >= HTTP_G->persistent.handles.limit) { + provider->dtor(*handle); + } else { + if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) { + return FAILURE; + } + } + + *handle = NULL; + --provider->list.used; + --list->used; + return SUCCESS; + } + + return FAILURE; +} + +static inline STATUS http_persistent_handle_do_accrete(http_persistent_handle_provider *provider, void *old_handle, void **new_handle TSRMLS_DC) +{ + http_persistent_handle_list *list; + + if (provider->copy && (*new_handle = provider->copy(old_handle))) { + if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { + ++list->used; + } + ++provider->list.used; + return SUCCESS; + } + return FAILURE; } static void http_persistent_handles_hash_dtor(void *p) { http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p; - http_persistent_handle_list *list; + http_persistent_handle_list **list, *list_tmp; HashPosition pos; - FOREACH_HASH_VAL(pos, provider->list, list) { - http_persistent_handle_list_dtor(*list, provider->dtor); - zend_hash_destroy(*list); - pefree(*list, 1); + FOREACH_HASH_VAL(pos, &provider->list.free, list) { + /* fix shutdown crash in PHP4 */ + list_tmp = *list; + http_persistent_handle_list_free(&list_tmp, provider->dtor); } - zend_hash_destroy(provider->list); - pefree(provider->list, 1); + + zend_hash_destroy(&provider->list.free); } PHP_MINIT_FUNCTION(http_persistent_handle) @@ -116,26 +215,23 @@ PHP_MSHUTDOWN_FUNCTION(http_persistent_handle) return SUCCESS; } -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) +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) { STATUS status = FAILURE; http_persistent_handle_provider provider; LOCK(); - provider.list = pemalloc(sizeof(HashTable), 1); - if (provider.list) { + if (http_persistent_handle_list_init(&provider.list)) { provider.ctor = ctor; provider.dtor = dtor; - zend_hash_init(provider.list, 0, NULL, NULL, 1); + provider.copy = copy; #if HTTP_DEBUG_PHANDLES - fprintf(stderr, "PROVIDE: %p (%s)\n", provider.list, name_str); + fprintf(stderr, "PROVIDE: %s\n", name_str); #endif - if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) { + 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)) { status = SUCCESS; - } else { - pefree(provider.list, 1); } } UNLOCK(); @@ -143,88 +239,97 @@ PHP_HTTP_API STATUS _http_persistent_handle_provide_ex(const char *name_str, siz return status; } -PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC) +PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC) { STATUS status = FAILURE; - ulong index; http_persistent_handle_provider *provider; - http_persistent_handle_list *list; - http_persistent_handle *handle; - *handle_ptr = NULL; + *handle = NULL; LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) { - if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) { - zend_hash_internal_pointer_end(*list); - if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(*list, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(*list, (void *) &handle)) { - *handle_ptr = handle->ptr; - zend_hash_index_del(*list, index); - } - } - if (*handle_ptr || (*handle_ptr = provider->ctor())) { - status = SUCCESS; - } + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { + status = http_persistent_handle_do_acquire(provider, handle TSRMLS_CC); } UNLOCK(); #if HTTP_DEBUG_PHANDLES - fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle_ptr, name_str); + fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle, name_str); #endif return status; } -PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC) +PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle TSRMLS_DC) { STATUS status = FAILURE; http_persistent_handle_provider *provider; - http_persistent_handle_list *list; - http_persistent_handle handle = {*handle_ptr}; +#if HTTP_DEBUG_PHANDLES + void *handle_tmp = *handle; +#endif LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) { - if ( SUCCESS == http_persistent_handle_list_find(provider->list, &list, 1 TSRMLS_CC) && - SUCCESS == zend_hash_next_index_insert(*list, (void *) &handle, sizeof(http_persistent_handle), NULL)) { - status = SUCCESS; - } + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { + status = http_persistent_handle_do_release(provider, handle TSRMLS_CC); } UNLOCK(); #if HTTP_DEBUG_PHANDLES - fprintf(stderr, "RELEASE: %p (%s)\n", *handle_ptr, name_str); + fprintf(stderr, "RELEASE: %p (%s)\n", handle_tmp, name_str); #endif return status; } + +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) +{ + STATUS status = FAILURE; + http_persistent_handle_provider *provider; + *new_handle = NULL; + LOCK(); + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { + status = http_persistent_handle_do_accrete(provider, old_handle, new_handle TSRMLS_CC); + } + UNLOCK(); + +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str); +#endif + + return status; +} + PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC) { http_persistent_handle_provider *provider; - http_persistent_handle_list *list; + http_persistent_handle_list *list, **listp; HashPosition pos1, pos2; LOCK(); if (name_str && name_len) { - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) { + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, HTTP_ZAPI_CONST_CAST(char *) name_str, name_len+1, (void *) &provider)) { if (current_ident_only) { - if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) { - http_persistent_handle_list_dtor(*list, provider->dtor); + if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { + http_persistent_handle_list_dtor(list, provider->dtor); + http_persistent_handle_list_init(list); } } else { - FOREACH_HASH_VAL(pos1, provider->list, list) { - http_persistent_handle_list_dtor(*list, provider->dtor); + FOREACH_HASH_VAL(pos1, &provider->list.free, listp) { + http_persistent_handle_list_dtor(*listp, provider->dtor); + http_persistent_handle_list_init(*listp); } } } } else { FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) { if (current_ident_only) { - if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) { - http_persistent_handle_list_dtor(*list, provider->dtor); + if ((list = http_persistent_handle_list_find(provider TSRMLS_CC))) { + http_persistent_handle_list_dtor(list, provider->dtor); + http_persistent_handle_list_init(list); } } else { - FOREACH_HASH_VAL(pos2, provider->list, list) { - http_persistent_handle_list_dtor(*list, provider->dtor); + FOREACH_HASH_VAL(pos2, &provider->list.free, listp) { + http_persistent_handle_list_dtor(*listp, provider->dtor); + http_persistent_handle_list_init(*listp); } } } @@ -232,13 +337,13 @@ PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_ UNLOCK(); } -PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht) +PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht TSRMLS_DC) { - zval *zlist, *zentry; + zval *zentry[2]; HashPosition pos1, pos2; HashKey key1 = initHashKey(0), key2 = initHashKey(0); http_persistent_handle_provider *provider; - http_persistent_handle_list *list; + http_persistent_handle_list **list; LOCK(); if (zend_hash_num_elements(&http_persistent_handles_hash)) { @@ -248,14 +353,20 @@ PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht) } FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) { - MAKE_STD_ZVAL(zlist); - array_init(zlist); - FOREACH_HASH_KEYVAL(pos2, provider->list, key2, list) { - MAKE_STD_ZVAL(zentry); - ZVAL_LONG(zentry, zend_hash_num_elements(*list)); - zend_hash_add(Z_ARRVAL_P(zlist), key2.str, key2.len, (void *) &zentry, sizeof(zval *), NULL); + MAKE_STD_ZVAL(zentry[0]); + array_init(zentry[0]); + + FOREACH_HASH_KEYVAL(pos2, &provider->list.free, key2, list) { + MAKE_STD_ZVAL(zentry[1]); + array_init(zentry[1]); + add_assoc_long_ex(zentry[1], ZEND_STRS("used"), (*list)->used); + add_assoc_long_ex(zentry[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list)->free)); + + /* use zend_hash_* not add_assoc_* (which is zend_symtable_*) as we want a string even for numbers */ + zend_hash_add(Z_ARRVAL_P(zentry[0]), key2.str, key2.len, &zentry[1], sizeof(zval *), NULL); } - zend_hash_add(ht, key1.str, key1.len, (void *) &zlist, sizeof(zval *), NULL); + + zend_hash_add(ht, key1.str, key1.len, &zentry[0], sizeof(zval *), NULL); } } else if (ht) { ht = NULL; @@ -265,7 +376,6 @@ PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht) return ht; } -#endif /* HTTP_HAVE_PERSISTENT_HANDLES */ /* * Local variables: