1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 2006-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Georg Richter <georg@mysql.com> |
16 : | Andrey Hristov <andrey@mysql.com> |
17 : | Ulf Wendel <uwendel@mysql.com> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : /* $Id: mysqlnd_palloc.c 289028 2009-09-30 23:13:43Z andrey $ */
22 : #include "php.h"
23 : #include "mysqlnd.h"
24 : #include "mysqlnd_priv.h"
25 : #include "mysqlnd_palloc.h"
26 : #include "mysqlnd_debug.h"
27 :
28 : /* Used in mysqlnd_debug.c */
29 : char * mysqlnd_palloc_zval_ptr_dtor_name = "mysqlnd_palloc_zval_ptr_dtor";
30 : char * mysqlnd_palloc_get_zval_name = "mysqlnd_palloc_get_zval";
31 :
32 :
33 : #ifdef ZTS
34 : #define LOCK_PCACHE(cache) tsrm_mutex_lock((cache)->LOCK_access)
35 : #define UNLOCK_PCACHE(cache) tsrm_mutex_unlock((cache)->LOCK_access)
36 : #else
37 : #define LOCK_PCACHE(cache)
38 : #define UNLOCK_PCACHE(cache)
39 : #endif
40 :
41 :
42 : /* {{{ _mysqlnd_palloc_init_cache */
43 : PHPAPI MYSQLND_ZVAL_PCACHE* _mysqlnd_palloc_init_cache(unsigned int cache_size TSRMLS_DC)
44 52899 : {
45 52899 : MYSQLND_ZVAL_PCACHE *ret = mnd_calloc(1, sizeof(MYSQLND_ZVAL_PCACHE));
46 : unsigned int i;
47 :
48 52899 : DBG_ENTER("_mysqlnd_palloc_init_cache");
49 52899 : DBG_INF_FMT("cache=%p size=%u", ret, cache_size);
50 :
51 : #ifdef ZTS
52 : ret->LOCK_access = tsrm_mutex_alloc();
53 : #endif
54 :
55 52899 : ret->max_items = cache_size;
56 52899 : ret->free_items = cache_size;
57 52899 : ret->references = 1;
58 :
59 : /* 1. First initialize the free list part of the structure */
60 : /* One more for empty position of last_added - always 0x0, bounds checking */
61 52899 : ret->free_list.ptr_line = mnd_calloc(ret->max_items + 1, sizeof(mysqlnd_zval *));
62 52899 : ret->free_list.last_added = ret->free_list.ptr_line + ret->max_items;
63 52899 : ret->free_list.canary1 = (void*)0xBEEF;
64 52899 : ret->free_list.canary2 = (void*)0xAFFE;
65 :
66 : /* 3. Allocate and initialize our zvals and initialize the free list */
67 52899 : ret->block = mnd_calloc(ret->max_items, sizeof(mysqlnd_zval));
68 52899 : ret->last_in_block = &(ret->block[ret->max_items]);
69 105850899 : for (i = 0; i < ret->max_items; i++) {
70 : /* 1. Initialize */
71 105798000 : INIT_PZVAL(&(ret->block[i].zv));
72 105798000 : ZVAL_NULL(&(ret->block[i].zv));
73 : /* Assure it will never be freed before MSHUTDOWN */
74 105798000 : Z_ADDREF_P(&(ret->block[i].zv));
75 : /* 2. Add to the free list */
76 105798000 : *(--ret->free_list.last_added) = &(ret->block[i]);
77 : }
78 :
79 52899 : DBG_RETURN(ret);
80 : }
81 : /* }}} */
82 :
83 :
84 : /* {{{ mysqlnd_palloc_get_cache_reference */
85 : MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_get_cache_reference(MYSQLND_ZVAL_PCACHE * const cache)
86 59686 : {
87 59686 : if (cache) {
88 : LOCK_PCACHE(cache);
89 59686 : cache->references++;
90 : UNLOCK_PCACHE(cache);
91 : }
92 59686 : return cache;
93 : }
94 : /* }}} */
95 :
96 :
97 : /* {{{ mysqlnd_palloc_free_cache */
98 : /*
99 : As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with
100 : copy_ctor but scrap what they point to with zval_dtor() and then just free our
101 : pre-allocated block. Precondition is that we ZVAL_NULL() the zvals when we put them
102 : to the free list after usage. We ZVAL_NULL() them when we allocate them in the
103 : constructor of the cache.
104 : */
105 : void _mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache TSRMLS_DC)
106 52995 : {
107 52995 : DBG_ENTER("_mysqlnd_palloc_free_cache");
108 52995 : DBG_INF_FMT("cache=%p", cache);
109 :
110 : #ifdef ZTS
111 : tsrm_mutex_free(cache->LOCK_access);
112 : #endif
113 :
114 : /* Data in pointed by 'block' was cleaned in RSHUTDOWN */
115 52995 : mnd_free(cache->block);
116 52995 : mnd_free(cache->free_list.ptr_line);
117 52995 : mnd_free(cache);
118 :
119 : DBG_VOID_RETURN;
120 : }
121 : /* }}} */
122 :
123 :
124 : /* {{{ _mysqlnd_palloc_init_thd_cache */
125 : PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC)
126 52857 : {
127 52857 : MYSQLND_THD_ZVAL_PCACHE *ret = mnd_calloc(1, sizeof(MYSQLND_THD_ZVAL_PCACHE));
128 52857 : DBG_ENTER("_mysqlnd_palloc_init_thd_cache");
129 52857 : DBG_INF_FMT("ret = %p", ret);
130 :
131 : #if PHP_DEBUG
132 : LOCK_PCACHE(cache);
133 : if (cache->references == 1 && cache->max_items != cache->free_items) {
134 : UNLOCK_PCACHE(cache);
135 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No references to mysqlnd's zval cache but max_items != free_items");
136 : } else {
137 : UNLOCK_PCACHE(cache);
138 : }
139 : #endif
140 52857 : ret->parent = mysqlnd_palloc_get_cache_reference(cache);
141 :
142 : #ifdef ZTS
143 : ret->thread_id = tsrm_thread_id();
144 : #endif
145 :
146 52857 : ret->references = 1;
147 :
148 : /* 1. Initialize the GC list */
149 52857 : ret->gc_list.ptr_line = mnd_calloc(cache->max_items, sizeof(mysqlnd_zval *));
150 : /* Backward and forward looping is possible */
151 52857 : ret->gc_list.last_added = ret->gc_list.ptr_line;
152 52857 : ret->gc_list.canary1 = (void*)0xCAFE;
153 52857 : ret->gc_list.canary2 = (void*)0x190280;
154 :
155 52857 : DBG_INF_FMT("ptr_line=%p last_added=%p", ret->gc_list.ptr_line, ret->gc_list.last_added);
156 52857 : DBG_RETURN(ret);
157 : }
158 : /* }}} */
159 :
160 :
161 : /* {{{ _mysqlnd_palloc_get_thd_cache_reference */
162 : MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache TSRMLS_DC)
163 6829 : {
164 6829 : DBG_ENTER("_mysqlnd_palloc_get_thd_cache_reference");
165 6829 : if (cache) {
166 6829 : ++cache->references;
167 6829 : DBG_INF_FMT("cache=%p new_refc=%d gc_list.canary1=%p gc_list.canary2=%p",
168 : cache, cache->references, cache->gc_list.canary1, cache->gc_list.canary2);
169 6829 : mysqlnd_palloc_get_cache_reference(cache->parent);
170 : }
171 6829 : DBG_RETURN(cache);
172 : }
173 : /* }}} */
174 :
175 :
176 : /* {{{ mysqlnd_palloc_free_cache */
177 : /*
178 : As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with
179 : copy_ctor but scrap what they point to with zval_dtor() and then just free our
180 : pre-allocated block. Precondition is that we ZVAL_NULL() the zvals when we put them
181 : to the free list after usage. We ZVAL_NULL() them when we allocate them in the
182 : constructor of the cache.
183 : */
184 : static
185 : void mysqlnd_palloc_free_thd_cache(MYSQLND_THD_ZVAL_PCACHE *thd_cache TSRMLS_DC)
186 52952 : {
187 : MYSQLND_ZVAL_PCACHE *global_cache;
188 : mysqlnd_zval **p;
189 :
190 52952 : DBG_ENTER("mysqlnd_palloc_free_thd_cache");
191 52952 : DBG_INF_FMT("thd_cache=%p", thd_cache);
192 :
193 52952 : if ((global_cache = thd_cache->parent)) {
194 : /*
195 : Keep in mind that for pthreads pthread_equal() should be used to be
196 : fully standard compliant. However, the PHP code all-around, incl. the
197 : the Zend MM uses direct comparison.
198 : */
199 52952 : p = thd_cache->gc_list.ptr_line;
200 105904 : while (p < thd_cache->gc_list.last_added) {
201 0 : zval_dtor(&(*p)->zv);
202 0 : p++;
203 : }
204 :
205 52952 : p = thd_cache->gc_list.ptr_line;
206 :
207 : LOCK_PCACHE(global_cache);
208 105904 : while (p < thd_cache->gc_list.last_added) {
209 0 : (*p)->point_type = MYSQLND_POINTS_FREE;
210 0 : *(--global_cache->free_list.last_added) = *p;
211 0 : ++global_cache->free_items;
212 : #ifdef ZTS
213 : memset(&((*p)->thread_id), 0, sizeof(THREAD_T));
214 : #endif
215 0 : p++;
216 : }
217 : UNLOCK_PCACHE(global_cache);
218 :
219 : }
220 52952 : mnd_free(thd_cache->gc_list.ptr_line);
221 52952 : mnd_free(thd_cache);
222 :
223 : DBG_VOID_RETURN;
224 : }
225 : /* }}} */
226 :
227 :
228 : /* {{{ _mysqlnd_palloc_free_thd_cache_reference */
229 : PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC)
230 59798 : {
231 59798 : DBG_ENTER("_mysqlnd_palloc_free_thd_cache_reference");
232 59798 : if (*cache) {
233 59784 : --(*cache)->parent->references;
234 59784 : DBG_INF_FMT("cache=%p references_left=%d canary1=%p canary2=%p",
235 : *cache, (*cache)->references, (*cache)->gc_list.canary1, (*cache)->gc_list.canary2);
236 :
237 59784 : DBG_INF_FMT("gc_list.ptr_line=%p gc_list.last_added=%p", (*cache)->gc_list.ptr_line, (*cache)->gc_list.last_added);
238 :
239 59784 : if (--(*cache)->references == 0) {
240 52952 : mysqlnd_palloc_free_thd_cache(*cache TSRMLS_CC);
241 : }
242 59784 : *cache = NULL;
243 : }
244 : DBG_VOID_RETURN;
245 : }
246 : /* }}} */
247 :
248 :
249 : /*
250 : The cache line is a big contiguous array of zval pointers.
251 : Because the CPU cache will cache starting from an address, and not
252 : before it, then we have to organize our structure according to this.
253 : Thus, if 'last_added' is valid pointer (not NULL) then last_added is
254 : increased. When zval is cached, if there is room, last_added is decreased
255 : and then the zval pointer will be assigned to it. This means that some
256 : positions may become hot points and stay in the cache.
257 : Imagine we have 5 pointers in a line
258 : 1. last_added = list_item->ptr_line + cache->max_items;
259 : 2. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
260 : 3. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
261 : 4. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
262 : 0x0
263 : 0x0
264 : 0x0
265 : 0x0
266 : 0x0
267 : ---
268 : empty_position, always 0x0 <-- last_added
269 :
270 : 5. free_zval -> if (free_items++ != max_items) {// we can add more
271 : *(--last_added) = zval_ptr;
272 : }
273 : (memory addresses increase downwards)
274 : 0x0
275 : 0x0
276 : 0x0
277 : 0x0
278 : 0xA <-- last_added
279 : ---
280 : 0x0
281 :
282 : 6. free_zval -> if (free_items++ != max_items) {// we can add more
283 : *(--last_added) = zval_ptr;
284 : }
285 : 0x0
286 : 0x0
287 : 0x0
288 : 0xB <-- last_added
289 : 0xA
290 : ---
291 : 0x0
292 :
293 : 7. free_zval -> if (free_items++ != max_items) {// we can add more
294 : *(--last_added) = zval_ptr;
295 : }
296 : 0x0
297 : 0x0
298 : 0xC <-- last_added
299 : 0xB
300 : 0xA
301 : ---
302 : 0x0
303 :
304 : 8. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
305 : 0x0
306 : 0x0
307 : 0x0
308 : 0xB <-- last_added
309 : 0xA
310 : ---
311 : 0x0
312 :
313 : 9. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
314 : 0x0
315 : 0x0
316 : 0x0
317 : 0x0
318 : 0xA <-- last_added
319 : ---
320 : 0x0
321 :
322 : 10. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
323 : 0x0
324 : 0x0
325 : 0x0
326 : 0x0
327 : 0x0
328 : ---
329 : 0x0 <-- last_added
330 :
331 : */
332 :
333 :
334 : /* {{{ mysqlnd_palloc_get_zval */
335 : void *mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const thd_cache, zend_bool *allocated TSRMLS_DC)
336 0 : {
337 0 : void *ret = NULL;
338 :
339 0 : DBG_ENTER("mysqlnd_palloc_get_zval");
340 0 : if (thd_cache) {
341 0 : DBG_INF_FMT("cache=%p *last_added=%p free_items=%d",
342 : thd_cache, thd_cache->parent->free_list.last_added,
343 : thd_cache->parent->free_items);
344 0 : DBG_INF_FMT("gc_list.ptr_line=%p gc_list.last_added=%p gc_list.canary1=%p gc_list.canary2=%p",
345 : thd_cache->gc_list.ptr_line, thd_cache->gc_list.last_added,
346 : thd_cache->gc_list.canary1, thd_cache->gc_list.canary2);
347 : }
348 :
349 0 : if (thd_cache) {
350 0 : MYSQLND_ZVAL_PCACHE *cache = thd_cache->parent;
351 : LOCK_PCACHE(cache);
352 :
353 0 : DBG_INF_FMT("free_items=%d free_list.ptr_line=%p free_list.last_added=%p *free_list.last_added=%p free_list.canary1=%p free_list.canary2=%p",
354 : cache->free_items, cache->free_list.ptr_line, cache->free_list.last_added,
355 : *cache->free_list.last_added,
356 : cache->free_list.canary1, cache->free_list.canary2);
357 :
358 : /* We have max_items + 1 allocated block for free_list, thus we know if we */
359 0 : if ((ret = *cache->free_list.last_added)) {
360 0 : *cache->free_list.last_added++ = NULL;
361 0 : *allocated = FALSE;
362 : #ifdef ZTS
363 : ((mysqlnd_zval *) ret)->thread_id = thd_cache->thread_id;
364 : #endif
365 0 : --cache->free_items;
366 0 : ++cache->get_hits;
367 : } else {
368 0 : ++cache->get_misses;
369 : }
370 : UNLOCK_PCACHE(cache);
371 : }
372 0 : if (!ret) {
373 : /*
374 : We allocate a bit more. The user of this function will use it, but at
375 : end it will use only the zval part. Because the zval part is first then
376 : when freeing the zval part the whole allocated block will be cleaned, not
377 : only the zval part (by the Engine when destructing the zval).
378 : */
379 0 : ALLOC_ZVAL(ret);
380 0 : INIT_PZVAL((zval *) ret);
381 0 : *allocated = TRUE;
382 : } else {
383 : /* This will set the refcount to 1, increase it, to keep the variable */
384 0 : INIT_PZVAL(&((mysqlnd_zval *) ret)->zv);
385 0 : Z_ADDREF_P(&(((mysqlnd_zval *)ret)->zv));
386 : }
387 :
388 0 : DBG_INF_FMT("allocated=%d ret=%p", *allocated, ret);
389 0 : DBG_RETURN(ret);
390 : }
391 : /* }}} */
392 :
393 :
394 : /* {{{ mysqlnd_palloc_zval_ptr_dtor */
395 : void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd_cache,
396 : enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC)
397 72851 : {
398 : MYSQLND_ZVAL_PCACHE *cache;
399 72851 : DBG_ENTER("mysqlnd_palloc_zval_ptr_dtor");
400 72851 : if (thd_cache) {
401 72851 : DBG_INF_FMT("cache=%p parent_block=%p last_in_block=%p *zv=%p refc=%d type=%d ",
402 : thd_cache,
403 : thd_cache->parent->block,
404 : thd_cache->parent->last_in_block,
405 : *zv, Z_REFCOUNT_PP(zv), type);
406 72851 : DBG_INF_FMT("gc_list.ptr_line=%p gc_list.last_added=%p gc_list.canary1=%p gc_list.canary2=%p",
407 : thd_cache->gc_list.ptr_line, thd_cache->gc_list.last_added, thd_cache->gc_list.canary1, thd_cache->gc_list.canary2);
408 : }
409 72851 : *copy_ctor_called = FALSE;
410 : /* Check whether cache is used and the zval is from the cache */
411 72851 : if (!thd_cache || !(cache = thd_cache->parent) || ((char *)*zv < (char *)thd_cache->parent->block ||
412 : (char *)*zv > (char *)thd_cache->parent->last_in_block)) {
413 : /*
414 : This zval is not from the cache block.
415 : Thus the refcount is -1 than of a zval from the cache,
416 : because the zvals from the cache are owned by it.
417 : */
418 72851 : if (type == MYSQLND_RES_PS_BUF || type == MYSQLND_RES_PS_UNBUF) {
419 : ; /* do nothing, zval_ptr_dtor will do the job*/
420 44922 : } else if (Z_REFCOUNT_PP(zv) > 1) {
421 : /*
422 : Not a prepared statement, then we have to
423 : call copy_ctor and then zval_ptr_dtor()
424 :
425 : In Unicode mode the destruction of the zvals should not call
426 : zval_copy_ctor() because then we will leak.
427 : I suppose we can use UG(unicode) in mysqlnd.c when freeing a result set
428 : to check if we need to call copy_ctor().
429 :
430 : If the type is IS_UNICODE, which can happen with PHP6, then we don't
431 : need to copy_ctor, as the data doesn't point to our internal buffers.
432 : If it's string (in PHP5 always) and in PHP6 if data is binary, then
433 : it still points to internal buffers and has to be copied.
434 : */
435 4420 : if (Z_TYPE_PP(zv) == IS_STRING) {
436 3739 : zval_copy_ctor(*zv);
437 : }
438 4420 : *copy_ctor_called = TRUE;
439 : } else {
440 40502 : if (Z_TYPE_PP(zv) == IS_STRING) {
441 40453 : ZVAL_NULL(*zv);
442 : }
443 : }
444 72851 : zval_ptr_dtor(zv);
445 72851 : DBG_VOID_RETURN;
446 : }
447 :
448 : /* The zval is from our cache */
449 : /* refcount is always > 1, because we call Z_ADDREF_P(). Thus test refcount > 2 */
450 0 : if (Z_REFCOUNT_PP(zv) > 2) {
451 : /*
452 : Because the zval is first element in mysqlnd_zval structure, then we can
453 : do upcasting from zval to mysqlnd_zval here. Because we know that this
454 : zval is part of our pre-allocated block.
455 :
456 : Now check whether this zval points to ZE allocated memory or to our
457 : buffers. If it points to the internal buffers, call copy_ctor()
458 : which will do estrndup for strings. And nothing for null, int, double.
459 :
460 : This branch will be skipped for PS, because there is no need to copy
461 : what is pointed by them, as they don't point to the internal buffers.
462 : */
463 0 : if (((mysqlnd_zval *)*zv)->point_type == MYSQLND_POINTS_INT_BUFFER) {
464 0 : zval_copy_ctor(*zv);
465 0 : *copy_ctor_called = TRUE;
466 0 : ((mysqlnd_zval *)*zv)->point_type = MYSQLND_POINTS_EXT_BUFFER;
467 : }
468 : /*
469 : This will decrease the counter of the user-level (mysqlnd). When the engine
470 : layer (the script) has finished working this this zval, when the variable is
471 : no more used, out of scope whatever, then it will try zval_ptr_dtor() but
472 : and the refcount will reach 1 and the engine won't try to destruct the
473 : memory allocated by us.
474 : */
475 0 : zval_ptr_dtor(zv);
476 :
477 : /*
478 : Unfortunately, we can't return this variable to the free_list
479 : because it's still used. And this cleaning up will happen at request
480 : shutdown :(.
481 : */
482 : LOCK_PCACHE(cache);
483 0 : DBG_INF_FMT("gc_list.ptr_line=%p gc_list.last_added=%p *gc_list.last_added=%p free_list.canary1=%p free_list.canary2=%p",
484 : thd_cache->gc_list.ptr_line,
485 : thd_cache->gc_list.last_added,
486 : *thd_cache->gc_list.last_added,
487 : cache->free_list.canary1, cache->free_list.canary2);
488 0 : if ((thd_cache->gc_list.last_added - thd_cache->gc_list.ptr_line) > (int) cache->max_items) {
489 0 : DBG_ERR("Buffer overflow follows");
490 0 : DBG_ERR_FMT("parent->max_items=%d parent->free_items=%d diff=%d",
491 : cache->max_items, cache->free_items,
492 : thd_cache->gc_list.last_added - thd_cache->gc_list.ptr_line);
493 :
494 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "We will get buffer overflow");
495 : }
496 0 : ++cache->put_misses;
497 0 : *(thd_cache->gc_list.last_added++) = (mysqlnd_zval *)*zv;
498 : UNLOCK_PCACHE(cache);
499 : } else {
500 0 : DBG_INF("No user reference");
501 : /* No user reference */
502 0 : if (((mysqlnd_zval *)*zv)->point_type == MYSQLND_POINTS_EXT_BUFFER) {
503 0 : DBG_INF("Points to external buffer. Calling zval_dtor");
504 : /*
505 : PS are here
506 : Unicode mode goes also here if the column is not binary but a text
507 : */
508 0 : zval_dtor(*zv);
509 : }
510 : LOCK_PCACHE(cache);
511 0 : ++cache->put_hits;
512 0 : ++cache->free_items;
513 0 : ((mysqlnd_zval *)*zv)->point_type = MYSQLND_POINTS_FREE;
514 0 : Z_DELREF_PP(zv); /* Make it 1 */
515 0 : ZVAL_NULL(*zv);
516 : #ifdef ZTS
517 : memset(&((mysqlnd_zval *)*zv)->thread_id, 0, sizeof(THREAD_T));
518 : #endif
519 0 : *(--cache->free_list.last_added) = (mysqlnd_zval *)*zv;
520 :
521 : UNLOCK_PCACHE(cache);
522 : }
523 0 : DBG_VOID_RETURN;
524 : }
525 : /* }}} */
526 :
527 :
528 : /* {{{ _mysqlnd_palloc_rinit */
529 : PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache TSRMLS_DC)
530 52857 : {
531 52857 : return mysqlnd_palloc_init_thd_cache(cache);
532 : }
533 : /* }}} */
534 :
535 :
536 : /* {{{ _mysqlnd_palloc_rshutdown */
537 : PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS_DC)
538 52953 : {
539 52953 : DBG_ENTER("_mysqlnd_palloc_rshutdown");
540 52953 : DBG_INF_FMT("cache=%p", thd_cache);
541 52953 : mysqlnd_palloc_free_thd_cache_reference(&thd_cache);
542 : DBG_VOID_RETURN;
543 : }
544 : /* }}} */
545 :
546 :
547 : /* {{{ mysqlnd_palloc_rshutdown */
548 : PHPAPI void mysqlnd_palloc_stats(const MYSQLND_ZVAL_PCACHE * const cache, zval *return_value)
549 139 : {
550 139 : if (cache) {
551 : #if PHP_MAJOR_VERSION >= 6
552 : UChar *ustr;
553 : int ulen;
554 :
555 : TSRMLS_FETCH();
556 : #endif
557 :
558 : LOCK_PCACHE(cache);
559 139 : array_init(return_value);
560 : #if PHP_MAJOR_VERSION >= 6
561 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "put_hits", sizeof("put_hits") TSRMLS_CC);
562 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
563 : efree(ustr);
564 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "put_misses", sizeof("put_misses") TSRMLS_CC);
565 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
566 : efree(ustr);
567 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "get_hits", sizeof("get_hits") TSRMLS_CC);
568 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
569 : efree(ustr);
570 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "get_misses", sizeof("get_misses") TSRMLS_CC);
571 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
572 : efree(ustr);
573 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "size", sizeof("size") TSRMLS_CC);
574 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
575 : efree(ustr);
576 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "free_items", sizeof("free_items") TSRMLS_CC);
577 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
578 : efree(ustr);
579 : zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "references", sizeof("references") TSRMLS_CC);
580 : add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
581 : efree(ustr);
582 : #else
583 139 : add_assoc_long_ex(return_value, "put_hits", sizeof("put_hits"), cache->put_hits);
584 139 : add_assoc_long_ex(return_value, "put_misses", sizeof("put_misses"), cache->put_misses);
585 139 : add_assoc_long_ex(return_value, "get_hits", sizeof("get_hits"), cache->get_hits);
586 139 : add_assoc_long_ex(return_value, "get_misses", sizeof("get_misses"), cache->get_misses);
587 139 : add_assoc_long_ex(return_value, "size", sizeof("size"), cache->max_items);
588 139 : add_assoc_long_ex(return_value, "free_items", sizeof("free_items"), cache->free_items);
589 139 : add_assoc_long_ex(return_value, "references", sizeof("references"), cache->references);
590 : #endif
591 : UNLOCK_PCACHE(cache);
592 : } else {
593 0 : ZVAL_NULL(return_value);
594 : }
595 139 : }
596 : /* }}} */
597 :
598 : /*
599 : * Local variables:
600 : * tab-width: 4
601 : * c-basic-offset: 4
602 : * End:
603 : * vim600: noet sw=4 ts=4 fdm=marker
604 : * vim<600: noet sw=4 ts=4
605 : */
|