r5:
[php5-apc.git] / apc_main.c
1 /*
2   +----------------------------------------------------------------------+
3   | APC                                                                  |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2006 The PHP Group                                     |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Daniel Cowgill <dcowgill@communityconnect.com>              |
16   |          Rasmus Lerdorf <rasmus@php.net>                             |
17   |          Arun C. Murthy <arunc@yahoo-inc.com>                        |
18   |          Gopal Vijayaraghavan <gopalv@yahoo-inc.com>                 |
19   +----------------------------------------------------------------------+
20
21    This software was contributed to PHP by Community Connect Inc. in 2002
22    and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
23    Future revisions and derivatives of this source code must acknowledge
24    Community Connect Inc. as the original contributor of this module by
25    leaving this note intact in the source code.
26
27    All other licensing and usage conditions are those of the PHP Group.
28
29  */
30
31 /* $Id: apc_main.c,v 3.103 2007/11/14 19:46:46 shire Exp $ */
32
33 #include "apc_php.h"
34 #include "apc_main.h"
35 #include "apc.h"
36 #include "apc_lock.h"
37 #include "apc_cache.h"
38 #include "apc_compile.h"
39 #include "apc_globals.h"
40 #include "apc_sma.h"
41 #include "apc_stack.h"
42 #include "apc_zend.h"
43 #include "SAPI.h"
44 #if PHP_API_VERSION <= 20020918
45 #if HAVE_APACHE
46 #ifdef APC_PHP4_STAT
47 #undef XtOffsetOf
48 #include "httpd.h"
49 #endif
50 #endif
51 #endif
52
53 /* {{{ module variables */
54
55 /* pointer to the original Zend engine compile_file function */
56 typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
57 static zend_compile_t *old_compile_file;
58
59 /* }}} */
60
61 /* {{{ get/set old_compile_file (to interact with other extensions that need the compile hook) */
62 static zend_compile_t* set_compile_hook(zend_compile_t *ptr)
63 {
64     zend_compile_t *retval = old_compile_file;
65
66     if (ptr != NULL) old_compile_file = ptr;
67     return retval;
68 }
69 /* }}} */
70
71 /* {{{ install_function */
72 static int install_function(apc_function_t fn TSRMLS_DC)
73 {
74     int status =
75         zend_hash_add(EG(function_table),
76                       fn.name,
77                       fn.name_len+1,
78                       apc_copy_function_for_execution(fn.function),
79                       sizeof(fn.function[0]),
80                       NULL);
81
82     if (status == FAILURE) {
83         /* apc_eprint("Cannot redeclare %s()", fn.name); */
84     }
85
86     return status;
87 }
88 /* }}} */
89
90 /* {{{ install_class */
91 static int install_class(apc_class_t cl TSRMLS_DC)
92 {
93     zend_class_entry* class_entry = cl.class_entry;
94     zend_class_entry* parent = NULL;
95     int status;
96 #ifdef ZEND_ENGINE_2
97     zend_class_entry** allocated_ce = NULL;
98 #endif
99
100
101     /* Special case for mangled names. Mangled names are unique to a file.
102      * There is no way two classes with the same mangled name will occur,
103      * unless a file is included twice. And if in case, a file is included
104      * twice, all mangled name conflicts can be ignored and the class redeclaration
105      * error may be deferred till runtime of the corresponding DECLARE_CLASS
106      * calls.
107      */
108
109     if(cl.name_len != 0 && cl.name[0] == '\0') {
110         if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) {
111             return SUCCESS;
112         }
113     }
114     
115 #ifdef ZEND_ENGINE_2    
116     /*
117      * XXX: We need to free this somewhere...
118      */
119     allocated_ce = apc_php_malloc(sizeof(zend_class_entry*));    
120
121     if(!allocated_ce) {
122         return FAILURE;
123     }
124
125     *allocated_ce = 
126 #endif        
127     class_entry =
128         apc_copy_class_entry_for_execution(cl.class_entry,
129                                            cl.is_derived);
130
131
132     /* restore parent class pointer for compile-time inheritance */
133     if (cl.parent_name != NULL) {
134 #ifdef ZEND_ENGINE_2    
135         zend_class_entry** parent_ptr = NULL;
136         /*
137          * zend_lookup_class has to be due to presence of __autoload, 
138          * just looking up the EG(class_table) is not enough in php5!
139          * Even more dangerously, thanks to __autoload and people using
140          * class names as filepaths for inclusion, this has to be case
141          * sensitive. zend_lookup_class automatically does a case_fold
142          * internally, but passes the case preserved version to __autoload.
143          * Aside: Do NOT pass *strlen(cl.parent_name)+1* because 
144          * zend_lookup_class does it internally anyway!
145          */
146         status = zend_lookup_class(cl.parent_name,
147                                     strlen(cl.parent_name),
148                                     &parent_ptr TSRMLS_CC);
149 #else
150         status = zend_hash_find(EG(class_table),
151                                 cl.parent_name,
152                                 strlen(cl.parent_name)+1,
153                                 (void**) &parent);
154 #endif
155         if (status == FAILURE) {
156             if(APCG(report_autofilter)) {
157                 apc_wprint("Dynamic inheritance detected for class %s", cl.name);
158             }
159             class_entry->parent = NULL;
160             return status;
161         }
162         else {
163 #ifdef ZEND_ENGINE_2            
164             parent = *parent_ptr;
165 #endif 
166             class_entry->parent = parent;
167 #ifdef ZEND_ENGINE_2
168             zend_do_inheritance(class_entry, parent TSRMLS_CC);
169 #else
170             zend_do_inheritance(class_entry, parent);
171 #endif
172         }
173
174
175     }
176
177 #ifdef ZEND_ENGINE_2                           
178     status = zend_hash_add(EG(class_table),
179                            cl.name,
180                            cl.name_len+1,
181                            allocated_ce,
182                            sizeof(zend_class_entry*),
183                            NULL);
184 #else                           
185     status = zend_hash_add(EG(class_table),
186                            cl.name,
187                            cl.name_len+1,
188                            class_entry,
189                            sizeof(zend_class_entry),
190                            NULL);
191 #endif                           
192
193     if (status == FAILURE) {
194         apc_eprint("Cannot redeclare class %s", cl.name);
195     } 
196     return status;
197 }
198 /* }}} */
199
200 /* {{{ uninstall_class */
201 static int uninstall_class(apc_class_t cl TSRMLS_DC)
202 {
203     int status;
204
205 #ifdef ZEND_ENGINE_2                           
206     status = zend_hash_del(EG(class_table),
207                            cl.name,
208                            cl.name_len+1);
209 #else                           
210     status = zend_hash_del(EG(class_table),
211                            cl.name,
212                            cl.name_len+1);
213 #endif                           
214     if (status == FAILURE) {
215         apc_eprint("Cannot delete class %s", cl.name);
216     } 
217     return status;
218 }
219 /* }}} */
220
221 /* {{{ compare_file_handles */
222 static int compare_file_handles(void* a, void* b)
223 {
224     zend_file_handle* fh1 = (zend_file_handle*)a;
225     zend_file_handle* fh2 = (zend_file_handle*)b;
226     return (fh1->type == fh2->type && 
227             fh1->filename == fh2->filename &&
228             fh1->opened_path == fh2->opened_path);
229 }
230 /* }}} */
231
232 /* {{{ cached_compile */
233 static zend_op_array* cached_compile(zend_file_handle* h,
234                                         int type TSRMLS_DC)
235 {
236     apc_cache_entry_t* cache_entry;
237     int i, ii;
238
239     cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack));
240     assert(cache_entry != NULL);
241
242     if (cache_entry->data.file.classes) {
243         for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
244             if(install_class(cache_entry->data.file.classes[i] TSRMLS_CC) == FAILURE) {
245                 goto default_compile;
246             }
247         }
248     }
249
250     if (cache_entry->data.file.functions) {
251         for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
252             install_function(cache_entry->data.file.functions[i] TSRMLS_CC);
253         }
254     }
255
256
257     return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array TSRMLS_CC);
258
259 default_compile:
260
261     if(APCG(report_autofilter)) {
262         apc_wprint("Autofiltering %s", h->opened_path);
263     }
264
265     if(cache_entry->data.file.classes) {
266         for(ii = 0; ii < i ; ii++) {
267             uninstall_class(cache_entry->data.file.classes[ii] TSRMLS_CC);
268         }
269     }
270     
271     apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */
272     
273     apc_cache_release(apc_cache, cache_entry);
274
275     /* cannot free up cache data yet, it maybe in use */
276     
277     zend_llist_del_element(&CG(open_files), h, compare_file_handles); /* XXX: kludge */
278     
279     h->type = ZEND_HANDLE_FILENAME;
280
281     return NULL;
282 }
283 /* }}} */
284
285 /* {{{ my_compile_file
286    Overrides zend_compile_file */
287 static zend_op_array* my_compile_file(zend_file_handle* h,
288                                                int type TSRMLS_DC)
289 {
290     apc_cache_key_t key;
291     apc_cache_entry_t* cache_entry;
292     zend_op_array* op_array;
293     int num_functions, num_classes, ret;
294     zend_op_array* alloc_op_array;
295     apc_function_t* alloc_functions;
296     apc_class_t* alloc_classes;
297     time_t t;
298     char *path;
299     size_t mem_size;
300
301     if (!APCG(enabled) || (apc_cache_busy(apc_cache) && !APCG(localcache))) {
302                 return old_compile_file(h, type TSRMLS_CC);
303         }
304
305     /* check our regular expression filters */
306     if (APCG(filters) && apc_compiled_filters) {
307         int ret = apc_regex_match_array(apc_compiled_filters, h->filename);
308         if(ret == APC_NEGATIVE_MATCH || (ret != APC_POSITIVE_MATCH && !APCG(cache_by_default))) {
309             return old_compile_file(h, type TSRMLS_CC);
310         }
311     } else if(!APCG(cache_by_default)) {
312         return old_compile_file(h, type TSRMLS_CC);
313     }
314
315 #if PHP_API_VERSION < 20041225
316 #if HAVE_APACHE && defined(APC_PHP4_STAT)
317     t = ((request_rec *)SG(server_context))->request_time;
318 #else 
319     t = time(0);
320 #endif
321 #else 
322     t = sapi_get_request_time(TSRMLS_C);
323 #endif
324
325 #ifdef __DEBUG_APC__
326     fprintf(stderr,"1. h->opened_path=[%s]  h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename);
327 #endif
328
329     /* try to create a cache key; if we fail, give up on caching */
330     if (!apc_cache_make_file_key(&key, h->filename, PG(include_path), t TSRMLS_CC)) {
331         return old_compile_file(h, type TSRMLS_CC);
332     }
333
334
335     if(!APCG(force_file_update)) {
336         if(APCG(localcache)) {
337             /* search for the file in the local cache */
338             cache_entry = apc_local_cache_find(APCG(lcache), key, t);
339         } else {
340             /* search for the file in the cache */
341             cache_entry = apc_cache_find(apc_cache, key, t);
342         }
343     } else {
344         cache_entry = NULL;
345     }
346
347     if (cache_entry != NULL) {
348         int dummy = 1;
349         if (h->opened_path == NULL) {
350             h->opened_path = estrdup(cache_entry->data.file.filename);
351         }
352         zend_hash_add(&EG(included_files), h->opened_path, strlen(h->opened_path)+1, (void *)&dummy, sizeof(int), NULL);
353         zend_llist_add_element(&CG(open_files), h); /* XXX kludge */
354         apc_stack_push(APCG(cache_stack), cache_entry);
355         op_array = cached_compile(h, type TSRMLS_CC);
356         if(op_array) {
357 #ifdef APC_FILEHITS
358             /* If the file comes from the cache, add it to the global request file list */
359             add_next_index_string(APCG(filehits), h->filename, 1);
360 #endif
361             return op_array;
362         }
363         if(APCG(report_autofilter)) {
364             apc_wprint("Recompiling %s", h->opened_path);
365         }
366         /* TODO: check what happens with EG(included_files) */
367     }
368     
369     if(apc_cache_busy(apc_cache) && APCG(localcache)) {
370         /* possibly local cache returned NULL because cache is busy */
371                 return old_compile_file(h, type TSRMLS_CC);
372         }
373
374     /* remember how many functions and classes existed before compilation */
375     num_functions = zend_hash_num_elements(CG(function_table));
376     num_classes   = zend_hash_num_elements(CG(class_table));
377     
378     /* compile the file using the default compile function */
379     op_array = old_compile_file(h, type TSRMLS_CC);
380     if (op_array == NULL) {
381         return NULL;
382     }
383     /*
384      * Basically this will cause a file only to be cached on a percentage 
385      * of the attempts.  This is to avoid cache slams when starting up a
386      * very busy server or when modifying files on a very busy live server.
387      * There is no point having many processes all trying to cache the same
388      * file at the same time.  By introducing a chance of being cached
389      * we theoretically cut the cache slam problem by the given percentage.
390      * For example if apc.slam_defense is set to 66 then 2/3 of the attempts
391      * to cache an uncached file will be ignored.
392      */
393     if(APCG(slam_defense)) {
394         if(APCG(slam_rand)==-1) {
395             APCG(slam_rand) = (int)(100.0*rand()/(RAND_MAX+1.0));
396         }
397         if(APCG(slam_rand) < APCG(slam_defense)) {
398             return op_array;
399         }
400     }
401
402     /* Make sure the mtime reflects the files last known mtime in the case of fpstat==0 */
403     if(key.type == APC_CACHE_KEY_FPFILE) {
404         apc_fileinfo_t fileinfo;
405         struct stat *tmp_buf = NULL;
406         if(!strcmp(SG(request_info).path_translated, h->filename)) {
407             tmp_buf = sapi_get_stat(TSRMLS_C);  /* Apache has already done this stat() for us */
408         }
409         if(tmp_buf) { 
410             fileinfo.st_buf = *tmp_buf;
411         } else {
412             if (apc_search_paths(h->filename, PG(include_path), &fileinfo) != 0) {
413 #ifdef __DEBUG_APC__
414                 fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated);
415 #endif
416                 return op_array;
417             }
418         }
419         key.mtime = fileinfo.st_buf.st_mtime;
420     }
421
422     HANDLE_BLOCK_INTERRUPTIONS();
423
424 #if NONBLOCKING_LOCK_AVAILABLE
425     if(APCG(write_lock)) {
426         if(!apc_cache_write_lock(apc_cache)) {
427             HANDLE_UNBLOCK_INTERRUPTIONS();
428             return op_array;
429         }
430     }
431 #endif
432
433     mem_size = 0;
434     APCG(mem_size_ptr) = &mem_size;
435     if(!(alloc_op_array = apc_copy_op_array(NULL, op_array, apc_sma_malloc, apc_sma_free TSRMLS_CC))) {
436         apc_cache_expunge(apc_cache,t);
437         apc_cache_expunge(apc_user_cache,t);
438         APCG(mem_size_ptr) = NULL;
439 #if NONBLOCKING_LOCK_AVAILABLE
440         if(APCG(write_lock)) {
441             apc_cache_write_unlock(apc_cache);
442         }
443 #endif
444         HANDLE_UNBLOCK_INTERRUPTIONS();
445         return op_array;
446     }
447     
448     if(!(alloc_functions = apc_copy_new_functions(num_functions, apc_sma_malloc, apc_sma_free TSRMLS_CC))) {
449         apc_free_op_array(alloc_op_array, apc_sma_free);
450         apc_cache_expunge(apc_cache,t);
451         apc_cache_expunge(apc_user_cache,t);
452         APCG(mem_size_ptr) = NULL;
453 #if NONBLOCKING_LOCK_AVAILABLE
454         if(APCG(write_lock)) {
455             apc_cache_write_unlock(apc_cache);
456         }
457 #endif
458         HANDLE_UNBLOCK_INTERRUPTIONS();
459         return op_array;
460     }
461     if(!(alloc_classes = apc_copy_new_classes(op_array, num_classes, apc_sma_malloc, apc_sma_free TSRMLS_CC))) {
462         apc_free_op_array(alloc_op_array, apc_sma_free);
463         apc_free_functions(alloc_functions, apc_sma_free);
464         apc_cache_expunge(apc_cache,t);
465         apc_cache_expunge(apc_user_cache,t);
466         APCG(mem_size_ptr) = NULL;
467 #if NONBLOCKING_LOCK_AVAILABLE
468         if(APCG(write_lock)) {
469             apc_cache_write_unlock(apc_cache);
470         }
471 #endif
472         HANDLE_UNBLOCK_INTERRUPTIONS();
473         return op_array;
474     }
475
476     path = h->opened_path;
477     if(!path) path=h->filename;
478
479 #ifdef __DEBUG_APC__
480     fprintf(stderr,"2. h->opened_path=[%s]  h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename);
481 #endif
482
483     if(!(cache_entry = apc_cache_make_file_entry(path, alloc_op_array, alloc_functions, alloc_classes))) {
484         apc_free_op_array(alloc_op_array, apc_sma_free);
485         apc_free_functions(alloc_functions, apc_sma_free);
486         apc_free_classes(alloc_classes, apc_sma_free);
487         apc_cache_expunge(apc_cache,t);
488         apc_cache_expunge(apc_user_cache,t);
489         APCG(mem_size_ptr) = NULL;
490 #if NONBLOCKING_LOCK_AVAILABLE
491         if(APCG(write_lock)) {
492             apc_cache_write_unlock(apc_cache);
493         }
494 #endif
495         HANDLE_UNBLOCK_INTERRUPTIONS();
496         return op_array;
497     }
498     APCG(mem_size_ptr) = NULL;
499     cache_entry->mem_size = mem_size;
500
501     if ((ret = apc_cache_insert(apc_cache, key, cache_entry, t)) != 1) {
502         apc_cache_free_entry(cache_entry);
503         if(ret==-1) {
504             apc_cache_expunge(apc_cache,t);
505             apc_cache_expunge(apc_user_cache,t);
506         }
507     }
508
509 #if NONBLOCKING_LOCK_AVAILABLE
510     if(APCG(write_lock)) {
511         apc_cache_write_unlock(apc_cache);
512     }
513 #endif
514     HANDLE_UNBLOCK_INTERRUPTIONS();
515
516     return op_array;
517 }
518 /* }}} */
519
520 /* {{{ module init and shutdown */
521
522 int apc_module_init(int module_number TSRMLS_DC)
523 {
524     /* apc initialization */
525 #if APC_MMAP
526     apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, APCG(mmap_file_mask));
527 #else
528     apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, NULL);
529 #endif
530     apc_cache = apc_cache_create(APCG(num_files_hint), APCG(gc_ttl), APCG(ttl));
531     apc_user_cache = apc_cache_create(APCG(user_entries_hint), APCG(gc_ttl), APCG(user_ttl));
532
533     apc_compiled_filters = apc_regex_compile_array(APCG(filters));
534
535     /* override compilation */
536     old_compile_file = zend_compile_file;
537     zend_compile_file = my_compile_file;
538     REGISTER_LONG_CONSTANT("\000apc_magic", (long)&set_compile_hook, CONST_PERSISTENT | CONST_CS);
539
540     APCG(initialized) = 1;
541     return 0;
542 }
543
544 int apc_module_shutdown(TSRMLS_D)
545 {
546     if (!APCG(initialized))
547         return 0;
548
549     /* restore compilation */
550     zend_compile_file = old_compile_file;
551
552     /* 
553      * In case we got interrupted by a SIGTERM or something else during execution
554      * we may have cache entries left on the stack that we need to check to make
555      * sure that any functions or classes these may have added to the global function
556      * and class tables are removed before we blow away the memory that hold them.
557      * 
558      * This is merely to remove memory leak warnings - as the process is terminated
559      * immediately after shutdown. The following while loop can be removed without
560      * affecting anything else.
561      */
562     while (apc_stack_size(APCG(cache_stack)) > 0) {
563         int i;
564         apc_cache_entry_t* cache_entry = (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
565         if (cache_entry->data.file.functions) {
566             for (i = 0; cache_entry->data.file.functions[i].function != NULL; i++) {
567                 zend_hash_del(EG(function_table),
568                     cache_entry->data.file.functions[i].name,
569                     cache_entry->data.file.functions[i].name_len+1);
570             }
571         }
572         if (cache_entry->data.file.classes) {
573             for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
574                 zend_hash_del(EG(class_table),
575                     cache_entry->data.file.classes[i].name,
576                     cache_entry->data.file.classes[i].name_len+1);
577             }
578         }
579         apc_cache_release(apc_cache, cache_entry);
580     }
581
582     apc_cache_destroy(apc_cache);
583     apc_cache_destroy(apc_user_cache);
584     apc_sma_cleanup();
585
586     APCG(initialized) = 0;
587     return 0;
588 }
589
590 /* }}} */
591
592 /* {{{ process init and shutdown */
593 int apc_process_init(int module_number TSRMLS_DC)
594 {
595     int minttl = (APCG(gc_ttl) >  APCG(ttl) ? APCG(ttl) : APCG(gc_ttl))/2;
596     int size = APCG(localcache_size);
597     if(APCG(initialized) && APCG(localcache)) {
598         /* TTL is 2 mins by default */
599         APCG(lcache) = apc_local_cache_create(apc_cache, size, minttl ? minttl : 120); 
600     }
601     return 0;
602 }
603
604 int apc_process_shutdown(TSRMLS_D)
605 {
606     if(APCG(initialized) && APCG(localcache) && APCG(lcache)) {
607         apc_local_cache_destroy(APCG(lcache));
608         APCG(lcache) = NULL;
609     }
610         return 0;
611 }
612 /* }}} */
613
614 /* {{{ request init and shutdown */
615
616 int apc_request_init(TSRMLS_D)
617 {
618     apc_stack_clear(APCG(cache_stack));
619     APCG(slam_rand) = -1;
620     APCG(copied_zvals) = NULL;
621
622 #ifdef APC_FILEHITS
623     ALLOC_INIT_ZVAL(APCG(filehits));
624     array_init(APCG(filehits));
625 #endif
626
627     return 0;
628 }
629
630 int apc_request_shutdown(TSRMLS_D)
631 {
632     apc_deactivate(TSRMLS_C);
633
634 #ifdef APC_FILEHITS
635     zval_ptr_dtor(&APCG(filehits));
636 #endif
637
638     return 0;
639 }
640
641 /* }}} */
642
643 /* {{{ apc_deactivate */
644 void apc_deactivate(TSRMLS_D)
645 {
646     /* The execution stack was unwound, which prevented us from decrementing
647      * the reference counts on active cache entries in `my_execute`.
648      */
649     while (apc_stack_size(APCG(cache_stack)) > 0) {
650         int i;
651         zend_class_entry* zce = NULL;
652         void ** centry = (void*)(&zce);
653 #ifdef ZEND_ENGINE_2
654         zend_class_entry** pzce = NULL;
655 #endif
656         
657         apc_cache_entry_t* cache_entry =
658             (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
659
660         if (cache_entry->data.file.classes) {
661             for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
662 #ifdef ZEND_ENGINE_2
663                 centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */
664 #endif
665                 if(zend_hash_find(EG(class_table), 
666                     cache_entry->data.file.classes[i].name,
667                     cache_entry->data.file.classes[i].name_len+1,
668                     (void**)centry) == FAILURE)
669                 {
670                     /* double inclusion of conditional classes ends up failing 
671                      * this lookup the second time around.
672                      */
673                     continue;
674                 }
675
676 #ifdef ZEND_ENGINE_2
677                 zce = *pzce;
678 #endif
679                 zend_hash_del(EG(class_table),
680                     cache_entry->data.file.classes[i].name,
681                     cache_entry->data.file.classes[i].name_len+1);
682                 
683                 apc_free_class_entry_after_execution(zce);
684             }
685         }
686         apc_cache_release(apc_cache, cache_entry);
687     }
688     if(APCG(localcache)) {
689         apc_local_cache_cleanup(APCG(lcache)); 
690     }
691 }
692 /* }}} */
693
694 /*
695  * Local variables:
696  * tab-width: 4
697  * c-basic-offset: 4
698  * End:
699  * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
700  * vim<600: expandtab sw=4 ts=4 sts=4
701  */