header cleanups and fix some warnings
[m6w6/ext-http] / php_http_persistent_handle.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-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 #ifndef PHP_HTTP_DEBUG_PHANDLES
16 # define PHP_HTTP_DEBUG_PHANDLES 0
17 #endif
18 #if PHP_HTTP_DEBUG_PHANDLES
19 # undef inline
20 # define inline
21 #endif
22
23 static HashTable php_http_persistent_handles_hash;
24 #ifdef ZTS
25 # define LOCK() tsrm_mutex_lock(php_http_persistent_handles_lock)
26 # define UNLOCK() tsrm_mutex_unlock(php_http_persistent_handles_lock)
27 static MUTEX_T php_http_persistent_handles_lock;
28 #else
29 # define LOCK()
30 # define UNLOCK()
31 #endif
32
33 typedef struct php_http_persistent_handle_list {
34 HashTable free;
35 ulong used;
36 } php_http_persistent_handle_list_t;
37
38 typedef struct php_http_persistent_handle_provider {
39 php_http_persistent_handle_list_t list; /* "ident" => array(handles) entries */
40 php_http_resource_factory_t rf;
41 } php_http_persistent_handle_provider_t;
42
43 static inline php_http_persistent_handle_list_t *php_http_persistent_handle_list_init(php_http_persistent_handle_list_t *list)
44 {
45 int free_list;
46
47 if ((free_list = !list)) {
48 list = pemalloc(sizeof(php_http_persistent_handle_list_t), 1);
49 }
50
51 list->used = 0;
52
53 if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) {
54 if (free_list) {
55 pefree(list, 1);
56 }
57 list = NULL;
58 }
59
60 return list;
61 }
62
63 static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t *list, php_http_persistent_handle_provider_t *provider TSRMLS_DC)
64 {
65 HashPosition pos;
66 void **handle;
67
68 #if PHP_HTTP_DEBUG_PHANDLES
69 fprintf(stderr, "LSTDTOR: %p\n", list);
70 #endif
71 FOREACH_HASH_VAL(pos, &list->free, handle) {
72 #if PHP_HTTP_DEBUG_PHANDLES
73 fprintf(stderr, "DESTROY: %p\n", *handle);
74 #endif
75
76 provider->rf.fops.dtor(provider->rf.data, *handle TSRMLS_CC);
77 }
78 zend_hash_destroy(&list->free);
79 }
80
81 static inline void php_http_persistent_handle_list_free(php_http_persistent_handle_list_t **list, php_http_persistent_handle_provider_t *provider TSRMLS_DC)
82 {
83 php_http_persistent_handle_list_dtor(*list, provider TSRMLS_CC);
84 #if PHP_HTTP_DEBUG_PHANDLES
85 fprintf(stderr, "LSTFREE: %p\n", *list);
86 #endif
87 pefree(*list, 1);
88 *list = NULL;
89 }
90
91 static inline php_http_persistent_handle_list_t *php_http_persistent_handle_list_find(php_http_persistent_handle_provider_t *provider, const char *ident_str, size_t ident_len TSRMLS_DC)
92 {
93 php_http_persistent_handle_list_t **list, *new_list;
94
95 if (SUCCESS == zend_symtable_find(&provider->list.free, ident_str, ident_len + 1, (void *) &list)) {
96 #if PHP_HTTP_DEBUG_PHANDLES
97 fprintf(stderr, "LSTFIND: %p\n", *list);
98 #endif
99 return *list;
100 }
101
102 if ((new_list = php_http_persistent_handle_list_init(NULL))) {
103 if (SUCCESS == zend_symtable_update(&provider->list.free, ident_str, ident_len + 1, (void *) &new_list, sizeof(php_http_persistent_handle_list_t *), (void *) &list)) {
104 #if PHP_HTTP_DEBUG_PHANDLES
105 fprintf(stderr, "LSTFIND: %p (new)\n", *list);
106 #endif
107 return *list;
108 }
109 php_http_persistent_handle_list_free(&new_list, provider TSRMLS_CC);
110 }
111
112 return NULL;
113 }
114
115 static inline STATUS php_http_persistent_handle_do_acquire(php_http_persistent_handle_provider_t *provider, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC)
116 {
117 ulong index;
118 void **handle_ptr;
119 php_http_persistent_handle_list_t *list;
120
121 if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) {
122 zend_hash_internal_pointer_end(&list->free);
123 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)) {
124 *handle = *handle_ptr;
125 zend_hash_index_del(&list->free, index);
126 } else {
127 *handle = provider->rf.fops.ctor(provider->rf.data TSRMLS_CC);
128 }
129
130 if (*handle) {
131 ++provider->list.used;
132 ++list->used;
133 return SUCCESS;
134 }
135 } else {
136 *handle = NULL;
137 }
138
139 return FAILURE;
140 }
141
142 static inline STATUS php_http_persistent_handle_do_release(php_http_persistent_handle_provider_t *provider, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC)
143 {
144 php_http_persistent_handle_list_t *list;
145
146 if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) {
147 if (provider->list.used >= PHP_HTTP_G->persistent_handle.limit) {
148 provider->rf.fops.dtor(provider->rf.data, *handle TSRMLS_CC);
149 } else {
150 if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) {
151 return FAILURE;
152 }
153 }
154
155 *handle = NULL;
156 --provider->list.used;
157 --list->used;
158 return SUCCESS;
159 }
160
161 return FAILURE;
162 }
163
164 static inline STATUS php_http_persistent_handle_do_accrete(php_http_persistent_handle_provider_t *provider, const char *ident_str, size_t ident_len, void *old_handle, void **new_handle TSRMLS_DC)
165 {
166 php_http_persistent_handle_list_t *list;
167
168 if (provider->rf.fops.copy && (*new_handle = provider->rf.fops.copy(provider->rf.data, old_handle TSRMLS_CC))) {
169 if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) {
170 ++list->used;
171 }
172 ++provider->list.used;
173 return SUCCESS;
174 }
175 return FAILURE;
176 }
177
178 static void php_http_persistent_handles_hash_dtor(void *p)
179 {
180 php_http_persistent_handle_provider_t *provider = (php_http_persistent_handle_provider_t *) p;
181 php_http_persistent_handle_list_t **list, *list_tmp;
182 HashPosition pos;
183 TSRMLS_FETCH();
184
185 FOREACH_HASH_VAL(pos, &provider->list.free, list) {
186 /* fix shutdown crash in PHP4 */
187 list_tmp = *list;
188 php_http_persistent_handle_list_free(&list_tmp, provider TSRMLS_CC);
189 }
190
191 zend_hash_destroy(&provider->list.free);
192 php_http_resource_factory_dtor(&provider->rf);
193 }
194
195 PHP_MINIT_FUNCTION(http_persistent_handle)
196 {
197 zend_hash_init(&php_http_persistent_handles_hash, 0, NULL, php_http_persistent_handles_hash_dtor, 1);
198 #ifdef ZTS
199 php_http_persistent_handles_lock = tsrm_mutex_alloc();
200 #endif
201 return SUCCESS;
202 }
203
204 PHP_MSHUTDOWN_FUNCTION(http_persistent_handle)
205 {
206 zend_hash_destroy(&php_http_persistent_handles_hash);
207 #ifdef ZTS
208 tsrm_mutex_free(php_http_persistent_handles_lock);
209 #endif
210 return SUCCESS;
211 }
212
213 PHP_HTTP_API STATUS php_http_persistent_handle_provide(const char *name_str, size_t name_len, php_http_resource_factory_ops_t *fops, void *data, void (*dtor)(void *))
214 {
215 STATUS status = FAILURE;
216 php_http_persistent_handle_provider_t provider;
217
218 LOCK();
219 if (php_http_persistent_handle_list_init(&provider.list)) {
220 if (php_http_resource_factory_init(&provider.rf, fops, data, dtor)) {
221 #if PHP_HTTP_DEBUG_PHANDLES
222 fprintf(stderr, "PROVIDE: %s\n", name_str);
223 #endif
224
225 if (SUCCESS == zend_symtable_update(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider, sizeof(php_http_persistent_handle_provider_t), NULL)) {
226 status = SUCCESS;
227 } else {
228 php_http_resource_factory_dtor(&provider.rf);
229 }
230 }
231 }
232 UNLOCK();
233
234 return status;
235 }
236
237 PHP_HTTP_API php_http_persistent_handle_factory_t *php_http_persistent_handle_concede(php_http_persistent_handle_factory_t *a, const char *name_str, size_t name_len, const char *ident_str, size_t ident_len TSRMLS_DC)
238 {
239 STATUS status = FAILURE;
240 php_http_persistent_handle_factory_t *free_a = NULL;
241
242 if (!a) {
243 free_a = a = emalloc(sizeof(*a));
244 }
245 memset(a, 0, sizeof(*a));
246
247 LOCK();
248 status = zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &a->provider);
249 UNLOCK();
250
251 if (SUCCESS == status) {
252 a->ident.str = estrndup(ident_str, a->ident.len = ident_len);
253 if (free_a) {
254 a->free_on_abandon = 1;
255 }
256 } else {
257 if (free_a) {
258 efree(a);
259 }
260 a = NULL;
261 }
262
263 #if PHP_HTTP_DEBUG_PHANDLES
264 fprintf(stderr, "CONCETE: %p (%s) (%s)\n", a ? a->provider : NULL, name_str, ident_str);
265 #endif
266
267 return a;
268 }
269
270 PHP_HTTP_API void php_http_persistent_handle_abandon(php_http_persistent_handle_factory_t *a)
271 {
272 zend_bool f = a->free_on_abandon;
273
274 STR_FREE(a->ident.str);
275 memset(a, 0, sizeof(*a));
276 if (f) {
277 efree(a);
278 }
279 }
280
281 PHP_HTTP_API void *php_http_persistent_handle_acquire(php_http_persistent_handle_factory_t *a TSRMLS_DC)
282 {
283 void *handle = NULL;
284
285 LOCK();
286 php_http_persistent_handle_do_acquire(a->provider, a->ident.str, a->ident.len, &handle TSRMLS_CC);
287 UNLOCK();
288
289 return handle;
290 }
291
292 PHP_HTTP_API void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t *a, void *handle TSRMLS_DC)
293 {
294 void *new_handle;
295
296 LOCK();
297 php_http_persistent_handle_do_accrete(a->provider, a->ident.str, a->ident.len, handle, &new_handle TSRMLS_CC);
298 UNLOCK();
299
300 return new_handle;
301 }
302
303 PHP_HTTP_API void php_http_persistent_handle_release(php_http_persistent_handle_factory_t *a, void *handle TSRMLS_DC)
304 {
305 LOCK();
306 php_http_persistent_handle_do_release(a->provider, a->ident.str, a->ident.len, &handle TSRMLS_CC);
307 UNLOCK();
308 }
309
310 PHP_HTTP_API STATUS php_http_persistent_handle_acquire2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC)
311 {
312 STATUS status = FAILURE;
313 php_http_persistent_handle_provider_t *provider;
314
315 *handle = NULL;
316 LOCK();
317 if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
318 status = php_http_persistent_handle_do_acquire(provider, ident_str, ident_len, handle TSRMLS_CC);
319 }
320 UNLOCK();
321
322 #if PHP_HTTP_DEBUG_PHANDLES
323 fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle, name_str);
324 #endif
325
326 return status;
327 }
328
329 PHP_HTTP_API STATUS php_http_persistent_handle_release2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC)
330 {
331 STATUS status = FAILURE;
332 php_http_persistent_handle_provider_t *provider;
333 #if PHP_HTTP_DEBUG_PHANDLES
334 void *handle_tmp = *handle;
335 #endif
336
337 LOCK();
338 if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
339 status = php_http_persistent_handle_do_release(provider, ident_str, ident_len, handle TSRMLS_CC);
340 }
341 UNLOCK();
342
343 #if PHP_HTTP_DEBUG_PHANDLES
344 fprintf(stderr, "RELEASE: %p (%s)\n", handle_tmp, name_str);
345 #endif
346
347 return status;
348 }
349
350 PHP_HTTP_API STATUS php_http_persistent_handle_accrete2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void *old_handle, void **new_handle TSRMLS_DC)
351 {
352 STATUS status = FAILURE;
353 php_http_persistent_handle_provider_t *provider;
354
355 *new_handle = NULL;
356 LOCK();
357 if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
358 status = php_http_persistent_handle_do_accrete(provider, ident_str, ident_len, old_handle, new_handle TSRMLS_CC);
359 }
360 UNLOCK();
361
362 #if PHP_HTTP_DEBUG_PHANDLES
363 fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str);
364 #endif
365
366 return status;
367 }
368
369 PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len TSRMLS_DC)
370 {
371 php_http_persistent_handle_provider_t *provider;
372 php_http_persistent_handle_list_t *list, **listp;
373 HashPosition pos1, pos2;
374
375 LOCK();
376 if (name_str && name_len) {
377 if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) {
378 if (ident_str && ident_len) {
379 if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) {
380 php_http_persistent_handle_list_dtor(list, provider TSRMLS_CC);
381 php_http_persistent_handle_list_init(list);
382 }
383 } else {
384 FOREACH_HASH_VAL(pos1, &provider->list.free, listp) {
385 php_http_persistent_handle_list_dtor(*listp, provider TSRMLS_CC);
386 php_http_persistent_handle_list_init(*listp);
387 }
388 }
389 }
390 } else {
391 FOREACH_HASH_VAL(pos1, &php_http_persistent_handles_hash, provider) {
392 if (ident_str && ident_len) {
393 if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) {
394 php_http_persistent_handle_list_dtor(list, provider TSRMLS_CC);
395 php_http_persistent_handle_list_init(list);
396 }
397 } else {
398 FOREACH_HASH_VAL(pos2, &provider->list.free, listp) {
399 php_http_persistent_handle_list_dtor(*listp, provider TSRMLS_CC);
400 php_http_persistent_handle_list_init(*listp);
401 }
402 }
403 }
404 }
405 UNLOCK();
406 }
407
408 PHP_HTTP_API HashTable *php_http_persistent_handle_statall(HashTable *ht TSRMLS_DC)
409 {
410 zval *zentry[2];
411 HashPosition pos1, pos2;
412 php_http_array_hashkey_t key1 = php_http_array_hashkey_init(0), key2 = php_http_array_hashkey_init(0);
413 php_http_persistent_handle_provider_t *provider;
414 php_http_persistent_handle_list_t **list;
415
416 LOCK();
417 if (zend_hash_num_elements(&php_http_persistent_handles_hash)) {
418 if (!ht) {
419 ALLOC_HASHTABLE(ht);
420 zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
421 }
422
423 FOREACH_HASH_KEYVAL(pos1, &php_http_persistent_handles_hash, key1, provider) {
424 MAKE_STD_ZVAL(zentry[0]);
425 array_init(zentry[0]);
426
427 FOREACH_HASH_KEYVAL(pos2, &provider->list.free, key2, list) {
428 MAKE_STD_ZVAL(zentry[1]);
429 array_init(zentry[1]);
430 add_assoc_long_ex(zentry[1], ZEND_STRS("used"), (*list)->used);
431 add_assoc_long_ex(zentry[1], ZEND_STRS("free"), zend_hash_num_elements(&(*list)->free));
432 add_assoc_zval_ex(zentry[0], key2.str, key2.len, zentry[1]);
433 }
434
435 zend_symtable_update(ht, key1.str, key1.len, &zentry[0], sizeof(zval *), NULL);
436 }
437 } else if (ht) {
438 ht = NULL;
439 }
440 UNLOCK();
441
442 return ht;
443 }
444
445
446 /*
447 * Local variables:
448 * tab-width: 4
449 * c-basic-offset: 4
450 * End:
451 * vim600: noet sw=4 ts=4 fdm=marker
452 * vim<600: noet sw=4 ts=4
453 */
454