2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
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.
27 All other licensing and usage conditions are those of the PHP Group.
31 /* $Id: apc_main.c,v 3.103 2007/11/14 19:46:46 shire Exp $ */
37 #include "apc_cache.h"
38 #include "apc_compile.h"
39 #include "apc_globals.h"
41 #include "apc_stack.h"
44 #if PHP_API_VERSION <= 20020918
53 /* {{{ module variables */
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;
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)
64 zend_compile_t *retval = old_compile_file;
66 if (ptr != NULL) old_compile_file = ptr;
71 /* {{{ install_function */
72 static int install_function(apc_function_t fn TSRMLS_DC)
75 zend_hash_add(EG(function_table),
78 apc_copy_function_for_execution(fn.function),
79 sizeof(fn.function[0]),
82 if (status == FAILURE) {
83 /* apc_eprint("Cannot redeclare %s()", fn.name); */
90 /* {{{ install_class */
91 static int install_class(apc_class_t cl TSRMLS_DC)
93 zend_class_entry* class_entry = cl.class_entry;
94 zend_class_entry* parent = NULL;
97 zend_class_entry** allocated_ce = NULL;
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
109 if(cl.name_len != 0 && cl.name[0] == '\0') {
110 if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) {
117 * XXX: We need to free this somewhere...
119 allocated_ce = apc_php_malloc(sizeof(zend_class_entry*));
128 apc_copy_class_entry_for_execution(cl.class_entry,
132 /* restore parent class pointer for compile-time inheritance */
133 if (cl.parent_name != NULL) {
135 zend_class_entry** parent_ptr = NULL;
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!
146 status = zend_lookup_class(cl.parent_name,
147 strlen(cl.parent_name),
148 &parent_ptr TSRMLS_CC);
150 status = zend_hash_find(EG(class_table),
152 strlen(cl.parent_name)+1,
155 if (status == FAILURE) {
156 if(APCG(report_autofilter)) {
157 apc_wprint("Dynamic inheritance detected for class %s", cl.name);
159 class_entry->parent = NULL;
164 parent = *parent_ptr;
166 class_entry->parent = parent;
168 zend_do_inheritance(class_entry, parent TSRMLS_CC);
170 zend_do_inheritance(class_entry, parent);
178 status = zend_hash_add(EG(class_table),
182 sizeof(zend_class_entry*),
185 status = zend_hash_add(EG(class_table),
189 sizeof(zend_class_entry),
193 if (status == FAILURE) {
194 apc_eprint("Cannot redeclare class %s", cl.name);
200 /* {{{ uninstall_class */
201 static int uninstall_class(apc_class_t cl TSRMLS_DC)
206 status = zend_hash_del(EG(class_table),
210 status = zend_hash_del(EG(class_table),
214 if (status == FAILURE) {
215 apc_eprint("Cannot delete class %s", cl.name);
221 /* {{{ compare_file_handles */
222 static int compare_file_handles(void* a, void* b)
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);
232 /* {{{ cached_compile */
233 static zend_op_array* cached_compile(zend_file_handle* h,
236 apc_cache_entry_t* cache_entry;
239 cache_entry = (apc_cache_entry_t*) apc_stack_top(APCG(cache_stack));
240 assert(cache_entry != NULL);
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;
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);
257 return apc_copy_op_array_for_execution(NULL, cache_entry->data.file.op_array TSRMLS_CC);
261 if(APCG(report_autofilter)) {
262 apc_wprint("Autofiltering %s", h->opened_path);
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);
271 apc_stack_pop(APCG(cache_stack)); /* pop out cache_entry */
273 apc_cache_release(apc_cache, cache_entry);
275 /* cannot free up cache data yet, it maybe in use */
277 zend_llist_del_element(&CG(open_files), h, compare_file_handles); /* XXX: kludge */
279 h->type = ZEND_HANDLE_FILENAME;
285 /* {{{ my_compile_file
286 Overrides zend_compile_file */
287 static zend_op_array* my_compile_file(zend_file_handle* h,
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;
301 if (!APCG(enabled) || (apc_cache_busy(apc_cache) && !APCG(localcache))) {
302 return old_compile_file(h, type TSRMLS_CC);
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);
311 } else if(!APCG(cache_by_default)) {
312 return old_compile_file(h, type TSRMLS_CC);
315 #if PHP_API_VERSION < 20041225
316 #if HAVE_APACHE && defined(APC_PHP4_STAT)
317 t = ((request_rec *)SG(server_context))->request_time;
322 t = sapi_get_request_time(TSRMLS_C);
326 fprintf(stderr,"1. h->opened_path=[%s] h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename);
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);
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);
340 /* search for the file in the cache */
341 cache_entry = apc_cache_find(apc_cache, key, t);
347 if (cache_entry != NULL) {
349 if (h->opened_path == NULL) {
350 h->opened_path = estrdup(cache_entry->data.file.filename);
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);
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);
363 if(APCG(report_autofilter)) {
364 apc_wprint("Recompiling %s", h->opened_path);
366 /* TODO: check what happens with EG(included_files) */
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);
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));
378 /* compile the file using the default compile function */
379 op_array = old_compile_file(h, type TSRMLS_CC);
380 if (op_array == NULL) {
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.
393 if(APCG(slam_defense)) {
394 if(APCG(slam_rand)==-1) {
395 APCG(slam_rand) = (int)(100.0*rand()/(RAND_MAX+1.0));
397 if(APCG(slam_rand) < APCG(slam_defense)) {
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 */
410 fileinfo.st_buf = *tmp_buf;
412 if (apc_search_paths(h->filename, PG(include_path), &fileinfo) != 0) {
414 fprintf(stderr,"Stat failed %s - bailing (%s) (%d)\n",filename,SG(request_info).path_translated);
419 key.mtime = fileinfo.st_buf.st_mtime;
422 HANDLE_BLOCK_INTERRUPTIONS();
424 #if NONBLOCKING_LOCK_AVAILABLE
425 if(APCG(write_lock)) {
426 if(!apc_cache_write_lock(apc_cache)) {
427 HANDLE_UNBLOCK_INTERRUPTIONS();
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);
444 HANDLE_UNBLOCK_INTERRUPTIONS();
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);
458 HANDLE_UNBLOCK_INTERRUPTIONS();
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);
472 HANDLE_UNBLOCK_INTERRUPTIONS();
476 path = h->opened_path;
477 if(!path) path=h->filename;
480 fprintf(stderr,"2. h->opened_path=[%s] h->filename=[%s]\n", h->opened_path?h->opened_path:"null",h->filename);
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);
495 HANDLE_UNBLOCK_INTERRUPTIONS();
498 APCG(mem_size_ptr) = NULL;
499 cache_entry->mem_size = mem_size;
501 if ((ret = apc_cache_insert(apc_cache, key, cache_entry, t)) != 1) {
502 apc_cache_free_entry(cache_entry);
504 apc_cache_expunge(apc_cache,t);
505 apc_cache_expunge(apc_user_cache,t);
509 #if NONBLOCKING_LOCK_AVAILABLE
510 if(APCG(write_lock)) {
511 apc_cache_write_unlock(apc_cache);
514 HANDLE_UNBLOCK_INTERRUPTIONS();
520 /* {{{ module init and shutdown */
522 int apc_module_init(int module_number TSRMLS_DC)
524 /* apc initialization */
526 apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, APCG(mmap_file_mask));
528 apc_sma_init(APCG(shm_segments), APCG(shm_size)*1024*1024, NULL);
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));
533 apc_compiled_filters = apc_regex_compile_array(APCG(filters));
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);
540 APCG(initialized) = 1;
544 int apc_module_shutdown(TSRMLS_D)
546 if (!APCG(initialized))
549 /* restore compilation */
550 zend_compile_file = old_compile_file;
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.
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.
562 while (apc_stack_size(APCG(cache_stack)) > 0) {
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);
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);
579 apc_cache_release(apc_cache, cache_entry);
582 apc_cache_destroy(apc_cache);
583 apc_cache_destroy(apc_user_cache);
586 APCG(initialized) = 0;
592 /* {{{ process init and shutdown */
593 int apc_process_init(int module_number TSRMLS_DC)
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);
604 int apc_process_shutdown(TSRMLS_D)
606 if(APCG(initialized) && APCG(localcache) && APCG(lcache)) {
607 apc_local_cache_destroy(APCG(lcache));
614 /* {{{ request init and shutdown */
616 int apc_request_init(TSRMLS_D)
618 apc_stack_clear(APCG(cache_stack));
619 APCG(slam_rand) = -1;
620 APCG(copied_zvals) = NULL;
623 ALLOC_INIT_ZVAL(APCG(filehits));
624 array_init(APCG(filehits));
630 int apc_request_shutdown(TSRMLS_D)
632 apc_deactivate(TSRMLS_C);
635 zval_ptr_dtor(&APCG(filehits));
643 /* {{{ apc_deactivate */
644 void apc_deactivate(TSRMLS_D)
646 /* The execution stack was unwound, which prevented us from decrementing
647 * the reference counts on active cache entries in `my_execute`.
649 while (apc_stack_size(APCG(cache_stack)) > 0) {
651 zend_class_entry* zce = NULL;
652 void ** centry = (void*)(&zce);
654 zend_class_entry** pzce = NULL;
657 apc_cache_entry_t* cache_entry =
658 (apc_cache_entry_t*) apc_stack_pop(APCG(cache_stack));
660 if (cache_entry->data.file.classes) {
661 for (i = 0; cache_entry->data.file.classes[i].class_entry != NULL; i++) {
663 centry = (void**)&pzce; /* a triple indirection to get zend_class_entry*** */
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)
670 /* double inclusion of conditional classes ends up failing
671 * this lookup the second time around.
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);
683 apc_free_class_entry_after_execution(zce);
686 apc_cache_release(apc_cache, cache_entry);
688 if(APCG(localcache)) {
689 apc_local_cache_cleanup(APCG(lcache));
699 * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
700 * vim<600: expandtab sw=4 ts=4 sts=4