diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 7e681bb112815..f2fb23cc56f1f 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -23,6 +23,18 @@ if test "$PHP_OPCACHE" != "no"; then dnl Always build as shared extension ext_shared=yes + if test "$pthreads_working" = "yes"; then + AC_CHECK_FUNC(pthread_mutexattr_setpshared, [ + AC_DEFINE(HAVE_PTHREAD_PROCESS_SHARED, 1, [Define to use pthread_mutexattr_setpshared(PTHREAD_PROCESS_SHARED)]) + if test -n "$ac_cv_pthreads_lib"; then + PHP_EVAL_LIBLINE(-l$ac_cv_pthreads_lib, OPCACHE_SHARED_LIBADD) + fi + if test -n "$ac_cv_pthreads_cflags"; then + PHP_EVAL_INCLINE($ac_cv_pthreads_cflags) + fi + ], []) + fi + if test "$PHP_HUGE_CODE_PAGES" = "yes"; then AC_DEFINE(HAVE_HUGE_CODE_PAGES, 1, [Define to enable copying PHP CODE pages into HUGE PAGES (experimental)]) fi diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 6fbf8ea20ae12..b221b1e60267c 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -55,6 +55,29 @@ static const char *g_shared_model; /* pointer to globals allocated in SHM and shared across processes */ zend_smm_shared_globals *smm_shared_globals; +#ifdef HAVE_PTHREAD_PROCESS_SHARED + +#include + +/** + * This struct is allocated from shared memory and contains a + * PTHREAD_PROCESS_SHARED mutex. + */ +struct opcache_locks { + /** + * The mutex for zend_shared_alloc_lock(). + */ + pthread_mutex_t alloc; +}; + +/** + * Note, this variable should not be put in struct zend_accel_globals + * because this is not a per-thread variable. + */ +static struct opcache_locks *opcache_locks; + +#endif // HAVE_PTHREAD_PROCESS_SHARED + #ifndef ZEND_WIN32 #ifdef ZTS static MUTEX_T zts_lock; @@ -82,12 +105,24 @@ static const zend_shared_memory_handler_entry handler_table[] = { #ifndef ZEND_WIN32 void zend_shared_alloc_create_lock(char *lockfile_path) { - int val; - #ifdef ZTS zts_lock = tsrm_mutex_alloc(); #endif +#ifdef HAVE_PTHREAD_PROCESS_SHARED + opcache_locks = mmap(NULL, sizeof(*opcache_locks), + PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, -1, 0); + if (opcache_locks == MAP_FAILED) { + zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Unable to create opcache_locks: %s (%d)", strerror(errno), errno); + } + + pthread_mutexattr_t mutexattr; + pthread_mutexattr_init(&mutexattr); + pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(&opcache_locks->alloc, &mutexattr); +#endif // HAVE_PTHREAD_PROCESS_SHARED + #if defined(__linux__) && defined(HAVE_MEMFD_CREATE) /* on Linux, we can use a memfd instead of a "real" file, so * we can do this without a writable filesystem and without @@ -108,7 +143,7 @@ void zend_shared_alloc_create_lock(char *lockfile_path) fchmod(lock_file, 0666); - val = fcntl(lock_file, F_GETFD, 0); + int val = fcntl(lock_file, F_GETFD, 0); val |= FD_CLOEXEC; fcntl(lock_file, F_SETFD, val); @@ -320,6 +355,12 @@ void zend_shared_alloc_shutdown(void) } ZSMMG(shared_segments) = NULL; g_shared_alloc_handler = NULL; + +#ifdef HAVE_PTHREAD_PROCESS_SHARED + pthread_mutex_destroy(&opcache_locks->alloc); + munmap(opcache_locks, sizeof(opcache_locks)); +#endif + #ifndef ZEND_WIN32 close(lock_file); @@ -471,7 +512,13 @@ void zend_shared_alloc_lock(void) { ZEND_ASSERT(!ZCG(locked)); -#ifndef ZEND_WIN32 +#if !defined(ZEND_WIN32) && defined(ZTS) + tsrm_mutex_lock(zts_lock); +#endif + +#ifdef HAVE_PTHREAD_PROCESS_SHARED + pthread_mutex_lock(&opcache_locks->alloc); +#elif !defined(ZEND_WIN32) struct flock mem_write_lock; mem_write_lock.l_type = F_WRLCK; @@ -479,10 +526,6 @@ void zend_shared_alloc_lock(void) mem_write_lock.l_start = 0; mem_write_lock.l_len = 1; -#ifdef ZTS - tsrm_mutex_lock(zts_lock); -#endif - #if 0 /* this will happen once per process, and will un-globalize mem_write_lock */ if (mem_write_lock.l_pid == -1) { @@ -510,7 +553,7 @@ void zend_shared_alloc_unlock(void) { ZEND_ASSERT(ZCG(locked)); -#ifndef ZEND_WIN32 +#if !defined(ZEND_WIN32) && !defined(HAVE_PTHREAD_PROCESS_SHARED) struct flock mem_write_unlock; mem_write_unlock.l_type = F_UNLCK; @@ -521,16 +564,19 @@ void zend_shared_alloc_unlock(void) ZCG(locked) = 0; -#ifndef ZEND_WIN32 +#ifdef HAVE_PTHREAD_PROCESS_SHARED + pthread_mutex_unlock(&opcache_locks->alloc); +#elif !defined(ZEND_WIN32) if (fcntl(lock_file, F_SETLK, &mem_write_unlock) == -1) { zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot remove lock - %s (%d)", strerror(errno), errno); } -#ifdef ZTS - tsrm_mutex_unlock(zts_lock); -#endif #else zend_shared_alloc_unlock_win32(); #endif + +#if !defined(ZEND_WIN32) && defined(ZTS) + tsrm_mutex_unlock(zts_lock); +#endif } void zend_shared_alloc_init_xlat_table(void)