X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;ds=sidebyside;f=http_persistent_handle_api.c;h=b07caffdda4220966b5dc4564d48292387fd6a20;hb=18dc0cdcdaf502f2cf2ad9e824212cfab0df7808;hp=8fc1b02f72d1a775d9a0a00c256472712774fd2c;hpb=fa6e9a361695e1c273266c79d0d27ff19059bb8a;p=m6w6%2Fext-http diff --git a/http_persistent_handle_api.c b/http_persistent_handle_api.c index 8fc1b02..b07caff 100644 --- a/http_persistent_handle_api.c +++ b/http_persistent_handle_api.c @@ -6,18 +6,22 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2006, Michael Wallner | + | Copyright (c) 2004-2007, Michael Wallner | +--------------------------------------------------------------------+ */ /* $Id$ */ #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 + static HashTable http_persistent_handles_hash; #ifdef ZTS # define LOCK() tsrm_mutex_lock(http_persistent_handles_lock) @@ -28,34 +32,70 @@ static MUTEX_T http_persistent_handles_lock; # define UNLOCK() #endif -typedef struct _http_persistent_handles_hash_entry_t { - HashTable list; +typedef struct _http_persistent_handle_t { + void *ptr; +} http_persistent_handle; + +typedef HashTable *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_handles_hash_entry; +} http_persistent_handle_provider; -typedef struct _http_persistent_handles_list_entry_t { - void *handle; -} http_persistent_handles_list_entry; -static inline void http_persistent_handles_hash_dtor_ex(http_persistent_handles_hash_entry *hentry, void (*list_dtor)(HashTable*)) +static inline STATUS http_persistent_handle_list_find(http_persistent_handle_list parent_list, http_persistent_handle_list **ident_list, int create TSRMLS_DC) { - http_persistent_handles_list_entry *lentry; + http_persistent_handle_list new_list; - for ( zend_hash_internal_pointer_reset(&hentry->list); - SUCCESS == zend_hash_get_current_data(&hentry->list, (void *) &lentry); - zend_hash_move_forward(&hentry->list)) { - hentry->dtor(lentry->handle); + 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 (list_dtor) { - list_dtor(&hentry->list); + 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); + } } + + return FAILURE; } -static void http_persistent_handles_hash_dtor(void *h) +static inline void http_persistent_handle_list_dtor(http_persistent_handle_list list, http_persistent_handle_dtor dtor) { - http_persistent_handles_hash_dtor_ex(h, zend_hash_destroy); + HashPosition pos; + http_persistent_handle *handle; + + FOREACH_HASH_VAL(pos, list, handle) { +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "DESTROY: %p\n", handle->ptr); +#endif + + dtor(handle->ptr); + } + zend_hash_clean(list); +} + +static void http_persistent_handles_hash_dtor(void *p) +{ + http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p; + http_persistent_handle_list *list; + HashPosition pos; + + FOREACH_HASH_VAL(pos, provider->list, list) { + http_persistent_handle_list_dtor(*list, provider->dtor); + zend_hash_destroy(*list); + pefree(*list, 1); + } + zend_hash_destroy(provider->list); + pefree(provider->list, 1); } PHP_MINIT_FUNCTION(http_persistent_handle) @@ -78,106 +118,151 @@ PHP_MSHUTDOWN_FUNCTION(http_persistent_handle) 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) { - STATUS status = SUCCESS; - http_persistent_handles_hash_entry e; - - zend_hash_init(&e.list, 0, NULL, NULL, 1); - e.ctor = ctor; - e.dtor = dtor; + STATUS status = FAILURE; + http_persistent_handle_provider provider; LOCK(); - if (SUCCESS != zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &e, sizeof(http_persistent_handles_hash_entry), NULL)) { - zend_hash_destroy(&e.list); - status = FAILURE; + provider.list = pemalloc(sizeof(HashTable), 1); + if (provider.list) { + provider.ctor = ctor; + provider.dtor = dtor; + zend_hash_init(provider.list, 0, NULL, NULL, 1); + +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "PROVIDE: %p (%s)\n", provider.list, 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)) { + status = SUCCESS; + } else { + pefree(provider.list, 1); + } } UNLOCK(); return status; } -PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len) +PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC) { - http_persistent_handles_hash_entry *hentry; + STATUS status = FAILURE; + ulong index; + http_persistent_handle_provider *provider; + http_persistent_handle_list *list; + http_persistent_handle *handle; + *handle_ptr = NULL; LOCK(); - if (name_str && name_len) { - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) { - http_persistent_handles_hash_dtor_ex(hentry, zend_hash_clean); + 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); + } } - } else { - for ( zend_hash_internal_pointer_reset(&http_persistent_handles_hash); - SUCCESS == zend_hash_get_current_data(&http_persistent_handles_hash, (void *) &hentry); - zend_hash_move_forward(&http_persistent_handles_hash)) { - http_persistent_handles_hash_dtor_ex(hentry, zend_hash_clean); + if (*handle_ptr || (*handle_ptr = provider->ctor())) { + status = SUCCESS; } } UNLOCK(); + +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle_ptr, name_str); +#endif + + return status; } -PHP_HTTP_API int _http_persistent_handle_statall_ex(char ***names, int **counts, int persistent) +PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC) { - int i, n; - char *key; - http_persistent_handles_hash_entry *hentry; + STATUS status = FAILURE; + http_persistent_handle_provider *provider; + http_persistent_handle_list *list; + http_persistent_handle handle = {*handle_ptr}; LOCK(); - if ((n = zend_hash_num_elements(&http_persistent_handles_hash))) { - *names = safe_pemalloc(n, sizeof(char **), 0, persistent); - *counts = safe_pemalloc(n, sizeof(int), 0, persistent); - - for ( i = 0, zend_hash_internal_pointer_reset(&http_persistent_handles_hash); - HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&http_persistent_handles_hash, &key, NULL, 0) && - SUCCESS == zend_hash_get_current_data(&http_persistent_handles_hash, (void *) &hentry); - ++i, zend_hash_move_forward(&http_persistent_handles_hash)) { - (*names)[i] = pestrdup(key, persistent); - (*counts)[i] = zend_hash_num_elements(&hentry->list); + 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; } } UNLOCK(); - return n; +#if HTTP_DEBUG_PHANDLES + fprintf(stderr, "RELEASE: %p (%s)\n", *handle_ptr, name_str); +#endif + + return status; } - -PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle) + +PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC) { - STATUS status = FAILURE; - ulong index; - http_persistent_handles_hash_entry *hentry; - http_persistent_handles_list_entry *lentry; + http_persistent_handle_provider *provider; + http_persistent_handle_list *list; + HashPosition pos1, pos2; LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) { - zend_hash_internal_pointer_reset(&hentry->list); - if ( HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(&hentry->list, NULL, &index, 0) && - SUCCESS == zend_hash_get_current_data(&hentry->list, (void *) &lentry)) { - *handle = lentry->handle; - zend_hash_index_del(&hentry->list, index); - status = SUCCESS; - } else if ((*handle = hentry->ctor())) { - status = SUCCESS; + if (name_str && name_len) { + if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (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); + } + } else { + FOREACH_HASH_VAL(pos1, provider->list, list) { + http_persistent_handle_list_dtor(*list, provider->dtor); + } + } + } + } 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); + } + } else { + FOREACH_HASH_VAL(pos2, provider->list, list) { + http_persistent_handle_list_dtor(*list, provider->dtor); + } + } } } UNLOCK(); - - return status; } -PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle) +PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht) { - STATUS status = FAILURE; - http_persistent_handles_hash_entry *hentry; - http_persistent_handles_list_entry lentry; + zval *zlist, *zentry; + HashPosition pos1, pos2; + HashKey key1 = initHashKey(0), key2 = initHashKey(0); + http_persistent_handle_provider *provider; + http_persistent_handle_list *list; LOCK(); - if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &hentry)) { - lentry.handle = *handle; - if (SUCCESS == zend_hash_next_index_insert(&hentry->list, (void *) &lentry, sizeof(http_persistent_handles_list_entry), NULL)) { - status = SUCCESS; + if (zend_hash_num_elements(&http_persistent_handles_hash)) { + if (!ht) { + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0); } + + 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); + } + zend_hash_add(ht, key1.str, key1.len, (void *) &zlist, sizeof(zval *), NULL); + } + } else if (ht) { + ht = NULL; } UNLOCK(); - return status; + return ht; } #endif /* HTTP_HAVE_PERSISTENT_HANDLES */