[packages] php5: update APC module to 3.1.11
[openwrt/svn-archive/archive.git] / lang / php5 / patches / 005-APC.patch
1 diff -Naur a/ext/apc/apc_bin.c b/ext/apc/apc_bin.c
2 --- a/ext/apc/apc_bin.c 1970-01-01 01:00:00.000000000 +0100
3 +++ b/ext/apc/apc_bin.c 2012-07-20 00:10:35.000000000 +0200
4 @@ -0,0 +1,987 @@
5 +/*
6 + +----------------------------------------------------------------------+
7 + | APC |
8 + +----------------------------------------------------------------------+
9 + | Copyright (c) 2006-2011 The PHP Group |
10 + +----------------------------------------------------------------------+
11 + | This source file is subject to version 3.01 of the PHP license, |
12 + | that is bundled with this package in the file LICENSE, and is |
13 + | available through the world-wide-web at the following url: |
14 + | http://www.php.net/license/3_01.txt. |
15 + | If you did not receive a copy of the PHP license and are unable to |
16 + | obtain it through the world-wide-web, please send a note to |
17 + | license@php.net so we can mail you a copy immediately. |
18 + +----------------------------------------------------------------------+
19 + | Authors: Brian Shire <shire@php.net> |
20 + +----------------------------------------------------------------------+
21 +
22 + */
23 +
24 +/* $Id: apc_bin.c 324017 2012-03-08 09:46:22Z pajoye $ */
25 +
26 +/* Creates a binary architecture specific output to a string or file containing
27 + * the current cache contents for both fies and user variables. This is accomplished
28 + * via the apc_copy_* functions and "swizzling" pointer values to a position
29 + * independent value, and unswizzling them on restoration.
30 + */
31 +
32 +#include "apc_globals.h"
33 +#include "apc_bin.h"
34 +#include "apc_zend.h"
35 +#include "apc_php.h"
36 +#include "apc_sma.h"
37 +#include "apc_pool.h"
38 +#include "ext/standard/md5.h"
39 +#include "ext/standard/crc32.h"
40 +
41 +extern apc_cache_t* apc_cache;
42 +extern apc_cache_t* apc_user_cache;
43 +
44 +extern int _apc_store(char *strkey, int strkey_len, const zval *val, const uint ttl, const int exclusive TSRMLS_DC); /* this is hacky */
45 +
46 +#define APC_BINDUMP_DEBUG 0
47 +
48 +
49 +#if APC_BINDUMP_DEBUG
50 +
51 +#define SWIZZLE(bd, ptr) \
52 + do { \
53 + if((long)bd < (long)ptr && (ulong)ptr < ((long)bd + bd->size)) { \
54 + printf("SWIZZLE: %x ~> ", ptr); \
55 + ptr = (void*)((long)(ptr) - (long)(bd)); \
56 + printf("%x in %s on line %d", ptr, __FILE__, __LINE__); \
57 + } else if((long)ptr > bd->size) { /* not swizzled */ \
58 + apc_error("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d" TSRMLS_CC, (long)bd, ptr, ((long)bd + bd->size), __FILE__, __LINE__); \
59 + return; \
60 + } \
61 + printf("\n"); \
62 + } while(0);
63 +
64 +#define UNSWIZZLE(bd, ptr) \
65 + do { \
66 + printf("UNSWIZZLE: %x -> ", ptr); \
67 + ptr = (void*)((long)(ptr) + (long)(bd)); \
68 + printf("%x in %s on line %d \n", ptr, __FILE__, __LINE__); \
69 + } while(0);
70 +
71 +#else /* !APC_BINDUMP_DEBUG */
72 +
73 +#define SWIZZLE(bd, ptr) \
74 + do { \
75 + if((long)bd < (long)ptr && (ulong)ptr < ((long)bd + bd->size)) { \
76 + ptr = (void*)((long)(ptr) - (long)(bd)); \
77 + } else if((ulong)ptr > bd->size) { /* not swizzled */ \
78 + apc_error("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d" TSRMLS_CC, (long)bd, ptr, ((long)bd + bd->size), __FILE__, __LINE__); \
79 + return NULL; \
80 + } \
81 + } while(0);
82 +
83 +#define UNSWIZZLE(bd, ptr) \
84 + do { \
85 + ptr = (void*)((long)(ptr) + (long)(bd)); \
86 + } while(0);
87 +
88 +#endif
89 +
90 +
91 +static void *apc_bd_alloc(size_t size TSRMLS_DC);
92 +static void apc_bd_free(void *ptr TSRMLS_DC);
93 +static void *apc_bd_alloc_ex(void *ptr_new, size_t size TSRMLS_DC);
94 +
95 +typedef void (*apc_swizzle_cb_t)(apc_bd_t *bd, zend_llist *ll, void *ptr TSRMLS_DC);
96 +
97 +#if APC_BINDUMP_DEBUG
98 +#define apc_swizzle_ptr(bd, ll, ptr) _apc_swizzle_ptr(bd, ll, (void*)ptr, __FILE__, __LINE__ TSRMLS_CC)
99 +#else
100 +#define apc_swizzle_ptr(bd, ll, ptr) _apc_swizzle_ptr(bd, ll, (void*)ptr, NULL, 0 TSRMLS_CC)
101 +#endif
102 +
103 +static void _apc_swizzle_ptr(apc_bd_t *bd, zend_llist *ll, void **ptr, const char* file, int line TSRMLS_DC);
104 +static void apc_swizzle_function(apc_bd_t *bd, zend_llist *ll, zend_function *func TSRMLS_DC);
105 +static void apc_swizzle_class_entry(apc_bd_t *bd, zend_llist *ll, zend_class_entry *ce TSRMLS_DC);
106 +static void apc_swizzle_hashtable(apc_bd_t *bd, zend_llist *ll, HashTable *ht, apc_swizzle_cb_t swizzle_cb, int is_ptr TSRMLS_DC);
107 +static void apc_swizzle_zval(apc_bd_t *bd, zend_llist *ll, zval *zv TSRMLS_DC);
108 +static void apc_swizzle_op_array(apc_bd_t *bd, zend_llist *ll, zend_op_array *op_array TSRMLS_DC);
109 +static void apc_swizzle_property_info(apc_bd_t *bd, zend_llist *ll, zend_property_info *pi TSRMLS_DC);
110 +static void apc_swizzle_function_entry(apc_bd_t *bd, zend_llist *ll, const zend_function_entry *fe TSRMLS_DC);
111 +static void apc_swizzle_arg_info_array(apc_bd_t *bd, zend_llist *ll, const zend_arg_info* arg_info_array, uint num_args TSRMLS_DC);
112 +
113 +static apc_bd_t* apc_swizzle_bd(apc_bd_t* bd, zend_llist *ll TSRMLS_DC);
114 +static int apc_unswizzle_bd(apc_bd_t *bd, int flags TSRMLS_DC);
115 +
116 +
117 +/* {{{ apc_bd_alloc
118 + * callback for copy_* functions */
119 +static void *apc_bd_alloc(size_t size TSRMLS_DC) {
120 + return apc_bd_alloc_ex(NULL, size TSRMLS_CC);
121 +} /* }}} */
122 +
123 +
124 +/* {{{ apc_bd_free
125 + * callback for copy_* functions */
126 +static void apc_bd_free(void *ptr TSRMLS_DC) {
127 + size_t *size;
128 + if(zend_hash_index_find(&APCG(apc_bd_alloc_list), (ulong)ptr, (void**)&size) == FAILURE) {
129 + apc_error("apc_bd_free could not free pointer (not found in list: %x)" TSRMLS_CC, ptr);
130 + return;
131 + }
132 + APCG(apc_bd_alloc_ptr) = (void*)((size_t)APCG(apc_bd_alloc_ptr) - *size);
133 + zend_hash_index_del(&APCG(apc_bd_alloc_list), (ulong)ptr);
134 +} /* }}} */
135 +
136 +
137 +/* {{{ apc_bd_alloc_ex
138 + * set ranges or allocate a block of data from an already (e)malloc'd range.
139 + * if ptr_new is not NULL, it will reset the pointer to start at ptr_new,
140 + * with a range of size. If ptr_new is NULL, returns the next available
141 + * block of given size.
142 + */
143 +static void *apc_bd_alloc_ex(void *ptr_new, size_t size TSRMLS_DC) {
144 + void *rval;
145 +
146 + rval = APCG(apc_bd_alloc_ptr);
147 + if(ptr_new != NULL) { /* reset ptrs */
148 + APCG(apc_bd_alloc_ptr) = ptr_new;
149 + APCG(apc_bd_alloc_ubptr) = (void*)((unsigned char *) ptr_new + size);
150 + } else { /* alloc block */
151 + APCG(apc_bd_alloc_ptr) = (void*)((size_t)APCG(apc_bd_alloc_ptr) + size);
152 +#if APC_BINDUMP_DEBUG
153 + apc_notice("apc_bd_alloc: rval: 0x%x ptr: 0x%x ubptr: 0x%x size: %d" TSRMLS_CC, rval, APCG(apc_bd_alloc_ptr), APCG(apc_bd_alloc_ubptr), size);
154 +#endif
155 + if(APCG(apc_bd_alloc_ptr) > APCG(apc_bd_alloc_ubptr)) {
156 + apc_error("Exceeded bounds check in apc_bd_alloc_ex by %d bytes." TSRMLS_CC, (unsigned char *) APCG(apc_bd_alloc_ptr) - (unsigned char *) APCG(apc_bd_alloc_ubptr));
157 + return NULL;
158 + }
159 + zend_hash_index_update(&APCG(apc_bd_alloc_list), (ulong)rval, &size, sizeof(size_t), NULL);
160 + }
161 +
162 + return rval;
163 +} /* }}} */
164 +
165 +
166 +/* {{{ _apc_swizzle_ptr */
167 +static void _apc_swizzle_ptr(apc_bd_t *bd, zend_llist *ll, void **ptr, const char* file, int line TSRMLS_DC) {
168 + if(*ptr) {
169 + if((long)bd < (long)*ptr && (ulong)*ptr < ((long)bd + bd->size)) {
170 + zend_llist_add_element(ll, &ptr);
171 +#if APC_BINDUMP_DEBUG
172 + printf("[%06d] apc_swizzle_ptr: %x -> %x ", zend_llist_count(ll), ptr, *ptr);
173 + printf(" in %s on line %d \n", file, line);
174 +#endif
175 + } else if((ulong)ptr > bd->size) {
176 + apc_error("pointer to be swizzled is not within allowed memory range! (%x < %x < %x) in %s on %d" TSRMLS_CC, (long)bd, *ptr, ((long)bd + bd->size), file, line); \
177 + return;
178 + }
179 + }
180 +} /* }}} */
181 +
182 +
183 +/* {{{ apc_swizzle_op_array */
184 +static void apc_swizzle_op_array(apc_bd_t *bd, zend_llist *ll, zend_op_array *op_array TSRMLS_DC) {
185 + uint i;
186 +
187 +#ifdef ZEND_ENGINE_2
188 + apc_swizzle_arg_info_array(bd, ll, op_array->arg_info, op_array->num_args TSRMLS_CC);
189 + apc_swizzle_ptr(bd, ll, &op_array->arg_info);
190 +#else
191 + if (op_array->arg_types) {
192 + apc_swizzle_ptr(bd, ll, &op_array->arg_types);
193 + }
194 +#endif
195 +
196 + apc_swizzle_ptr(bd, ll, &op_array->function_name);
197 + apc_swizzle_ptr(bd, ll, &op_array->filename);
198 + apc_swizzle_ptr(bd, ll, &op_array->refcount);
199 +
200 + /* swizzle op_array */
201 + for(i=0; i < op_array->last; i++) {
202 +#ifndef ZEND_ENGINE_2_4
203 + if(op_array->opcodes[i].result.op_type == IS_CONST) {
204 + apc_swizzle_zval(bd, ll, &op_array->opcodes[i].result.u.constant TSRMLS_CC);
205 + }
206 + if(op_array->opcodes[i].op1.op_type == IS_CONST) {
207 + apc_swizzle_zval(bd, ll, &op_array->opcodes[i].op1.u.constant TSRMLS_CC);
208 + }
209 + if(op_array->opcodes[i].op2.op_type == IS_CONST) {
210 + apc_swizzle_zval(bd, ll, &op_array->opcodes[i].op2.u.constant TSRMLS_CC);
211 + }
212 +#endif
213 + switch (op_array->opcodes[i].opcode) {
214 + case ZEND_JMP:
215 +#ifdef ZEND_ENGINE_2_4
216 + apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op1.jmp_addr);
217 +#else
218 + apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op1.u.jmp_addr);
219 +#endif
220 + case ZEND_JMPZ:
221 + case ZEND_JMPNZ:
222 + case ZEND_JMPZ_EX:
223 + case ZEND_JMPNZ_EX:
224 +#ifdef ZEND_ENGINE_2_4
225 + apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op2.jmp_addr);
226 +#else
227 + apc_swizzle_ptr(bd, ll, &op_array->opcodes[i].op2.u.jmp_addr);
228 +#endif
229 + }
230 + }
231 + apc_swizzle_ptr(bd, ll, &op_array->opcodes);
232 +
233 + /* break-continue array ptr */
234 + if(op_array->brk_cont_array) {
235 + apc_swizzle_ptr(bd, ll, &op_array->brk_cont_array);
236 + }
237 +
238 + /* static voriables */
239 + if(op_array->static_variables) {
240 + apc_swizzle_hashtable(bd, ll, op_array->static_variables, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
241 + apc_swizzle_ptr(bd, ll, &op_array->static_variables);
242 + }
243 +
244 +#ifdef ZEND_ENGINE_2
245 + /* try-catch */
246 + if(op_array->try_catch_array) {
247 + apc_swizzle_ptr(bd, ll, &op_array->try_catch_array);
248 + }
249 +#endif
250 +
251 +#ifdef ZEND_ENGINE_2_1 /* PHP 5.1 */
252 + /* vars */
253 + if(op_array->vars) {
254 + for(i=0; (signed int) i < op_array->last_var; i++) {
255 + apc_swizzle_ptr(bd, ll, &op_array->vars[i].name);
256 + }
257 + apc_swizzle_ptr(bd, ll, &op_array->vars);
258 + }
259 +#endif
260 +
261 +#ifdef ZEND_ENGINE_2
262 + /* doc comment */
263 + if(op_array->doc_comment) {
264 + apc_swizzle_ptr(bd, ll, &op_array->doc_comment);
265 + }
266 +#endif
267 +
268 +} /* }}} */
269 +
270 +
271 +/* {{{ apc_swizzle_function */
272 +static void apc_swizzle_function(apc_bd_t *bd, zend_llist *ll, zend_function *func TSRMLS_DC) {
273 + apc_swizzle_op_array(bd, ll, &func->op_array TSRMLS_CC);
274 +#ifdef ZEND_ENGINE_2
275 + if(func->common.scope) {
276 + apc_swizzle_ptr(bd, ll, &func->common.scope);
277 + }
278 +#endif
279 +} /* }}} */
280 +
281 +
282 +/* {{{ apc_swizzle_class_entry */
283 +static void apc_swizzle_class_entry(apc_bd_t *bd, zend_llist *ll, zend_class_entry *ce TSRMLS_DC) {
284 +
285 + uint i;
286 +
287 + if(ce->name) {
288 + apc_swizzle_ptr(bd, ll, &ce->name);
289 + }
290 +
291 + if (ce->type == ZEND_USER_CLASS && ZEND_CE_DOC_COMMENT(ce)) {
292 + apc_swizzle_ptr(bd, ll, &ZEND_CE_DOC_COMMENT(ce));
293 + }
294 +
295 +#ifndef ZEND_ENGINE_2
296 + apc_swizzle_ptr(bd, ll, &ce->refcount);
297 +#endif
298 +
299 + apc_swizzle_hashtable(bd, ll, &ce->function_table, (apc_swizzle_cb_t)apc_swizzle_function, 0 TSRMLS_CC);
300 +#ifdef ZEND_ENGINE_2_4
301 + if (ce->default_properties_table) {
302 + for (i = 0; i < ce->default_properties_count; i++) {
303 + if (ce->default_properties_table[i]) {
304 + apc_swizzle_ptr(bd, ll, &ce->default_properties_table[i]);
305 + apc_swizzle_zval(bd, ll, ce->default_properties_table[i] TSRMLS_CC);
306 + }
307 + }
308 + }
309 +#else
310 + apc_swizzle_hashtable(bd, ll, &ce->default_properties, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
311 +#endif
312 +
313 +#ifdef ZEND_ENGINE_2
314 + apc_swizzle_hashtable(bd, ll, &ce->properties_info, (apc_swizzle_cb_t)apc_swizzle_property_info, 0 TSRMLS_CC);
315 +#endif
316 +
317 +#ifdef ZEND_ENGINE_2_4
318 + if (ce->default_static_members_table) {
319 + for (i = 0; i < ce->default_static_members_count; i++) {
320 + if (ce->default_static_members_table[i]) {
321 + apc_swizzle_ptr(bd, ll, &ce->default_static_members_table[i]);
322 + apc_swizzle_zval(bd, ll, ce->default_static_members_table[i] TSRMLS_CC);
323 + }
324 + }
325 + }
326 + ce->static_members_table = ce->default_static_members_table;
327 +#else
328 + apc_swizzle_hashtable(bd, ll, &ce->default_static_members, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
329 +
330 + if(ce->static_members != &ce->default_static_members) {
331 + apc_swizzle_hashtable(bd, ll, ce->static_members, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
332 + } else {
333 + apc_swizzle_ptr(bd, ll, &ce->static_members);
334 + }
335 +#endif
336 +
337 + apc_swizzle_hashtable(bd, ll, &ce->constants_table, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
338 +
339 + if(ce->type == ZEND_INTERNAL_CLASS && ZEND_CE_BUILTIN_FUNCTIONS(ce)) {
340 + for(i=0; ZEND_CE_BUILTIN_FUNCTIONS(ce)[i].fname; i++) {
341 + apc_swizzle_function_entry(bd, ll, &ZEND_CE_BUILTIN_FUNCTIONS(ce)[i] TSRMLS_CC);
342 + }
343 + }
344 +
345 + apc_swizzle_ptr(bd, ll, &ce->constructor);
346 + apc_swizzle_ptr(bd, ll, &ce->destructor);
347 + apc_swizzle_ptr(bd, ll, &ce->clone);
348 + apc_swizzle_ptr(bd, ll, &ce->__get);
349 + apc_swizzle_ptr(bd, ll, &ce->__set);
350 + apc_swizzle_ptr(bd, ll, &ce->__unset);
351 + apc_swizzle_ptr(bd, ll, &ce->__isset);
352 + apc_swizzle_ptr(bd, ll, &ce->__call);
353 + apc_swizzle_ptr(bd, ll, &ce->serialize_func);
354 + apc_swizzle_ptr(bd, ll, &ce->unserialize_func);
355 +
356 +#ifdef ZEND_ENGINE_2_2
357 + apc_swizzle_ptr(bd, ll, &ce->__tostring);
358 +#endif
359 +
360 + if (ce->type == ZEND_USER_CLASS) {
361 + apc_swizzle_ptr(bd, ll, &ZEND_CE_FILENAME(ce));
362 + }
363 +} /* }}} */
364 +
365 +
366 +/* {{{ apc_swizzle_property_info */
367 +static void apc_swizzle_property_info(apc_bd_t *bd, zend_llist *ll, zend_property_info *pi TSRMLS_DC) {
368 + apc_swizzle_ptr(bd, ll, &pi->name);
369 + apc_swizzle_ptr(bd, ll, &pi->doc_comment);
370 +
371 +#ifdef ZEND_ENGINE_2_2
372 + apc_swizzle_ptr(bd, ll, &pi->ce);
373 +#endif
374 +} /* }}} */
375 +
376 +
377 +/* {{{ apc_swizzle_function_entry */
378 +static void apc_swizzle_function_entry(apc_bd_t *bd, zend_llist *ll, const zend_function_entry *fe TSRMLS_DC) {
379 + apc_swizzle_ptr(bd, ll, &fe->fname);
380 + apc_swizzle_arg_info_array(bd, ll, fe->arg_info, fe->num_args TSRMLS_CC);
381 + apc_swizzle_ptr(bd, ll, &fe->arg_info);
382 +} /* }}} */
383 +
384 +
385 +/* {{{ apc_swizzle_arg_info_array */
386 +static void apc_swizzle_arg_info_array(apc_bd_t *bd, zend_llist *ll, const zend_arg_info* arg_info_array, uint num_args TSRMLS_DC) {
387 + if(arg_info_array) {
388 + uint i;
389 +
390 + for(i=0; i < num_args; i++) {
391 + apc_swizzle_ptr(bd, ll, &arg_info_array[i].name);
392 + apc_swizzle_ptr(bd, ll, &arg_info_array[i].class_name);
393 + }
394 + }
395 +
396 +} /* }}} */
397 +
398 +
399 +/* {{{ apc_swizzle_hashtable */
400 +static void apc_swizzle_hashtable(apc_bd_t *bd, zend_llist *ll, HashTable *ht, apc_swizzle_cb_t swizzle_cb, int is_ptr TSRMLS_DC) {
401 + uint i;
402 + Bucket **bp, **bp_prev;
403 +
404 + bp = &ht->pListHead;
405 + while(*bp) {
406 + bp_prev = bp;
407 + bp = &(*bp)->pListNext;
408 + if(is_ptr) {
409 + swizzle_cb(bd, ll, *(void**)(*bp_prev)->pData TSRMLS_CC);
410 + apc_swizzle_ptr(bd, ll, (*bp_prev)->pData);
411 + } else {
412 + swizzle_cb(bd, ll, (void**)(*bp_prev)->pData TSRMLS_CC);
413 + }
414 + apc_swizzle_ptr(bd, ll, &(*bp_prev)->pData);
415 + if((*bp_prev)->pDataPtr) {
416 + apc_swizzle_ptr(bd, ll, &(*bp_prev)->pDataPtr);
417 + }
418 + if((*bp_prev)->pListLast) {
419 + apc_swizzle_ptr(bd, ll, &(*bp_prev)->pListLast);
420 + }
421 + if((*bp_prev)->pNext) {
422 + apc_swizzle_ptr(bd, ll, &(*bp_prev)->pNext);
423 + }
424 + if((*bp_prev)->pLast) {
425 + apc_swizzle_ptr(bd, ll, &(*bp_prev)->pLast);
426 + }
427 + apc_swizzle_ptr(bd, ll, bp_prev);
428 + }
429 + for(i=0; i < ht->nTableSize; i++) {
430 + if(ht->arBuckets[i]) {
431 + apc_swizzle_ptr(bd, ll, &ht->arBuckets[i]);
432 + }
433 + }
434 + apc_swizzle_ptr(bd, ll, &ht->pListTail);
435 +
436 + apc_swizzle_ptr(bd, ll, &ht->arBuckets);
437 +} /* }}} */
438 +
439 +
440 +/* {{{ apc_swizzle_zval */
441 +static void apc_swizzle_zval(apc_bd_t *bd, zend_llist *ll, zval *zv TSRMLS_DC) {
442 +
443 + if(APCG(copied_zvals).nTableSize) {
444 + if(zend_hash_index_exists(&APCG(copied_zvals), (ulong)zv)) {
445 + return;
446 + }
447 + zend_hash_index_update(&APCG(copied_zvals), (ulong)zv, (void**)&zv, sizeof(zval*), NULL);
448 + }
449 +
450 + switch(zv->type & IS_CONSTANT_TYPE_MASK) {
451 + case IS_NULL:
452 + case IS_LONG:
453 + case IS_DOUBLE:
454 + case IS_BOOL:
455 + case IS_RESOURCE:
456 + /* nothing to do */
457 + break;
458 + case IS_CONSTANT:
459 + case IS_STRING:
460 + apc_swizzle_ptr(bd, ll, &zv->value.str.val);
461 + break;
462 + case IS_ARRAY:
463 + case IS_CONSTANT_ARRAY:
464 + apc_swizzle_hashtable(bd, ll, zv->value.ht, (apc_swizzle_cb_t)apc_swizzle_zval, 1 TSRMLS_CC);
465 + apc_swizzle_ptr(bd, ll, &zv->value.ht);
466 + break;
467 + case IS_OBJECT:
468 + break;
469 + default:
470 + assert(0); /* shouldn't happen */
471 + }
472 +} /* }}} */
473 +
474 +
475 +/* {{{ apc_swizzle_bd */
476 +static apc_bd_t* apc_swizzle_bd(apc_bd_t* bd, zend_llist *ll TSRMLS_DC) {
477 + int count, i;
478 + PHP_MD5_CTX context;
479 + unsigned char digest[16];
480 + register php_uint32 crc;
481 + php_uint32 crcinit = 0;
482 + char *crc_p;
483 + void ***ptr;
484 + void ***ptr_list;
485 +
486 + count = zend_llist_count(ll);
487 + ptr_list = emalloc(count * sizeof(void**));
488 + ptr = zend_llist_get_first(ll);
489 + for(i=0; i < count; i++) {
490 +#if APC_BINDUMP_DEBUG
491 + printf("[%06d] ", i+1);
492 +#endif
493 + SWIZZLE(bd, **ptr); /* swizzle ptr */
494 + if((long)bd < (long)*ptr && (ulong)*ptr < ((long)bd + bd->size)) { /* exclude ptrs that aren't actually included in the ptr list */
495 +#if APC_BINDUMP_DEBUG
496 + printf("[------] ");
497 +#endif
498 + SWIZZLE(bd, *ptr); /* swizzle ptr list */
499 + ptr_list[i] = *ptr;
500 + }
501 + ptr = zend_llist_get_next(ll);
502 + }
503 + SWIZZLE(bd, bd->entries);
504 +
505 + if(count > 0) {
506 + bd = erealloc(bd, bd->size + (count * sizeof(void**)));
507 + bd->num_swizzled_ptrs = count;
508 + bd->swizzled_ptrs = (void***)((unsigned char *)bd + bd->size -2); /* extra -1 for null termination */
509 + bd->size += count * sizeof(void**);
510 + memcpy(bd->swizzled_ptrs, ptr_list, count * sizeof(void**));
511 + SWIZZLE(bd, bd->swizzled_ptrs);
512 + } else {
513 + bd->num_swizzled_ptrs = 0;
514 + bd->swizzled_ptrs = NULL;
515 + }
516 + ((char*)bd)[bd->size-1] = 0; /* silence null termination for zval strings */
517 + efree(ptr_list);
518 + bd->swizzled = 1;
519 +
520 + /* Generate MD5/CRC32 checksum */
521 + for(i=0; i<16; i++) { bd->md5[i] = 0; }
522 + bd->crc=0;
523 + PHP_MD5Init(&context);
524 + PHP_MD5Update(&context, (const unsigned char*)bd, bd->size);
525 + PHP_MD5Final(digest, &context);
526 + crc = crcinit^0xFFFFFFFF;
527 + crc_p = (char*)bd;
528 + for(i=bd->size; i--; ++crc_p) {
529 + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*crc_p)) & 0xFF ];
530 + }
531 + memcpy(bd->md5, digest, 16);
532 + bd->crc = crc;
533 +
534 + return bd;
535 +} /* }}} */
536 +
537 +
538 +/* {{{ apc_unswizzle_bd */
539 +static int apc_unswizzle_bd(apc_bd_t *bd, int flags TSRMLS_DC) {
540 + int i;
541 + unsigned char md5_orig[16];
542 + unsigned char digest[16];
543 + PHP_MD5_CTX context;
544 + register php_uint32 crc;
545 + php_uint32 crcinit = 0;
546 + php_uint32 crc_orig;
547 + char *crc_p;
548 +
549 + /* Verify the md5 or crc32 before we unswizzle */
550 + memcpy(md5_orig, bd->md5, 16);
551 + for(i=0; i<16; i++) { bd->md5[i] = 0; }
552 + crc_orig = bd->crc;
553 + bd->crc=0;
554 + if(flags & APC_BIN_VERIFY_MD5) {
555 + PHP_MD5Init(&context);
556 + PHP_MD5Update(&context, (const unsigned char*)bd, bd->size);
557 + PHP_MD5Final(digest, &context);
558 + if(memcmp(md5_orig, digest, 16)) {
559 + apc_error("MD5 checksum of binary dump failed." TSRMLS_CC);
560 + return -1;
561 + }
562 + }
563 + if(flags & APC_BIN_VERIFY_CRC32) {
564 + crc = crcinit^0xFFFFFFFF;
565 + crc_p = (char*)bd;
566 + for(i=bd->size; i--; ++crc_p) {
567 + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[(crc ^ (*crc_p)) & 0xFF ];
568 + }
569 + if(crc_orig != crc) {
570 + apc_error("CRC32 checksum of binary dump failed." TSRMLS_CC);
571 + return -1;
572 + }
573 + }
574 + memcpy(bd->md5, md5_orig, 16); /* add back md5 checksum */
575 + bd->crc = crc_orig;
576 +
577 + UNSWIZZLE(bd, bd->entries);
578 + UNSWIZZLE(bd, bd->swizzled_ptrs);
579 + for(i=0; i < bd->num_swizzled_ptrs; i++) {
580 + if(bd->swizzled_ptrs[i]) {
581 + UNSWIZZLE(bd, bd->swizzled_ptrs[i]);
582 + if(*bd->swizzled_ptrs[i] && (*bd->swizzled_ptrs[i] < (void*)bd)) {
583 + UNSWIZZLE(bd, *bd->swizzled_ptrs[i]);
584 + }
585 + }
586 + }
587 +
588 + bd->swizzled=0;
589 +
590 + return 0;
591 +} /* }}} */
592 +
593 +
594 +/* {{{ apc_bin_checkfilter */
595 +static int apc_bin_checkfilter(HashTable *filter, const char *key, uint key_len) {
596 + zval **zptr;
597 +
598 + if(filter == NULL) {
599 + return 1;
600 + }
601 +
602 + if(zend_hash_find(filter, (char*)key, key_len, (void**)&zptr) == SUCCESS) {
603 + if(Z_TYPE_PP(zptr) == IS_LONG && Z_LVAL_PP(zptr) == 0) {
604 + return 0;
605 + }
606 + } else {
607 + return 0;
608 + }
609 +
610 +
611 + return 1;
612 +} /* }}} */
613 +
614 +/* {{{ apc_bin_fixup_op_array */
615 +static inline void apc_bin_fixup_op_array(zend_op_array *op_array) {
616 + ulong i;
617 + for (i = 0; i < op_array->last; i++) {
618 + op_array->opcodes[i].handler = zend_opcode_handlers[APC_OPCODE_HANDLER_DECODE(&op_array->opcodes[i])];
619 + }
620 +}
621 +/* }}} */
622 +
623 +/* {{{ apc_bin_fixup_class_entry */
624 +static inline void apc_bin_fixup_class_entry(zend_class_entry *ce) {
625 + zend_function *fe;
626 + HashPosition hpos;
627 +
628 + /* fixup the opcodes in each method */
629 + zend_hash_internal_pointer_reset_ex(&ce->function_table, &hpos);
630 + while(zend_hash_get_current_data_ex(&ce->function_table, (void**)&fe, &hpos) == SUCCESS) {
631 + apc_bin_fixup_op_array(&fe->op_array);
632 + zend_hash_move_forward_ex(&ce->function_table, &hpos);
633 + }
634 +
635 + /* fixup hashtable destructor pointers */
636 + ce->function_table.pDestructor = (dtor_func_t)zend_function_dtor;
637 +#ifndef ZEND_ENGINE_2_4
638 + ce->default_properties.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
639 +#endif
640 + ce->properties_info.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
641 +#ifndef ZEND_ENGINE_2_4
642 + ce->default_static_members.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
643 + if (ce->static_members) {
644 + ce->static_members->pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
645 + }
646 +#endif
647 + ce->constants_table.pDestructor = (dtor_func_t)zval_ptr_dtor_wrapper;
648 +}
649 +/* }}} */
650 +
651 +/* {{{ apc_bin_dump */
652 +apc_bd_t* apc_bin_dump(HashTable *files, HashTable *user_vars TSRMLS_DC) {
653 +
654 + int i;
655 + uint fcount;
656 + slot_t *sp;
657 + apc_bd_entry_t *ep;
658 + int count=0;
659 + apc_bd_t *bd;
660 + zend_llist ll;
661 + zend_function *efp, *sfp;
662 + long size=0;
663 + apc_context_t ctxt;
664 + void *pool_ptr;
665 +
666 + zend_llist_init(&ll, sizeof(void*), NULL, 0);
667 + zend_hash_init(&APCG(apc_bd_alloc_list), 0, NULL, NULL, 0);
668 +
669 + /* flip the hash for faster filter checking */
670 + files = apc_flip_hash(files);
671 + user_vars = apc_flip_hash(user_vars);
672 +
673 + /* get size and entry counts */
674 + for(i=0; i < apc_user_cache->num_slots; i++) {
675 + sp = apc_user_cache->slots[i];
676 + for(; sp != NULL; sp = sp->next) {
677 + if(apc_bin_checkfilter(user_vars, sp->key.data.user.identifier, sp->key.data.user.identifier_len)) {
678 + size += sizeof(apc_bd_entry_t*) + sizeof(apc_bd_entry_t);
679 + size += sp->value->mem_size - (sizeof(apc_cache_entry_t) - sizeof(apc_cache_entry_value_t));
680 + count++;
681 + }
682 + }
683 + }
684 + for(i=0; i < apc_cache->num_slots; i++) {
685 + sp = apc_cache->slots[i];
686 + for(; sp != NULL; sp = sp->next) {
687 + if(sp->key.type == APC_CACHE_KEY_FPFILE) {
688 + if(apc_bin_checkfilter(files, sp->key.data.fpfile.fullpath, sp->key.data.fpfile.fullpath_len+1)) {
689 + size += sizeof(apc_bd_entry_t*) + sizeof(apc_bd_entry_t);
690 + size += sp->value->mem_size - (sizeof(apc_cache_entry_t) - sizeof(apc_cache_entry_value_t));
691 + count++;
692 + }
693 + } else {
694 + /* TODO: Currently we don't support APC_CACHE_KEY_FILE type. We need to store the path and re-stat on load */
695 + apc_warning("Excluding some files from apc_bin_dump[file]. Cached files must be included using full path with apc.stat=0." TSRMLS_CC);
696 + }
697 + }
698 + }
699 +
700 + size += sizeof(apc_bd_t) +1; /* +1 for null termination */
701 + bd = emalloc(size);
702 + bd->size = size;
703 + pool_ptr = emalloc(sizeof(apc_pool));
704 + apc_bd_alloc_ex(pool_ptr, sizeof(apc_pool) TSRMLS_CC);
705 + ctxt.pool = apc_pool_create(APC_UNPOOL, apc_bd_alloc, apc_bd_free, NULL, NULL TSRMLS_CC); /* ideally the pool wouldn't be alloc'd as part of this */
706 + if (!ctxt.pool) { /* TODO need to cleanup */
707 + apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
708 + return NULL;
709 + }
710 + ctxt.copy = APC_COPY_IN_USER; /* avoid stupid ALLOC_ZVAL calls here, hack */
711 + apc_bd_alloc_ex((void*)((long)bd + sizeof(apc_bd_t)), bd->size - sizeof(apc_bd_t) -1 TSRMLS_CC);
712 + bd->num_entries = count;
713 + bd->entries = apc_bd_alloc_ex(NULL, sizeof(apc_bd_entry_t) * count TSRMLS_CC);
714 +
715 + /* User entries */
716 + zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
717 + count = 0;
718 + for(i=0; i < apc_user_cache->num_slots; i++) {
719 + sp = apc_user_cache->slots[i];
720 + for(; sp != NULL; sp = sp->next) {
721 + if(apc_bin_checkfilter(user_vars, sp->key.data.user.identifier, sp->key.data.user.identifier_len)) {
722 + ep = &bd->entries[count];
723 + ep->type = sp->value->type;
724 + ep->val.user.info = apc_bd_alloc(sp->value->data.user.info_len TSRMLS_CC);
725 + memcpy(ep->val.user.info, sp->value->data.user.info, sp->value->data.user.info_len);
726 + ep->val.user.info_len = sp->value->data.user.info_len;
727 + ep->val.user.val = apc_copy_zval(NULL, sp->value->data.user.val, &ctxt TSRMLS_CC);
728 + ep->val.user.ttl = sp->value->data.user.ttl;
729 +
730 + /* swizzle pointers */
731 + apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.user.info);
732 + zend_hash_clean(&APCG(copied_zvals));
733 + apc_swizzle_zval(bd, &ll, bd->entries[count].val.user.val TSRMLS_CC);
734 + apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.user.val);
735 +
736 + count++;
737 + }
738 + }
739 + }
740 + zend_hash_destroy(&APCG(copied_zvals));
741 + APCG(copied_zvals).nTableSize=0;
742 +
743 + /* File entries */
744 + for(i=0; i < apc_cache->num_slots; i++) {
745 + for(sp=apc_cache->slots[i]; sp != NULL; sp = sp->next) {
746 + if(sp->key.type == APC_CACHE_KEY_FPFILE) {
747 + if(apc_bin_checkfilter(files, sp->key.data.fpfile.fullpath, sp->key.data.fpfile.fullpath_len+1)) {
748 + ep = &bd->entries[count];
749 + ep->type = sp->key.type;
750 + ep->val.file.filename = apc_bd_alloc(strlen(sp->value->data.file.filename) + 1 TSRMLS_CC);
751 + strcpy(ep->val.file.filename, sp->value->data.file.filename);
752 + ep->val.file.op_array = apc_copy_op_array(NULL, sp->value->data.file.op_array, &ctxt TSRMLS_CC);
753 +
754 + for(ep->num_functions=0; sp->value->data.file.functions[ep->num_functions].function != NULL;) { ep->num_functions++; }
755 + ep->val.file.functions = apc_bd_alloc(sizeof(apc_function_t) * ep->num_functions TSRMLS_CC);
756 + for(fcount=0; fcount < ep->num_functions; fcount++) {
757 + memcpy(&ep->val.file.functions[fcount], &sp->value->data.file.functions[fcount], sizeof(apc_function_t));
758 + ep->val.file.functions[fcount].name = apc_xmemcpy(sp->value->data.file.functions[fcount].name, sp->value->data.file.functions[fcount].name_len+1, apc_bd_alloc TSRMLS_CC);
759 + ep->val.file.functions[fcount].name_len = sp->value->data.file.functions[fcount].name_len;
760 + ep->val.file.functions[fcount].function = apc_bd_alloc(sizeof(zend_function) TSRMLS_CC);
761 + efp = ep->val.file.functions[fcount].function;
762 + sfp = sp->value->data.file.functions[fcount].function;
763 + switch(sfp->type) {
764 + case ZEND_INTERNAL_FUNCTION:
765 + case ZEND_OVERLOADED_FUNCTION:
766 + efp->op_array = sfp->op_array;
767 + break;
768 + case ZEND_USER_FUNCTION:
769 + case ZEND_EVAL_CODE:
770 + apc_copy_op_array(&efp->op_array, &sfp->op_array, &ctxt TSRMLS_CC);
771 + break;
772 + default:
773 + assert(0);
774 + }
775 +#ifdef ZEND_ENGINE_2
776 + efp->common.prototype = NULL;
777 + efp->common.fn_flags = sfp->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
778 +#endif
779 + apc_swizzle_ptr(bd, &ll, &ep->val.file.functions[fcount].name);
780 + apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.functions[fcount].function);
781 + apc_swizzle_op_array(bd, &ll, &efp->op_array TSRMLS_CC);
782 + }
783 +
784 +
785 + for(ep->num_classes=0; sp->value->data.file.classes[ep->num_classes].class_entry != NULL;) { ep->num_classes++; }
786 + ep->val.file.classes = apc_bd_alloc(sizeof(apc_class_t) * ep->num_classes TSRMLS_CC);
787 + for(fcount=0; fcount < ep->num_classes; fcount++) {
788 + ep->val.file.classes[fcount].name = apc_xmemcpy(sp->value->data.file.classes[fcount].name, sp->value->data.file.classes[fcount].name_len + 1, apc_bd_alloc TSRMLS_CC);
789 + ep->val.file.classes[fcount].name_len = sp->value->data.file.classes[fcount].name_len;
790 + ep->val.file.classes[fcount].class_entry = apc_copy_class_entry(NULL, sp->value->data.file.classes[fcount].class_entry, &ctxt TSRMLS_CC);
791 + ep->val.file.classes[fcount].parent_name = apc_xstrdup(sp->value->data.file.classes[fcount].parent_name, apc_bd_alloc TSRMLS_CC);
792 +
793 + apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].name);
794 + apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].parent_name);
795 + apc_swizzle_class_entry(bd, &ll, ep->val.file.classes[fcount].class_entry TSRMLS_CC);
796 + apc_swizzle_ptr(bd, &ll, &ep->val.file.classes[fcount].class_entry);
797 + }
798 +
799 + apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.file.filename);
800 + apc_swizzle_op_array(bd, &ll, bd->entries[count].val.file.op_array TSRMLS_CC);
801 + apc_swizzle_ptr(bd, &ll, &bd->entries[count].val.file.op_array);
802 + apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.functions);
803 + apc_swizzle_ptr(bd, &ll, (void**)&ep->val.file.classes);
804 +
805 + count++;
806 + } else {
807 + /* TODO: Currently we don't support APC_CACHE_KEY_FILE type. We need to store the path and re-stat on load */
808 + }
809 + }
810 + }
811 + }
812 +
813 + /* append swizzle pointer list to bd */
814 + bd = apc_swizzle_bd(bd, &ll TSRMLS_CC);
815 + zend_llist_destroy(&ll);
816 + zend_hash_destroy(&APCG(apc_bd_alloc_list));
817 +
818 + if(files) {
819 + zend_hash_destroy(files);
820 + efree(files);
821 + }
822 + if(user_vars) {
823 + zend_hash_destroy(user_vars);
824 + efree(user_vars);
825 + }
826 +
827 + efree(pool_ptr);
828 +
829 + return bd;
830 +} /* }}} */
831 +
832 +
833 +/* {{{ apc_bin_load */
834 +int apc_bin_load(apc_bd_t *bd, int flags TSRMLS_DC) {
835 +
836 + apc_bd_entry_t *ep;
837 + uint i, i2;
838 + int ret;
839 + time_t t;
840 + zend_op_array *alloc_op_array = NULL;
841 + apc_function_t *alloc_functions = NULL;
842 + apc_class_t *alloc_classes = NULL;
843 + apc_cache_entry_t *cache_entry;
844 + apc_cache_key_t cache_key;
845 + apc_context_t ctxt;
846 +
847 + if (bd->swizzled) {
848 + if(apc_unswizzle_bd(bd, flags TSRMLS_CC) < 0) {
849 + return -1;
850 + }
851 + }
852 +
853 + t = apc_time();
854 +
855 + for(i = 0; i < bd->num_entries; i++) {
856 + ctxt.pool = apc_pool_create(APC_SMALL_POOL, apc_sma_malloc, apc_sma_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC);
857 + if (!ctxt.pool) { /* TODO need to cleanup previous pools */
858 + apc_warning("Unable to allocate memory for pool." TSRMLS_CC);
859 + goto failure;
860 + }
861 + ep = &bd->entries[i];
862 + switch (ep->type) {
863 + case APC_CACHE_KEY_FILE:
864 + /* TODO: Currently we don't support APC_CACHE_KEY_FILE type. We need to store the path and re-stat on load (or something else perhaps?) */
865 + break;
866 + case APC_CACHE_KEY_FPFILE:
867 + ctxt.copy = APC_COPY_IN_OPCODE;
868 +
869 + HANDLE_BLOCK_INTERRUPTIONS();
870 +#if NONBLOCKING_LOCK_AVAILABLE
871 + if(APCG(write_lock)) {
872 + if(!apc_cache_write_lock(apc_cache TSRMLS_CC)) {
873 + HANDLE_UNBLOCK_INTERRUPTIONS();
874 + return -1;
875 + }
876 + }
877 +#endif
878 + if(! (alloc_op_array = apc_copy_op_array(NULL, ep->val.file.op_array, &ctxt TSRMLS_CC))) {
879 + goto failure;
880 + }
881 + apc_bin_fixup_op_array(alloc_op_array);
882 +
883 + if(! (alloc_functions = apc_sma_malloc(sizeof(apc_function_t) * (ep->num_functions + 1) TSRMLS_CC))) {
884 + goto failure;
885 + }
886 + for(i2=0; i2 < ep->num_functions; i2++) {
887 + if(! (alloc_functions[i2].name = apc_xmemcpy(ep->val.file.functions[i2].name, ep->val.file.functions[i2].name_len + 1, apc_sma_malloc TSRMLS_CC))) {
888 + goto failure;
889 + }
890 + alloc_functions[i2].name_len = ep->val.file.functions[i2].name_len;
891 + if(! (alloc_functions[i2].function = apc_sma_malloc(sizeof(zend_function) TSRMLS_CC))) {
892 + goto failure;
893 + }
894 + switch(ep->val.file.functions[i2].function->type) {
895 + case ZEND_INTERNAL_FUNCTION:
896 + case ZEND_OVERLOADED_FUNCTION:
897 + alloc_functions[i2].function->op_array = ep->val.file.functions[i2].function->op_array;
898 + break;
899 + case ZEND_USER_FUNCTION:
900 + case ZEND_EVAL_CODE:
901 + if (!apc_copy_op_array(&alloc_functions[i2].function->op_array, &ep->val.file.functions[i2].function->op_array, &ctxt TSRMLS_CC)) {
902 + goto failure;
903 + }
904 + apc_bin_fixup_op_array(&alloc_functions[i2].function->op_array);
905 + break;
906 + default:
907 + assert(0);
908 + }
909 +#ifdef ZEND_ENGINE_2
910 + alloc_functions[i2].function->common.prototype=NULL;
911 + alloc_functions[i2].function->common.fn_flags=ep->val.file.functions[i2].function->common.fn_flags & (~ZEND_ACC_IMPLEMENTED_ABSTRACT);
912 +#endif
913 + }
914 + alloc_functions[i2].name = NULL;
915 + alloc_functions[i2].function = NULL;
916 +
917 + if(! (alloc_classes = apc_sma_malloc(sizeof(apc_class_t) * (ep->num_classes + 1) TSRMLS_CC))) {
918 + goto failure;
919 + }
920 + for(i2=0; i2 < ep->num_classes; i2++) {
921 + if(! (alloc_classes[i2].name = apc_xmemcpy(ep->val.file.classes[i2].name, ep->val.file.classes[i2].name_len+1, apc_sma_malloc TSRMLS_CC))) {
922 + goto failure;
923 + }
924 + alloc_classes[i2].name_len = ep->val.file.classes[i2].name_len;
925 + if(! (alloc_classes[i2].class_entry = apc_copy_class_entry(NULL, ep->val.file.classes[i2].class_entry, &ctxt TSRMLS_CC))) {
926 + goto failure;
927 + }
928 + apc_bin_fixup_class_entry(alloc_classes[i2].class_entry);
929 + if(! (alloc_classes[i2].parent_name = apc_xstrdup(ep->val.file.classes[i2].parent_name, apc_sma_malloc TSRMLS_CC))) {
930 + if(ep->val.file.classes[i2].parent_name != NULL) {
931 + goto failure;
932 + }
933 + }
934 + }
935 + alloc_classes[i2].name = NULL;
936 + alloc_classes[i2].class_entry = NULL;
937 +
938 + if(!(cache_entry = apc_cache_make_file_entry(ep->val.file.filename, alloc_op_array, alloc_functions, alloc_classes, &ctxt TSRMLS_CC))) {
939 + goto failure;
940 + }
941 +
942 + if (!apc_cache_make_file_key(&cache_key, ep->val.file.filename, PG(include_path), t TSRMLS_CC)) {
943 + goto failure;
944 + }
945 +
946 + if ((ret = apc_cache_insert(apc_cache, cache_key, cache_entry, &ctxt, t TSRMLS_CC)) != 1) {
947 + if(ret==-1) {
948 + goto failure;
949 + }
950 + }
951 +
952 +#if NONBLOCKING_LOCK_AVAILABLE
953 + if(APCG(write_lock)) {
954 + apc_cache_write_unlock(apc_cache TSRMLS_CC);
955 + }
956 +#endif
957 + HANDLE_UNBLOCK_INTERRUPTIONS();
958 +
959 + break;
960 + case APC_CACHE_KEY_USER:
961 + ctxt.copy = APC_COPY_IN_USER;
962 + _apc_store(ep->val.user.info, ep->val.user.info_len, ep->val.user.val, ep->val.user.ttl, 0 TSRMLS_CC);
963 + break;
964 + default:
965 + break;
966 + }
967 + }
968 +
969 + return 0;
970 +
971 +failure:
972 + apc_pool_destroy(ctxt.pool TSRMLS_CC);
973 + apc_warning("Unable to allocate memory for apc binary load/dump functionality." TSRMLS_CC);
974 +#if NONBLOCKING_LOCK_AVAILABLE
975 + if(APCG(write_lock)) {
976 + apc_cache_write_unlock(apc_cache TSRMLS_CC);
977 + }
978 +#endif
979 + HANDLE_UNBLOCK_INTERRUPTIONS();
980 + return -1;
981 +} /* }}} */
982 +
983 +
984 +/*
985 + * Local variables:
986 + * tab-width: 4
987 + * c-basic-offset: 4
988 + * End:
989 + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
990 + * vim<600: expandtab sw=4 ts=4 sts=4
991 + */
992 diff -Naur a/ext/apc/apc_bin.h b/ext/apc/apc_bin.h
993 --- a/ext/apc/apc_bin.h 1970-01-01 01:00:00.000000000 +0100
994 +++ b/ext/apc/apc_bin.h 2012-07-20 00:10:35.000000000 +0200
995 @@ -0,0 +1,63 @@
996 +/*
997 + +----------------------------------------------------------------------+
998 + | APC |
999 + +----------------------------------------------------------------------+
1000 + | Copyright (c) 2006-2011 The PHP Group |
1001 + +----------------------------------------------------------------------+
1002 + | This source file is subject to version 3.01 of the PHP license, |
1003 + | that is bundled with this package in the file LICENSE, and is |
1004 + | available through the world-wide-web at the following url: |
1005 + | http://www.php.net/license/3_01.txt |
1006 + | If you did not receive a copy of the PHP license and are unable to |
1007 + | obtain it through the world-wide-web, please send a note to |
1008 + | license@php.net so we can mail you a copy immediately. |
1009 + +----------------------------------------------------------------------+
1010 + | Authors: Brian Shire <shire@php.net> |
1011 + +----------------------------------------------------------------------+
1012 +
1013 + */
1014 +
1015 +/* $Id: apc_bin.h 307048 2011-01-03 23:53:17Z kalle $ */
1016 +
1017 +#ifndef APC_BINDUMP_H
1018 +#define APC_BINDUMP_H
1019 +
1020 +#include "apc.h"
1021 +#include "apc_php.h"
1022 +#include "ext/standard/basic_functions.h"
1023 +
1024 +/* APC binload flags */
1025 +#define APC_BIN_VERIFY_MD5 1 << 0
1026 +#define APC_BIN_VERIFY_CRC32 1 << 1
1027 +
1028 +typedef struct _apc_bd_entry_t {
1029 + unsigned char type;
1030 + uint num_functions;
1031 + uint num_classes;
1032 + apc_cache_entry_value_t val;
1033 +} apc_bd_entry_t;
1034 +
1035 +typedef struct _apc_bd_t {
1036 + unsigned int size;
1037 + int swizzled;
1038 + unsigned char md5[16];
1039 + php_uint32 crc;
1040 + unsigned int num_entries;
1041 + apc_bd_entry_t *entries;
1042 + int num_swizzled_ptrs;
1043 + void ***swizzled_ptrs;
1044 +} apc_bd_t;
1045 +
1046 +apc_bd_t* apc_bin_dump(HashTable *files, HashTable *user_vars TSRMLS_DC);
1047 +int apc_bin_load(apc_bd_t *bd, int flags TSRMLS_DC);
1048 +
1049 +#endif
1050 +
1051 +/*
1052 + * Local variables:
1053 + * tab-width: 4
1054 + * c-basic-offset: 4
1055 + * End:
1056 + * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
1057 + * vim<600: expandtab sw=4 ts=4 sts=4
1058 + */
1059 diff -Naur a/ext/apc/apc.c b/ext/apc/apc.c
1060 --- a/ext/apc/apc.c 1970-01-01 01:00:00.000000000 +0100
1061 +++ b/ext/apc/apc.c 2012-07-20 00:10:35.000000000 +0200
1062 @@ -0,0 +1,670 @@
1063 +/*
1064 + +----------------------------------------------------------------------+
1065 + | APC |
1066 + +----------------------------------------------------------------------+
1067 + | Copyright (c) 2006-2011 The PHP Group |
1068 + +----------------------------------------------------------------------+
1069 + | This source file is subject to version 3.01 of the PHP license, |
1070 + | that is bundled with this package in the file LICENSE, and is |
1071 + | available through the world-wide-web at the following url: |
1072 + | http://www.php.net/license/3_01.txt |
1073 + | If you did not receive a copy of the PHP license and are unable to |
1074 + | obtain it through the world-wide-web, please send a note to |
1075 + | license@php.net so we can mail you a copy immediately. |
1076 + +----------------------------------------------------------------------+
1077 + | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
1078 + | George Schlossnagle <george@omniti.com> |
1079 + | Rasmus Lerdorf <rasmus@php.net> |
1080 + | Arun C. Murthy <arunc@yahoo-inc.com> |
1081 + | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
1082 + +----------------------------------------------------------------------+
1083 +
1084 + This software was contributed to PHP by Community Connect Inc. in 2002
1085 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
1086 + Future revisions and derivatives of this source code must acknowledge
1087 + Community Connect Inc. as the original contributor of this module by
1088 + leaving this note intact in the source code.
1089 +
1090 + All other licensing and usage conditions are those of the PHP Group.
1091 +
1092 + */
1093 +
1094 +/* $Id: apc.c 326710 2012-07-19 20:51:04Z rasmus $ */
1095 +
1096 +#include "apc.h"
1097 +#include "apc_zend.h"
1098 +#include "apc_cache.h"
1099 +#include "apc_globals.h"
1100 +#include "php.h"
1101 +
1102 +#if HAVE_PCRE || HAVE_BUNDLED_PCRE
1103 +/* Deal with problem present until php-5.2.2 where php_pcre.h was not installed correctly */
1104 +# if !HAVE_BUNDLED_PCRE && PHP_MAJOR_VERSION == 5 && (PHP_MINOR_VERSION < 2 || (PHP_MINOR_VERSION == 2 && PHP_RELEASE_VERSION < 2))
1105 +# include "apc_php_pcre.h"
1106 +# else
1107 +# include "ext/pcre/php_pcre.h"
1108 +# endif
1109 +# include "ext/standard/php_smart_str.h"
1110 +#endif
1111 +
1112 +#define NELEMS(a) (sizeof(a)/sizeof((a)[0]))
1113 +
1114 +/* {{{ memory allocation wrappers */
1115 +
1116 +void* apc_emalloc(size_t n TSRMLS_DC)
1117 +{
1118 + void* p = malloc(n);
1119 + if (p == NULL) {
1120 + apc_error("apc_emalloc: malloc failed to allocate %u bytes:" TSRMLS_CC, n);
1121 + return NULL;
1122 + }
1123 + return p;
1124 +}
1125 +
1126 +void* apc_erealloc(void* p, size_t n TSRMLS_DC)
1127 +{
1128 + void *new;
1129 + new = realloc(p, n);
1130 + if (new == NULL) {
1131 + apc_error("apc_erealloc: realloc failed to allocate %u bytes:" TSRMLS_CC, n);
1132 + return NULL;
1133 + }
1134 + return new;
1135 +}
1136 +
1137 +void apc_efree(void* p TSRMLS_DC)
1138 +{
1139 + if (p == NULL) {
1140 + apc_error("apc_efree: attempt to free null pointer" TSRMLS_CC);
1141 + return;
1142 + }
1143 + free(p);
1144 +}
1145 +
1146 +char* APC_ALLOC apc_estrdup(const char* s TSRMLS_DC)
1147 +{
1148 + int len;
1149 + char* dup;
1150 +
1151 + if (s == NULL) {
1152 + return NULL;
1153 + }
1154 + len = strlen(s);
1155 + dup = (char*) malloc(len+1);
1156 + if (dup == NULL) {
1157 + apc_error("apc_estrdup: malloc failed to allocate %u bytes:" TSRMLS_CC, len+1);
1158 + return NULL;
1159 + }
1160 + memcpy(dup, s, len);
1161 + dup[len] = '\0';
1162 + return dup;
1163 +}
1164 +
1165 +void* APC_ALLOC apc_xstrdup(const char* s, apc_malloc_t f TSRMLS_DC)
1166 +{
1167 + return s != NULL ? apc_xmemcpy(s, strlen(s)+1, f TSRMLS_CC) : NULL;
1168 +}
1169 +
1170 +void* APC_ALLOC apc_xmemcpy(const void* p, size_t n, apc_malloc_t f TSRMLS_DC)
1171 +{
1172 + void* q;
1173 +
1174 + if (p != NULL && (q = f(n TSRMLS_CC)) != NULL) {
1175 + memcpy(q, p, n);
1176 + return q;
1177 + }
1178 + return NULL;
1179 +}
1180 +
1181 +/* }}} */
1182 +
1183 +/* {{{ console display functions */
1184 +#ifdef ZTS
1185 +# define APC_PRINT_FUNCTION_PARAMETER TSRMLS_C
1186 +#else
1187 +# define APC_PRINT_FUNCTION_PARAMETER format
1188 +#endif
1189 +
1190 +#define APC_PRINT_FUNCTION(name, verbosity) \
1191 + void apc_##name(const char *format TSRMLS_DC, ...) \
1192 + { \
1193 + va_list args; \
1194 + \
1195 + va_start(args, APC_PRINT_FUNCTION_PARAMETER); \
1196 + php_verror(NULL, "", verbosity, format, args TSRMLS_CC); \
1197 + va_end(args); \
1198 + }
1199 +
1200 +APC_PRINT_FUNCTION(error, E_ERROR)
1201 +APC_PRINT_FUNCTION(warning, E_WARNING)
1202 +APC_PRINT_FUNCTION(notice, E_NOTICE)
1203 +
1204 +#ifdef __DEBUG_APC__
1205 +APC_PRINT_FUNCTION(debug, E_NOTICE)
1206 +#else
1207 +void apc_debug(const char *format TSRMLS_DC, ...) {}
1208 +#endif
1209 +/* }}} */
1210 +
1211 +/* {{{ string and text manipulation */
1212 +
1213 +char* apc_append(const char* s, const char* t TSRMLS_DC)
1214 +{
1215 + int slen;
1216 + int tlen;
1217 + char* p;
1218 +
1219 + slen = strlen(s);
1220 + tlen = strlen(t);
1221 +
1222 + p = (char*) apc_emalloc((slen + tlen + 1) * sizeof(char) TSRMLS_CC);
1223 + memcpy(p, s, slen);
1224 + memcpy(p + slen, t, tlen + 1);
1225 +
1226 + return p;
1227 +}
1228 +
1229 +char* apc_substr(const char* s, int start, int length TSRMLS_DC)
1230 +{
1231 + char* substr;
1232 + int src_len = strlen(s);
1233 +
1234 + /* bring start into range */
1235 + if (start < 0) {
1236 + start = 0;
1237 + }
1238 + else if (start >= src_len) {
1239 + start = src_len - 1;
1240 + }
1241 +
1242 + /* bring length into range */
1243 + if (length < 0 || src_len - start < length) {
1244 + length = src_len - start;
1245 + }
1246 +
1247 + /* create the substring */
1248 + substr = apc_xmemcpy(s + start, length + 1, apc_emalloc TSRMLS_CC);
1249 + substr[length] = '\0';
1250 + return substr;
1251 +}
1252 +
1253 +char** apc_tokenize(const char* s, char delim TSRMLS_DC)
1254 +{
1255 + char** tokens; /* array of tokens, NULL terminated */
1256 + int size; /* size of tokens array */
1257 + int n; /* index of next token in tokens array */
1258 + int cur; /* current position in input string */
1259 + int end; /* final legal position in input string */
1260 + int next; /* position of next delimiter in input */
1261 +
1262 + if (!s) {
1263 + return NULL;
1264 + }
1265 +
1266 + size = 2;
1267 + n = 0;
1268 + cur = 0;
1269 + end = strlen(s) - 1;
1270 +
1271 + tokens = (char**) apc_emalloc(size * sizeof(char*) TSRMLS_CC);
1272 + tokens[n] = NULL;
1273 +
1274 + while (cur <= end) {
1275 + /* search for the next delimiter */
1276 + char* p = strchr(s + cur, delim);
1277 + next = p ? p-s : end+1;
1278 +
1279 + /* resize token array if necessary */
1280 + if (n == size-1) {
1281 + size *= 2;
1282 + tokens = (char**) apc_erealloc(tokens, size * sizeof(char*) TSRMLS_CC);
1283 + }
1284 +
1285 + /* save the current token */
1286 + tokens[n] = apc_substr(s, cur, next-cur TSRMLS_CC);
1287 +
1288 + tokens[++n] = NULL;
1289 + cur = next + 1;
1290 + }
1291 +
1292 + return tokens;
1293 +}
1294 +
1295 +/* }}} */
1296 +
1297 +
1298 +/* {{{ apc_win32_restat */
1299 +#ifdef PHP_WIN32
1300 +static int apc_restat(apc_fileinfo_t *fileinfo TSRMLS_DC)
1301 +{
1302 + HANDLE hFile;
1303 + BY_HANDLE_FILE_INFORMATION hInfo;
1304 +
1305 + hFile = CreateFile(fileinfo->fullpath, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1306 +
1307 + if (!hFile) {
1308 + apc_debug("Cannot create a file HANDLE for %s\n" TSRMLS_CC, fileinfo->fullpath);
1309 + return -1;
1310 + }
1311 +
1312 + if (!GetFileInformationByHandle(hFile, &hInfo)) {
1313 + apc_debug("Cannot get file information from handle\n" TSRMLS_CC);
1314 + CloseHandle(hFile);
1315 + return -1;
1316 + }
1317 +
1318 + CloseHandle(hFile);
1319 +
1320 + fileinfo->st_buf.sb.st_dev = hInfo.dwVolumeSerialNumber;
1321 + fileinfo->st_buf.sb.st_ino = (((apc_ino_t)(hInfo.nFileIndexHigh) << 32) | (apc_ino_t) hInfo.nFileIndexLow);
1322 +
1323 + return 0;
1324 +}
1325 +#else
1326 +static int apc_restat(apc_fileinfo_t *fileinfo TSRMLS_DC)
1327 +{
1328 + return 0;
1329 +}
1330 +#endif
1331 +/* }}} */
1332 +
1333 +/* {{{ apc_search_paths */
1334 +/* similar to php_stream_stat_path */
1335 +#define APC_URL_STAT(wrapper, filename, pstatbuf) \
1336 + ((wrapper)->wops->url_stat((wrapper), (filename), PHP_STREAM_URL_STAT_QUIET, (pstatbuf), NULL TSRMLS_CC))
1337 +
1338 +/* copy out to path_buf if path_for_open isn't the same as filename */
1339 +#define COPY_IF_CHANGED(p) \
1340 + (char*) (((p) == filename) ? filename : \
1341 + (strlcpy((char*)fileinfo->path_buf, (p), sizeof(fileinfo->path_buf))) \
1342 + ? (fileinfo->path_buf) : NULL)
1343 +
1344 +/* len checks can be skipped here because filename is NUL terminated */
1345 +#define IS_RELATIVE_PATH(filename, len) \
1346 + ((filename) && (filename[0] == '.' && \
1347 + (IS_SLASH(filename[1]) || \
1348 + (filename[1] == '.' && \
1349 + IS_SLASH(filename[2])))))
1350 +
1351 +/* {{{ stupid stringifcation */
1352 +#if DEFAULT_SLASH == '/'
1353 + #define DEFAULT_SLASH_STRING "/"
1354 +#elif DEFAULT_SLASH == '\\'
1355 + #define DEFAULT_SLASH_STRING "\\"
1356 +#else
1357 + #error "Unknown value for DEFAULT_SLASH"
1358 +#endif
1359 +/* }}} */
1360 +
1361 +int apc_search_paths(const char* filename, const char* path, apc_fileinfo_t* fileinfo TSRMLS_DC)
1362 +{
1363 + char** paths = NULL;
1364 + char *exec_fname;
1365 + int exec_fname_length;
1366 + int found = 0;
1367 + int i;
1368 + php_stream_wrapper *wrapper = NULL;
1369 + char *path_for_open = NULL;
1370 +
1371 + assert(filename && fileinfo);
1372 +
1373 +
1374 + wrapper = php_stream_locate_url_wrapper(filename, &path_for_open, 0 TSRMLS_CC);
1375 +
1376 + if(!wrapper || !wrapper->wops || !wrapper->wops->url_stat) {
1377 + return -1;
1378 + }
1379 +
1380 + if(wrapper != &php_plain_files_wrapper) {
1381 + if(APC_URL_STAT(wrapper, path_for_open, &fileinfo->st_buf) == 0) {
1382 + fileinfo->fullpath = COPY_IF_CHANGED(path_for_open);
1383 + return apc_restat(fileinfo TSRMLS_CC);
1384 + }
1385 + return -1; /* cannot stat */
1386 + }
1387 +
1388 + if (IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) &&
1389 + APC_URL_STAT(wrapper, path_for_open, &fileinfo->st_buf) == 0) {
1390 + fileinfo->fullpath = COPY_IF_CHANGED(path_for_open);
1391 + return apc_restat(fileinfo TSRMLS_CC);
1392 + }
1393 +
1394 + if (!IS_RELATIVE_PATH(path_for_open, strlen(path_for_open))) {
1395 + paths = apc_tokenize(path, DEFAULT_DIR_SEPARATOR TSRMLS_CC);
1396 + if (!paths)
1397 + return -1;
1398 +
1399 + /* for each directory in paths, look for filename inside */
1400 + for (i = 0; paths[i]; i++) {
1401 + snprintf(fileinfo->path_buf, sizeof(fileinfo->path_buf), "%s%c%s", paths[i], DEFAULT_SLASH, path_for_open);
1402 + if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) {
1403 + fileinfo->fullpath = (char*) fileinfo->path_buf;
1404 + found = 1;
1405 + break;
1406 + }
1407 + }
1408 + /* in cli mode PHP explicitly checks the cwd, so we should as well */
1409 + if(APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) {
1410 + snprintf(fileinfo->path_buf, sizeof(fileinfo->path_buf), ".%c%s", DEFAULT_SLASH, path_for_open);
1411 + if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) {
1412 + fileinfo->fullpath = (char*) fileinfo->path_buf;
1413 + found = 1;
1414 + }
1415 + }
1416 + } else {
1417 + /* read cwd and try to fake up fullpath */
1418 + fileinfo->path_buf[0] = '\0';
1419 + if(VCWD_GETCWD(fileinfo->path_buf, sizeof(fileinfo->path_buf))) {
1420 + strlcat(fileinfo->path_buf, DEFAULT_SLASH_STRING, sizeof(fileinfo->path_buf));
1421 + strlcat(fileinfo->path_buf, path_for_open, sizeof(fileinfo->path_buf));
1422 + if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) {
1423 + fileinfo->fullpath = (char*) fileinfo->path_buf;
1424 + return apc_restat(fileinfo TSRMLS_CC);
1425 + }
1426 + }
1427 + }
1428 +
1429 + /* check in path of the calling scripts' current working directory */
1430 + /* modified from main/streams/plain_wrapper.c */
1431 + if(!found && zend_is_executing(TSRMLS_C)) {
1432 + exec_fname = zend_get_executed_filename(TSRMLS_C);
1433 + exec_fname_length = strlen(exec_fname);
1434 + while((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
1435 + if((exec_fname && exec_fname[0] != '[') && exec_fname_length > 0) {
1436 + /* not: [no active file] or no path */
1437 + memcpy(fileinfo->path_buf, exec_fname, exec_fname_length);
1438 + fileinfo->path_buf[exec_fname_length] = DEFAULT_SLASH;
1439 + strlcpy(fileinfo->path_buf +exec_fname_length +1, path_for_open,sizeof(fileinfo->path_buf)-exec_fname_length-1);
1440 + /* apc_warning("filename: %s, exec_fname: %s, fileinfo->path_buf: %s" TSRMLS_CC, path_for_open, exec_fname, fileinfo->path_buf); */
1441 + if (APC_URL_STAT(wrapper, fileinfo->path_buf, &fileinfo->st_buf) == 0) {
1442 + fileinfo->fullpath = (char*) fileinfo->path_buf;
1443 + found = 1;
1444 + }
1445 + }
1446 + }
1447 +
1448 + if(paths) {
1449 + /* free the value returned by apc_tokenize */
1450 + for (i = 0; paths[i]; i++) {
1451 + apc_efree(paths[i] TSRMLS_CC);
1452 + }
1453 + apc_efree(paths TSRMLS_CC);
1454 + }
1455 +
1456 + return found ? apc_restat(fileinfo TSRMLS_CC) : -1;
1457 +}
1458 +
1459 +/* }}} */
1460 +
1461 +/* {{{ regular expression wrapper functions */
1462 +
1463 +#if (HAVE_PCRE || HAVE_BUNDLED_PCRE)
1464 +typedef struct {
1465 + pcre *preg;
1466 + pcre *nreg;
1467 +} apc_regex;
1468 +
1469 +#define APC_ADD_PATTERN(match, pat) do {\
1470 + if(match.len > 1) {\
1471 + smart_str_appendc(&match, '|');\
1472 + }\
1473 + smart_str_appendc(&match, '(');\
1474 + while(*pat) {\
1475 + if(*pat == '/') smart_str_appendc(&match, '\\');\
1476 + \
1477 + smart_str_appendc(&match, *(pat++));\
1478 + }\
1479 + smart_str_appendc(&match, ')');\
1480 +} while(0)
1481 +
1482 +#define APC_COMPILE_PATTERN(re, match) do {\
1483 + if(match.len > 2) { /* more than just "//" */\
1484 + if (((re) = pcre_get_compiled_regex(match.c, NULL, NULL TSRMLS_CC)) == NULL) {\
1485 + apc_warning("apc_regex_compile_array: invalid expression '%s'" TSRMLS_CC, match.c); \
1486 + smart_str_free(&match);\
1487 + return NULL;\
1488 + }\
1489 + } else { \
1490 + (re) = NULL;\
1491 + }\
1492 +} while(0)
1493 +
1494 +void* apc_regex_compile_array(char* patterns[] TSRMLS_DC)
1495 +{
1496 + apc_regex* regs;
1497 + int npat;
1498 + smart_str pmatch = {0,};
1499 + smart_str nmatch = {0,};
1500 + char* pattern;
1501 +
1502 + if (!patterns)
1503 + return NULL;
1504 +
1505 + regs = (apc_regex*) apc_emalloc(sizeof(apc_regex) TSRMLS_CC);
1506 +
1507 + smart_str_appendc(&pmatch, '/');
1508 + smart_str_appendc(&nmatch, '/');
1509 +
1510 + for (npat = 0; patterns[npat] != NULL; npat++) {
1511 + pattern = patterns[npat];
1512 + if(pattern[0] == '+') {
1513 + pattern += sizeof(char);
1514 + APC_ADD_PATTERN(pmatch, pattern);
1515 + } else {
1516 + if(pattern[0] == '-') pattern += sizeof(char);
1517 + APC_ADD_PATTERN(nmatch, pattern);
1518 + }
1519 + }
1520 + smart_str_appendc(&pmatch, '/');
1521 + smart_str_appendc(&nmatch, '/');
1522 +
1523 + smart_str_0(&nmatch);
1524 + smart_str_0(&pmatch);
1525 +
1526 + APC_COMPILE_PATTERN(regs->preg, pmatch);
1527 + APC_COMPILE_PATTERN(regs->nreg, nmatch);
1528 +
1529 + smart_str_free(&pmatch);
1530 + smart_str_free(&nmatch);
1531 +
1532 + return (void*) regs;
1533 +}
1534 +
1535 +void apc_regex_destroy_array(void* p TSRMLS_DC)
1536 +{
1537 + if (p != NULL) {
1538 + apc_regex* regs = (apc_regex*) p;
1539 + apc_efree(regs TSRMLS_CC);
1540 + }
1541 +}
1542 +
1543 +#define APC_MATCH_PATTERN(re, input, output) do {\
1544 + if (re && pcre_exec(re, NULL, (input), strlen(input), 0, 0, NULL, 0) >= 0) {\
1545 + return (output);\
1546 + }\
1547 +} while(0)
1548 +
1549 +
1550 +int apc_regex_match_array(void* p, const char* input)
1551 +{
1552 + apc_regex* regs;
1553 +
1554 + if (!p)
1555 + return 0;
1556 +
1557 + regs = (apc_regex*) p;
1558 +
1559 + APC_MATCH_PATTERN(regs->preg, input, APC_POSITIVE_MATCH);
1560 + APC_MATCH_PATTERN(regs->nreg, input, APC_NEGATIVE_MATCH);
1561 +
1562 + return 0;
1563 +}
1564 +#else /* no pcre */
1565 +void* apc_regex_compile_array(char* patterns[] TSRMLS_DC)
1566 +{
1567 + if(patterns && patterns[0] != NULL) {
1568 + apc_warning("pcre missing, disabling filters" TSRMLS_CC);
1569 + }
1570 + return NULL;
1571 +}
1572 +void apc_regex_destroy_array(void* p)
1573 +{
1574 + /* nothing */
1575 +}
1576 +int apc_regex_match_array(void* p, const char* input)
1577 +{
1578 + return 0;
1579 +}
1580 +#endif
1581 +/* }}} */
1582 +
1583 +/* {{{ crc32 implementation */
1584 +
1585 +/* this table was generated by crc32gen() */
1586 +static unsigned int crc32tab[] = {
1587 + /* 0 */ 0x00000000, 0x3b83984b, 0x77073096, 0x4c84a8dd,
1588 + /* 4 */ 0xee0e612c, 0xd58df967, 0x990951ba, 0xa28ac9f1,
1589 + /* 8 */ 0x076dc419, 0x3cee5c52, 0x706af48f, 0x4be96cc4,
1590 + /* 12 */ 0xe963a535, 0xd2e03d7e, 0x9e6495a3, 0xa5e70de8,
1591 + /* 16 */ 0x0edb8832, 0x35581079, 0x79dcb8a4, 0x425f20ef,
1592 + /* 20 */ 0xe0d5e91e, 0xdb567155, 0x97d2d988, 0xac5141c3,
1593 + /* 24 */ 0x09b64c2b, 0x3235d460, 0x7eb17cbd, 0x4532e4f6,
1594 + /* 28 */ 0xe7b82d07, 0xdc3bb54c, 0x90bf1d91, 0xab3c85da,
1595 + /* 32 */ 0x1db71064, 0x2634882f, 0x6ab020f2, 0x5133b8b9,
1596 + /* 36 */ 0xf3b97148, 0xc83ae903, 0x84be41de, 0xbf3dd995,
1597 + /* 40 */ 0x1adad47d, 0x21594c36, 0x6ddde4eb, 0x565e7ca0,
1598 + /* 44 */ 0xf4d4b551, 0xcf572d1a, 0x83d385c7, 0xb8501d8c,
1599 + /* 48 */ 0x136c9856, 0x28ef001d, 0x646ba8c0, 0x5fe8308b,
1600 + /* 52 */ 0xfd62f97a, 0xc6e16131, 0x8a65c9ec, 0xb1e651a7,
1601 + /* 56 */ 0x14015c4f, 0x2f82c404, 0x63066cd9, 0x5885f492,
1602 + /* 60 */ 0xfa0f3d63, 0xc18ca528, 0x8d080df5, 0xb68b95be,
1603 + /* 64 */ 0x3b6e20c8, 0x00edb883, 0x4c69105e, 0x77ea8815,
1604 + /* 68 */ 0xd56041e4, 0xeee3d9af, 0xa2677172, 0x99e4e939,
1605 + /* 72 */ 0x3c03e4d1, 0x07807c9a, 0x4b04d447, 0x70874c0c,
1606 + /* 76 */ 0xd20d85fd, 0xe98e1db6, 0xa50ab56b, 0x9e892d20,
1607 + /* 80 */ 0x35b5a8fa, 0x0e3630b1, 0x42b2986c, 0x79310027,
1608 + /* 84 */ 0xdbbbc9d6, 0xe038519d, 0xacbcf940, 0x973f610b,
1609 + /* 88 */ 0x32d86ce3, 0x095bf4a8, 0x45df5c75, 0x7e5cc43e,
1610 + /* 92 */ 0xdcd60dcf, 0xe7559584, 0xabd13d59, 0x9052a512,
1611 + /* 96 */ 0x26d930ac, 0x1d5aa8e7, 0x51de003a, 0x6a5d9871,
1612 + /* 100 */ 0xc8d75180, 0xf354c9cb, 0xbfd06116, 0x8453f95d,
1613 + /* 104 */ 0x21b4f4b5, 0x1a376cfe, 0x56b3c423, 0x6d305c68,
1614 + /* 108 */ 0xcfba9599, 0xf4390dd2, 0xb8bda50f, 0x833e3d44,
1615 + /* 112 */ 0x2802b89e, 0x138120d5, 0x5f058808, 0x64861043,
1616 + /* 116 */ 0xc60cd9b2, 0xfd8f41f9, 0xb10be924, 0x8a88716f,
1617 + /* 120 */ 0x2f6f7c87, 0x14ece4cc, 0x58684c11, 0x63ebd45a,
1618 + /* 124 */ 0xc1611dab, 0xfae285e0, 0xb6662d3d, 0x8de5b576,
1619 + /* 128 */ 0x76dc4190, 0x4d5fd9db, 0x01db7106, 0x3a58e94d,
1620 + /* 132 */ 0x98d220bc, 0xa351b8f7, 0xefd5102a, 0xd4568861,
1621 + /* 136 */ 0x71b18589, 0x4a321dc2, 0x06b6b51f, 0x3d352d54,
1622 + /* 140 */ 0x9fbfe4a5, 0xa43c7cee, 0xe8b8d433, 0xd33b4c78,
1623 + /* 144 */ 0x7807c9a2, 0x438451e9, 0x0f00f934, 0x3483617f,
1624 + /* 148 */ 0x9609a88e, 0xad8a30c5, 0xe10e9818, 0xda8d0053,
1625 + /* 152 */ 0x7f6a0dbb, 0x44e995f0, 0x086d3d2d, 0x33eea566,
1626 + /* 156 */ 0x91646c97, 0xaae7f4dc, 0xe6635c01, 0xdde0c44a,
1627 + /* 160 */ 0x6b6b51f4, 0x50e8c9bf, 0x1c6c6162, 0x27eff929,
1628 + /* 164 */ 0x856530d8, 0xbee6a893, 0xf262004e, 0xc9e19805,
1629 + /* 168 */ 0x6c0695ed, 0x57850da6, 0x1b01a57b, 0x20823d30,
1630 + /* 172 */ 0x8208f4c1, 0xb98b6c8a, 0xf50fc457, 0xce8c5c1c,
1631 + /* 176 */ 0x65b0d9c6, 0x5e33418d, 0x12b7e950, 0x2934711b,
1632 + /* 180 */ 0x8bbeb8ea, 0xb03d20a1, 0xfcb9887c, 0xc73a1037,
1633 + /* 184 */ 0x62dd1ddf, 0x595e8594, 0x15da2d49, 0x2e59b502,
1634 + /* 188 */ 0x8cd37cf3, 0xb750e4b8, 0xfbd44c65, 0xc057d42e,
1635 + /* 192 */ 0x4db26158, 0x7631f913, 0x3ab551ce, 0x0136c985,
1636 + /* 196 */ 0xa3bc0074, 0x983f983f, 0xd4bb30e2, 0xef38a8a9,
1637 + /* 200 */ 0x4adfa541, 0x715c3d0a, 0x3dd895d7, 0x065b0d9c,
1638 + /* 204 */ 0xa4d1c46d, 0x9f525c26, 0xd3d6f4fb, 0xe8556cb0,
1639 + /* 208 */ 0x4369e96a, 0x78ea7121, 0x346ed9fc, 0x0fed41b7,
1640 + /* 212 */ 0xad678846, 0x96e4100d, 0xda60b8d0, 0xe1e3209b,
1641 + /* 216 */ 0x44042d73, 0x7f87b538, 0x33031de5, 0x088085ae,
1642 + /* 220 */ 0xaa0a4c5f, 0x9189d414, 0xdd0d7cc9, 0xe68ee482,
1643 + /* 224 */ 0x5005713c, 0x6b86e977, 0x270241aa, 0x1c81d9e1,
1644 + /* 228 */ 0xbe0b1010, 0x8588885b, 0xc90c2086, 0xf28fb8cd,
1645 + /* 232 */ 0x5768b525, 0x6ceb2d6e, 0x206f85b3, 0x1bec1df8,
1646 + /* 236 */ 0xb966d409, 0x82e54c42, 0xce61e49f, 0xf5e27cd4,
1647 + /* 240 */ 0x5edef90e, 0x655d6145, 0x29d9c998, 0x125a51d3,
1648 + /* 244 */ 0xb0d09822, 0x8b530069, 0xc7d7a8b4, 0xfc5430ff,
1649 + /* 248 */ 0x59b33d17, 0x6230a55c, 0x2eb40d81, 0x153795ca,
1650 + /* 252 */ 0xb7bd5c3b, 0x8c3ec470, 0xc0ba6cad, 0xfb39f4e6,
1651 +};
1652 +
1653 +unsigned int apc_crc32(const char* buf, int len)
1654 +{
1655 + int i;
1656 + int k;
1657 + unsigned int crc;
1658 +
1659 + /* preconditioning */
1660 + crc = 0xFFFFFFFF;
1661 +
1662 + for (i = 0; i < len; i++) {
1663 + k = (crc ^ buf[i]) & 0x000000FF;
1664 + crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32tab[k];
1665 + }
1666 +
1667 + /* postconditioning */
1668 + return ~crc;
1669 +}
1670 +
1671 +/* crc32gen: generate the nth (0..255) crc32 table value */
1672 +#if 0
1673 +static unsigned long crc32gen(int n)
1674 +{
1675 + int i;
1676 + unsigned long crc;
1677 +
1678 + crc = n;
1679 + for (i = 8; i >= 0; i--) {
1680 + if (crc & 1) {
1681 + crc = (crc >> 1) ^ 0xEDB88320;
1682 + }
1683 + else {
1684 + crc >>= 1;
1685 + }
1686 + }
1687 + return crc;
1688 +}
1689 +#endif
1690 +
1691 +/* }}} */
1692 +
1693 +
1694 +/* {{{ apc_flip_hash() */
1695 +HashTable* apc_flip_hash(HashTable *hash) {
1696 + zval **entry, *data;
1697 + HashTable *new_hash;
1698 + HashPosition pos;
1699 +
1700 + if(hash == NULL) return hash;
1701 +
1702 + MAKE_STD_ZVAL(data);
1703 + ZVAL_LONG(data, 1);
1704 +
1705 + new_hash = emalloc(sizeof(HashTable));
1706 + zend_hash_init(new_hash, hash->nTableSize, NULL, ZVAL_PTR_DTOR, 0);
1707 +
1708 + zend_hash_internal_pointer_reset_ex(hash, &pos);
1709 + while (zend_hash_get_current_data_ex(hash, (void **)&entry, &pos) == SUCCESS) {
1710 + if(Z_TYPE_PP(entry) == IS_STRING) {
1711 + zend_hash_update(new_hash, Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) +1, &data, sizeof(data), NULL);
1712 + } else {
1713 + zend_hash_index_update(new_hash, Z_LVAL_PP(entry), &data, sizeof(data), NULL);
1714 + }
1715 + Z_ADDREF_P(data);
1716 + zend_hash_move_forward_ex(hash, &pos);
1717 + }
1718 + zval_ptr_dtor(&data);
1719 +
1720 + return new_hash;
1721 +}
1722 +/* }}} */
1723 +
1724 +
1725 +/*
1726 + * Local variables:
1727 + * tab-width: 4
1728 + * c-basic-offset: 4
1729 + * End:
1730 + * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
1731 + * vim<600: expandtab sw=4 ts=4 sts=4
1732 + */
1733 diff -Naur a/ext/apc/apc_cache.c b/ext/apc/apc_cache.c
1734 --- a/ext/apc/apc_cache.c 1970-01-01 01:00:00.000000000 +0100
1735 +++ b/ext/apc/apc_cache.c 2012-07-20 00:10:35.000000000 +0200
1736 @@ -0,0 +1,1383 @@
1737 +/*
1738 + +----------------------------------------------------------------------+
1739 + | APC |
1740 + +----------------------------------------------------------------------+
1741 + | Copyright (c) 2006-2011 The PHP Group |
1742 + +----------------------------------------------------------------------+
1743 + | This source file is subject to version 3.01 of the PHP license, |
1744 + | that is bundled with this package in the file LICENSE, and is |
1745 + | available through the world-wide-web at the following url: |
1746 + | http://www.php.net/license/3_01.txt |
1747 + | If you did not receive a copy of the PHP license and are unable to |
1748 + | obtain it through the world-wide-web, please send a note to |
1749 + | license@php.net so we can mail you a copy immediately. |
1750 + +----------------------------------------------------------------------+
1751 + | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
1752 + | Rasmus Lerdorf <rasmus@php.net> |
1753 + | Arun C. Murthy <arunc@yahoo-inc.com> |
1754 + | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
1755 + +----------------------------------------------------------------------+
1756 +
1757 + This software was contributed to PHP by Community Connect Inc. in 2002
1758 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
1759 + Future revisions and derivatives of this source code must acknowledge
1760 + Community Connect Inc. as the original contributor of this module by
1761 + leaving this note intact in the source code.
1762 +
1763 + All other licensing and usage conditions are those of the PHP Group.
1764 +
1765 + */
1766 +
1767 +/* $Id: apc_cache.c 325482 2012-05-01 00:09:36Z rasmus $ */
1768 +
1769 +#include "apc_cache.h"
1770 +#include "apc_zend.h"
1771 +#include "apc_sma.h"
1772 +#include "apc_globals.h"
1773 +#include "SAPI.h"
1774 +#include "TSRM.h"
1775 +#include "ext/standard/md5.h"
1776 +
1777 +/* TODO: rehash when load factor exceeds threshold */
1778 +
1779 +#define CHECK(p) { if ((p) == NULL) return NULL; }
1780 +
1781 +/* {{{ key_equals */
1782 +#define key_equals(a, b) (a.inode==b.inode && a.device==b.device)
1783 +/* }}} */
1784 +
1785 +static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC);
1786 +
1787 +/* {{{ hash */
1788 +static unsigned long hash(apc_cache_key_t key)
1789 +{
1790 + return (unsigned long)(key.data.file.device + key.data.file.inode);
1791 +}
1792 +/* }}} */
1793 +
1794 +/* {{{ string_nhash_8 */
1795 +#define string_nhash_8(s,len) (unsigned long)(zend_inline_hash_func((s), len))
1796 +/* }}} */
1797 +
1798 +/* {{{ murmurhash */
1799 +#if 0
1800 +static inline unsigned long murmurhash(const char *skey, size_t keylen)
1801 +{
1802 + const long m = 0x7fd652ad;
1803 + const long r = 16;
1804 + unsigned int h = 0xdeadbeef;
1805 +
1806 + while(keylen >= 4)
1807 + {
1808 + h += *(unsigned int*)skey;
1809 + h *= m;
1810 + h ^= h >> r;
1811 +
1812 + skey += 4;
1813 + keylen -= 4;
1814 + }
1815 +
1816 + switch(keylen)
1817 + {
1818 + case 3:
1819 + h += skey[2] << 16;
1820 + case 2:
1821 + h += skey[1] << 8;
1822 + case 1:
1823 + h += skey[0];
1824 + h *= m;
1825 + h ^= h >> r;
1826 + };
1827 +
1828 + h *= m;
1829 + h ^= h >> 10;
1830 + h *= m;
1831 + h ^= h >> 17;
1832 +
1833 + return h;
1834 +}
1835 +#endif
1836 +/* }}} */
1837 +
1838 +
1839 +/* {{{ make_prime */
1840 +static int const primes[] = {
1841 + 257, /* 256 */
1842 + 521, /* 512 */
1843 + 1031, /* 1024 */
1844 + 2053, /* 2048 */
1845 + 3079, /* 3072 */
1846 + 4099, /* 4096 */
1847 + 5147, /* 5120 */
1848 + 6151, /* 6144 */
1849 + 7177, /* 7168 */
1850 + 8209, /* 8192 */
1851 + 9221, /* 9216 */
1852 +10243, /* 10240 */
1853 +11273, /* 11264 */
1854 +12289, /* 12288 */
1855 +13313, /* 13312 */
1856 +14341, /* 14336 */
1857 +15361, /* 15360 */
1858 +16411, /* 16384 */
1859 +17417, /* 17408 */
1860 +18433, /* 18432 */
1861 +19457, /* 19456 */
1862 +0 /* sentinel */
1863 +};
1864 +
1865 +static int make_prime(int n)
1866 +{
1867 + int *k = (int*)primes;
1868 + while(*k) {
1869 + if((*k) > n) return *k;
1870 + k++;
1871 + }
1872 + return *(k-1);
1873 +}
1874 +/* }}} */
1875 +
1876 +/* {{{ make_slot */
1877 +slot_t* make_slot(apc_cache_key_t *key, apc_cache_entry_t* value, slot_t* next, time_t t TSRMLS_DC)
1878 +{
1879 + slot_t* p = apc_pool_alloc(value->pool, sizeof(slot_t));
1880 +
1881 + if (!p) return NULL;
1882 +
1883 + if(key->type == APC_CACHE_KEY_USER) {
1884 + char *identifier = (char*) apc_pmemcpy(key->data.user.identifier, key->data.user.identifier_len, value->pool TSRMLS_CC);
1885 + if (!identifier) {
1886 + return NULL;
1887 + }
1888 + key->data.user.identifier = identifier;
1889 + } else if(key->type == APC_CACHE_KEY_FPFILE) {
1890 + char *fullpath = (char*) apc_pstrdup(key->data.fpfile.fullpath, value->pool TSRMLS_CC);
1891 + if (!fullpath) {
1892 + return NULL;
1893 + }
1894 + key->data.fpfile.fullpath = fullpath;
1895 + }
1896 + p->key = key[0];
1897 + p->value = value;
1898 + p->next = next;
1899 + p->num_hits = 0;
1900 + p->creation_time = t;
1901 + p->access_time = t;
1902 + p->deletion_time = 0;
1903 + return p;
1904 +}
1905 +/* }}} */
1906 +
1907 +/* {{{ free_slot */
1908 +static void free_slot(slot_t* slot TSRMLS_DC)
1909 +{
1910 + apc_pool_destroy(slot->value->pool TSRMLS_CC);
1911 +}
1912 +/* }}} */
1913 +
1914 +/* {{{ remove_slot */
1915 +static void remove_slot(apc_cache_t* cache, slot_t** slot TSRMLS_DC)
1916 +{
1917 + slot_t* dead = *slot;
1918 + *slot = (*slot)->next;
1919 +
1920 + cache->header->mem_size -= dead->value->mem_size;
1921 + CACHE_FAST_DEC(cache, cache->header->num_entries);
1922 + if (dead->value->ref_count <= 0) {
1923 + free_slot(dead TSRMLS_CC);
1924 + }
1925 + else {
1926 + dead->next = cache->header->deleted_list;
1927 + dead->deletion_time = time(0);
1928 + cache->header->deleted_list = dead;
1929 + }
1930 +}
1931 +/* }}} */
1932 +
1933 +/* {{{ process_pending_removals */
1934 +static void process_pending_removals(apc_cache_t* cache TSRMLS_DC)
1935 +{
1936 + slot_t** slot;
1937 + time_t now;
1938 +
1939 + /* This function scans the list of removed cache entries and deletes any
1940 + * entry whose reference count is zero (indicating that it is no longer
1941 + * being executed) or that has been on the pending list for more than
1942 + * cache->gc_ttl seconds (we issue a warning in the latter case).
1943 + */
1944 +
1945 + if (!cache->header->deleted_list)
1946 + return;
1947 +
1948 + slot = &cache->header->deleted_list;
1949 + now = time(0);
1950 +
1951 + while (*slot != NULL) {
1952 + int gc_sec = cache->gc_ttl ? (now - (*slot)->deletion_time) : 0;
1953 +
1954 + if ((*slot)->value->ref_count <= 0 || gc_sec > cache->gc_ttl) {
1955 + slot_t* dead = *slot;
1956 +
1957 + if (dead->value->ref_count > 0) {
1958 + switch(dead->value->type) {
1959 + case APC_CACHE_ENTRY_FILE:
1960 + apc_debug("GC cache entry '%s' (dev=%d ino=%d) was on gc-list for %d seconds" TSRMLS_CC,
1961 + dead->value->data.file.filename, dead->key.data.file.device, dead->key.data.file.inode, gc_sec);
1962 + break;
1963 + case APC_CACHE_ENTRY_USER:
1964 + apc_debug("GC cache entry '%s' was on gc-list for %d seconds" TSRMLS_CC, dead->value->data.user.info, gc_sec);
1965 + break;
1966 + }
1967 + }
1968 + *slot = dead->next;
1969 + free_slot(dead TSRMLS_CC);
1970 + }
1971 + else {
1972 + slot = &(*slot)->next;
1973 + }
1974 + }
1975 +}
1976 +/* }}} */
1977 +
1978 +/* {{{ prevent_garbage_collection */
1979 +static void prevent_garbage_collection(apc_cache_entry_t* entry)
1980 +{
1981 + /* set reference counts on zend objects to an arbitrarily high value to
1982 + * prevent garbage collection after execution */
1983 +
1984 + enum { BIG_VALUE = 1000 };
1985 +
1986 + if(entry->data.file.op_array) {
1987 + entry->data.file.op_array->refcount[0] = BIG_VALUE;
1988 + }
1989 + if (entry->data.file.functions) {
1990 + int i;
1991 + apc_function_t* fns = entry->data.file.functions;
1992 + for (i=0; fns[i].function != NULL; i++) {
1993 + *(fns[i].function->op_array.refcount) = BIG_VALUE;
1994 + }
1995 + }
1996 + if (entry->data.file.classes) {
1997 + int i;
1998 + apc_class_t* classes = entry->data.file.classes;
1999 + for (i=0; classes[i].class_entry != NULL; i++) {
2000 + classes[i].class_entry->refcount = BIG_VALUE;
2001 + }
2002 + }
2003 +}
2004 +/* }}} */
2005 +
2006 +/* {{{ apc_cache_create */
2007 +apc_cache_t* apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC)
2008 +{
2009 + apc_cache_t* cache;
2010 + int cache_size;
2011 + int num_slots;
2012 +
2013 + num_slots = make_prime(size_hint > 0 ? size_hint : 2000);
2014 +
2015 + cache = (apc_cache_t*) apc_emalloc(sizeof(apc_cache_t) TSRMLS_CC);
2016 + cache_size = sizeof(cache_header_t) + num_slots*sizeof(slot_t*);
2017 +
2018 + cache->shmaddr = apc_sma_malloc(cache_size TSRMLS_CC);
2019 + if(!cache->shmaddr) {
2020 + apc_error("Unable to allocate shared memory for cache structures. (Perhaps your shared memory size isn't large enough?). " TSRMLS_CC);
2021 + return NULL;
2022 + }
2023 + memset(cache->shmaddr, 0, cache_size);
2024 +
2025 + cache->header = (cache_header_t*) cache->shmaddr;
2026 + cache->header->num_hits = 0;
2027 + cache->header->num_misses = 0;
2028 + cache->header->deleted_list = NULL;
2029 + cache->header->start_time = time(NULL);
2030 + cache->header->expunges = 0;
2031 + cache->header->busy = 0;
2032 +
2033 + cache->slots = (slot_t**) (((char*) cache->shmaddr) + sizeof(cache_header_t));
2034 + cache->num_slots = num_slots;
2035 + cache->gc_ttl = gc_ttl;
2036 + cache->ttl = ttl;
2037 + CREATE_LOCK(cache->header->lock);
2038 +#if NONBLOCKING_LOCK_AVAILABLE
2039 + CREATE_LOCK(cache->header->wrlock);
2040 +#endif
2041 + memset(cache->slots, 0, sizeof(slot_t*)*num_slots);
2042 + cache->expunge_cb = apc_cache_expunge;
2043 + cache->has_lock = 0;
2044 +
2045 + return cache;
2046 +}
2047 +/* }}} */
2048 +
2049 +/* {{{ apc_cache_destroy */
2050 +void apc_cache_destroy(apc_cache_t* cache TSRMLS_DC)
2051 +{
2052 + DESTROY_LOCK(cache->header->lock);
2053 +#if NONBLOCKING_LOCK_AVAILABLE
2054 + DESTROY_LOCK(cache->header->wrlock);
2055 +#endif
2056 + apc_efree(cache TSRMLS_CC);
2057 +}
2058 +/* }}} */
2059 +
2060 +/* {{{ apc_cache_clear */
2061 +void apc_cache_clear(apc_cache_t* cache TSRMLS_DC)
2062 +{
2063 + int i;
2064 +
2065 + if(!cache) return;
2066 +
2067 + CACHE_LOCK(cache);
2068 + cache->header->busy = 1;
2069 + cache->header->num_hits = 0;
2070 + cache->header->num_misses = 0;
2071 + cache->header->start_time = time(NULL);
2072 + cache->header->expunges = 0;
2073 +
2074 + for (i = 0; i < cache->num_slots; i++) {
2075 + slot_t* p = cache->slots[i];
2076 + while (p) {
2077 + remove_slot(cache, &p TSRMLS_CC);
2078 + }
2079 + cache->slots[i] = NULL;
2080 + }
2081 +
2082 + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
2083 +
2084 + cache->header->busy = 0;
2085 + CACHE_UNLOCK(cache);
2086 +}
2087 +/* }}} */
2088 +
2089 +/* {{{ apc_cache_expunge */
2090 +static void apc_cache_expunge(apc_cache_t* cache, size_t size TSRMLS_DC)
2091 +{
2092 + int i;
2093 + time_t t;
2094 +
2095 + t = apc_time();
2096 +
2097 + if(!cache) return;
2098 +
2099 + if(!cache->ttl) {
2100 + /*
2101 + * If cache->ttl is not set, we wipe out the entire cache when
2102 + * we run out of space.
2103 + */
2104 + CACHE_SAFE_LOCK(cache);
2105 + process_pending_removals(cache TSRMLS_CC);
2106 + if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) {
2107 + /* probably a queued up expunge, we don't need to do this */
2108 + CACHE_SAFE_UNLOCK(cache);
2109 + return;
2110 + }
2111 + cache->header->busy = 1;
2112 + CACHE_FAST_INC(cache, cache->header->expunges);
2113 +clear_all:
2114 + for (i = 0; i < cache->num_slots; i++) {
2115 + slot_t* p = cache->slots[i];
2116 + while (p) {
2117 + remove_slot(cache, &p TSRMLS_CC);
2118 + }
2119 + cache->slots[i] = NULL;
2120 + }
2121 + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
2122 + cache->header->busy = 0;
2123 + CACHE_SAFE_UNLOCK(cache);
2124 + } else {
2125 + slot_t **p;
2126 + /*
2127 + * If the ttl for the cache is set we walk through and delete stale
2128 + * entries. For the user cache that is slightly confusing since
2129 + * we have the individual entry ttl's we can look at, but that would be
2130 + * too much work. So if you want the user cache expunged, set a high
2131 + * default apc.user_ttl and still provide a specific ttl for each entry
2132 + * on insert
2133 + */
2134 +
2135 + CACHE_SAFE_LOCK(cache);
2136 + process_pending_removals(cache TSRMLS_CC);
2137 + if (apc_sma_get_avail_mem() > (size_t)(APCG(shm_size)/2)) {
2138 + /* probably a queued up expunge, we don't need to do this */
2139 + CACHE_SAFE_UNLOCK(cache);
2140 + return;
2141 + }
2142 + cache->header->busy = 1;
2143 + CACHE_FAST_INC(cache, cache->header->expunges);
2144 + for (i = 0; i < cache->num_slots; i++) {
2145 + p = &cache->slots[i];
2146 + while(*p) {
2147 + /*
2148 + * For the user cache we look at the individual entry ttl values
2149 + * and if not set fall back to the default ttl for the user cache
2150 + */
2151 + if((*p)->value->type == APC_CACHE_ENTRY_USER) {
2152 + if((*p)->value->data.user.ttl) {
2153 + if((time_t) ((*p)->creation_time + (*p)->value->data.user.ttl) < t) {
2154 + remove_slot(cache, p TSRMLS_CC);
2155 + continue;
2156 + }
2157 + } else if(cache->ttl) {
2158 + if((*p)->creation_time + cache->ttl < t) {
2159 + remove_slot(cache, p TSRMLS_CC);
2160 + continue;
2161 + }
2162 + }
2163 + } else if((*p)->access_time < (t - cache->ttl)) {
2164 + remove_slot(cache, p TSRMLS_CC);
2165 + continue;
2166 + }
2167 + p = &(*p)->next;
2168 + }
2169 + }
2170 +
2171 + if (!apc_sma_get_avail_size(size)) {
2172 + /* TODO: re-do this to remove goto across locked sections */
2173 + goto clear_all;
2174 + }
2175 + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
2176 + cache->header->busy = 0;
2177 + CACHE_SAFE_UNLOCK(cache);
2178 + }
2179 +}
2180 +/* }}} */
2181 +
2182 +/* {{{ apc_cache_insert */
2183 +static inline int _apc_cache_insert(apc_cache_t* cache,
2184 + apc_cache_key_t key,
2185 + apc_cache_entry_t* value,
2186 + apc_context_t* ctxt,
2187 + time_t t
2188 + TSRMLS_DC)
2189 +{
2190 + slot_t** slot;
2191 +
2192 + if (!value) {
2193 + return 0;
2194 + }
2195 +
2196 + apc_debug("Inserting [%s]\n" TSRMLS_CC, value->data.file.filename);
2197 +
2198 + process_pending_removals(cache TSRMLS_CC);
2199 +
2200 + slot = &cache->slots[key.h % cache->num_slots];
2201 +
2202 + while(*slot) {
2203 + if(key.type == (*slot)->key.type) {
2204 + if(key.type == APC_CACHE_KEY_FILE) {
2205 + if(key_equals((*slot)->key.data.file, key.data.file)) {
2206 + /* If existing slot for the same device+inode is different, remove it and insert the new version */
2207 + if (ctxt->force_update || (*slot)->key.mtime != key.mtime) {
2208 + remove_slot(cache, slot TSRMLS_CC);
2209 + break;
2210 + }
2211 + return 0;
2212 + } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
2213 + remove_slot(cache, slot TSRMLS_CC);
2214 + continue;
2215 + }
2216 + } else { /* APC_CACHE_KEY_FPFILE */
2217 + if((key.h == (*slot)->key.h) &&
2218 + !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
2219 + /* Hrm.. it's already here, remove it and insert new one */
2220 + remove_slot(cache, slot TSRMLS_CC);
2221 + break;
2222 + } else if(cache->ttl && (*slot)->access_time < (t - cache->ttl)) {
2223 + remove_slot(cache, slot TSRMLS_CC);
2224 + continue;
2225 + }
2226 + }
2227 + }
2228 + slot = &(*slot)->next;
2229 + }
2230 +
2231 + if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) {
2232 + return -1;
2233 + }
2234 +
2235 + value->mem_size = ctxt->pool->size;
2236 + cache->header->mem_size += ctxt->pool->size;
2237 + CACHE_FAST_INC(cache, cache->header->num_entries);
2238 + CACHE_FAST_INC(cache, cache->header->num_inserts);
2239 +
2240 + return 1;
2241 +}
2242 +/* }}} */
2243 +
2244 +/* {{{ apc_cache_insert */
2245 +int apc_cache_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t *ctxt, time_t t TSRMLS_DC)
2246 +{
2247 + int rval;
2248 + CACHE_LOCK(cache);
2249 + rval = _apc_cache_insert(cache, key, value, ctxt, t TSRMLS_CC);
2250 + CACHE_UNLOCK(cache);
2251 + return rval;
2252 +}
2253 +/* }}} */
2254 +
2255 +/* {{{ apc_cache_insert */
2256 +int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys, apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries TSRMLS_DC)
2257 +{
2258 + int *rval;
2259 + int i;
2260 +
2261 + rval = emalloc(sizeof(int) * num_entries);
2262 + CACHE_LOCK(cache);
2263 + for (i=0; i < num_entries; i++) {
2264 + if (values[i]) {
2265 + ctxt->pool = values[i]->pool;
2266 + rval[i] = _apc_cache_insert(cache, keys[i], values[i], ctxt, t TSRMLS_CC);
2267 + }
2268 + }
2269 + CACHE_UNLOCK(cache);
2270 + return rval;
2271 +}
2272 +/* }}} */
2273 +
2274 +
2275 +/* {{{ apc_cache_user_insert */
2276 +int apc_cache_user_insert(apc_cache_t* cache, apc_cache_key_t key, apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC)
2277 +{
2278 + slot_t** slot;
2279 + unsigned int keylen = key.data.user.identifier_len;
2280 + apc_keyid_t *lastkey = &cache->header->lastkey;
2281 +
2282 + if (!value) {
2283 + return 0;
2284 + }
2285 +
2286 + if(apc_cache_busy(cache)) {
2287 + /* cache cleanup in progress, do not wait */
2288 + return 0;
2289 + }
2290 +
2291 + if(apc_cache_is_last_key(cache, &key, t TSRMLS_CC)) {
2292 + /* potential cache slam */
2293 + return 0;
2294 + }
2295 +
2296 + CACHE_LOCK(cache);
2297 +
2298 + memset(lastkey, 0, sizeof(apc_keyid_t));
2299 +
2300 + lastkey->h = key.h;
2301 + lastkey->keylen = keylen;
2302 + lastkey->mtime = t;
2303 +#ifdef ZTS
2304 + lastkey->tid = tsrm_thread_id();
2305 +#else
2306 + lastkey->pid = getpid();
2307 +#endif
2308 +
2309 + /* we do not reset lastkey after the insert. Whether it is inserted
2310 + * or not, another insert in the same second is always a bad idea.
2311 + */
2312 +
2313 + process_pending_removals(cache TSRMLS_CC);
2314 +
2315 + slot = &cache->slots[key.h % cache->num_slots];
2316 +
2317 + while (*slot) {
2318 + if (((*slot)->key.h == key.h) &&
2319 + (!memcmp((*slot)->key.data.user.identifier, key.data.user.identifier, keylen))) {
2320 + /*
2321 + * At this point we have found the user cache entry. If we are doing
2322 + * an exclusive insert (apc_add) we are going to bail right away if
2323 + * the user entry already exists and it has no ttl, or
2324 + * there is a ttl and the entry has not timed out yet.
2325 + */
2326 + if(exclusive && ( !(*slot)->value->data.user.ttl ||
2327 + ( (*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) >= t )
2328 + ) ) {
2329 + goto fail;
2330 + }
2331 + remove_slot(cache, slot TSRMLS_CC);
2332 + break;
2333 + } else
2334 + /*
2335 + * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of
2336 + * slot entries so we don't always have to skip past a bunch of stale entries. We check
2337 + * for staleness here and get rid of them by first checking to see if the cache has a global
2338 + * access ttl on it and removing entries that haven't been accessed for ttl seconds and secondly
2339 + * we see if the entry has a hard ttl on it and remove it if it has been around longer than its ttl
2340 + */
2341 + if((cache->ttl && (*slot)->access_time < (t - cache->ttl)) ||
2342 + ((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t)) {
2343 + remove_slot(cache, slot TSRMLS_CC);
2344 + continue;
2345 + }
2346 + slot = &(*slot)->next;
2347 + }
2348 +
2349 + if ((*slot = make_slot(&key, value, *slot, t TSRMLS_CC)) == NULL) {
2350 + goto fail;
2351 + }
2352 +
2353 + value->mem_size = ctxt->pool->size;
2354 + cache->header->mem_size += ctxt->pool->size;
2355 +
2356 + CACHE_FAST_INC(cache, cache->header->num_entries);
2357 + CACHE_FAST_INC(cache, cache->header->num_inserts);
2358 +
2359 + CACHE_UNLOCK(cache);
2360 +
2361 + return 1;
2362 +
2363 +fail:
2364 + CACHE_UNLOCK(cache);
2365 +
2366 + return 0;
2367 +}
2368 +/* }}} */
2369 +
2370 +/* {{{ apc_cache_find_slot */
2371 +slot_t* apc_cache_find_slot(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC)
2372 +{
2373 + slot_t** slot;
2374 + volatile slot_t* retval = NULL;
2375 +
2376 + CACHE_RDLOCK(cache);
2377 + if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
2378 + else slot = &cache->slots[key.h % cache->num_slots];
2379 +
2380 + while (*slot) {
2381 + if(key.type == (*slot)->key.type) {
2382 + if(key.type == APC_CACHE_KEY_FILE) {
2383 + if(key_equals((*slot)->key.data.file, key.data.file)) {
2384 + if((*slot)->key.mtime != key.mtime) {
2385 + #if (USE_READ_LOCKS == 0)
2386 + /* this is merely a memory-friendly optimization, if we do have a write-lock
2387 + * might as well move this to the deleted_list right-away. Otherwise an insert
2388 + * of the same key wil do it (or an expunge, *eventually*).
2389 + */
2390 + remove_slot(cache, slot TSRMLS_CC);
2391 + #endif
2392 + CACHE_SAFE_INC(cache, cache->header->num_misses);
2393 + CACHE_RDUNLOCK(cache);
2394 + return NULL;
2395 + }
2396 + CACHE_SAFE_INC(cache, (*slot)->num_hits);
2397 + CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
2398 + (*slot)->access_time = t;
2399 + prevent_garbage_collection((*slot)->value);
2400 + CACHE_FAST_INC(cache, cache->header->num_hits);
2401 + retval = *slot;
2402 + CACHE_RDUNLOCK(cache);
2403 + return (slot_t*)retval;
2404 + }
2405 + } else { /* APC_CACHE_KEY_FPFILE */
2406 + if(((*slot)->key.h == key.h) &&
2407 + !memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1)) {
2408 + /* TTL Check ? */
2409 + CACHE_SAFE_INC(cache, (*slot)->num_hits);
2410 + CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
2411 + (*slot)->access_time = t;
2412 + prevent_garbage_collection((*slot)->value);
2413 + CACHE_FAST_INC(cache, cache->header->num_hits);
2414 + retval = *slot;
2415 + CACHE_RDUNLOCK(cache);
2416 + return (slot_t*)retval;
2417 + }
2418 + }
2419 + }
2420 + slot = &(*slot)->next;
2421 + }
2422 + CACHE_FAST_INC(cache, cache->header->num_misses);
2423 + CACHE_RDUNLOCK(cache);
2424 + return NULL;
2425 +}
2426 +/* }}} */
2427 +
2428 +/* {{{ apc_cache_find */
2429 +apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, apc_cache_key_t key, time_t t TSRMLS_DC)
2430 +{
2431 + slot_t * slot = apc_cache_find_slot(cache, key, t TSRMLS_CC);
2432 + apc_debug("apc_cache_find [%i]\n" TSRMLS_CC, key.h);
2433 + return (slot) ? slot->value : NULL;
2434 +}
2435 +/* }}} */
2436 +
2437 +/* {{{ apc_cache_user_find */
2438 +apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC)
2439 +{
2440 + slot_t** slot;
2441 + volatile apc_cache_entry_t* value = NULL;
2442 + unsigned long h;
2443 +
2444 + if(apc_cache_busy(cache))
2445 + {
2446 + /* cache cleanup in progress */
2447 + return NULL;
2448 + }
2449 +
2450 + CACHE_RDLOCK(cache);
2451 +
2452 + h = string_nhash_8(strkey, keylen);
2453 +
2454 + slot = &cache->slots[h % cache->num_slots];
2455 +
2456 + while (*slot) {
2457 + if ((h == (*slot)->key.h) &&
2458 + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
2459 + /* Check to make sure this entry isn't expired by a hard TTL */
2460 + if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
2461 + #if (USE_READ_LOCKS == 0)
2462 + /* this is merely a memory-friendly optimization, if we do have a write-lock
2463 + * might as well move this to the deleted_list right-away. Otherwise an insert
2464 + * of the same key wil do it (or an expunge, *eventually*).
2465 + */
2466 + remove_slot(cache, slot TSRMLS_CC);
2467 + #endif
2468 + CACHE_FAST_INC(cache, cache->header->num_misses);
2469 + CACHE_RDUNLOCK(cache);
2470 + return NULL;
2471 + }
2472 + /* Otherwise we are fine, increase counters and return the cache entry */
2473 + CACHE_SAFE_INC(cache, (*slot)->num_hits);
2474 + CACHE_SAFE_INC(cache, (*slot)->value->ref_count);
2475 + (*slot)->access_time = t;
2476 +
2477 + CACHE_FAST_INC(cache, cache->header->num_hits);
2478 + value = (*slot)->value;
2479 + CACHE_RDUNLOCK(cache);
2480 + return (apc_cache_entry_t*)value;
2481 + }
2482 + slot = &(*slot)->next;
2483 + }
2484 +
2485 + CACHE_FAST_INC(cache, cache->header->num_misses);
2486 + CACHE_RDUNLOCK(cache);
2487 + return NULL;
2488 +}
2489 +/* }}} */
2490 +
2491 +/* {{{ apc_cache_user_exists */
2492 +apc_cache_entry_t* apc_cache_user_exists(apc_cache_t* cache, char *strkey, int keylen, time_t t TSRMLS_DC)
2493 +{
2494 + slot_t** slot;
2495 + volatile apc_cache_entry_t* value = NULL;
2496 + unsigned long h;
2497 +
2498 + if(apc_cache_busy(cache))
2499 + {
2500 + /* cache cleanup in progress */
2501 + return NULL;
2502 + }
2503 +
2504 + CACHE_RDLOCK(cache);
2505 +
2506 + h = string_nhash_8(strkey, keylen);
2507 +
2508 + slot = &cache->slots[h % cache->num_slots];
2509 +
2510 + while (*slot) {
2511 + if ((h == (*slot)->key.h) &&
2512 + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
2513 + /* Check to make sure this entry isn't expired by a hard TTL */
2514 + if((*slot)->value->data.user.ttl && (time_t) ((*slot)->creation_time + (*slot)->value->data.user.ttl) < t) {
2515 + CACHE_UNLOCK(cache);
2516 + return NULL;
2517 + }
2518 + /* Return the cache entry ptr */
2519 + value = (*slot)->value;
2520 + CACHE_RDUNLOCK(cache);
2521 + return (apc_cache_entry_t*)value;
2522 + }
2523 + slot = &(*slot)->next;
2524 + }
2525 + CACHE_RDUNLOCK(cache);
2526 + return NULL;
2527 +}
2528 +/* }}} */
2529 +
2530 +/* {{{ apc_cache_user_update */
2531 +int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen, apc_cache_updater_t updater, void* data TSRMLS_DC)
2532 +{
2533 + slot_t** slot;
2534 + int retval;
2535 + unsigned long h;
2536 +
2537 + if(apc_cache_busy(cache))
2538 + {
2539 + /* cache cleanup in progress */
2540 + return 0;
2541 + }
2542 +
2543 + CACHE_LOCK(cache);
2544 +
2545 + h = string_nhash_8(strkey, keylen);
2546 + slot = &cache->slots[h % cache->num_slots];
2547 +
2548 + while (*slot) {
2549 + if ((h == (*slot)->key.h) &&
2550 + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
2551 + switch(Z_TYPE_P((*slot)->value->data.user.val) & ~IS_CONSTANT_INDEX) {
2552 + case IS_ARRAY:
2553 + case IS_CONSTANT_ARRAY:
2554 + case IS_OBJECT:
2555 + {
2556 + if(APCG(serializer)) {
2557 + retval = 0;
2558 + break;
2559 + } else {
2560 + /* fall through */
2561 + }
2562 + }
2563 + /* fall through */
2564 + default:
2565 + {
2566 + retval = updater(cache, (*slot)->value, data);
2567 + (*slot)->key.mtime = apc_time();
2568 + }
2569 + break;
2570 + }
2571 + CACHE_UNLOCK(cache);
2572 + return retval;
2573 + }
2574 + slot = &(*slot)->next;
2575 + }
2576 + CACHE_UNLOCK(cache);
2577 + return 0;
2578 +}
2579 +/* }}} */
2580 +
2581 +/* {{{ apc_cache_user_delete */
2582 +int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC)
2583 +{
2584 + slot_t** slot;
2585 + unsigned long h;
2586 +
2587 + CACHE_LOCK(cache);
2588 +
2589 + h = string_nhash_8(strkey, keylen);
2590 +
2591 + slot = &cache->slots[h % cache->num_slots];
2592 +
2593 + while (*slot) {
2594 + if ((h == (*slot)->key.h) &&
2595 + !memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
2596 + remove_slot(cache, slot TSRMLS_CC);
2597 + CACHE_UNLOCK(cache);
2598 + return 1;
2599 + }
2600 + slot = &(*slot)->next;
2601 + }
2602 +
2603 + CACHE_UNLOCK(cache);
2604 + return 0;
2605 +}
2606 +/* }}} */
2607 +
2608 +/* {{{ apc_cache_delete */
2609 +int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC)
2610 +{
2611 + slot_t** slot;
2612 + time_t t;
2613 + apc_cache_key_t key;
2614 +
2615 + t = apc_time();
2616 +
2617 + /* try to create a cache key; if we fail, give up on caching */
2618 + if (!apc_cache_make_file_key(&key, filename, PG(include_path), t TSRMLS_CC)) {
2619 + apc_warning("Could not stat file %s, unable to delete from cache." TSRMLS_CC, filename);
2620 + return -1;
2621 + }
2622 +
2623 + CACHE_LOCK(cache);
2624 +
2625 + if(key.type == APC_CACHE_KEY_FILE) slot = &cache->slots[hash(key) % cache->num_slots];
2626 + else slot = &cache->slots[key.h % cache->num_slots];
2627 +
2628 + while(*slot) {
2629 + if(key.type == (*slot)->key.type) {
2630 + if(key.type == APC_CACHE_KEY_FILE) {
2631 + if(key_equals((*slot)->key.data.file, key.data.file)) {
2632 + remove_slot(cache, slot TSRMLS_CC);
2633 + CACHE_UNLOCK(cache);
2634 + return 1;
2635 + }
2636 + } else { /* APC_CACHE_KEY_FPFILE */
2637 + if(((*slot)->key.h == key.h) &&
2638 + (!memcmp((*slot)->key.data.fpfile.fullpath, key.data.fpfile.fullpath, key.data.fpfile.fullpath_len+1))) {
2639 + remove_slot(cache, slot TSRMLS_CC);
2640 + CACHE_UNLOCK(cache);
2641 + return 1;
2642 + }
2643 + }
2644 + }
2645 + slot = &(*slot)->next;
2646 + }
2647 +
2648 + memset(&cache->header->lastkey, 0, sizeof(apc_keyid_t));
2649 +
2650 + CACHE_UNLOCK(cache);
2651 + return 0;
2652 +
2653 +}
2654 +/* }}} */
2655 +
2656 +/* {{{ apc_cache_release */
2657 +void apc_cache_release(apc_cache_t* cache, apc_cache_entry_t* entry TSRMLS_DC)
2658 +{
2659 + CACHE_SAFE_DEC(cache, entry->ref_count);
2660 +}
2661 +/* }}} */
2662 +
2663 +/* {{{ apc_cache_make_file_key */
2664 +int apc_cache_make_file_key(apc_cache_key_t* key,
2665 + const char* filename,
2666 + const char* include_path,
2667 + time_t t
2668 + TSRMLS_DC)
2669 +{
2670 + struct stat *tmp_buf=NULL;
2671 + struct apc_fileinfo_t *fileinfo = NULL;
2672 + int len;
2673 +
2674 + assert(key != NULL);
2675 +
2676 + if (!filename || !SG(request_info).path_translated) {
2677 + apc_debug("No filename and no path_translated - bailing\n" TSRMLS_CC);
2678 + goto cleanup;
2679 + }
2680 +
2681 + len = strlen(filename);
2682 + if(APCG(fpstat)==0) {
2683 + if(IS_ABSOLUTE_PATH(filename,len) || strstr(filename, "://")) {
2684 + key->data.fpfile.fullpath = filename;
2685 + key->data.fpfile.fullpath_len = len;
2686 + key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len);
2687 + key->mtime = t;
2688 + key->type = APC_CACHE_KEY_FPFILE;
2689 + goto success;
2690 + } else if(APCG(canonicalize)) {
2691 +
2692 + fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC);
2693 +
2694 + if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) {
2695 + apc_warning("apc failed to locate %s - bailing" TSRMLS_CC, filename);
2696 + goto cleanup;
2697 + }
2698 +
2699 + if(!VCWD_REALPATH(fileinfo->fullpath, APCG(canon_path))) {
2700 + apc_warning("realpath failed to canonicalize %s - bailing" TSRMLS_CC, filename);
2701 + goto cleanup;
2702 + }
2703 +
2704 + key->data.fpfile.fullpath = APCG(canon_path);
2705 + key->data.fpfile.fullpath_len = strlen(APCG(canon_path));
2706 + key->h = string_nhash_8(key->data.fpfile.fullpath, key->data.fpfile.fullpath_len);
2707 + key->mtime = t;
2708 + key->type = APC_CACHE_KEY_FPFILE;
2709 + goto success;
2710 + }
2711 + /* fall through to stat mode */
2712 + }
2713 +
2714 + fileinfo = apc_php_malloc(sizeof(apc_fileinfo_t) TSRMLS_CC);
2715 +
2716 + assert(fileinfo != NULL);
2717 +
2718 + if(!strcmp(SG(request_info).path_translated, filename)) {
2719 + tmp_buf = sapi_get_stat(TSRMLS_C); /* Apache has already done this stat() for us */
2720 + }
2721 +
2722 + if(tmp_buf) {
2723 + fileinfo->st_buf.sb = *tmp_buf;
2724 + } else {
2725 + if (apc_search_paths(filename, include_path, fileinfo TSRMLS_CC) != 0) {
2726 + apc_debug("Stat failed %s - bailing (%s) (%d)\n" TSRMLS_CC, filename,SG(request_info).path_translated);
2727 + goto cleanup;
2728 + }
2729 + }
2730 +
2731 + if(APCG(max_file_size) < fileinfo->st_buf.sb.st_size) {
2732 + apc_debug("File is too big %s (%d - %ld) - bailing\n" TSRMLS_CC, filename,t,fileinfo->st_buf.sb.st_size);
2733 + goto cleanup;
2734 + }
2735 +
2736 + /*
2737 + * This is a bit of a hack.
2738 + *
2739 + * Here I am checking to see if the file is at least 2 seconds old.
2740 + * The idea is that if the file is currently being written to then its
2741 + * mtime is going to match or at most be 1 second off of the current
2742 + * request time and we want to avoid caching files that have not been
2743 + * completely written. Of course, people should be using atomic
2744 + * mechanisms to push files onto live web servers, but adding this
2745 + * tiny safety is easier than educating the world. This is now
2746 + * configurable, but the default is still 2 seconds.
2747 + */
2748 + if(APCG(file_update_protection) && (t - fileinfo->st_buf.sb.st_mtime < APCG(file_update_protection)) && !APCG(force_file_update)) {
2749 + apc_debug("File is too new %s (%d - %d) - bailing\n" TSRMLS_CC,filename,t,fileinfo->st_buf.sb.st_mtime);
2750 + goto cleanup;
2751 + }
2752 +
2753 + key->data.file.device = fileinfo->st_buf.sb.st_dev;
2754 + key->data.file.inode = fileinfo->st_buf.sb.st_ino;
2755 + key->h = (unsigned long) key->data.file.device + (unsigned long) key->data.file.inode;
2756 +
2757 + /*
2758 + * If working with content management systems that like to munge the mtime,
2759 + * it might be appropriate to key off of the ctime to be immune to systems
2760 + * that try to backdate a template. If the mtime is set to something older
2761 + * than the previous mtime of a template we will obviously never see this
2762 + * "older" template. At some point the Smarty templating system did this.
2763 + * I generally disagree with using the ctime here because you lose the
2764 + * ability to warm up new content by saving it to a temporary file, hitting
2765 + * it once to cache it and then renaming it into its permanent location so
2766 + * set the apc.stat_ctime=true to enable this check.
2767 + */
2768 + if(APCG(stat_ctime)) {
2769 + key->mtime = (fileinfo->st_buf.sb.st_ctime > fileinfo->st_buf.sb.st_mtime) ? fileinfo->st_buf.sb.st_ctime : fileinfo->st_buf.sb.st_mtime;
2770 + } else {
2771 + key->mtime = fileinfo->st_buf.sb.st_mtime;
2772 + }
2773 + key->type = APC_CACHE_KEY_FILE;
2774 +
2775 +success:
2776 +
2777 + if(fileinfo != NULL) {
2778 + apc_php_free(fileinfo TSRMLS_CC);
2779 + }
2780 +
2781 + return 1;
2782 +
2783 +cleanup:
2784 +
2785 + if(fileinfo != NULL) {
2786 + apc_php_free(fileinfo TSRMLS_CC);
2787 + }
2788 +
2789 + return 0;
2790 +}
2791 +/* }}} */
2792 +
2793 +/* {{{ apc_cache_make_user_key */
2794 +int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t)
2795 +{
2796 + assert(key != NULL);
2797 +
2798 + if (!identifier)
2799 + return 0;
2800 +
2801 + key->data.user.identifier = identifier;
2802 + key->data.user.identifier_len = identifier_len;
2803 + key->h = string_nhash_8(key->data.user.identifier, key->data.user.identifier_len);
2804 + key->mtime = t;
2805 + key->type = APC_CACHE_KEY_USER;
2806 + return 1;
2807 +}
2808 +/* }}} */
2809 +
2810 +/* {{{ apc_cache_make_file_entry */
2811 +apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
2812 + zend_op_array* op_array,
2813 + apc_function_t* functions,
2814 + apc_class_t* classes,
2815 + apc_context_t* ctxt
2816 + TSRMLS_DC)
2817 +{
2818 + apc_cache_entry_t* entry;
2819 + apc_pool* pool = ctxt->pool;
2820 +
2821 + entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
2822 + if (!entry) return NULL;
2823 +
2824 + entry->data.file.filename = apc_pstrdup(filename, pool TSRMLS_CC);
2825 + if(!entry->data.file.filename) {
2826 + apc_debug("apc_cache_make_file_entry: entry->data.file.filename is NULL - bailing\n" TSRMLS_CC);
2827 + return NULL;
2828 + }
2829 + apc_debug("apc_cache_make_file_entry: entry->data.file.filename is [%s]\n" TSRMLS_CC,entry->data.file.filename);
2830 + entry->data.file.op_array = op_array;
2831 + entry->data.file.functions = functions;
2832 + entry->data.file.classes = classes;
2833 +
2834 + entry->data.file.halt_offset = apc_file_halt_offset(filename TSRMLS_CC);
2835 +
2836 + entry->type = APC_CACHE_ENTRY_FILE;
2837 + entry->ref_count = 0;
2838 + entry->mem_size = 0;
2839 + entry->pool = pool;
2840 + return entry;
2841 +}
2842 +/* }}} */
2843 +
2844 +/* {{{ apc_cache_store_zval */
2845 +zval* apc_cache_store_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
2846 +{
2847 + if (Z_TYPE_P(src) == IS_ARRAY) {
2848 + /* Maintain a list of zvals we've copied to properly handle recursive structures */
2849 + zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
2850 + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
2851 + zend_hash_destroy(&APCG(copied_zvals));
2852 + APCG(copied_zvals).nTableSize=0;
2853 + } else {
2854 + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
2855 + }
2856 +
2857 +
2858 + return dst;
2859 +}
2860 +/* }}} */
2861 +
2862 +/* {{{ apc_cache_fetch_zval */
2863 +zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
2864 +{
2865 + if (Z_TYPE_P(src) == IS_ARRAY) {
2866 + /* Maintain a list of zvals we've copied to properly handle recursive structures */
2867 + zend_hash_init(&APCG(copied_zvals), 0, NULL, NULL, 0);
2868 + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
2869 + zend_hash_destroy(&APCG(copied_zvals));
2870 + APCG(copied_zvals).nTableSize=0;
2871 + } else {
2872 + dst = apc_copy_zval(dst, src, ctxt TSRMLS_CC);
2873 + }
2874 +
2875 +
2876 + return dst;
2877 +}
2878 +/* }}} */
2879 +
2880 +/* {{{ apc_cache_make_user_entry */
2881 +apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval* val, apc_context_t* ctxt, const unsigned int ttl TSRMLS_DC)
2882 +{
2883 + apc_cache_entry_t* entry;
2884 + apc_pool* pool = ctxt->pool;
2885 +
2886 + entry = (apc_cache_entry_t*) apc_pool_alloc(pool, sizeof(apc_cache_entry_t));
2887 + if (!entry) return NULL;
2888 +
2889 + entry->data.user.info = apc_pmemcpy(info, info_len, pool TSRMLS_CC);
2890 + entry->data.user.info_len = info_len;
2891 + if(!entry->data.user.info) {
2892 + return NULL;
2893 + }
2894 + entry->data.user.val = apc_cache_store_zval(NULL, val, ctxt TSRMLS_CC);
2895 + if(!entry->data.user.val) {
2896 + return NULL;
2897 + }
2898 + INIT_PZVAL(entry->data.user.val);
2899 + entry->data.user.ttl = ttl;
2900 + entry->type = APC_CACHE_ENTRY_USER;
2901 + entry->ref_count = 0;
2902 + entry->mem_size = 0;
2903 + entry->pool = pool;
2904 + return entry;
2905 +}
2906 +/* }}} */
2907 +
2908 +/* {{{ */
2909 +static zval* apc_cache_link_info(apc_cache_t *cache, slot_t* p TSRMLS_DC)
2910 +{
2911 + zval *link = NULL;
2912 + char md5str[33];
2913 +
2914 + ALLOC_INIT_ZVAL(link);
2915 +
2916 + if(!link) {
2917 + return NULL;
2918 + }
2919 +
2920 + array_init(link);
2921 +
2922 + if(p->value->type == APC_CACHE_ENTRY_FILE) {
2923 + add_assoc_string(link, "type", "file", 1);
2924 + if(p->key.type == APC_CACHE_KEY_FILE) {
2925 +
2926 + #ifdef PHP_WIN32
2927 + {
2928 + char buf[20];
2929 + sprintf(buf, "%I64d", p->key.data.file.device);
2930 + add_assoc_string(link, "device", buf, 1);
2931 +
2932 + sprintf(buf, "%I64d", p->key.data.file.inode);
2933 + add_assoc_string(link, "inode", buf, 1);
2934 + }
2935 + #else
2936 + add_assoc_long(link, "device", p->key.data.file.device);
2937 + add_assoc_long(link, "inode", p->key.data.file.inode);
2938 + #endif
2939 +
2940 + add_assoc_string(link, "filename", p->value->data.file.filename, 1);
2941 + } else { /* This is a no-stat fullpath file entry */
2942 + add_assoc_long(link, "device", 0);
2943 + add_assoc_long(link, "inode", 0);
2944 + add_assoc_string(link, "filename", (char*)p->key.data.fpfile.fullpath, 1);
2945 + }
2946 + if (APCG(file_md5)) {
2947 + make_digest(md5str, p->key.md5);
2948 + add_assoc_string(link, "md5", md5str, 1);
2949 + }
2950 + } else if(p->value->type == APC_CACHE_ENTRY_USER) {
2951 + add_assoc_stringl(link, "info", p->value->data.user.info, p->value->data.user.info_len-1, 1);
2952 + add_assoc_long(link, "ttl", (long)p->value->data.user.ttl);
2953 + add_assoc_string(link, "type", "user", 1);
2954 + }
2955 +
2956 + add_assoc_double(link, "num_hits", (double)p->num_hits);
2957 + add_assoc_long(link, "mtime", p->key.mtime);
2958 + add_assoc_long(link, "creation_time", p->creation_time);
2959 + add_assoc_long(link, "deletion_time", p->deletion_time);
2960 + add_assoc_long(link, "access_time", p->access_time);
2961 + add_assoc_long(link, "ref_count", p->value->ref_count);
2962 + add_assoc_long(link, "mem_size", p->value->mem_size);
2963 +
2964 + return link;
2965 +}
2966 +/* }}} */
2967 +
2968 +/* {{{ apc_cache_info */
2969 +zval* apc_cache_info(apc_cache_t* cache, zend_bool limited TSRMLS_DC)
2970 +{
2971 + zval *info = NULL;
2972 + zval *list = NULL;
2973 + zval *deleted_list = NULL;
2974 + zval *slots = NULL;
2975 + slot_t* p;
2976 + int i, j;
2977 +
2978 + if(!cache) return NULL;
2979 +
2980 + CACHE_RDLOCK(cache);
2981 +
2982 + ALLOC_INIT_ZVAL(info);
2983 +
2984 + if(!info) {
2985 + CACHE_RDUNLOCK(cache);
2986 + return NULL;
2987 + }
2988 +
2989 + array_init(info);
2990 + add_assoc_long(info, "num_slots", cache->num_slots);
2991 + add_assoc_long(info, "ttl", cache->ttl);
2992 +
2993 + add_assoc_double(info, "num_hits", (double)cache->header->num_hits);
2994 + add_assoc_double(info, "num_misses", (double)cache->header->num_misses);
2995 + add_assoc_double(info, "num_inserts", (double)cache->header->num_inserts);
2996 + add_assoc_double(info, "expunges", (double)cache->header->expunges);
2997 +
2998 + add_assoc_long(info, "start_time", cache->header->start_time);
2999 + add_assoc_double(info, "mem_size", (double)cache->header->mem_size);
3000 + add_assoc_long(info, "num_entries", cache->header->num_entries);
3001 +#ifdef MULTIPART_EVENT_FORMDATA
3002 + add_assoc_long(info, "file_upload_progress", 1);
3003 +#else
3004 + add_assoc_long(info, "file_upload_progress", 0);
3005 +#endif
3006 +#if APC_MMAP
3007 + add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1, 1);
3008 +#else
3009 + add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1, 1);
3010 +#endif
3011 + add_assoc_stringl(info, "locking_type", APC_LOCK_TYPE, sizeof(APC_LOCK_TYPE)-1, 1);
3012 +
3013 + if(!limited) {
3014 + /* For each hashtable slot */
3015 + ALLOC_INIT_ZVAL(list);
3016 + array_init(list);
3017 +
3018 + ALLOC_INIT_ZVAL(slots);
3019 + array_init(slots);
3020 +
3021 + for (i = 0; i < cache->num_slots; i++) {
3022 + p = cache->slots[i];
3023 + j = 0;
3024 + for (; p != NULL; p = p->next) {
3025 + zval *link = apc_cache_link_info(cache, p TSRMLS_CC);
3026 + add_next_index_zval(list, link);
3027 + j++;
3028 + }
3029 + if(j != 0) {
3030 + add_index_long(slots, (ulong)i, j);
3031 + }
3032 + }
3033 +
3034 + /* For each slot pending deletion */
3035 + ALLOC_INIT_ZVAL(deleted_list);
3036 + array_init(deleted_list);
3037 +
3038 + for (p = cache->header->deleted_list; p != NULL; p = p->next) {
3039 + zval *link = apc_cache_link_info(cache, p TSRMLS_CC);
3040 + add_next_index_zval(deleted_list, link);
3041 + }
3042 +
3043 + add_assoc_zval(info, "cache_list", list);
3044 + add_assoc_zval(info, "deleted_list", deleted_list);
3045 + add_assoc_zval(info, "slot_distribution", slots);
3046 + }
3047 +
3048 + CACHE_RDUNLOCK(cache);
3049 + return info;
3050 +}
3051 +/* }}} */
3052 +
3053 +/* {{{ apc_cache_unlock */
3054 +void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC)
3055 +{
3056 + CACHE_UNLOCK(cache);
3057 +}
3058 +/* }}} */
3059 +
3060 +/* {{{ apc_cache_busy */
3061 +zend_bool apc_cache_busy(apc_cache_t* cache)
3062 +{
3063 + return cache->header->busy;
3064 +}
3065 +/* }}} */
3066 +
3067 +/* {{{ apc_cache_is_last_key */
3068 +zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC)
3069 +{
3070 + apc_keyid_t *lastkey = &cache->header->lastkey;
3071 + unsigned int keylen = key->data.user.identifier_len;
3072 +#ifdef ZTS
3073 + THREAD_T tid = tsrm_thread_id();
3074 + #define FROM_DIFFERENT_THREAD(k) (memcmp(&((k)->tid), &tid, sizeof(THREAD_T))!=0)
3075 +#else
3076 + pid_t pid = getpid();
3077 + #define FROM_DIFFERENT_THREAD(k) (pid != (k)->pid)
3078 +#endif
3079 +
3080 +
3081 + /* unlocked reads, but we're not shooting for 100% success with this */
3082 + if(lastkey->h == key->h && keylen == lastkey->keylen) {
3083 + if(lastkey->mtime == t && FROM_DIFFERENT_THREAD(lastkey)) {
3084 + /* potential cache slam */
3085 + if(APCG(slam_defense)) {
3086 + apc_debug("Potential cache slam averted for key '%s'" TSRMLS_CC, key->data.user.identifier);
3087 + return 1;
3088 + }
3089 + }
3090 + }
3091 +
3092 + return 0;
3093 +}
3094 +/* }}} */
3095 +
3096 +#if NONBLOCKING_LOCK_AVAILABLE
3097 +/* {{{ apc_cache_write_lock */
3098 +zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC)
3099 +{
3100 + return apc_lck_nb_lock(cache->header->wrlock);
3101 +}
3102 +/* }}} */
3103 +
3104 +/* {{{ apc_cache_write_unlock */
3105 +void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC)
3106 +{
3107 + apc_lck_unlock(cache->header->wrlock);
3108 +}
3109 +/* }}} */
3110 +#endif
3111 +
3112 +/*
3113 + * Local variables:
3114 + * tab-width: 4
3115 + * c-basic-offset: 4
3116 + * End:
3117 + * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
3118 + * vim<600: expandtab sw=4 ts=4 sts=4
3119 + */
3120 diff -Naur a/ext/apc/apc_cache.h b/ext/apc/apc_cache.h
3121 --- a/ext/apc/apc_cache.h 1970-01-01 01:00:00.000000000 +0100
3122 +++ b/ext/apc/apc_cache.h 2012-07-20 00:10:35.000000000 +0200
3123 @@ -0,0 +1,371 @@
3124 +/*
3125 + +----------------------------------------------------------------------+
3126 + | APC |
3127 + +----------------------------------------------------------------------+
3128 + | Copyright (c) 2006-2011 The PHP Group |
3129 + +----------------------------------------------------------------------+
3130 + | This source file is subject to version 3.01 of the PHP license, |
3131 + | that is bundled with this package in the file LICENSE, and is |
3132 + | available through the world-wide-web at the following url: |
3133 + | http://www.php.net/license/3_01.txt. |
3134 + | If you did not receive a copy of the PHP license and are unable to |
3135 + | obtain it through the world-wide-web, please send a note to |
3136 + | license@php.net so we can mail you a copy immediately. |
3137 + +----------------------------------------------------------------------+
3138 + | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
3139 + | Rasmus Lerdorf <rasmus@php.net> |
3140 + +----------------------------------------------------------------------+
3141 +
3142 + This software was contributed to PHP by Community Connect Inc. in 2002
3143 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
3144 + Future revisions and derivatives of this source code must acknowledge
3145 + Community Connect Inc. as the original contributor of this module by
3146 + leaving this note intact in the source code.
3147 +
3148 + All other licensing and usage conditions are those of the PHP Group.
3149 +
3150 + */
3151 +
3152 +/* $Id: apc_cache.h 324329 2012-03-18 15:29:37Z mike $ */
3153 +
3154 +#ifndef APC_CACHE_H
3155 +#define APC_CACHE_H
3156 +
3157 +/*
3158 + * This module defines the shared memory file cache. Basically all of the
3159 + * logic for storing and retrieving cache entries lives here.
3160 + */
3161 +
3162 +#include "apc.h"
3163 +#include "apc_compile.h"
3164 +#include "apc_lock.h"
3165 +#include "apc_pool.h"
3166 +#include "apc_main.h"
3167 +#include "TSRM.h"
3168 +
3169 +#define APC_CACHE_ENTRY_FILE 1
3170 +#define APC_CACHE_ENTRY_USER 2
3171 +
3172 +#define APC_CACHE_KEY_FILE 1
3173 +#define APC_CACHE_KEY_USER 2
3174 +#define APC_CACHE_KEY_FPFILE 3
3175 +
3176 +#ifdef PHP_WIN32
3177 +typedef unsigned __int64 apc_ino_t;
3178 +typedef unsigned __int64 apc_dev_t;
3179 +#else
3180 +typedef ino_t apc_ino_t;
3181 +typedef dev_t apc_dev_t;
3182 +#endif
3183 +
3184 +/* {{{ cache locking macros */
3185 +#define CACHE_LOCK(cache) { LOCK(cache->header->lock); cache->has_lock = 1; }
3186 +#define CACHE_UNLOCK(cache) { UNLOCK(cache->header->lock); cache->has_lock = 0; }
3187 +#define CACHE_SAFE_LOCK(cache) { if ((++cache->has_lock) == 1) LOCK(cache->header->lock); }
3188 +#define CACHE_SAFE_UNLOCK(cache) { if ((--cache->has_lock) == 0) UNLOCK(cache->header->lock); }
3189 +
3190 +#if (RDLOCK_AVAILABLE == 1) && defined(HAVE_ATOMIC_OPERATIONS)
3191 +#define USE_READ_LOCKS 1
3192 +#define CACHE_RDLOCK(cache) { RDLOCK(cache->header->lock); cache->has_lock = 0; }
3193 +#define CACHE_RDUNLOCK(cache) { RDUNLOCK(cache->header->lock); cache->has_lock = 0; }
3194 +#define CACHE_SAFE_INC(cache, obj) { ATOMIC_INC(obj); }
3195 +#define CACHE_SAFE_DEC(cache, obj) { ATOMIC_DEC(obj); }
3196 +#else
3197 +#define USE_READ_LOCKS 0
3198 +#define CACHE_RDLOCK(cache) { LOCK(cache->header->lock); cache->has_lock = 1; }
3199 +#define CACHE_RDUNLOCK(cache) { UNLOCK(cache->header->lock); cache->has_lock = 0; }
3200 +#define CACHE_SAFE_INC(cache, obj) { CACHE_SAFE_LOCK(cache); obj++; CACHE_SAFE_UNLOCK(cache);}
3201 +#define CACHE_SAFE_DEC(cache, obj) { CACHE_SAFE_LOCK(cache); obj--; CACHE_SAFE_UNLOCK(cache);}
3202 +#endif
3203 +
3204 +#define CACHE_FAST_INC(cache, obj) { obj++; }
3205 +#define CACHE_FAST_DEC(cache, obj) { obj--; }
3206 +/* }}} */
3207 +
3208 +/* {{{ struct definition: apc_cache_key_t */
3209 +#define T apc_cache_t*
3210 +typedef struct apc_cache_t apc_cache_t; /* opaque cache type */
3211 +
3212 +typedef union _apc_cache_key_data_t {
3213 + struct {
3214 + apc_dev_t device; /* the filesystem device */
3215 + apc_ino_t inode; /* the filesystem inode */
3216 + } file;
3217 + struct {
3218 + const char *identifier;
3219 + int identifier_len;
3220 + } user;
3221 + struct {
3222 + const char *fullpath;
3223 + int fullpath_len;
3224 + } fpfile;
3225 +} apc_cache_key_data_t;
3226 +
3227 +typedef struct apc_cache_key_t apc_cache_key_t;
3228 +struct apc_cache_key_t {
3229 + apc_cache_key_data_t data;
3230 + unsigned long h; /* pre-computed hash value */
3231 + time_t mtime; /* the mtime of this cached entry */
3232 + unsigned char type;
3233 + unsigned char md5[16]; /* md5 hash of the source file */
3234 +};
3235 +
3236 +
3237 +typedef struct apc_keyid_t apc_keyid_t;
3238 +
3239 +struct apc_keyid_t {
3240 + unsigned int h;
3241 + unsigned int keylen;
3242 + time_t mtime;
3243 +#ifdef ZTS
3244 + THREAD_T tid;
3245 +#else
3246 + pid_t pid;
3247 +#endif
3248 +};
3249 +/* }}} */
3250 +
3251 +/* {{{ struct definition: apc_cache_entry_t */
3252 +typedef union _apc_cache_entry_value_t {
3253 + struct {
3254 + char *filename; /* absolute path to source file */
3255 + zend_op_array* op_array; /* op_array allocated in shared memory */
3256 + apc_function_t* functions; /* array of apc_function_t's */
3257 + apc_class_t* classes; /* array of apc_class_t's */
3258 + long halt_offset; /* value of __COMPILER_HALT_OFFSET__ for the file */
3259 + } file;
3260 + struct {
3261 + char *info;
3262 + int info_len;
3263 + zval *val;
3264 + unsigned int ttl;
3265 + } user;
3266 +} apc_cache_entry_value_t;
3267 +
3268 +typedef struct apc_cache_entry_t apc_cache_entry_t;
3269 +struct apc_cache_entry_t {
3270 + apc_cache_entry_value_t data;
3271 + unsigned char type;
3272 + int ref_count;
3273 + size_t mem_size;
3274 + apc_pool *pool;
3275 +};
3276 +/* }}} */
3277 +
3278 +/*
3279 + * apc_cache_create creates the shared memory compiler cache. This function
3280 + * should be called just once (ideally in the web server parent process, e.g.
3281 + * in apache), otherwise you will end up with multiple caches (which won't
3282 + * necessarily break anything). Returns a pointer to the cache object.
3283 + *
3284 + * size_hint is a "hint" at the total number of source files that will be
3285 + * cached. It determines the physical size of the hash table. Passing 0 for
3286 + * this argument will use a reasonable default value.
3287 + *
3288 + * gc_ttl is the maximum time a cache entry may speed on the garbage
3289 + * collection list. This is basically a work around for the inherent
3290 + * unreliability of our reference counting mechanism (see apc_cache_release).
3291 + *
3292 + * ttl is the maximum time a cache entry can idle in a slot in case the slot
3293 + * is needed. This helps in cleaning up the cache and ensuring that entries
3294 + * hit frequently stay cached and ones not hit very often eventually disappear.
3295 + */
3296 +extern T apc_cache_create(int size_hint, int gc_ttl, int ttl TSRMLS_DC);
3297 +
3298 +/*
3299 + * apc_cache_destroy releases any OS resources associated with a cache object.
3300 + * Under apache, this function can be safely called by the child processes
3301 + * when they exit.
3302 + */
3303 +extern void apc_cache_destroy(T cache TSRMLS_DC);
3304 +
3305 +/*
3306 + * apc_cache_clear empties a cache. This can safely be called at any time,
3307 + * even while other server processes are executing cached source files.
3308 + */
3309 +extern void apc_cache_clear(T cache TSRMLS_DC);
3310 +
3311 +/*
3312 + * apc_cache_insert adds an entry to the cache, using a filename as a key.
3313 + * Internally, the filename is translated to a canonical representation, so
3314 + * that relative and absolute filenames will map to a single key. Returns
3315 + * non-zero if the file was successfully inserted, 0 otherwise. If 0 is
3316 + * returned, the caller must free the cache entry by calling
3317 + * apc_cache_free_entry (see below).
3318 + *
3319 + * key is the value created by apc_cache_make_file_key for file keys.
3320 + *
3321 + * value is a cache entry returned by apc_cache_make_entry (see below).
3322 + */
3323 +extern int apc_cache_insert(T cache, apc_cache_key_t key,
3324 + apc_cache_entry_t* value, apc_context_t* ctxt, time_t t TSRMLS_DC);
3325 +
3326 +extern int apc_cache_user_insert(T cache, apc_cache_key_t key,
3327 + apc_cache_entry_t* value, apc_context_t* ctxt, time_t t, int exclusive TSRMLS_DC);
3328 +
3329 +extern int *apc_cache_insert_mult(apc_cache_t* cache, apc_cache_key_t* keys,
3330 + apc_cache_entry_t** values, apc_context_t *ctxt, time_t t, int num_entries TSRMLS_DC);
3331 +
3332 +/*
3333 + * apc_cache_find searches for a cache entry by filename, and returns a
3334 + * pointer to the entry if found, NULL otherwise.
3335 + *
3336 + * key is a value created by apc_cache_make_file_key for file keys.
3337 + */
3338 +extern apc_cache_entry_t* apc_cache_find(T cache, apc_cache_key_t key, time_t t TSRMLS_DC);
3339 +
3340 +/*
3341 + * apc_cache_user_find searches for a cache entry by its hashed identifier,
3342 + * and returns a pointer to the entry if found, NULL otherwise.
3343 + *
3344 + */
3345 +extern apc_cache_entry_t* apc_cache_user_find(T cache, char* strkey, int keylen, time_t t TSRMLS_DC);
3346 +
3347 +/*
3348 + * apc_cache_user_exists searches for a cache entry by its hashed identifier,
3349 + * and returns a pointer to the entry if found, NULL otherwise. This is a
3350 + * quick non-locking version of apc_cache_user_find that does not modify the
3351 + * shared memory segment in any way.
3352 + *
3353 + */
3354 +extern apc_cache_entry_t* apc_cache_user_exists(T cache, char* strkey, int keylen, time_t t TSRMLS_DC);
3355 +
3356 +/*
3357 + * apc_cache_delete and apc_cache_user_delete finds an entry in the cache and deletes it.
3358 + */
3359 +extern int apc_cache_delete(apc_cache_t* cache, char *filename, int filename_len TSRMLS_DC);
3360 +extern int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen TSRMLS_DC);
3361 +
3362 +/* apc_cach_fetch_zval takes a zval in the cache and reconstructs a runtime
3363 + * zval from it.
3364 + *
3365 + */
3366 +zval* apc_cache_fetch_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC);
3367 +
3368 +/*
3369 + * apc_cache_release decrements the reference count associated with a cache
3370 + * entry. Calling apc_cache_find automatically increments the reference count,
3371 + * and this function must be called post-execution to return the count to its
3372 + * original value. Failing to do so will prevent the entry from being
3373 + * garbage-collected.
3374 + *
3375 + * entry is the cache entry whose ref count you want to decrement.
3376 + */
3377 +extern void apc_cache_release(T cache, apc_cache_entry_t* entry TSRMLS_DC);
3378 +
3379 +/*
3380 + * apc_cache_make_file_key creates a key object given a relative or absolute
3381 + * filename and an optional list of auxillary paths to search. include_path is
3382 + * searched if the filename cannot be found relative to the current working
3383 + * directory.
3384 + *
3385 + * key points to caller-allocated storage (must not be null).
3386 + *
3387 + * filename is the path to the source file.
3388 + *
3389 + * include_path is a colon-separated list of directories to search.
3390 + *
3391 + * and finally we pass in the current request time so we can avoid
3392 + * caching files with a current mtime which tends to indicate that
3393 + * they are still being written to.
3394 + */
3395 +extern int apc_cache_make_file_key(apc_cache_key_t* key,
3396 + const char* filename,
3397 + const char* include_path,
3398 + time_t t
3399 + TSRMLS_DC);
3400 +
3401 +/*
3402 + * apc_cache_make_file_entry creates an apc_cache_entry_t object given a filename
3403 + * and the compilation results returned by the PHP compiler.
3404 + */
3405 +extern apc_cache_entry_t* apc_cache_make_file_entry(const char* filename,
3406 + zend_op_array* op_array,
3407 + apc_function_t* functions,
3408 + apc_class_t* classes,
3409 + apc_context_t* ctxt
3410 + TSRMLS_DC);
3411 +
3412 +
3413 +zend_bool apc_compile_cache_entry(apc_cache_key_t *key, zend_file_handle* h, int type, time_t t, zend_op_array** op_array_pp, apc_cache_entry_t** cache_entry_pp TSRMLS_DC);
3414 +
3415 +/*
3416 + * apc_cache_make_user_entry creates an apc_cache_entry_t object given an info string
3417 + * and the zval to be stored.
3418 + */
3419 +extern apc_cache_entry_t* apc_cache_make_user_entry(const char* info, int info_len, const zval *val, apc_context_t* ctxt, const unsigned int ttl TSRMLS_DC);
3420 +
3421 +extern int apc_cache_make_user_key(apc_cache_key_t* key, char* identifier, int identifier_len, const time_t t);
3422 +
3423 +/* {{{ struct definition: slot_t */
3424 +typedef struct slot_t slot_t;
3425 +struct slot_t {
3426 + apc_cache_key_t key; /* slot key */
3427 + apc_cache_entry_t* value; /* slot value */
3428 + slot_t* next; /* next slot in linked list */
3429 + unsigned long num_hits; /* number of hits to this bucket */
3430 + time_t creation_time; /* time slot was initialized */
3431 + time_t deletion_time; /* time slot was removed from cache */
3432 + time_t access_time; /* time slot was last accessed */
3433 +};
3434 +/* }}} */
3435 +
3436 +/* {{{ struct definition: cache_header_t
3437 + Any values that must be shared among processes should go in here. */
3438 +typedef struct cache_header_t cache_header_t;
3439 +struct cache_header_t {
3440 + apc_lck_t lock; /* read/write lock (exclusive blocking cache lock) */
3441 + apc_lck_t wrlock; /* write lock (non-blocking used to prevent cache slams) */
3442 + unsigned long num_hits; /* total successful hits in cache */
3443 + unsigned long num_misses; /* total unsuccessful hits in cache */
3444 + unsigned long num_inserts; /* total successful inserts in cache */
3445 + unsigned long expunges; /* total number of expunges */
3446 + slot_t* deleted_list; /* linked list of to-be-deleted slots */
3447 + time_t start_time; /* time the above counters were reset */
3448 + zend_bool busy; /* Flag to tell clients when we are busy cleaning the cache */
3449 + int num_entries; /* Statistic on the number of entries */
3450 + size_t mem_size; /* Statistic on the memory size used by this cache */
3451 + apc_keyid_t lastkey; /* the key that is being inserted (user cache) */
3452 +};
3453 +/* }}} */
3454 +
3455 +typedef void (*apc_expunge_cb_t)(T cache, size_t n TSRMLS_DC);
3456 +
3457 +/* {{{ struct definition: apc_cache_t */
3458 +struct apc_cache_t {
3459 + void* shmaddr; /* process (local) address of shared cache */
3460 + cache_header_t* header; /* cache header (stored in SHM) */
3461 + slot_t** slots; /* array of cache slots (stored in SHM) */
3462 + int num_slots; /* number of slots in cache */
3463 + int gc_ttl; /* maximum time on GC list for a slot */
3464 + int ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */
3465 + apc_expunge_cb_t expunge_cb; /* cache specific expunge callback to free up sma memory */
3466 + uint has_lock; /* flag for possible recursive locks within the same process */
3467 +};
3468 +/* }}} */
3469 +
3470 +extern zval* apc_cache_info(T cache, zend_bool limited TSRMLS_DC);
3471 +extern void apc_cache_unlock(apc_cache_t* cache TSRMLS_DC);
3472 +extern zend_bool apc_cache_busy(apc_cache_t* cache);
3473 +extern zend_bool apc_cache_write_lock(apc_cache_t* cache TSRMLS_DC);
3474 +extern void apc_cache_write_unlock(apc_cache_t* cache TSRMLS_DC);
3475 +extern zend_bool apc_cache_is_last_key(apc_cache_t* cache, apc_cache_key_t* key, time_t t TSRMLS_DC);
3476 +
3477 +/* used by apc_rfc1867 to update data in-place - not to be used elsewhere */
3478 +
3479 +typedef int (*apc_cache_updater_t)(apc_cache_t*, apc_cache_entry_t*, void* data);
3480 +extern int _apc_cache_user_update(apc_cache_t* cache, char *strkey, int keylen,
3481 + apc_cache_updater_t updater, void* data TSRMLS_DC);
3482 +
3483 +
3484 +#undef T
3485 +#endif
3486 +
3487 +/*
3488 + * Local variables:
3489 + * tab-width: 4
3490 + * c-basic-offset: 4
3491 + * End:
3492 + * vim>600: expandtab sw=4 ts=4 sts=4 fdm=marker
3493 + * vim<600: expandtab sw=4 ts=4 sts=4
3494 + */
3495 diff -Naur a/ext/apc/apc_compile.c b/ext/apc/apc_compile.c
3496 --- a/ext/apc/apc_compile.c 1970-01-01 01:00:00.000000000 +0100
3497 +++ b/ext/apc/apc_compile.c 2012-07-20 00:10:35.000000000 +0200
3498 @@ -0,0 +1,2164 @@
3499 +/*
3500 + +----------------------------------------------------------------------+
3501 + | APC |
3502 + +----------------------------------------------------------------------+
3503 + | Copyright (c) 2006-2011 The PHP Group |
3504 + +----------------------------------------------------------------------+
3505 + | This source file is subject to version 3.01 of the PHP license, |
3506 + | that is bundled with this package in the file LICENSE, and is |
3507 + | available through the world-wide-web at the following url: |
3508 + | http://www.php.net/license/3_01.txt. |
3509 + | If you did not receive a copy of the PHP license and are unable to |
3510 + | obtain it through the world-wide-web, please send a note to |
3511 + | license@php.net so we can mail you a copy immediately. |
3512 + +----------------------------------------------------------------------+
3513 + | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
3514 + | Rasmus Lerdorf <rasmus@php.net> |
3515 + | Arun C. Murthy <arunc@yahoo-inc.com> |
3516 + | Gopal Vijayaraghavan <gopalv@yahoo-inc.com> |
3517 + +----------------------------------------------------------------------+
3518 +
3519 + This software was contributed to PHP by Community Connect Inc. in 2002
3520 + and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
3521 + Future revisions and derivatives of this source code must acknowledge
3522 + Community Connect Inc. as the original contributor of this module by
3523 + leaving this note intact in the source code.
3524 +
3525 + All other licensing and usage conditions are those of the PHP Group.
3526 +
3527 + */
3528 +
3529 +/* $Id: apc_compile.c 326703 2012-07-19 17:06:12Z rasmus $ */
3530 +
3531 +#include "apc_compile.h"
3532 +#include "apc_globals.h"
3533 +#include "apc_zend.h"
3534 +#include "apc_php.h"
3535 +#include "apc_string.h"
3536 +#include "ext/standard/php_var.h"
3537 +#include "ext/standard/php_smart_str.h"
3538 +
3539 +typedef void* (*ht_copy_fun_t)(void*, void*, apc_context_t* TSRMLS_DC);
3540 +//typedef void (*ht_free_fun_t)(void*, apc_context_t*);
3541 +typedef int (*ht_check_copy_fun_t)(Bucket*, va_list);
3542 +
3543 +typedef void (*ht_fixup_fun_t)(Bucket*, zend_class_entry*, zend_class_entry*);
3544 +
3545 +#define CHECK(p) { if ((p) == NULL) return NULL; }
3546 +
3547 +/* {{{ internal function declarations */
3548 +
3549 +static zend_function* my_bitwise_copy_function(zend_function*, zend_function*, apc_context_t* TSRMLS_DC);
3550 +
3551 +/*
3552 + * The "copy" functions perform deep-copies on a particular data structure
3553 + * (passed as the second argument). They also optionally allocate space for
3554 + * the destination data structure if the first argument is null.
3555 + */
3556 +static zval** my_copy_zval_ptr(zval**, const zval**, apc_context_t* TSRMLS_DC);
3557 +static zval* my_copy_zval(zval*, const zval*, apc_context_t* TSRMLS_DC);
3558 +#ifndef ZEND_ENGINE_2_4
3559 +static znode* my_copy_znode(znode*, znode*, apc_context_t* TSRMLS_DC);
3560 +#endif
3561 +static zend_op* my_copy_zend_op(zend_op*, zend_op*, apc_context_t* TSRMLS_DC);
3562 +static zend_function* my_copy_function(zend_function*, zend_function*, apc_context_t* TSRMLS_DC);
3563 +static zend_function_entry* my_copy_function_entry(zend_function_entry*, const zend_function_entry*, apc_context_t* TSRMLS_DC);
3564 +static zend_class_entry* my_copy_class_entry(zend_class_entry*, zend_class_entry*, apc_context_t* TSRMLS_DC);
3565 +static HashTable* my_copy_hashtable_ex(HashTable*, HashTable* TSRMLS_DC, ht_copy_fun_t, int, apc_context_t*, ht_check_copy_fun_t, ...);
3566 +#define my_copy_hashtable( dst, src, copy_fn, holds_ptr, ctxt) \
3567 + my_copy_hashtable_ex(dst, src TSRMLS_CC, copy_fn, holds_ptr, ctxt, NULL)
3568 +static HashTable* my_copy_static_variables(zend_op_array* src, apc_context_t* TSRMLS_DC);
3569 +static zend_property_info* my_copy_property_info(zend_property_info* dst, zend_property_info* src, apc_context_t* TSRMLS_DC);
3570 +static zend_arg_info* my_copy_arg_info_array(zend_arg_info*, const zend_arg_info*, uint, apc_context_t* TSRMLS_DC);
3571 +static zend_arg_info* my_copy_arg_info(zend_arg_info*, const zend_arg_info*, apc_context_t* TSRMLS_DC);
3572 +
3573 +/*
3574 + * The "fixup" functions need for ZEND_ENGINE_2
3575 + */
3576 +static void my_fixup_function( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
3577 +static void my_fixup_hashtable( HashTable *ht, ht_fixup_fun_t fixup, zend_class_entry *src, zend_class_entry *dst );
3578 +/* my_fixup_function_for_execution is the same as my_fixup_function
3579 + * but named differently for clarity
3580 + */
3581 +#define my_fixup_function_for_execution my_fixup_function
3582 +
3583 +#ifdef ZEND_ENGINE_2_2
3584 +static void my_fixup_property_info( Bucket *p, zend_class_entry *src, zend_class_entry *dst );
3585 +#define my_fixup_property_info_for_execution my_fixup_property_info
3586 +#endif
3587 +
3588 +/*
3589 + * These functions return "1" if the member/function is
3590 + * defined/overridden in the 'current' class and not inherited.
3591 + */
3592 +static int my_check_copy_function(Bucket* src, va_list args);
3593 +static int my_check_copy_property_info(Bucket* src, va_list args);
3594 +#ifndef ZEND_ENGINE_2_4
3595 +static int my_check_copy_default_property(Bucket* p, va_list args);
3596 +static int my_check_copy_static_member(Bucket* src, va_list args);
3597 +#endif
3598 +static int my_check_copy_constant(Bucket* src, va_list args);
3599 +
3600 +/* }}} */
3601 +
3602 +/* {{{ apc php serializers */
3603 +int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS)
3604 +{
3605 + smart_str strbuf = {0};
3606 + php_serialize_data_t var_hash;
3607 + PHP_VAR_SERIALIZE_INIT(var_hash);
3608 + php_var_serialize(&strbuf, (zval**)&value, &var_hash TSRMLS_CC);
3609 + PHP_VAR_SERIALIZE_DESTROY(var_hash);
3610 + if(strbuf.c) {
3611 + *buf = (unsigned char*)strbuf.c;
3612 + *buf_len = strbuf.len;
3613 + smart_str_0(&strbuf);
3614 + return 1;
3615 + }
3616 + return 0;
3617 +}
3618 +
3619 +int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS)
3620 +{
3621 + const unsigned char *tmp = buf;
3622 + php_unserialize_data_t var_hash;
3623 + PHP_VAR_UNSERIALIZE_INIT(var_hash);
3624 + if(!php_var_unserialize(value, &tmp, buf + buf_len, &var_hash TSRMLS_CC)) {
3625 + PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
3626 + zval_dtor(*value);
3627 + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %ld bytes", (long)(tmp - buf), (long)buf_len);
3628 + (*value)->type = IS_NULL;
3629 + return 0;
3630 + }
3631 + PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
3632 + return 1;
3633 +}
3634 +/* }}} */
3635 +
3636 +/* {{{ check_op_array_integrity */
3637 +#if 0
3638 +static void check_op_array_integrity(zend_op_array* src)
3639 +{
3640 + int i, j;
3641 +
3642 + /* These sorts of checks really aren't particularly effective, but they
3643 + * can provide a welcome sanity check when debugging. Just don't enable
3644 + * for production use! */
3645 +
3646 + assert(src->refcount != NULL);
3647 + assert(src->opcodes != NULL);
3648 + assert(src->last > 0);
3649 +
3650 + for (i = 0; i < src->last; i++) {
3651 + zend_op* op = &src->opcodes[i];
3652 + znode* nodes[] = { &op->result, &op->op1, &op->op2 };
3653 + for (j = 0; j < 3; j++) {
3654 + assert(nodes[j]->op_type == IS_CONST ||
3655 + nodes[j]->op_type == IS_VAR ||
3656 + nodes[j]->op_type == IS_TMP_VAR ||
3657 + nodes[j]->op_type == IS_UNUSED);
3658 +
3659 + if (nodes[j]->op_type == IS_CONST) {
3660 + int type = nodes[j]->u.constant.type;
3661 + assert(type == IS_RESOURCE ||
3662 + type == IS_BOOL ||
3663 + type == IS_LONG ||
3664 + type == IS_DOUBLE ||
3665 + type == IS_NULL ||
3666 + type == IS_CONSTANT ||
3667 + type == IS_STRING ||
3668 + type == FLAG_IS_BC ||
3669 + type == IS_ARRAY ||
3670 + type == IS_CONSTANT_ARRAY ||
3671 + type == IS_OBJECT);
3672 + }
3673 + }
3674 + }
3675 +}
3676 +#endif
3677 +/* }}} */
3678 +
3679 +/* {{{ my_bitwise_copy_function */
3680 +static zend_function* my_bitwise_copy_function(zend_function* dst, zend_function* src, apc_context_t* ctxt TSRMLS_DC)
3681 +{
3682 + apc_pool* pool = ctxt->pool;
3683 +
3684 + assert(src != NULL);
3685 +
3686 + if (!dst) {
3687 + CHECK(dst = (zend_function*) apc_pool_alloc(pool, sizeof(src[0])));
3688 + }
3689 +
3690 + /* We only need to do a bitwise copy */
3691 + memcpy(dst, src, sizeof(src[0]));
3692 +
3693 + return dst;
3694 +}
3695 +/* }}} */
3696 +
3697 +/* {{{ my_copy_zval_ptr */
3698 +static zval** my_copy_zval_ptr(zval** dst, const zval** src, apc_context_t* ctxt TSRMLS_DC)
3699 +{
3700 + zval* dst_new;
3701 + apc_pool* pool = ctxt->pool;
3702 + int usegc = (ctxt->copy == APC_COPY_OUT_OPCODE) || (ctxt->copy == APC_COPY_OUT_USER);
3703 +
3704 + assert(src != NULL);
3705 +
3706 + if (!dst) {
3707 + CHECK(dst = (zval**) apc_pool_alloc(pool, sizeof(zval*)));
3708 + }
3709 +
3710 + if(usegc) {
3711 + ALLOC_ZVAL(dst[0]);
3712 + CHECK(dst[0]);
3713 + } else {
3714 + CHECK((dst[0] = (zval*) apc_pool_alloc(pool, sizeof(zval))));
3715 + }
3716 +
3717 + CHECK((dst_new = my_copy_zval(*dst, *src, ctxt TSRMLS_CC)));
3718 +
3719 + if(dst_new != *dst) {
3720 + if(usegc) {
3721 + FREE_ZVAL(dst[0]);
3722 + }
3723 + *dst = dst_new;
3724 + }
3725 +
3726 + return dst;
3727 +}
3728 +/* }}} */
3729 +
3730 +/* {{{ my_serialize_object */
3731 +static zval* my_serialize_object(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
3732 +{
3733 + smart_str buf = {0};
3734 + apc_pool* pool = ctxt->pool;
3735 + apc_serialize_t serialize = APC_SERIALIZER_NAME(php);
3736 + void *config = NULL;
3737 +
3738 + if(APCG(serializer)) { /* TODO: move to ctxt */
3739 + serialize = APCG(serializer)->serialize;
3740 + config = APCG(serializer)->config;
3741 + }
3742 +
3743 + if(serialize((unsigned char**)&buf.c, &buf.len, src, config TSRMLS_CC)) {
3744 + dst->type = src->type & ~IS_CONSTANT_INDEX;
3745 + dst->value.str.len = buf.len;
3746 + CHECK(dst->value.str.val = apc_pmemcpy(buf.c, (buf.len + 1), pool TSRMLS_CC));
3747 + }
3748 +
3749 + if(buf.c) smart_str_free(&buf);
3750 +
3751 + return dst;
3752 +}
3753 +/* }}} */
3754 +
3755 +/* {{{ my_unserialize_object */
3756 +static zval* my_unserialize_object(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
3757 +{
3758 + apc_unserialize_t unserialize = APC_UNSERIALIZER_NAME(php);
3759 + unsigned char *p = (unsigned char*)Z_STRVAL_P(src);
3760 + void *config = NULL;
3761 +
3762 + if(APCG(serializer)) { /* TODO: move to ctxt */
3763 + unserialize = APCG(serializer)->unserialize;
3764 + config = APCG(serializer)->config;
3765 + }
3766 +
3767 + if(unserialize(&dst, p, Z_STRLEN_P(src), config TSRMLS_CC)) {
3768 + return dst;
3769 + } else {
3770 + zval_dtor(dst);
3771 + dst->type = IS_NULL;
3772 + }
3773 + return dst;
3774 +}
3775 +/* }}} */
3776 +
3777 +static char *apc_string_pmemcpy(char *str, size_t len, apc_pool* pool TSRMLS_DC)
3778 +{
3779 +#ifdef ZEND_ENGINE_2_4
3780 +#ifndef ZTS
3781 + if (pool->type != APC_UNPOOL) {
3782 + char * ret = (char*)apc_new_interned_string((const char*)str, len TSRMLS_CC);
3783 + if (ret) {
3784 + return ret;
3785 + }
3786 + }
3787 +#endif
3788 +#endif
3789 + return apc_pmemcpy(str, len, pool TSRMLS_CC);
3790 +}
3791 +
3792 +/* {{{ my_copy_zval */
3793 +static APC_HOTSPOT zval* my_copy_zval(zval* dst, const zval* src, apc_context_t* ctxt TSRMLS_DC)
3794 +{
3795 + zval **tmp;
3796 + apc_pool* pool = ctxt->pool;
3797 +
3798 + assert(dst != NULL);
3799 + assert(src != NULL);
3800 +
3801 + memcpy(dst, src, sizeof(src[0]));
3802 +
3803 + if(APCG(copied_zvals).nTableSize) {
3804 + if(zend_hash_index_find(&APCG(copied_zvals), (ulong)s