- add dbg output
[m6w6/ext-http] / http_persistent_handle_api.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
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-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #include "php_http.h"
16 #include "php_http_api.h"
17
18 #ifdef HTTP_HAVE_PERSISTENT_HANDLES
19 #include "php_http_persistent_handle_api.h"
20
21 #ifndef HTTP_DEBUG_PHANDLES
22 # define HTTP_DEBUG_PHANDLES 0
23 #endif
24
25 static HashTable http_persistent_handles_hash;
26 #ifdef ZTS
27 # define LOCK() tsrm_mutex_lock(http_persistent_handles_lock)
28 # define UNLOCK() tsrm_mutex_unlock(http_persistent_handles_lock)
29 static MUTEX_T http_persistent_handles_lock;
30 #else
31 # define LOCK()
32 # define UNLOCK()
33 #endif
34
35 typedef struct _http_persistent_handle_t {
36 void *ptr;
37 } http_persistent_handle;
38
39 typedef HashTable *http_persistent_handle_list;
40
41 typedef struct _http_persistent_handle_provider_t {
42 http_persistent_handle_list list; /* "ident" => array(handles) entries */
43 http_persistent_handle_ctor ctor;
44 http_persistent_handle_dtor dtor;
45 } http_persistent_handle_provider;
46
47 static void http_persistent_handles_hash_dtor(void *p)
48 {
49 http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p;
50 http_persistent_handle_list *list;
51 http_persistent_handle *handle;
52 HashPosition pos1, pos2;
53
54 #if HTTP_DEBUG_PHANDLES
55 fprintf(stderr, "DESTROY: %p\n", provider->list);
56 #endif
57
58 FOREACH_HASH_VAL(pos1, provider->list, list) {
59 FOREACH_HASH_VAL(pos2, *list, handle) {
60 provider->dtor(handle->ptr);
61 }
62 zend_hash_destroy(*list);
63 pefree(*list, 1);
64 }
65 zend_hash_destroy(provider->list);
66 pefree(provider->list, 1);
67 }
68
69 PHP_MINIT_FUNCTION(http_persistent_handle)
70 {
71 zend_hash_init(&http_persistent_handles_hash, 0, NULL, http_persistent_handles_hash_dtor, 1);
72 #ifdef ZTS
73 http_persistent_handles_lock = tsrm_mutex_alloc();
74 #endif
75 return SUCCESS;
76 }
77
78 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
79 {
80 zend_hash_destroy(&http_persistent_handles_hash);
81 #ifdef ZTS
82 tsrm_mutex_free(http_persistent_handles_lock);
83 #endif
84 return SUCCESS;
85 }
86
87 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)
88 {
89 STATUS status = FAILURE;
90 http_persistent_handle_provider provider;
91
92 LOCK();
93 provider.list = pemalloc(sizeof(HashTable), 1);
94 if (provider.list) {
95 provider.ctor = ctor;
96 provider.dtor = dtor;
97 zend_hash_init(provider.list, 0, NULL, NULL, 1);
98
99 #if HTTP_DEBUG_PHANDLES
100 fprintf(stderr, "PROVIDE: %p (%s)\n", provider.list, name_str);
101 #endif
102
103 if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) {
104 status = SUCCESS;
105 } else {
106 pefree(provider.list, 1);
107 }
108 }
109 UNLOCK();
110
111 return status;
112 }
113
114 PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
115 {
116 STATUS status = FAILURE;
117 ulong index;
118 http_persistent_handle_provider *provider;
119 http_persistent_handle_list *list;
120 http_persistent_handle *handle;
121
122 *handle_ptr = NULL;
123 LOCK();
124 if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
125 if (SUCCESS == zend_hash_quick_find(provider->list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) {
126 zend_hash_internal_pointer_end(*list);
127 if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(*list, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(*list, (void *) &handle)) {
128 *handle_ptr = handle->ptr;
129 zend_hash_index_del(*list, index);
130 }
131 }
132 if (*handle_ptr || (*handle_ptr = provider->ctor())) {
133 status = SUCCESS;
134 }
135 }
136 UNLOCK();
137
138 #if HTTP_DEBUG_PHANDLES
139 fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle_ptr, name_str);
140 #endif
141
142 return status;
143 }
144
145 PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
146 {
147 STATUS status = FAILURE;
148 http_persistent_handle_provider *provider;
149 http_persistent_handle_list *list, new_list;
150 http_persistent_handle handle = {*handle_ptr};
151
152 LOCK();
153 if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
154 if (SUCCESS == zend_hash_quick_find(provider->list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) {
155 status = zend_hash_next_index_insert(*list, (void *) &handle, sizeof(http_persistent_handle), NULL);
156 } else if ((new_list = pemalloc(sizeof(HashTable), 1))) {
157 zend_hash_init(new_list, 0, NULL, NULL, 1);
158 if ( SUCCESS == zend_hash_next_index_insert(new_list, (void *) &handle, sizeof(http_persistent_handle), NULL) &&
159 SUCCESS == zend_hash_quick_add(provider->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), NULL)) {
160 status = SUCCESS;
161 } else {
162 zend_hash_destroy(new_list);
163 pefree(new_list, 1);
164 }
165 }
166 }
167 UNLOCK();
168
169 #if HTTP_DEBUG_PHANDLES
170 fprintf(stderr, "RELEASE: %p (%s)\n", *handle_ptr, name_str);
171 #endif
172
173 return status;
174 }
175
176 PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC)
177 {
178 http_persistent_handle_provider *provider;
179 http_persistent_handle_list *list;
180 http_persistent_handle *handle;
181 HashPosition pos1, pos2, pos3;
182
183 LOCK();
184 if (name_str && name_len) {
185 if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
186 if (current_ident_only) {
187 if (SUCCESS == zend_hash_quick_find(provider->list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) {
188 FOREACH_HASH_VAL(pos1, *list, handle) {
189 provider->dtor(handle->ptr);
190 }
191 zend_hash_clean(*list);
192 }
193 } else {
194 FOREACH_HASH_VAL(pos1, provider->list, list) {
195 FOREACH_HASH_VAL(pos2, *list, handle) {
196 provider->dtor(handle->ptr);
197 }
198 zend_hash_clean(*list);
199 }
200 }
201 }
202 } else {
203 FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) {
204 if (current_ident_only) {
205 if (SUCCESS == zend_hash_quick_find(provider->list, HTTP_G->persistent.handles.ident.s, HTTP_G->persistent.handles.ident.l, HTTP_G->persistent.handles.ident.h, (void *) &list)) {
206 FOREACH_HASH_VAL(pos2, *list, handle) {
207 provider->dtor(handle->ptr);
208 }
209 zend_hash_clean(*list);
210 }
211 } else {
212 FOREACH_HASH_VAL(pos2, provider->list, list) {
213 FOREACH_HASH_VAL(pos3, *list, handle) {
214 provider->dtor(handle->ptr);
215 }
216 zend_hash_clean(*list);
217 }
218 }
219 }
220 }
221 UNLOCK();
222 }
223
224 PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht)
225 {
226 zval *zlist, *zentry;
227 HashPosition pos1, pos2;
228 HashKey key1 = initHashKey(0), key2 = initHashKey(0);
229 http_persistent_handle_provider *provider;
230 http_persistent_handle_list *list;
231
232 LOCK();
233 if (zend_hash_num_elements(&http_persistent_handles_hash)) {
234 if (!ht) {
235 ALLOC_HASHTABLE(ht);
236 zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
237 }
238
239 FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) {
240 MAKE_STD_ZVAL(zlist);
241 array_init(zlist);
242 FOREACH_HASH_KEYVAL(pos2, provider->list, key2, list) {
243 MAKE_STD_ZVAL(zentry);
244 ZVAL_LONG(zentry, zend_hash_num_elements(*list));
245 zend_hash_quick_add(Z_ARRVAL_P(zlist), key2.str, key2.len, key2.num, (void *) &zentry, sizeof(zval *), NULL);
246 }
247 zend_hash_quick_add(ht, key1.str, key1.len, key1.num, (void *) &zlist, sizeof(zval *), NULL);
248 }
249 } else if (ht) {
250 ht = NULL;
251 }
252 UNLOCK();
253
254 return ht;
255 }
256
257 #endif /* HTTP_HAVE_PERSISTENT_HANDLES */
258
259 /*
260 * Local variables:
261 * tab-width: 4
262 * c-basic-offset: 4
263 * End:
264 * vim600: noet sw=4 ts=4 fdm=marker
265 * vim<600: noet sw=4 ts=4
266 */
267