29#include "tsrm_win32.h"
35#define ACCEL_FILEMAP_NAME "ZendOPcache.SharedMemoryArea"
36#define ACCEL_MUTEX_NAME "ZendOPcache.SharedMemoryMutex"
37#define ACCEL_EVENT_SOURCE "Zend OPcache"
40#define ACCEL_BASE_POINTER_SIZE (2 * sizeof(void*))
42static HANDLE memfile =
NULL, memory_mutex =
NULL;
43static void *mapping_base;
45#define MAX_MAP_RETRIES 25
47static void zend_win_error_message(
int type,
char *
msg,
int err)
65 DeregisterEventSource(h);
72static char *create_name_with_username(
const char *
name,
size_t unique_id)
74 static char newname[
MAXPATHLEN + 1 + 32 + 1 + 20 + 1 + 32 +
sizeof(
"ffffffffffffffff")-1 + 1];
78 p = zend_mempcpy(
p, accel_uname_id, 32);
84 p +=
snprintf(
p,
sizeof(
"ffffffffffffffff"),
"%zx", unique_id) + 1;
100 ReleaseMutex(memory_mutex);
105 DWORD waitRes = WaitForSingleObject(memory_mutex, INFINITE);
107 if (waitRes == WAIT_FAILED) {
114 ReleaseMutex(memory_mutex);
117static int zend_shared_alloc_reattach(
size_t requested_size,
const char **error_in)
120 void *wanted_mapping_base;
121 MEMORY_BASIC_INFORMATION info;
122 void *execute_ex_base;
123 int execute_ex_moved;
126 if (mapping_base ==
NULL) {
127 err = GetLastError();
129 *error_in=
"read mapping base";
132 wanted_mapping_base = ((
void**)mapping_base)[0];
133 execute_ex_base = ((
void**)mapping_base)[1];
134 UnmapViewOfFile(mapping_base);
136 execute_ex_moved = (
void *)
execute_ex != execute_ex_base;
139 if (execute_ex_moved ||
140 VirtualQuery(wanted_mapping_base, &info,
sizeof(info)) == 0 ||
141 info.State != MEM_FREE ||
142 info.RegionSize < requested_size) {
143#if ENABLE_FILE_CACHE_FALLBACK
144 if (
ZCG(accel_directives).file_cache &&
ZCG(accel_directives).file_cache_fallback) {
145 size_t pre_size, wanted_mb_save;
147 wanted_mb_save = (size_t)wanted_mapping_base;
149 if (execute_ex_moved) {
150 err = ERROR_INVALID_ADDRESS;
151 zend_win_error_message(
ACCEL_LOG_WARNING,
"Opcode handlers are unusable due to ASLR (fall-back to file cache)",
err);
153 err = ERROR_INVALID_ADDRESS;
154 zend_win_error_message(
ACCEL_LOG_WARNING,
"Base address marks unusable memory region (fall-back to file cache)",
err);
160 if (mapping_base ==
NULL) {
161 err = GetLastError();
162 zend_win_error_message(
ACCEL_LOG_FATAL,
"Unable to reattach to opcache shared globals",
err);
170 if (execute_ex_moved) {
171 err = ERROR_INVALID_ADDRESS;
172 zend_win_error_message(
ACCEL_LOG_FATAL,
"Opcode handlers are unusable due to ASLR. Please setup opcache.file_cache and opcache.file_cache_fallback directives for more convenient Opcache usage",
err);
174 err = ERROR_INVALID_ADDRESS;
175 zend_win_error_message(
ACCEL_LOG_FATAL,
"Base address marks unusable memory region. Please setup opcache.file_cache and opcache.file_cache_fallback directives for more convenient Opcache usage",
err);
180 mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE, 0, 0, 0, wanted_mapping_base);
182 if (mapping_base ==
NULL) {
183 err = GetLastError();
184 if (
err == ERROR_INVALID_ADDRESS) {
192 if (!VirtualProtect(mapping_base, requested_size, PAGE_READWRITE, &old)) {
193 err = GetLastError();
204static int create_segments(
size_t requested_size,
zend_shared_segment ***shared_segments_p,
int *shared_segments_count,
const char **error_in)
209 void *default_mapping_base_set[] = { 0, 0 };
216 void *vista_mapping_base_set[] = { (
void *) 0x0000100000000000, (
void *) 0x0000200000000000, (
void *) 0x0000300000000000, (
void *) 0x0000700000000000, 0 };
217 DWORD size_high = (requested_size >> 32), size_low = (requested_size & 0xffffffff);
219 void *vista_mapping_base_set[] = { (
void *) 0x20000000, (
void *) 0x21000000, (
void *) 0x30000000, (
void *) 0x31000000, (
void *) 0x50000000, 0 };
220 DWORD size_high = 0, size_low = requested_size;
222 void **wanted_mapping_base = default_mapping_base_set;
229 memfile = OpenFileMapping(FILE_MAP_READ|FILE_MAP_WRITE|FILE_MAP_EXECUTE, 0, create_name_with_username(
ACCEL_FILEMAP_NAME, requested_size));
230 if (memfile ==
NULL) {
231 err = GetLastError();
235 ret = zend_shared_alloc_reattach(requested_size, error_in);
237 err = GetLastError();
239 CloseHandle(memfile);
245 Sleep(1000 * (map_retries + 1));
256 *error_in =
"OpenFileMapping";
261 *shared_segments_count = 1;
263 if (!*shared_segments_p) {
264 err = GetLastError();
267 *error_in =
"calloc";
271 (*shared_segments_p)[0] = shared_segment;
273 memfile = CreateFileMapping(INVALID_HANDLE_VALUE,
NULL, PAGE_EXECUTE_READWRITE | SEC_COMMIT, size_high, size_low,
275 if (memfile ==
NULL) {
276 err = GetLastError();
279 *error_in =
"CreateFileMapping";
286 if (!
ZCG(accel_directives).mmap_base || !*
ZCG(accel_directives).mmap_base) {
287 wanted_mapping_base = vista_mapping_base_set;
289 char *
s =
ZCG(accel_directives).mmap_base;
292 if (*
s ==
'0' && *(
s + 1) ==
'x') {
295 if (
sscanf(
s,
"%p", &default_mapping_base_set[0]) != 1) {
297 zend_win_error_message(
ACCEL_LOG_FATAL,
"Bad mapping address specified in opcache.mmap_base",
err);
303 shared_segment->
p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE, 0, 0, 0, *wanted_mapping_base);
304 if (*wanted_mapping_base ==
NULL) {
307 wanted_mapping_base++;
308 }
while (!mapping_base);
310 if (mapping_base ==
NULL) {
311 err = GetLastError();
313 zend_win_error_message(
ACCEL_LOG_FATAL,
"Unable to create view for file mapping",
err);
314 *error_in =
"MapViewOfFile";
319 if (!VirtualProtect(mapping_base, requested_size, PAGE_READWRITE, &old)) {
320 err = GetLastError();
325 ((
void**)mapping_base)[0] = mapping_base;
326 ((
void**)mapping_base)[1] = (
void*)
execute_ex;
341 UnmapViewOfFile(mapping_base);
344 CloseHandle(memfile);
347 CloseHandle(memory_mutex);
352static size_t segment_type_size(
void)
SAPI_API sapi_module_struct sapi_module
zend_accel_shared_globals * accel_shared_globals
struct _zend_accel_shared_globals zend_accel_shared_globals
sscanf(string $string, string $format, mixed &... $vars)
zend_ffi_ctype_name_buf buf
const zend_shared_memory_handlers zend_alloc_win32_handlers
#define ACCEL_EVENT_SOURCE
void zend_shared_alloc_lock_win32(void)
void zend_shared_alloc_unlock_win32(void)
#define ACCEL_BASE_POINTER_SIZE
void zend_shared_alloc_create_lock(void)
#define ACCEL_FILEMAP_NAME
PHP_WINUTIL_API char * php_win32_error_to_msg(HRESULT error)
PHP_WINUTIL_API void php_win32_error_msg_free(char *msg)
void zend_accel_error(int type, const char *format,...)
#define ACCEL_LOG_WARNING
ZEND_API void execute_ex(zend_execute_data *execute_data)
ZEND_EXT_API zend_smm_shared_globals * smm_shared_globals
struct _zend_shared_segment zend_shared_segment
#define ZEND_ALIGNED_SIZE(size)
#define SUCCESSFULLY_REATTACHED
#define ALLOC_FAIL_MAPPING
struct _zend_smm_shared_globals zend_smm_shared_globals
ZEND_API char zend_system_id[32]