From 844d4b0f44c3197e845f97b02d89963a1d6a3e1d Mon Sep 17 00:00:00 2001 From: Mikko Date: Sun, 25 Sep 2016 18:16:30 +0100 Subject: [PATCH 1/2] Ensure that exiting process releases locks --- apc_lock.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++-- apc_lock_api.h | 3 +- config.m4 | 21 +++++++- 3 files changed, 159 insertions(+), 6 deletions(-) diff --git a/apc_lock.c b/apc_lock.c index 80697a41..1af93562 100644 --- a/apc_lock.c +++ b/apc_lock.c @@ -22,6 +22,107 @@ # include "apc_lock.h" #endif +#ifndef PHP_WIN32 +# ifndef APC_SPIN_LOCK +# ifndef APC_FCNTL_LOCK +# ifdef APC_LOCK_RECURSIVE +# define APC_LOCK_ROBUST 1 +# endif +# endif +# endif +#endif + + + +#ifdef APC_LOCK_ROBUST + +#include "apc_stack.h" + +/* + rwlocks don't support robustness so we have to hack around it +*/ +static + pthread_key_t lock_key; + +static +void release_all_locks(apc_stack_t *locks) { + if (!locks) { + return; + } + + if (apc_stack_size(locks) > 0) { + apc_lock_t *lock; + + while ((lock = (apc_lock_t *) apc_stack_pop(locks)) != NULL) { + apc_lock_wunlock(lock); + } + } + apc_stack_destroy(locks); +} + +static +void release_all_locks_atexit() { + apc_stack_t *stack = (apc_stack_t *) pthread_getspecific(lock_key); + + release_all_locks(stack); + pthread_setspecific(lock_key, NULL); +} + +static +void make_lock_key() { + (void) pthread_key_create(&lock_key, release_all_locks); +} + +static +void locked(apc_lock_t *lock) { + apc_stack_t *stack = pthread_getspecific(lock_key); + + if (!stack) { + stack = apc_stack_create(10); + atexit(release_all_locks_atexit); + } + apc_stack_push(stack, lock); + pthread_setspecific(lock_key, stack); +} + +static +void unlocked(apc_lock_t *lock) { + apc_stack_t *stack = (apc_stack_t *) pthread_getspecific(lock_key); + apc_lock_t *stacked; + + if (!stack || apc_stack_size(stack) == 0) { + return; + } + + if (apc_stack_top(stack) == lock) { + apc_stack_pop(stack); + return; + } + else { + /* are there any unpaired lock/unlocks? that's costly here */ + apc_stack_t *new_stack = apc_stack_create(10); + apc_lock_t *l; + + while ((l = apc_stack_pop(stack)) != NULL) { + if (l != lock) { + apc_stack_push(new_stack, l); + } + } + apc_stack_destroy(stack); + stack = new_stack; + } + + assert (stacked == lock); + pthread_setspecific(lock_key, stack); +} + +static +void lock_destroy(apc_lock_t *lock) { + unlocked(lock); +} + +#endif + /* APCu never checks the return value of a locking call, it assumes it should not fail and execution continues regardless, therefore it is pointless to check the return @@ -117,6 +218,10 @@ PHP_APCU_API zend_bool apc_lock_init() { /* once per process please */ apc_lock_ready = 1; +#ifdef APC_LOCK_ROBUST + make_lock_key(); +#endif + #ifndef APC_SPIN_LOCK # ifndef APC_FCNTL_LOCK # ifdef APC_LOCK_RECURSIVE @@ -147,9 +252,6 @@ PHP_APCU_API void apc_lock_cleanup() { if (!apc_lock_ready) return; - /* once per process please */ - apc_lock_ready = 0; - #ifndef APC_SPIN_LOCK # ifndef APC_FCNTL_LOCK # ifdef APC_LOCK_RECURSIVE @@ -157,9 +259,14 @@ PHP_APCU_API void apc_lock_cleanup() { # else pthread_rwlockattr_destroy(&apc_lock_attr); # endif +# ifdef APC_LOCK_ROBUST + pthread_key_delete(lock_key); +# endif # endif #endif #endif + /* once per process please */ + apc_lock_ready = 0; } /* }}} */ PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) { @@ -216,7 +323,12 @@ PHP_APCU_API zend_bool apc_lock_rlock(apc_lock_t *lock) { pthread_mutex_lock(lock); # else pthread_rwlock_rdlock(lock); -# endif +# endif + +# ifdef APC_LOCK_ROBUST + locked(lock); +# endif + # else { /* FCNTL */ @@ -244,6 +356,11 @@ PHP_APCU_API zend_bool apc_lock_wlock(apc_lock_t *lock) { # else pthread_rwlock_wrlock(lock); # endif + +# ifdef APC_LOCK_ROBUST + locked(lock); +# endif + # else { /* FCNTL */ @@ -271,6 +388,11 @@ PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) { # else pthread_rwlock_unlock(lock); # endif + +# ifdef APC_LOCK_ROBUST + unlocked(lock); +# endif + # else { /* FCNTL */ @@ -298,6 +420,12 @@ PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) { # else pthread_rwlock_unlock(lock); # endif + +# ifdef APC_LOCK_ROBUST + unlocked(lock); +# endif + + # else { /* FCNTL */ @@ -325,6 +453,11 @@ PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) { # else /* nothing */ # endif + +# ifdef APC_LOCK_ROBUST + lock_destroy(lock); +# endif + # else { /* FCNTL */ diff --git a/apc_lock_api.h b/apc_lock_api.h index 2a6e7793..78d3fbd5 100644 --- a/apc_lock_api.h +++ b/apc_lock_api.h @@ -35,7 +35,8 @@ # include "pthread.h" # ifndef APC_SPIN_LOCK # ifndef APC_FCNTL_LOCK -# if defined(APC_NATIVE_RWLOCK) && defined(HAVE_ATOMIC_OPERATIONS) + /* Disable native rwlocks on Mac. Implementation has issues */ +# if defined(APC_NATIVE_RWLOCK) && defined(HAVE_ATOMIC_OPERATIONS) && !defined(__APPLE__) typedef pthread_rwlock_t apc_lock_t; # define APC_LOCK_SHARED # else diff --git a/config.m4 b/config.m4 index 436a494e..38641524 100644 --- a/config.m4 +++ b/config.m4 @@ -61,6 +61,20 @@ AC_ARG_ENABLE(apcu-spinlocks, ]) AC_MSG_RESULT($PHP_APCU_SPINLOCK) +PHP_APCU_ROBUST_LOCK=no +AC_MSG_CHECKING(if APCu should utilize robust locks) +AC_ARG_ENABLE(apcu-robust-lock, +[ --enable-apcu-robust-lock Use robust locks], +[ if test "x$enableval" = "xno"; then + PHP_APCU_ROBUST_LOCK=no + else + PHP_APCU_ROBUST_LOCK=yes + AC_DEFINE(APC_ROBUST_LOCK, 1, [ ]) + fi +]) +AC_MSG_RESULT($PHP_APCU_ROBUST_LOCK) + + if test "$PHP_APCU" != "no"; then if test "$PHP_APCU_DEBUG" != "no"; then AC_DEFINE(APC_DEBUG, 1, [ ]) @@ -79,7 +93,12 @@ if test "$PHP_APCU" != "no"; then #include main() { pthread_rwlock_t rwlock; - pthread_rwlockattr_t attr; + pthread_rwlockattr_t attr; + + #ifdef __APPLE__ + puts("Disabling rwlocks on __APPLE__"); + return 1; + #endif if(pthread_rwlockattr_init(&attr)) { puts("Unable to initialize pthread attributes (pthread_rwlockattr_init)."); From cfb5fcc2a4dc5411ebe7eb0f1ea38b8cc12c4108 Mon Sep 17 00:00:00 2001 From: Mikko Date: Sun, 25 Sep 2016 18:26:06 +0100 Subject: [PATCH 2/2] Fix this --- apc_lock.c | 2 +- config.m4 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apc_lock.c b/apc_lock.c index 1af93562..533104a7 100644 --- a/apc_lock.c +++ b/apc_lock.c @@ -26,7 +26,7 @@ # ifndef APC_SPIN_LOCK # ifndef APC_FCNTL_LOCK # ifdef APC_LOCK_RECURSIVE -# define APC_LOCK_ROBUST 1 +# define APC_LOCK_ROBUST APC_ROBUST_LOCK_AVAILABLE # endif # endif # endif diff --git a/config.m4 b/config.m4 index 38641524..02c20cbe 100644 --- a/config.m4 +++ b/config.m4 @@ -69,7 +69,7 @@ AC_ARG_ENABLE(apcu-robust-lock, PHP_APCU_ROBUST_LOCK=no else PHP_APCU_ROBUST_LOCK=yes - AC_DEFINE(APC_ROBUST_LOCK, 1, [ ]) + AC_DEFINE(APC_ROBUST_LOCK_AVAILABLE, 1, [ ]) fi ]) AC_MSG_RESULT($PHP_APCU_ROBUST_LOCK)