summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2019-07-16 21:14:57 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2019-07-17 19:51:07 +0200
commite2ed7e6716f9564fcd8b13b823519baaa7256662 (patch)
tree2bfb9548254d4b3e77e5741e8064094243b87930
parent6f617b7759a12c341a055de42e06717ebf905130 (diff)
downloadphp-git-e2ed7e6716f9564fcd8b13b823519baaa7256662.tar.gz
Allow multiple cache instances per user/host on Windows
Formerly, there was at most a single OPcache instance per user and the so called system ID (which is determined from the PHP version). Sometimes multiple OPcaches might be desired, though, particularly for unrelated CLI scripts, which may even be necessary (e.g. for our test suite in parallel mode). We therefore introduce a new INI directive `opcache.cache_id` which allows to configure independent OPcache instances for the same user. We also use `GetUserNameW()` instead of `php_win32_get_username()`, because the latter retrieves the user name encoded in the `default_charset`, which can obviously yield different results for different charsets, leading to OPcache "incompatibilities". Slightly worse, some characters may not even be encodeable in the `default_charset` and would be replaced by question marks, which could result in different users sharing the same OPcache. We also refactor, and re-use existing APIs to avoid duplicated code.
-rw-r--r--.appveyor.yml2
-rw-r--r--ext/opcache/ZendAccelerator.c45
-rw-r--r--ext/opcache/ZendAccelerator.h6
-rw-r--r--ext/opcache/shared_alloc_win32.c23
-rw-r--r--ext/opcache/zend_accelerator_module.c6
-rw-r--r--ext/opcache/zend_file_cache.c21
-rw-r--r--php.ini-development4
-rw-r--r--php.ini-production4
-rwxr-xr-xrun-tests.php2
9 files changed, 62 insertions, 51 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 909a9ad65a..ab888c3493 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -33,7 +33,7 @@ environment:
PARALLEL: -j2
- THREAD_SAFE: 1
OPCACHE: 1
- PARALLEL:
+ PARALLEL: -j2
INTRINSICS: AVX
services:
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 6fe08d6faa..0c3109ee50 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -45,6 +45,7 @@
#include "zend_file_cache.h"
#include "ext/pcre/php_pcre.h"
#include "ext/standard/md5.h"
+#include "ext/hash/php_hash.h"
#ifndef ZEND_WIN32
#include <netdb.h>
@@ -54,6 +55,7 @@
typedef int uid_t;
typedef int gid_t;
#include <io.h>
+#include <lmcons.h>
#endif
#ifndef ZEND_WIN32
@@ -110,6 +112,9 @@ zend_accel_shared_globals *accel_shared_globals = NULL;
/* true globals, no need for thread safety */
char accel_system_id[32];
+#ifdef ZEND_WIN32
+char accel_uname_id[32];
+#endif
zend_bool accel_startup_ok = 0;
static char *zps_failure_reason = NULL;
char *zps_api_failure_reason = NULL;
@@ -2180,6 +2185,26 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
return zend_accel_load_script(persistent_script, from_shared_memory);
}
+#ifdef ZEND_WIN32
+static int accel_gen_uname_id(void)
+{
+ PHP_MD5_CTX ctx;
+ unsigned char digest[16];
+ wchar_t uname[UNLEN + 1];
+ DWORD unsize = UNLEN;
+
+ if (!GetUserNameW(uname, &unsize)) {
+ return FAILURE;
+ }
+ PHP_MD5Init(&ctx);
+ PHP_MD5Update(&ctx, (void *) uname, (unsize - 1) * sizeof(wchar_t));
+ PHP_MD5Update(&ctx, ZCG(accel_directives).cache_id, strlen(ZCG(accel_directives).cache_id));
+ PHP_MD5Final(digest, &ctx);
+ php_hash_bin2hex(accel_uname_id, digest, sizeof digest);
+ return SUCCESS;
+}
+#endif
+
/* zend_stream_open_function() replacement for PHP 5.3 and above */
static int persistent_stream_open_function(const char *filename, zend_file_handle *handle)
{
@@ -2609,9 +2634,7 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals)
static void accel_gen_system_id(void)
{
PHP_MD5_CTX context;
- unsigned char digest[16], c;
- char *md5str = accel_system_id;
- int i;
+ unsigned char digest[16];
PHP_MD5Init(&context);
PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
@@ -2623,14 +2646,7 @@ static void accel_gen_system_id(void)
PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
}
PHP_MD5Final(digest, &context);
- for (i = 0; i < 16; i++) {
- c = digest[i] >> 4;
- c = (c <= 9) ? c + '0' : c - 10 + 'a';
- md5str[i * 2] = c;
- c = digest[i] & 0x0f;
- c = (c <= 9) ? c + '0' : c - 10 + 'a';
- md5str[(i * 2) + 1] = c;
- }
+ php_hash_bin2hex(accel_system_id, digest, sizeof digest);
}
#ifdef HAVE_HUGE_CODE_PAGES
@@ -2821,6 +2837,13 @@ static int accel_startup(zend_extension *extension)
return FAILURE;
}
+#ifdef ZEND_WIN32
+ if (UNEXPECTED(accel_gen_uname_id() == FAILURE)) {
+ zps_startup_failure("Unable to get user name", NULL, accelerator_remove_cb);
+ return SUCCESS;
+ }
+#endif
+
#ifdef HAVE_HUGE_CODE_PAGES
if (ZCG(accel_directives).huge_code_pages &&
(strcmp(sapi_module.name, "cli") == 0 ||
diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h
index a0df1c148a..20ac84583d 100644
--- a/ext/opcache/ZendAccelerator.h
+++ b/ext/opcache/ZendAccelerator.h
@@ -185,6 +185,9 @@ typedef struct _zend_accel_directives {
zend_bool huge_code_pages;
#endif
char *preload;
+#ifdef ZEND_WIN32
+ char *cache_id;
+#endif
} zend_accel_directives;
typedef struct _zend_accel_globals {
@@ -270,6 +273,9 @@ typedef struct _zend_accel_shared_globals {
} zend_accel_shared_globals;
extern char accel_system_id[32];
+#ifdef ZEND_WIN32
+extern char accel_uname_id[32];
+#endif
extern zend_bool accel_startup_ok;
extern zend_bool file_cache_only;
#if ENABLE_FILE_CACHE_FALLBACK
diff --git a/ext/opcache/shared_alloc_win32.c b/ext/opcache/shared_alloc_win32.c
index 2d0cea1e97..35abe367cf 100644
--- a/ext/opcache/shared_alloc_win32.c
+++ b/ext/opcache/shared_alloc_win32.c
@@ -19,6 +19,7 @@
+----------------------------------------------------------------------+
*/
+#include "php.h"
#include "ZendAccelerator.h"
#include "zend_shared_alloc.h"
#include "zend_accelerator_util_funcs.h"
@@ -67,38 +68,24 @@ static void zend_win_error_message(int type, char *msg, int err)
static char *create_name_with_username(char *name)
{
- static char newname[MAXPATHLEN + UNLEN + 4 + 1 + 32];
- char *uname;
-
- uname = php_win32_get_username();
- if (!uname) {
- return NULL;
- }
- snprintf(newname, sizeof(newname) - 1, "%s@%s@%.32s", name, uname, accel_system_id);
-
- free(uname);
+ static char newname[MAXPATHLEN + 32 + 4 + 1 + 32];
+ snprintf(newname, sizeof(newname) - 1, "%s@%.32s@%.32s", name, accel_uname_id, accel_system_id);
return newname;
}
static char *get_mmap_base_file(void)
{
- static char windir[MAXPATHLEN+UNLEN + 3 + sizeof("\\\\@") + 1 + 32];
- char *uname;
+ static char windir[MAXPATHLEN+ 32 + 3 + sizeof("\\\\@") + 1 + 32];
int l;
- uname = php_win32_get_username();
- if (!uname) {
- return NULL;
- }
GetTempPath(MAXPATHLEN, windir);
l = strlen(windir);
if ('\\' == windir[l-1]) {
l--;
}
- snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%s@%.32s", ACCEL_FILEMAP_BASE, uname, accel_system_id);
- free(uname);
+ snprintf(windir + l, sizeof(windir) - l - 1, "\\%s@%.32s@%.32s", ACCEL_FILEMAP_BASE, accel_uname_id, accel_system_id);
return windir;
}
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
index bcbc927703..25f3cc5b81 100644
--- a/ext/opcache/zend_accelerator_module.c
+++ b/ext/opcache/zend_accelerator_module.c
@@ -321,6 +321,9 @@ ZEND_INI_BEGIN()
STD_PHP_INI_BOOLEAN("opcache.huge_code_pages" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.huge_code_pages, zend_accel_globals, accel_globals)
#endif
STD_PHP_INI_ENTRY("opcache.preload" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload, zend_accel_globals, accel_globals)
+#if ZEND_WIN32
+ STD_PHP_INI_ENTRY("opcache.cache_id" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.cache_id, zend_accel_globals, accel_globals)
+#endif
ZEND_INI_END()
static int filename_is_in_cache(zend_string *filename)
@@ -768,6 +771,9 @@ static ZEND_FUNCTION(opcache_get_configuration)
add_assoc_bool(&directives, "opcache.huge_code_pages", ZCG(accel_directives).huge_code_pages);
#endif
add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload));
+#if ZEND_WIN32
+ add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id));
+#endif
add_assoc_zval(return_value, "directives", &directives);
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index 2c6c16002e..b5bab36e4b 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -835,31 +835,13 @@ static char *zend_file_cache_get_bin_file_path(zend_string *script_path)
memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
#else
- PHP_MD5_CTX ctx;
- char md5uname[32];
- unsigned char digest[16], c;
- size_t i;
- char *uname = php_win32_get_username();
-
- PHP_MD5Init(&ctx);
- PHP_MD5Update(&ctx, uname, strlen(uname));
- PHP_MD5Final(digest, &ctx);
- for (i = 0; i < 16; i++) {
- c = digest[i] >> 4;
- c = (c <= 9) ? c + '0' : c - 10 + 'a';
- md5uname[i * 2] = c;
- c = digest[i] & 0x0f;
- c = (c <= 9) ? c + '0' : c - 10 + 'a';
- md5uname[(i * 2) + 1] = c;
- }
-
len = strlen(ZCG(accel_directives).file_cache);
filename = emalloc(len + 33 + 33 + ZSTR_LEN(script_path) + sizeof(SUFFIX));
memcpy(filename, ZCG(accel_directives).file_cache, len);
filename[len] = '\\';
- memcpy(filename + 1 + len, md5uname, 32);
+ memcpy(filename + 1 + len, accel_uname_id, 32);
len += 1 + 32;
filename[len] = '\\';
@@ -889,7 +871,6 @@ static char *zend_file_cache_get_bin_file_path(zend_string *script_path)
memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
}
- free(uname);
#endif
return filename;
diff --git a/php.ini-development b/php.ini-development
index eb30bd389e..fd96f43534 100644
--- a/php.ini-development
+++ b/php.ini-development
@@ -1851,6 +1851,10 @@ ldap.max_links = -1
; errors.
;opcache.mmap_base=
+; Facilitates multiple OPcache instances per user (for Windows only). All PHP
+; processes with the same cache ID and user share an OPcache instance.
+;opcache.cache_id=
+
; Enables and sets the second level cache directory.
; It should improve performance when SHM memory is full, at server restart or
; SHM reset. The default "" disables file based caching.
diff --git a/php.ini-production b/php.ini-production
index 229846698d..8883566156 100644
--- a/php.ini-production
+++ b/php.ini-production
@@ -1858,6 +1858,10 @@ ldap.max_links = -1
; errors.
;opcache.mmap_base=
+; Facilitates multiple OPcache instances per user (for Windows only). All PHP
+; processes with the same cache ID and user share an OPcache instance.
+;opcache.cache_id=
+
; Enables and sets the second level cache directory.
; It should improve performance when SHM memory is full, at server restart or
; SHM reset. The default "" disables file based caching.
diff --git a/run-tests.php b/run-tests.php
index f54dc2d37a..58e8fc1dba 100755
--- a/run-tests.php
+++ b/run-tests.php
@@ -2076,7 +2076,7 @@ TEST $file
}
// Default ini settings
- $ini_settings = array();
+ $ini_settings = $workerID ? array('opcache.cache_id' => "worker$workerID") : array();
// Additional required extensions
if (array_key_exists('EXTENSIONS', $section_text)) {