void zend_accel_hash_init(zend_accel_hash *accel_hash, zend_uint hash_size) { uint i; for (i=0; i<num_prime_numbers; i++) { if (hash_size <= prime_numbers[i]) { hash_size = prime_numbers[i]; break; } } accel_hash->num_entries = 0; accel_hash->num_direct_entries = 0; accel_hash->max_num_entries = hash_size; /* set up hash pointers table */ accel_hash->hash_table = zend_shared_alloc(sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries); if (!accel_hash->hash_table) { zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); } /* set up hash values table */ accel_hash->hash_entries = zend_shared_alloc(sizeof(zend_accel_hash_entry)*accel_hash->max_num_entries); if (!accel_hash->hash_entries) { zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); } memset(accel_hash->hash_table, 0, sizeof(zend_accel_hash_entry *)*accel_hash->max_num_entries); }
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle) { zend_string *full_path = file_handle->opened_path; int fd; char *filename; zend_persistent_script *script; zend_file_cache_metainfo info; zend_accel_hash_entry *bucket; void *mem, *checkpoint, *buf; int cache_it = 1; if (!full_path) { return NULL; } filename = zend_file_cache_get_bin_file_path(full_path); fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { efree(filename); return NULL; } if (zend_file_cache_flock(fd, LOCK_SH) != 0) { close(fd); efree(filename); return NULL; } if (read(fd, &info, sizeof(info)) != sizeof(info)) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); unlink(filename); efree(filename); return NULL; } /* verify header */ if (memcmp(info.magic, "OPCACHE", 8) != 0) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong header)\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); unlink(filename); efree(filename); return NULL; } if (memcmp(info.system_id, ZCG(system_id), 32) != 0) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong \"system_id\")\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); unlink(filename); efree(filename); return NULL; } /* verify timestamp */ if (ZCG(accel_directives).validate_timestamps && zend_get_file_handle_timestamp(file_handle, NULL) != info.timestamp) { if (zend_file_cache_flock(fd, LOCK_UN) != 0) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename); } close(fd); unlink(filename); efree(filename); return NULL; } checkpoint = zend_arena_checkpoint(CG(arena)); #ifdef __SSE2__ /* Align to 64-byte boundary */ mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size + 64); mem = (void*)(((zend_uintptr_t)mem + 63L) & ~63L); #else mem = zend_arena_alloc(&CG(arena), info.mem_size + info.str_size); #endif if (read(fd, mem, info.mem_size + info.str_size) != (ssize_t)(info.mem_size + info.str_size)) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s'\n", filename); zend_file_cache_flock(fd, LOCK_UN); close(fd); unlink(filename); zend_arena_release(&CG(arena), checkpoint); efree(filename); return NULL; } if (zend_file_cache_flock(fd, LOCK_UN) != 0) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot unlock file '%s'\n", filename); } close(fd); /* verify checksum */ if (ZCG(accel_directives).file_cache_consistency_checks && zend_adler32(ADLER32_INIT, mem, info.mem_size + info.str_size) != info.checksum) { zend_accel_error(ACCEL_LOG_WARNING, "corrupted file '%s'\n", filename); unlink(filename); zend_arena_release(&CG(arena), checkpoint); efree(filename); return NULL; } if (!ZCG(accel_directives).file_cache_only && !ZCSG(restart_in_progress) && accelerator_shm_read_lock() == SUCCESS) { /* exclusive lock */ zend_shared_alloc_lock(); /* Check if we still need to put the file into the cache (may be it was * already stored by another process. This final check is done under * exclusive lock) */ bucket = zend_accel_hash_find_entry(&ZCSG(hash), full_path); if (bucket) { script = (zend_persistent_script *)bucket->data; if (!script->corrupted) { zend_shared_alloc_unlock(); zend_arena_release(&CG(arena), checkpoint); efree(filename); return script; } } if (zend_accel_hash_is_full(&ZCSG(hash))) { zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!"); ZSMMG(memory_exhausted) = 1; zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH); zend_shared_alloc_unlock(); goto use_process_mem; } #ifdef __SSE2__ /* Align to 64-byte boundary */ buf = zend_shared_alloc(info.mem_size + 64); buf = (void*)(((zend_uintptr_t)buf + 63L) & ~63L); #else buf = zend_shared_alloc(info.mem_size); #endif if (!buf) { zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM); zend_shared_alloc_unlock(); goto use_process_mem; } memcpy(buf, mem, info.mem_size); } else { use_process_mem: buf = mem; cache_it = 0; } ZCG(mem) = ((char*)mem + info.mem_size); script = (zend_persistent_script*)((char*)buf + info.script_offset); script->corrupted = !cache_it; /* used to check if script restored to SHM or process memory */ zend_file_cache_unserialize(script, buf); script->corrupted = 0; if (cache_it) { script->dynamic_members.checksum = zend_accel_script_checksum(script); script->dynamic_members.last_used = ZCG(request_time); zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(script->script.filename), ZSTR_LEN(script->script.filename), 0, script); zend_shared_alloc_unlock(); zend_arena_release(&CG(arena), checkpoint); } efree(filename); return script; }
int zend_shared_alloc_startup(size_t requested_size) { zend_shared_segment **tmp_shared_segments; size_t shared_segments_array_size; zend_smm_shared_globals tmp_shared_globals, *p_tmp_shared_globals; char *error_in = NULL; const zend_shared_memory_handler_entry *he; int res = ALLOC_FAILURE; /* shared_free must be valid before we call zend_shared_alloc() * - make it temporarily point to a local variable */ smm_shared_globals = &tmp_shared_globals; ZSMMG(shared_free) = requested_size; /* goes to tmp_shared_globals.shared_free */ zend_shared_alloc_create_lock(); if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) { char *model = ZCG(accel_directives).memory_model; /* "cgi" is really "shm"... */ if (strncmp(ZCG(accel_directives).memory_model, "cgi", sizeof("cgi")) == 0) { model = "shm"; } for (he = handler_table; he->name; he++) { if (strcmp(model, he->name) == 0) { res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in); if (res) { /* this model works! */ } break; } } } if (res == FAILED_REATTACHED) { smm_shared_globals = NULL; return res; } #if ENABLE_FILE_CACHE_FALLBACK if (ALLOC_FALLBACK == res) { return ALLOC_FALLBACK; } #endif if (!g_shared_alloc_handler) { /* try memory handlers in order */ for (he = handler_table; he->name; he++) { res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in); if (res) { /* this model works! */ break; } } } if (!g_shared_alloc_handler) { no_memory_bailout(requested_size, error_in); return ALLOC_FAILURE; } if (res == SUCCESSFULLY_REATTACHED) { return res; } #if ENABLE_FILE_CACHE_FALLBACK if (ALLOC_FALLBACK == res) { return ALLOC_FALLBACK; } #endif shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)(); /* move shared_segments and shared_free to shared memory */ ZCG(locked) = 1; /* no need to perform a real lock at this point */ p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals)); if (!p_tmp_shared_globals) { zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); return ALLOC_FAILURE;; } tmp_shared_segments = zend_shared_alloc(shared_segments_array_size + ZSMMG(shared_segments_count) * sizeof(void *)); if (!tmp_shared_segments) { zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); return ALLOC_FAILURE;; } copy_shared_segments(tmp_shared_segments, ZSMMG(shared_segments)[0], ZSMMG(shared_segments_count), S_H(segment_type_size)()); *p_tmp_shared_globals = tmp_shared_globals; smm_shared_globals = p_tmp_shared_globals; free(ZSMMG(shared_segments)); ZSMMG(shared_segments) = tmp_shared_segments; ZSMMG(shared_memory_state).positions = (int *)zend_shared_alloc(sizeof(int) * ZSMMG(shared_segments_count)); if (!ZSMMG(shared_memory_state).positions) { zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!"); return ALLOC_FAILURE;; } ZCG(locked) = 0; return res; }