/* {{{ apc_lookup_class_hook */ int apc_lookup_class_hook(char *name, int len, ulong hash, zend_class_entry ***ce) { apc_class_t *cl; apc_context_t ctxt = {0,}; TSRMLS_FETCH(); if(zend_is_compiling(TSRMLS_C)) { return FAILURE; } if(zend_hash_quick_find(APCG(lazy_class_table), name, len, hash, (void**)&cl) == FAILURE) { return FAILURE; } ctxt.pool = apc_pool_create(APC_UNPOOL, apc_php_malloc, apc_php_free, apc_sma_protect, apc_sma_unprotect TSRMLS_CC); ctxt.copy = APC_COPY_OUT_OPCODE; if(install_class(*cl, &ctxt, 0 TSRMLS_CC) == FAILURE) { apc_warning("apc_lookup_class_hook: could not install %s" TSRMLS_CC, name); return FAILURE; } if(zend_hash_quick_find(EG(class_table), name, len, hash, (void**)ce) == FAILURE) { apc_warning("apc_lookup_class_hook: known error trying to fetch class %s" TSRMLS_CC, name); return FAILURE; } return SUCCESS; }
void apc_unmap(apc_segment_t *segment) { if (munmap(segment->shmaddr, segment->size) < 0) { apc_warning("apc_unmap: munmap failed"); } #ifdef APC_MEMPROTECT if (segment->roaddr && munmap(segment->roaddr, segment->size) < 0) { apc_warning("apc_unmap: munmap failed"); } #endif }
/* {{{ apc_cache_make_context_ex */ PHP_APCU_API zend_bool apc_cache_make_context_ex(apc_context_t* context, apc_serializer_t* serializer, apc_malloc_t _malloc, apc_free_t _free, apc_protect_t _protect, apc_unprotect_t _unprotect, apc_pool_type pool_type, apc_copy_type copy_type, uint force_update) { /* attempt to create the pool */ context->pool = apc_pool_create( pool_type, _malloc, _free, _protect, _unprotect ); if (!context->pool) { apc_warning("Unable to allocate memory for pool."); return 0; } /* set context information */ context->serializer = serializer; context->copy = copy_type; context->force_update = force_update; /* set this to avoid memory errors */ memset(&context->copied, 0, sizeof(HashTable)); return 1; } /* }}} */
/* {{{ sma_debug_state(apc_sma_segment_t *segment, int canary_check, int verbose) * useful for debuging state of memory blocks and free list, and sanity checking */ static void sma_debug_state(void* shmaddr, int canary_check, int verbose TSRMLS_DC) { sma_header_t *header = (sma_header_t*)shmaddr; block_t *cur = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); block_t *prv = NULL; size_t avail; /* Verify free list */ if (verbose) apc_warning("Free List: " TSRMLS_CC); while(1) { if (verbose) apc_warning(" 0x%x[%d] (s%d)" TSRMLS_CC, cur, OFFSET(cur), cur->size); if (canary_check) CHECK_CANARY(cur); if (!cur->fnext) break; cur = BLOCKAT(cur->fnext); avail += cur->size; if (prv == cur) { apc_warning("Circular list detected!" TSRMLS_CC); assert(0); } if (prv && cur->fprev != OFFSET(prv)) { apc_warning("Previous pointer does not point to previous!" TSRMLS_CC); assert(0); } prv = cur; } assert(avail == header->avail); /* Verify each block */ if (verbose) apc_warning("Block List: " TSRMLS_CC); cur = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); while(1) { if(!cur->fnext) { if (verbose) apc_warning(" 0x%x[%d] (s%d) (u)" TSRMLS_CC, cur, OFFSET(cur), cur->size); } else { if (verbose) apc_warning(" 0x%x[%d] (s%d) (f)" TSRMLS_CC, cur, OFFSET(cur), cur->size); } if (canary_check) CHECK_CANARY(cur); if (!cur->size && !cur->fnext) break; if (!cur->size) { cur = BLOCKAT(OFFSET(cur) + ALIGNWORD(sizeof(block_t))); } else { cur = NEXT_SBLOCK(cur); } if (prv == cur) { apc_warning("Circular list detected!" TSRMLS_CC); assert(0); } prv = cur; } }
/* {{{ apc_register_signal * Set a handler for a previously installed signal and save so we can * callback when handled */ static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*)) { struct sigaction sa = {{0}}; apc_signal_entry_t p_sig = {0}; if (sigaction(signo, NULL, &sa) == 0) { if ((void*)sa.sa_handler == (void*)handler) { return SUCCESS; } if (sa.sa_handler != SIG_ERR && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { p_sig.signo = signo; p_sig.siginfo = ((sa.sa_flags & SA_SIGINFO) == SA_SIGINFO); p_sig.handler = (void *)sa.sa_handler; apc_signal_info.prev = (apc_signal_entry_t **)apc_erealloc(apc_signal_info.prev, (apc_signal_info.installed+1)*sizeof(apc_signal_entry_t *)); apc_signal_info.prev[apc_signal_info.installed] = (apc_signal_entry_t *)apc_emalloc(sizeof(apc_signal_entry_t)); *apc_signal_info.prev[apc_signal_info.installed++] = p_sig; } else { /* inherit flags and mask if already set */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_flags |= SA_SIGINFO; /* we'll use a siginfo handler */ #if defined(SA_ONESHOT) sa.sa_flags = SA_ONESHOT; #elif defined(SA_RESETHAND) sa.sa_flags = SA_RESETHAND; #endif } sa.sa_handler = (void*)handler; if (sigaction(signo, &sa, NULL) < 0) { apc_warning("Error installing apc signal handler for %d", signo); } return SUCCESS; } return FAILURE; } /* }}} */
/* {{{ install_class */ static int install_class(apc_class_t cl, apc_context_t* ctxt, int lazy TSRMLS_DC) { zend_class_entry* class_entry = cl.class_entry; zend_class_entry* parent = NULL; int status; /* Special case for mangled names. Mangled names are unique to a file. * There is no way two classes with the same mangled name will occur, * unless a file is included twice. And if in case, a file is included * twice, all mangled name conflicts can be ignored and the class redeclaration * error may be deferred till runtime of the corresponding DECLARE_CLASS * calls. */ if(cl.name_len != 0 && cl.name[0] == '\0') { if(zend_hash_exists(CG(class_table), cl.name, cl.name_len+1)) { return SUCCESS; } } if(lazy && cl.name_len != 0 && cl.name[0] != '\0') { status = zend_hash_add(APCG(lazy_class_table), cl.name, cl.name_len+1, &cl, sizeof(apc_class_t), NULL); if(status == FAILURE) { zend_error(E_ERROR, "Cannot redeclare class %s", cl.name); } return status; } class_entry = apc_copy_class_entry_for_execution(cl.class_entry, ctxt TSRMLS_CC); if (class_entry == NULL) return FAILURE; /* restore parent class pointer for compile-time inheritance */ if (cl.parent_name != NULL) { zend_class_entry** parent_ptr = NULL; /* * __autoload brings in the old issues with mixed inheritance. * When a statically inherited class triggers autoload, it runs * afoul of a potential require_once "parent.php" in the previous * line, which when executed provides the parent class, but right * now goes and hits __autoload which could fail. * * missing parent == re-compile. * * whether __autoload is enabled or not, because __autoload errors * cause php to die. * * Aside: Do NOT pass *strlen(cl.parent_name)+1* because * zend_lookup_class_ex does it internally anyway! */ status = zend_lookup_class_ex(cl.parent_name, strlen(cl.parent_name), #ifdef ZEND_ENGINE_2_4 NULL, #endif 0, &parent_ptr TSRMLS_CC); if (status == FAILURE) { if(APCG(report_autofilter)) { apc_warning("Dynamic inheritance detected for class %s" TSRMLS_CC, cl.name); } class_entry->parent = NULL; return status; } else { parent = *parent_ptr; class_entry->parent = parent; zend_do_inheritance(class_entry, parent TSRMLS_CC); } } status = zend_hash_add(EG(class_table), cl.name, cl.name_len+1, &class_entry, sizeof(zend_class_entry*), NULL); if (status == FAILURE) { apc_error("Cannot redeclare class %s" TSRMLS_CC, cl.name); } return status; }