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