This source file includes following definitions.
- zend_win_error_message
- accel_gen_system_id
- create_name_with_username
- get_mmap_base_file
- zend_shared_alloc_create_lock
- zend_shared_alloc_lock_win32
- zend_shared_alloc_unlock_win32
- zend_shared_alloc_reattach
- create_segments
- detach_segment
- segment_type_size
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "ZendAccelerator.h"
23 #include "zend_shared_alloc.h"
24 #include "zend_accelerator_util_funcs.h"
25 #include <winbase.h>
26 #include <process.h>
27 #include <LMCONS.H>
28
29 #include "main/php.h"
30 #include "ext/standard/md5.h"
31
32 #define ACCEL_FILEMAP_NAME "ZendOPcache.SharedMemoryArea"
33 #define ACCEL_MUTEX_NAME "ZendOPcache.SharedMemoryMutex"
34 #define ACCEL_FILEMAP_BASE_DEFAULT 0x01000000
35 #define ACCEL_FILEMAP_BASE "ZendOPcache.MemoryBase"
36 #define ACCEL_EVENT_SOURCE "Zend OPcache"
37
38 static HANDLE memfile = NULL, memory_mutex = NULL;
39 static void *mapping_base;
40
41 #define MAX_MAP_RETRIES 25
42
43 static void zend_win_error_message(int type, char *msg, int err)
44 {
45 LPVOID lpMsgBuf;
46 HANDLE h;
47 char *ev_msgs[2];
48
49 FormatMessage(
50 FORMAT_MESSAGE_ALLOCATE_BUFFER |
51 FORMAT_MESSAGE_FROM_SYSTEM |
52 FORMAT_MESSAGE_IGNORE_INSERTS,
53 NULL,
54 err,
55 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
56 (LPTSTR) &lpMsgBuf,
57 0,
58 NULL
59 );
60
61 h = RegisterEventSource(NULL, TEXT(ACCEL_EVENT_SOURCE));
62 ev_msgs[0] = msg;
63 ev_msgs[1] = lpMsgBuf;
64 ReportEvent(h,
65 EVENTLOG_ERROR_TYPE,
66 0,
67 err,
68 NULL,
69 2,
70 0,
71 ev_msgs,
72 NULL);
73 DeregisterEventSource(h);
74
75 LocalFree( lpMsgBuf );
76
77 zend_accel_error(type, msg);
78 }
79
80
81
82 #define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_CHAR) ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
83 static char *accel_gen_system_id(void)
84 {
85 PHP_MD5_CTX context;
86 unsigned char digest[16], c;
87 int i;
88 static char md5str[32];
89 static zend_bool done = 0;
90
91 if (done) {
92 return md5str;
93 }
94
95 PHP_MD5Init(&context);
96 PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
97 PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
98 PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
99 if (strstr(PHP_VERSION, "-dev") != 0) {
100
101 PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
102 PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
103 }
104 PHP_MD5Final(digest, &context);
105 for (i = 0; i < 16; i++) {
106 c = digest[i] >> 4;
107 c = (c <= 9) ? c + '0' : c - 10 + 'a';
108 md5str[i * 2] = c;
109 c = digest[i] & 0x0f;
110 c = (c <= 9) ? c + '0' : c - 10 + 'a';
111 md5str[(i * 2) + 1] = c;
112 }
113
114 done = 1;
115
116 return md5str;
117 }
118
119 static char *create_name_with_username(char *name)
120 {
121 static char newname[MAXPATHLEN + UNLEN + 4 + 1 + 32];
122 char uname[UNLEN + 1];
123 DWORD unsize = UNLEN;
124
125 GetUserName(uname, &unsize);
126 snprintf(newname, sizeof(newname) - 1, "%s@%s@%.32s", name, uname, accel_gen_system_id());
127 return newname;
128 }
129
130 static char *get_mmap_base_file(void)
131 {
132 static char windir[MAXPATHLEN+UNLEN + 3 + sizeof("\\\\@") + 1 + 32];
133 char uname[UNLEN + 1];
134 DWORD unsize = UNLEN;
135 int l;
136
137 GetTempPath(MAXPATHLEN, windir);
138 GetUserName(uname, &unsize);
139 l = strlen(windir);
140 snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s@%.32s", ACCEL_FILEMAP_BASE, uname, accel_gen_system_id());
141 return windir;
142 }
143
144 void zend_shared_alloc_create_lock(void)
145 {
146 memory_mutex = CreateMutex(NULL, FALSE, create_name_with_username(ACCEL_MUTEX_NAME));
147 if (!memory_mutex) {
148 zend_accel_error(ACCEL_LOG_FATAL, "Cannot create mutex");
149 return;
150 }
151 ReleaseMutex(memory_mutex);
152 }
153
154 void zend_shared_alloc_lock_win32(void)
155 {
156 DWORD waitRes = WaitForSingleObject(memory_mutex, INFINITE);
157
158 if (waitRes == WAIT_FAILED) {
159 zend_accel_error(ACCEL_LOG_ERROR, "Cannot lock mutex");
160 }
161 }
162
163 void zend_shared_alloc_unlock_win32(void)
164 {
165 ReleaseMutex(memory_mutex);
166 }
167
168 static int zend_shared_alloc_reattach(size_t requested_size, char **error_in)
169 {
170 int err;
171 void *wanted_mapping_base;
172 char *mmap_base_file = get_mmap_base_file();
173 FILE *fp = fopen(mmap_base_file, "r");
174 MEMORY_BASIC_INFORMATION info;
175
176 err = GetLastError();
177 if (!fp) {
178 zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err);
179 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open base address file", err);
180 *error_in="fopen";
181 return ALLOC_FAILURE;
182 }
183 if (!fscanf(fp, "%p", &wanted_mapping_base)) {
184 err = GetLastError();
185 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to read base address", err);
186 *error_in="read mapping base";
187 fclose(fp);
188 return ALLOC_FAILURE;
189 }
190 fclose(fp);
191
192
193 if (VirtualQuery(wanted_mapping_base, &info, sizeof(info)) == 0 ||
194 info.State != MEM_FREE ||
195 info.RegionSize < requested_size) {
196 err = ERROR_INVALID_ADDRESS;
197 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err);
198 return ALLOC_FAILURE;
199 }
200
201 mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base);
202 err = GetLastError();
203
204 if (mapping_base == NULL) {
205 if (err == ERROR_INVALID_ADDRESS) {
206 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to reattach to base address", err);
207 return ALLOC_FAILURE;
208 }
209 return ALLOC_FAIL_MAPPING;
210 }
211 smm_shared_globals = (zend_smm_shared_globals *) mapping_base;
212
213 return SUCCESSFULLY_REATTACHED;
214 }
215
216 static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
217 {
218 int err, ret;
219 zend_shared_segment *shared_segment;
220 int map_retries = 0;
221 void *default_mapping_base_set[] = { 0, 0 };
222
223
224
225
226
227 #if defined(_WIN64)
228 void *vista_mapping_base_set[] = { (void *) 0x0000100000000000, (void *) 0x0000200000000000, (void *) 0x0000300000000000, (void *) 0x0000700000000000, 0 };
229 #else
230 void *vista_mapping_base_set[] = { (void *) 0x20000000, (void *) 0x21000000, (void *) 0x30000000, (void *) 0x31000000, (void *) 0x50000000, 0 };
231 #endif
232 void **wanted_mapping_base = default_mapping_base_set;
233 TSRMLS_FETCH();
234
235 zend_shared_alloc_lock_win32();
236
237
238
239 do {
240 memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME));
241 err = GetLastError();
242 if (memfile == NULL) {
243 break;
244 }
245
246 ret = zend_shared_alloc_reattach(requested_size, error_in);
247 err = GetLastError();
248 if (ret == ALLOC_FAIL_MAPPING) {
249
250 CloseHandle(memfile);
251 memfile = NULL;
252 if (++map_retries >= MAX_MAP_RETRIES) {
253 break;
254 }
255 zend_shared_alloc_unlock_win32();
256 Sleep(1000 * (map_retries + 1));
257 zend_shared_alloc_lock_win32();
258 } else {
259 zend_shared_alloc_unlock_win32();
260 return ret;
261 }
262 } while (1);
263
264 if (map_retries == MAX_MAP_RETRIES) {
265 zend_shared_alloc_unlock_win32();
266 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to open file mapping", err);
267 *error_in = "OpenFileMapping";
268 return ALLOC_FAILURE;
269 }
270
271
272 *shared_segments_count = 1;
273 *shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment)+sizeof(void *));
274 if (!*shared_segments_p) {
275 zend_shared_alloc_unlock_win32();
276 zend_win_error_message(ACCEL_LOG_FATAL, "calloc() failed", GetLastError());
277 *error_in = "calloc";
278 return ALLOC_FAILURE;
279 }
280 shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *));
281 (*shared_segments_p)[0] = shared_segment;
282
283 memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, requested_size,
284 create_name_with_username(ACCEL_FILEMAP_NAME));
285 err = GetLastError();
286 if (memfile == NULL) {
287 zend_shared_alloc_unlock_win32();
288 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to create file mapping", err);
289 *error_in = "CreateFileMapping";
290 return ALLOC_FAILURE;
291 }
292
293
294
295
296 if (!ZCG(accel_directives).mmap_base || !*ZCG(accel_directives).mmap_base) {
297 do {
298 OSVERSIONINFOEX osvi;
299 SYSTEM_INFO si;
300
301 ZeroMemory(&si, sizeof(SYSTEM_INFO));
302 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
303
304 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
305
306 if (! GetVersionEx ((OSVERSIONINFO *) &osvi)) {
307 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
308 if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
309 break;
310 }
311 }
312
313 GetSystemInfo(&si);
314
315
316 if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 6) {
317 wanted_mapping_base = vista_mapping_base_set;
318 }
319 } while (0);
320 } else {
321 char *s = ZCG(accel_directives).mmap_base;
322
323
324 if (*s == '0' && *(s + 1) == 'x') {
325 s += 2;
326 }
327 if (sscanf(s, "%p", &default_mapping_base_set[0]) != 1) {
328 zend_shared_alloc_unlock_win32();
329 zend_win_error_message(ACCEL_LOG_FATAL, "Bad mapping address specified in opcache.mmap_base", err);
330 return ALLOC_FAILURE;
331 }
332 }
333
334 do {
335 shared_segment->p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base);
336 if (*wanted_mapping_base == NULL) {
337 break;
338 }
339 wanted_mapping_base++;
340 } while (!mapping_base);
341
342 err = GetLastError();
343 if (mapping_base == NULL) {
344 zend_shared_alloc_unlock_win32();
345 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to create view for file mapping", err);
346 *error_in = "MapViewOfFile";
347 return ALLOC_FAILURE;
348 } else {
349 char *mmap_base_file = get_mmap_base_file();
350 FILE *fp = fopen(mmap_base_file, "w");
351 err = GetLastError();
352 if (!fp) {
353 zend_shared_alloc_unlock_win32();
354 zend_win_error_message(ACCEL_LOG_WARNING, mmap_base_file, err);
355 zend_win_error_message(ACCEL_LOG_FATAL, "Unable to write base address", err);
356 return ALLOC_FAILURE;
357 }
358 fprintf(fp, "%p\n", mapping_base);
359 fclose(fp);
360 }
361
362 shared_segment->pos = 0;
363 shared_segment->size = requested_size;
364
365 zend_shared_alloc_unlock_win32();
366
367 return ALLOC_SUCCESS;
368 }
369
370 static int detach_segment(zend_shared_segment *shared_segment)
371 {
372 zend_shared_alloc_lock_win32();
373 if (mapping_base) {
374 UnmapViewOfFile(mapping_base);
375 }
376 CloseHandle(memfile);
377 zend_shared_alloc_unlock_win32();
378 CloseHandle(memory_mutex);
379 return 0;
380 }
381
382 static size_t segment_type_size(void)
383 {
384 return sizeof(zend_shared_segment);
385 }
386
387 zend_shared_memory_handlers zend_alloc_win32_handlers = {
388 create_segments,
389 detach_segment,
390 segment_type_size
391 };