Skip to content

ext/opcache: use pthread_mutex_t instead of a fcntl(F_SETLK) #10277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ext/opcache/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
72 changes: 59 additions & 13 deletions ext/opcache/zend_shared_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <pthread.h>

/**
* 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;
Expand Down Expand Up @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -471,18 +512,20 @@ 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;
mem_write_lock.l_whence = SEEK_SET;
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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down