b97918fab5eaafcf00e5ecd9e1de5438a9609044
[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
48 static inline STATUS http_persistent_handle_list_find(http_persistent_handle_list parent_list, http_persistent_handle_list **ident_list, int create TSRMLS_DC)
49 {
50 http_persistent_handle_list new_list;
51
52 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)) {
53 return SUCCESS;
54 }
55
56 if (create) {
57 if ((new_list = pemalloc(sizeof(HashTable), 1))) {
58 if (SUCCESS == zend_hash_init(new_list, 0, NULL, NULL, 1)) {
59 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)) {
60 return SUCCESS;
61 }
62 zend_hash_destroy(new_list);
63 }
64 pefree(new_list, 1);
65 }
66 }
67
68 return FAILURE;
69 }
70
71 static inline void http_persistent_handle_list_dtor(http_persistent_handle_list list, http_persistent_handle_dtor dtor)
72 {
73 HashPosition pos;
74 http_persistent_handle *handle;
75
76 FOREACH_HASH_VAL(pos, list, handle) {
77 #if HTTP_DEBUG_PHANDLES
78 fprintf(stderr, "DESTROY: %p\n", handle->ptr);
79 #endif
80
81 dtor(handle->ptr);
82 }
83 zend_hash_clean(list);
84 }
85
86 static void http_persistent_handles_hash_dtor(void *p)
87 {
88 http_persistent_handle_provider *provider = (http_persistent_handle_provider *) p;
89 http_persistent_handle_list *list;
90 HashPosition pos;
91
92 FOREACH_HASH_VAL(pos, provider->list, list) {
93 http_persistent_handle_list_dtor(*list, provider->dtor);
94 zend_hash_destroy(*list);
95 pefree(*list, 1);
96 }
97 zend_hash_destroy(provider->list);
98 pefree(provider->list, 1);
99 }
100
101 PHP_MINIT_FUNCTION(http_persistent_handle)
102 {
103 zend_hash_init(&http_persistent_handles_hash, 0, NULL, http_persistent_handles_hash_dtor, 1);
104 #ifdef ZTS
105 http_persistent_handles_lock = tsrm_mutex_alloc();
106 #endif
107 return SUCCESS;
108 }
109
110 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
111 {
112 zend_hash_destroy(&http_persistent_handles_hash);
113 #ifdef ZTS
114 tsrm_mutex_free(http_persistent_handles_lock);
115 #endif
116 return SUCCESS;
117 }
118
119 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)
120 {
121 STATUS status = FAILURE;
122 http_persistent_handle_provider provider;
123
124 LOCK();
125 provider.list = pemalloc(sizeof(HashTable), 1);
126 if (provider.list) {
127 provider.ctor = ctor;
128 provider.dtor = dtor;
129 zend_hash_init(provider.list, 0, NULL, NULL, 1);
130
131 #if HTTP_DEBUG_PHANDLES
132 fprintf(stderr, "PROVIDE: %p (%s)\n", provider.list, name_str);
133 #endif
134
135 if (SUCCESS == zend_hash_add(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider, sizeof(http_persistent_handle_provider), NULL)) {
136 status = SUCCESS;
137 } else {
138 pefree(provider.list, 1);
139 }
140 }
141 UNLOCK();
142
143 return status;
144 }
145
146 PHP_HTTP_API STATUS _http_persistent_handle_acquire_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
147 {
148 STATUS status = FAILURE;
149 ulong index;
150 http_persistent_handle_provider *provider;
151 http_persistent_handle_list *list;
152 http_persistent_handle *handle;
153
154 *handle_ptr = NULL;
155 LOCK();
156 if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
157 if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
158 zend_hash_internal_pointer_end(*list);
159 if (HASH_KEY_NON_EXISTANT != zend_hash_get_current_key(*list, NULL, &index, 0) && SUCCESS == zend_hash_get_current_data(*list, (void *) &handle)) {
160 *handle_ptr = handle->ptr;
161 zend_hash_index_del(*list, index);
162 }
163 }
164 if (*handle_ptr || (*handle_ptr = provider->ctor())) {
165 status = SUCCESS;
166 }
167 }
168 UNLOCK();
169
170 #if HTTP_DEBUG_PHANDLES
171 fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle_ptr, name_str);
172 #endif
173
174 return status;
175 }
176
177 PHP_HTTP_API STATUS _http_persistent_handle_release_ex(const char *name_str, size_t name_len, void **handle_ptr TSRMLS_DC)
178 {
179 STATUS status = FAILURE;
180 http_persistent_handle_provider *provider;
181 http_persistent_handle_list *list;
182 http_persistent_handle handle = {*handle_ptr};
183
184 LOCK();
185 if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
186 if ( SUCCESS == http_persistent_handle_list_find(provider->list, &list, 1 TSRMLS_CC) &&
187 SUCCESS == zend_hash_next_index_insert(*list, (void *) &handle, sizeof(http_persistent_handle), NULL)) {
188 status = SUCCESS;
189 }
190 }
191 UNLOCK();
192
193 #if HTTP_DEBUG_PHANDLES
194 fprintf(stderr, "RELEASE: %p (%s)\n", *handle_ptr, name_str);
195 #endif
196
197 return status;
198 }
199
200 PHP_HTTP_API void _http_persistent_handle_cleanup_ex(const char *name_str, size_t name_len, int current_ident_only TSRMLS_DC)
201 {
202 http_persistent_handle_provider *provider;
203 http_persistent_handle_list *list;
204 HashPosition pos1, pos2;
205
206 LOCK();
207 if (name_str && name_len) {
208 if (SUCCESS == zend_hash_find(&http_persistent_handles_hash, (char *) name_str, name_len+1, (void *) &provider)) {
209 if (current_ident_only) {
210 if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
211 http_persistent_handle_list_dtor(*list, provider->dtor);
212 }
213 } else {
214 FOREACH_HASH_VAL(pos1, provider->list, list) {
215 http_persistent_handle_list_dtor(*list, provider->dtor);
216 }
217 }
218 }
219 } else {
220 FOREACH_HASH_VAL(pos1, &http_persistent_handles_hash, provider) {
221 if (current_ident_only) {
222 if (SUCCESS == http_persistent_handle_list_find(provider->list, &list, 0 TSRMLS_CC)) {
223 http_persistent_handle_list_dtor(*list, provider->dtor);
224 }
225 } else {
226 FOREACH_HASH_VAL(pos2, provider->list, list) {
227 http_persistent_handle_list_dtor(*list, provider->dtor);
228 }
229 }
230 }
231 }
232 UNLOCK();
233 }
234
235 PHP_HTTP_API HashTable *_http_persistent_handle_statall_ex(HashTable *ht)
236 {
237 zval *zlist, *zentry;
238 HashPosition pos1, pos2;
239 HashKey key1 = initHashKey(0), key2 = initHashKey(0);
240 http_persistent_handle_provider *provider;
241 http_persistent_handle_list *list;
242
243 LOCK();
244 if (zend_hash_num_elements(&http_persistent_handles_hash)) {
245 if (!ht) {
246 ALLOC_HASHTABLE(ht);
247 zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
248 }
249
250 FOREACH_HASH_KEYVAL(pos1, &http_persistent_handles_hash, key1, provider) {
251 MAKE_STD_ZVAL(zlist);
252 array_init(zlist);
253 FOREACH_HASH_KEYVAL(pos2, provider->list, key2, list) {
254 MAKE_STD_ZVAL(zentry);
255 ZVAL_LONG(zentry, zend_hash_num_elements(*list));
256 zend_hash_quick_add(Z_ARRVAL_P(zlist), key2.str, key2.len, key2.num, (void *) &zentry, sizeof(zval *), NULL);
257 }
258 zend_hash_quick_add(ht, key1.str, key1.len, key1.num, (void *) &zlist, sizeof(zval *), NULL);
259 }
260 } else if (ht) {
261 ht = NULL;
262 }
263 UNLOCK();
264
265 return ht;
266 }
267
268 #endif /* HTTP_HAVE_PERSISTENT_HANDLES */
269
270 /*
271 * Local variables:
272 * tab-width: 4
273 * c-basic-offset: 4
274 * End:
275 * vim600: noet sw=4 ts=4 fdm=marker
276 * vim<600: noet sw=4 ts=4
277 */
278